commit e7fc91e0e77ef4d7723ec77b485a2066e018fd62 Author: Shohrat Date: Thu Mar 9 00:44:42 2023 +0500 first commit diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..71464e1 --- /dev/null +++ b/.babelrc @@ -0,0 +1,13 @@ +{ + "presets": ["@babel/preset-env"], + "plugins": [ + [ + "module-resolver", { + "root": ["."], + "alias": { + "helpers": "./tests/js/helpers" + } + } + ] + ] +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6af90e1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..63a1b61 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Composer ignores +/vendor +composer.phar +composer.lock + +# Framework ignores +.env +.env.*.php +.env.php +selenium.php +/bootstrap/compiled.php +.phpunit.result.cache + +# Hosting ignores +php_errors.log +nginx-error.log +nginx-access.log +nginx-ssl.access.log +nginx-ssl.error.log +sftp-config.json +.ftpconfig + +# Editor ignores +nbproject +.idea +.vscode +_ide_helper.php + +# Other ignores +.DS_Store +package-lock.json +/node_modules diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..ce6d788 --- /dev/null +++ b/.htaccess @@ -0,0 +1,64 @@ + + + + Options -MultiViews + + + RewriteEngine On + + + Header set Access-Control-Allow-Origin "*" + + + ## + ## You may need to uncomment the following line for some hosting environments, + ## if you have installed to a subdirectory, enter the name here also. + ## + # RewriteBase / + + ## + ## Uncomment following lines to force HTTPS. + ## + # RewriteCond %{HTTPS} off + # RewriteRule (.*) https://%{SERVER_NAME}/$1 [L,R=301] + + ## + ## Black listed folders + ## + RewriteRule ^bootstrap/.* index.php [L,NC] + RewriteRule ^config/.* index.php [L,NC] + RewriteRule ^vendor/.* index.php [L,NC] + RewriteRule ^storage/cms/.* index.php [L,NC] + RewriteRule ^storage/logs/.* index.php [L,NC] + RewriteRule ^storage/framework/.* index.php [L,NC] + RewriteRule ^storage/temp/protected/.* index.php [L,NC] + RewriteRule ^storage/app/uploads/protected/.* index.php [L,NC] + + ## + ## White listed folders + ## + RewriteCond %{REQUEST_FILENAME} -f + RewriteCond %{REQUEST_FILENAME} !/.well-known/* + RewriteCond %{REQUEST_FILENAME} !/storage/app/uploads/public/.* + RewriteCond %{REQUEST_FILENAME} !/storage/app/media/.* + RewriteCond %{REQUEST_FILENAME} !/storage/app/resized/.* + RewriteCond %{REQUEST_FILENAME} !/storage/temp/public/.* + RewriteCond %{REQUEST_FILENAME} !/themes/.*/(assets|resources)/.* + RewriteCond %{REQUEST_FILENAME} !/plugins/.*/(assets|resources)/.* + RewriteCond %{REQUEST_FILENAME} !/modules/.*/(assets|resources)/.* + RewriteRule !^index.php index.php [L,NC] + + ## + ## Block all PHP files, except index + ## + RewriteCond %{REQUEST_FILENAME} -f + RewriteCond %{REQUEST_FILENAME} \.php$ + RewriteRule !^index.php index.php [L,NC] + + ## + ## Standard routes + ## + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + + diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..bb55890 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,5 @@ +{ + "esversion": 6, + "curly": true, + "asi": true +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..7c2a2c0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1 @@ +View the changelog on the [OctoberCMS website](https://octobercms.com/changelog) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..bacdb20 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,5 @@ +# Code of Conduct + +We promise to extend courtesy and respect to everyone opening an issue. We expect anyone using the bug trackers to do the same. + +All reported issues to this project are valuable. Please act with respect and avoid demeaning, condescending, racist, sexist and other inappropriate language and conduct. Please ensure comments stay professional and constructive. \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cfd9b6c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2013-2021 Alexey Bobkov, Samuel Georges, October CMS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9ba7fa0 --- /dev/null +++ b/README.md @@ -0,0 +1,75 @@ +

+ October +

+ +[October](https://octobercms.com) is a Content Management System (CMS) and web platform whose sole purpose is to make your development workflow simple again. It was born out of frustration with existing systems. We feel building websites has become a convoluted and confusing process that leaves developers unsatisfied. We want to turn you around to the simpler side and get back to basics. + +October's mission is to show the world that web development is not rocket science. + +![Stable Build](https://github.com/octobercms/october/workflows/Tests/badge.svg?branch=1.1) +[![License](https://poser.pugx.org/october/october/license.svg)](https://packagist.org/packages/october/october) + +## Installing October + +Instructions on how to install October can be found at the [installation guide](https://octobercms.com/docs/setup/installation). + +### Quick Start Installation + +If you have composer installed, run this in your terminal to install October CMS from command line. This will place the files in a directory named **myoctober**. + + composer create-project october/october myoctober + +If you plan on using a database, run this command inside the application directory. + + php artisan october:install + +## Learning October + +The best place to learn October is by [reading the documentation](https://octobercms.com/docs), [watching some screencasts](https://octobercms.com/support/topic/screencast) or [following some tutorials](https://octobercms.com/support/articles/tutorials). + +You may also watch these introductory videos for [beginners](https://vimeo.com/79963873) and [advanced users](https://vimeo.com/172202661). + +## Development Team + +October was created by [Alexey Bobkov](https://www.linkedin.com/in/alexey-bobkov-232ba02b/) and [Samuel Georges](https://www.linkedin.com/in/samuel-georges-0a964131/), who both continue to develop the platform. + +## Foundation library + +The CMS uses [Laravel](https://laravel.com) as a foundation PHP framework. + +## Contact + +You can communicate with us using the following mediums: + +* [Follow us on Twitter](https://twitter.com/octobercms) for announcements and updates. +* [Follow us on Facebook](https://facebook.com/octobercms) for announcements and updates. +* [Join the Official Forum](https://octobercms.com/forum) to engage with the community. +* [Join us on Discord](https://octobercms.com/chat) to chat with us. + +### Premium Support + +October CMS can provide premium support for a monthly fee. Find out more via the [Premium Support Program](https://octobercms.com/premium-support). + +## Contributing + +Before sending a Pull Request, be sure to review the [Contributing Guidelines](.github/CONTRIBUTING.md) first. We are currently operating on a smaller staff and it may take some time to reach your issue. For priority issues, consider purchasing a [premium support plan](https://octobercms.com/premium-support). + +### Coding standards + +Please follow the following guides and code standards: + +* [PSR 4 Autoloader](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) +* [PSR 2 Coding Style Guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) +* [PSR 1 Coding Standards](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) + +### Code of Conduct + +In order to ensure that the October CMS community is welcoming to all, please review and abide by the [Code of Conduct](CODE_OF_CONDUCT.md). + +## License + +The October CMS platform is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). + +## Security Vulnerabilities + +Please review [our security policy](https://github.com/octobercms/october/security/policy) on how to report security vulnerabilities. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..182f232 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +**Please do NOT disclose security-related issues in public, [see instructions below](#reporting-a-vulnerability).** + +## Supported Versions + +October CMS is an evergreen product, no one version is singled out for security fixes because there is no way to update just one version. Builds are continually released and security fixes will always be available in the latest build. We encourage all users to upgrade their websites to the latest version. + +In cases where there are platform versioning constraints, such as old version of Laravel or PHP, we will make a best effort to backport security fixes to these compatible versions. + +## Reporting a Vulnerability + +If you discover a security vulnerability within October CMS, please send an email the security team at hello@octobercms.com. All security vulnerabilities will be promptly addressed. diff --git a/artisan b/artisan new file mode 100644 index 0000000..df630d0 --- /dev/null +++ b/artisan @@ -0,0 +1,51 @@ +#!/usr/bin/env php +make(Illuminate\Contracts\Console\Kernel::class); + +$status = $kernel->handle( + $input = new Symfony\Component\Console\Input\ArgvInput, + new Symfony\Component\Console\Output\ConsoleOutput +); + +/* +|-------------------------------------------------------------------------- +| Shutdown The Application +|-------------------------------------------------------------------------- +| +| Once Artisan has finished running. We will fire off the shutdown events +| so that any final work may be done by the application before we shut +| down the process. This is the last thing to happen to the request. +| +*/ + +$kernel->terminate($input, $status); + +exit($status); diff --git a/bootstrap/app.php b/bootstrap/app.php new file mode 100644 index 0000000..cc0ec8d --- /dev/null +++ b/bootstrap/app.php @@ -0,0 +1,55 @@ +singleton( + Illuminate\Contracts\Http\Kernel::class, + October\Rain\Foundation\Http\Kernel::class +); + +$app->singleton( + Illuminate\Contracts\Console\Kernel::class, + October\Rain\Foundation\Console\Kernel::class +); + +$app->singleton( + Illuminate\Contracts\Debug\ExceptionHandler::class, + October\Rain\Foundation\Exception\Handler::class +); + +/* +|-------------------------------------------------------------------------- +| Return The Application +|-------------------------------------------------------------------------- +| +| This script returns the application instance. The instance is given to +| the calling script so we can separate the building of the instances +| from the actual running of the application and sending responses. +| +*/ + +return $app; diff --git a/bootstrap/autoload.php b/bootstrap/autoload.php new file mode 100644 index 0000000..6533c54 --- /dev/null +++ b/bootstrap/autoload.php @@ -0,0 +1,37 @@ +=7.2.9", + "october/rain": "1.1.*", + "october/system": "1.1.*", + "october/backend": "1.1.*", + "october/cms": "1.1.*", + "laravel/framework": "~6.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.4|^9.3.3", + "mockery/mockery": "~1.3.3|^1.4.2", + "fzaninotto/faker": "~1.9", + "squizlabs/php_codesniffer": "3.*", + "php-parallel-lint/php-parallel-lint": "^1.0", + "dms/phpunit-arraysubset-asserts": "^0.1.0|^0.2.1" + }, + "autoload-dev": { + "classmap": [ + "tests/concerns/InteractsWithAuthentication.php", + "tests/fixtures/backend/models/UserFixture.php", + "tests/TestCase.php", + "tests/PluginTestCase.php" + ] + }, + "scripts": { + "post-create-project-cmd": [ + "php artisan key:generate" + ], + "post-update-cmd": [ + "php artisan october:version" + ], + "test": [ + "phpunit --stop-on-failure" + ], + "lint": [ + "parallel-lint --exclude vendor --exclude storage --exclude tests/fixtures/plugins/testvendor/goto/Plugin.php ." + ], + "sniff": [ + "phpcs --colors -nq --report=\"full\" --extensions=\"php\"" + ] + }, + "config": { + "preferred-install": "dist", + "allow-plugins": { + "composer/installers": true + } + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000..3ba7623 --- /dev/null +++ b/config/app.php @@ -0,0 +1,199 @@ + env('APP_DEBUG', true), + + /* + |-------------------------------------------------------------------------- + | Application Name + |-------------------------------------------------------------------------- + | + | This value is the name of your application. This value is used when the + | framework needs to place the application's name in a notification or + | any other location as required by the application or its packages. + */ + + 'name' => 'October CMS', + + /* + |-------------------------------------------------------------------------- + | Application URL + |-------------------------------------------------------------------------- + | + | This URL is used by the console to properly generate URLs when using + | the Artisan command line tool. You should set this to the root of + | your application so that it is used when running Artisan tasks. + | + */ + + 'url' => env('APP_URL', 'http://localhost'), + + /* + |-------------------------------------------------------------------------- + | Trusted hosts + |-------------------------------------------------------------------------- + | + | You may specify valid hosts for your application as an array or boolean + | below. This helps prevent host header poisoning attacks. + | + | Possible values: + | - `true`: Trust the host specified in app.url, as well as the "www" + | subdomain, if applicable. + | - `false`: Disable the trusted hosts feature. + | - array: Defines the domains to be trusted hosts. Each item should be + | a string defining a domain, IP address, or a regex pattern. + | + | Example of array values: + | + | 'trustedHosts' => [ + | 'example.com', // Matches just example.com + | 'www.example.com', // Matches just www.example.com + | '^(.+\.)?example\.com$', // Matches example.com and all subdomains + | 'https://example.com', // Matches just example.com + | ], + | + | NOTE: Even when set to `false`, this functionality is explicitly enabled + | on the Backend password reset flow for security reasons. + */ + + 'trustedHosts' => false, + + /* + |-------------------------------------------------------------------------- + | Application Timezone + |-------------------------------------------------------------------------- + | + | Here you may specify the default timezone for your application, which + | will be used by the PHP date and date-time functions. We have gone + | ahead and set this to a sensible default for you out of the box. + | + | + | -------- STOP! -------- + | Before you change this value, consider carefully if that is actually + | what you want to do. It is HIGHLY recommended that this is always set + | to UTC (as your server & DB timezone should be as well) and instead you + | use cms.backendTimezone to set the default timezone used in the backend + | to display dates & times. + | + */ + + 'timezone' => 'UTC', + + /* + |-------------------------------------------------------------------------- + | Application Locale Configuration + |-------------------------------------------------------------------------- + | + | The application locale determines the default locale that will be used + | by the translation service provider. You are free to set this value + | to any of the locales which will be supported by the application. + | + | WARNING: Avoid setting this to a locale that is not supported by the + | backend yet, as this can cause issues in the backend. + | + | Currently supported backend locales are listed in + | Backend\Models\Preference->getLocaleOptions()) + | + */ + + 'locale' => 'en', + + /* + |-------------------------------------------------------------------------- + | Application Fallback Locale + |-------------------------------------------------------------------------- + | + | The fallback locale determines the locale to use when the current one + | is not available. You may change the value to correspond to any of + | the language folders that are provided through your application. + | + */ + + 'fallback_locale' => 'en', + + /* + |-------------------------------------------------------------------------- + | Encryption Key + |-------------------------------------------------------------------------- + | + | This key is used by the Illuminate encrypter service and should be set + | to a random, 32 character string, otherwise these encrypted strings + | will not be safe. Please do this before deploying an application! + | + */ + + 'key' => env('APP_KEY', ''), + + 'cipher' => 'AES-256-CBC', + + /* + |-------------------------------------------------------------------------- + | Autoloaded Service Providers + |-------------------------------------------------------------------------- + | + | The service providers listed here will be automatically loaded on the + | request to your application. Feel free to add your own services to + | this array to grant expanded functionality to your applications. + | + */ + + 'providers' => array_merge(include(base_path('modules/system/providers.php')), [ + + // 'Illuminate\Html\HtmlServiceProvider', // Example + + 'System\ServiceProvider', + ]), + + /* + |-------------------------------------------------------------------------- + | Load automatically discovered packages + |-------------------------------------------------------------------------- + | + | By default, October CMS disables the loading of discovered packages + | through Laravel's package discovery service, in order to allow packages + | used by plugins to be disabled if the plugin itself is disabled. + | + | Set this to `true` to enable automatic loading of these packages. This + | will result in packages being loaded, even if the plugin using them is + | disabled. This is NOT RECOMMENDED. + | + | Please note that packages defined in `app.providers` will still be loaded + | even if discovery is disabled. + | + */ + + 'loadDiscoveredPackages' => false, + + /* + |-------------------------------------------------------------------------- + | Class Aliases + |-------------------------------------------------------------------------- + | + | This array of class aliases will be registered when this application + | is started. However, feel free to register as many as you wish as + | the aliases are "lazy" loaded so they don't hinder performance. + | + */ + + 'aliases' => array_merge(include(base_path('modules/system/aliases.php')), [ + + // 'Str' => 'Illuminate\Support\Str', // Example + + ]), + +]; diff --git a/config/auth.php b/config/auth.php new file mode 100644 index 0000000..8dc13b6 --- /dev/null +++ b/config/auth.php @@ -0,0 +1,39 @@ + [ + /* + |-------------------------------------------------------------------------- + | Enable throttling of Backend authentication attempts + |-------------------------------------------------------------------------- + | + | If set to true, users will be given a limited number of attempts to sign + | in to the Backend before being blocked for a specified number of minutes. + | + */ + 'enabled' => true, + + /* + |-------------------------------------------------------------------------- + | Failed Authentication Attempt Limit + |-------------------------------------------------------------------------- + | + | Number of failed attempts allowed while trying to authenticate a user. + | + */ + 'attemptLimit' => 5, + + /* + |-------------------------------------------------------------------------- + | Suspension Time + |-------------------------------------------------------------------------- + | + | The number of minutes to suspend further attempts on authentication once + | the attempt limit is reached. + | + */ + 'suspensionTime' => 15, + ], + +]; diff --git a/config/broadcasting.php b/config/broadcasting.php new file mode 100644 index 0000000..ed373cb --- /dev/null +++ b/config/broadcasting.php @@ -0,0 +1,52 @@ + 'pusher', + + /* + |-------------------------------------------------------------------------- + | Broadcast Connections + |-------------------------------------------------------------------------- + | + | Here you may define all of the broadcast connections that will be used + | to broadcast events to other systems or over websockets. Samples of + | each available type of connection are provided inside this array. + | + */ + + 'connections' => [ + + 'pusher' => [ + 'driver' => 'pusher', + 'key' => '', + 'secret' => '', + 'app_id' => '', + 'options' => [ + // + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + ], + + 'log' => [ + 'driver' => 'log', + ], + + ], + +]; diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000..93bfc05 --- /dev/null +++ b/config/cache.php @@ -0,0 +1,116 @@ + env('CACHE_DRIVER', 'file'), + + /* + |-------------------------------------------------------------------------- + | Cache Stores + |-------------------------------------------------------------------------- + | + | Here you may define all of the cache "stores" for your application as + | well as their drivers. You may even define multiple stores for the + | same cache driver to group types of items stored in your caches. + | + */ + + 'stores' => [ + + 'apc' => [ + 'driver' => 'apc', + ], + + 'array' => [ + 'driver' => 'array', + ], + + 'database' => [ + 'driver' => 'database', + 'table' => 'cache', + 'connection' => null, + ], + + 'file' => [ + 'driver' => 'file', + 'path' => storage_path('framework/cache'), + ], + + 'memcached' => [ + 'driver' => 'memcached', + 'servers' => [ + [ + 'host' => '127.0.0.1', + 'port' => 11211, + 'weight' => 100, + ], + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefix + |-------------------------------------------------------------------------- + | + | When utilizing a RAM based store such as APC or Memcached, there might + | be other applications utilizing the same cache. So, we'll specify a + | value to get prefixed to all our keys so we can avoid collisions. + | + */ + + 'prefix' => 'october', + + /* + |-------------------------------------------------------------------------- + | Cache Key for the CMS' PHP code parser cache + |-------------------------------------------------------------------------- + | + | This option controls the cache key used by the CMS when storing generated + | PHP from the theme PHP sections. Recommended to change this when multiple + | servers running OctoberCMS are connected to the same cache server to + | prevent conflicts. + | + */ + + 'codeParserDataCacheKey' => 'cms-php-file-data', + + /* + |-------------------------------------------------------------------------- + | Disable Request Cache + |-------------------------------------------------------------------------- + | + | The request cache stores cache retrievals from the cache store + | in memory to speed up consecutive retrievals within the same request. + | + | true - always disable this in-memory request cache + | + | false - always enable; be aware that long-running console commands + | (including queue workers) may retain cache entries in memory that + | have been changed in other processes or would have otherwise + | expired, causing issues with the `queue:restart` command, for + | example + | + | null - enable for HTTP requests, disable when running in CLI + | + */ + + 'disableRequestCache' => null, +]; diff --git a/config/cms.php b/config/cms.php new file mode 100644 index 0000000..9669470 --- /dev/null +++ b/config/cms.php @@ -0,0 +1,470 @@ + 'demo', + + /* + |-------------------------------------------------------------------------- + | Bleeding edge updates + |-------------------------------------------------------------------------- + | + | If you are developing with October, it is important to have the latest + | code base. Set this value to 'true' to tell the platform to download + | and use the development copies of core files and plugins. + | + */ + + 'edgeUpdates' => false, + + /* + |-------------------------------------------------------------------------- + | Back-end URI prefix + |-------------------------------------------------------------------------- + | + | Specifies the URL name used for accessing back-end pages. + | For example: backend -> http://localhost/backend + | + */ + + 'backendUri' => 'backend', + + /* + |-------------------------------------------------------------------------- + | Back-end force HTTPS security + |-------------------------------------------------------------------------- + | + | Use this setting to force a secure protocol when accessing any back-end + | pages, including the authentication pages. This is usually handled by + | web server config, but can be handled by the app for added security. + | + */ + + 'backendForceSecure' => false, + + /* + |-------------------------------------------------------------------------- + | Back-end login remember + |-------------------------------------------------------------------------- + | + | Define live duration of backend sessions: + | + | true - session never expire (cookie expiration in 5 years) + | + | false - session have a limited time (see session.lifetime) + | + | null - The form login display a checkbox that allow user to choose + | wanted behavior + | + */ + + 'backendForceRemember' => true, + + /* + |-------------------------------------------------------------------------- + | Back-end timezone + |-------------------------------------------------------------------------- + | + | This acts as the default setting for a back-end user's timezone. This can + | be changed by the user at any time using the backend preferences. All + | dates displayed in the back-end will be converted to this timezone. + | + */ + + 'backendTimezone' => 'UTC', + + /* + |-------------------------------------------------------------------------- + | Back-end Skin + |-------------------------------------------------------------------------- + | + | Specifies the back-end skin to use. + | + */ + + 'backendSkin' => 'Backend\Skins\Standard', + + /* + |-------------------------------------------------------------------------- + | Automatically run migrations on login + |-------------------------------------------------------------------------- + | + | If value is true, UpdateManager will be run on logging in to the backend. + | It's recommended to set this value to 'null' in production enviroments + | because it clears the cache every time a user logs in to the backend. + | If set to null, this setting is enabled when debug mode (app.debug) is enabled + | and disabled when debug mode is disabled. + | + */ + + 'runMigrationsOnLogin' => null, + + /* + |-------------------------------------------------------------------------- + | Determines which modules to load + |-------------------------------------------------------------------------- + | + | Specify which modules should be registered when using the application. + | + */ + + 'loadModules' => ['System', 'Backend', 'Cms'], + + /* + |-------------------------------------------------------------------------- + | Prevents application updates + |-------------------------------------------------------------------------- + | + | If using composer or git to download updates to the core files, set this + | value to 'true' to prevent the update gateway from trying to download + | these files again as part of the application update process. Plugins + | and themes will still be downloaded. + | + */ + + 'disableCoreUpdates' => true, + + /* + |-------------------------------------------------------------------------- + | Specific plugins to disable + |-------------------------------------------------------------------------- + | + | Specify plugin codes which will always be disabled in the application. + | + */ + + 'disablePlugins' => [], + + /* + |-------------------------------------------------------------------------- + | Determines if the routing caching is enabled. + |-------------------------------------------------------------------------- + | + | If the caching is enabled, the page URL map is saved in the cache. If a page + | URL was changed on the disk, the old URL value could be still saved in the cache. + | To update the cache the back-end Clear Cache feature should be used. It is recommended + | to disable the caching during the development, and enable it in the production mode. + | + */ + + 'enableRoutesCache' => env('ROUTES_CACHE', false), + + /* + |-------------------------------------------------------------------------- + | Time to live for the URL map. + |-------------------------------------------------------------------------- + | + | The URL map used in the CMS page routing process. By default + | the map is updated every time when a page is saved in the back-end or when the + | interval, in minutes, specified with the urlMapCacheTTL parameter expires. + | + */ + + 'urlCacheTtl' => 10, + + /* + |-------------------------------------------------------------------------- + | Time to live for parsed CMS objects. + |-------------------------------------------------------------------------- + | + | Specifies the number of minutes the CMS object cache lives. After the interval + | is expired item are re-cached. Note that items are re-cached automatically when + | the corresponding template file is modified. + | + */ + + 'parsedPageCacheTTL' => 10, + + /* + |-------------------------------------------------------------------------- + | Determines if the asset caching is enabled. + |-------------------------------------------------------------------------- + | + | If the caching is enabled, combined assets are cached. If a asset file + | is changed on the disk, the old file contents could be still saved in the cache. + | To update the cache the back-end Clear Cache feature should be used. It is recommended + | to disable the caching during the development, and enable it in the production mode. + | + */ + + 'enableAssetCache' => env('ASSET_CACHE', false), + + /* + |-------------------------------------------------------------------------- + | Determines if the asset minification is enabled. + |-------------------------------------------------------------------------- + | + | If the minification is enabled, combined assets are compressed (minified). + | It is recommended to disable the minification during development, and + | enable it in production mode. If set to null, assets are minified + | when debug mode (app.debug) is disabled. + | + */ + + 'enableAssetMinify' => null, + + /* + |-------------------------------------------------------------------------- + | Check import timestamps when combining assets + |-------------------------------------------------------------------------- + | + | If deep hashing is enabled, the combiner cache will be reset when a change + | is detected on imported files, in addition to those referenced directly. + | This will cause slower page performance. If set to null, deep hashing + | is used when debug mode (app.debug) is enabled. + | + */ + + 'enableAssetDeepHashing' => null, + + /* + |-------------------------------------------------------------------------- + | Database-driven Themes + |-------------------------------------------------------------------------- + | + | Stores theme templates in the database instead of the filesystem. + | + | false - All theme templates are sourced from the filesystem. + | + | true - Source theme templates from the database with fallback to the filesytem. + | + | null - Setting equal to the inverse of app.debug: debug enabled, this disabled. + | + | The database layer stores all modified CMS files in the database. Files that are + | not modified continue to be loaded from the filesystem. The `theme:sync $themeDir` + | console command is available to populate the database from the filesystem with + | the `--toFile` flag to sync in the other direction (database to filesystem) and + | the `--paths="/path/to/file.md,/path/to/file2.md" flag to sync only specific files. + | + | Files modified in the database are cached to indicate that they should be loaded + | from the database. + | + */ + + 'databaseTemplates' => env('DATABASE_TEMPLATES', false), + + /* + |-------------------------------------------------------------------------- + | Public plugins path + |-------------------------------------------------------------------------- + | + | Specifies the public plugins path relative to the application base URL, + | or you can specify a full URL path. + | + */ + + 'pluginsPath' => '/plugins', + + /* + |-------------------------------------------------------------------------- + | Public themes path + |-------------------------------------------------------------------------- + | + | Specifies the public themes path relative to the application base URL, + | or you can specify a full URL path. + | + */ + + 'themesPath' => '/themes', + + /* + |-------------------------------------------------------------------------- + | Resource storage + |-------------------------------------------------------------------------- + | + | Specifies the configuration for resource storage, such as media and + | upload files. These resources are used: + | + | media - generated by the media manager. + | uploads - generated by attachment model relationships. + | resized - generated by System\Classes\ImageResizer or the resize() Twig filter + | + | For each resource you can specify: + | + | disk - filesystem disk, as specified in filesystems.php config. + | folder - a folder prefix for storing all generated files inside. + | path - the public path relative to the application base URL, + | or you can specify a full URL path. + | + | Optionally, you can specify how long temporary URLs to protected files + | in cloud storage (ex. AWS, RackSpace) are valid for by setting + | temporaryUrlTTL to a value in seconds to define a validity period. This + | is only used for the 'uploads' config when using a supported cloud disk + | + | NOTE: If you have installed October in a subfolder, are using local + | storage and are not using a linkPolicy of 'force' you should include + | the path to the subfolder in the `path` option for these storage + | configurations. + | + | Example: October is installed under https://localhost/projects/october. + | You should then specify `/projects/october/storage/app/uploads` as the + | path for the uploads disk and `/projects/october/storage/app/media` as + | the path for the media disk. + */ + + 'storage' => [ + + 'uploads' => [ + 'disk' => 'local', + 'folder' => 'uploads', + 'path' => '/storage/app/uploads', + 'temporaryUrlTTL' => 3600, + ], + + 'media' => [ + 'disk' => 'local', + 'folder' => 'media', + 'path' => '/storage/app/media', + ], + + 'resized' => [ + 'disk' => 'local', + 'folder' => 'resized', + 'path' => '/storage/app/resized', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Convert Line Endings + |-------------------------------------------------------------------------- + | + | Determines if October should convert line endings from the windows style + | \r\n to the unix style \n. + | + */ + + 'convertLineEndings' => false, + + /* + |-------------------------------------------------------------------------- + | Linking policy + |-------------------------------------------------------------------------- + | + | Controls how URL links are generated throughout the application. + | + | detect - detect hostname and use the current schema + | secure - detect hostname and force HTTPS schema + | insecure - detect hostname and force HTTP schema + | force - force hostname and schema using app.url config value + | + */ + + 'linkPolicy' => env('LINK_POLICY', 'detect'), + + /* + |-------------------------------------------------------------------------- + | Default permission mask + |-------------------------------------------------------------------------- + | + | Specifies a default file and folder permission for newly created objects. + | + */ + + 'defaultMask' => ['file' => null, 'folder' => null], + + /* + |-------------------------------------------------------------------------- + | Safe mode + |-------------------------------------------------------------------------- + | + | If safe mode is enabled, the PHP code section is disabled in the CMS + | for security reasons. If set to null, safe mode is enabled when + | debug mode (app.debug) is disabled. + | + */ + + 'enableSafeMode' => null, + + /* + |-------------------------------------------------------------------------- + | Cross Site Request Forgery (CSRF) Protection + |-------------------------------------------------------------------------- + | + | If the CSRF protection is enabled, all "postback" & AJAX requests are + | checked for a valid security token. + | + */ + + 'enableCsrfProtection' => env('ENABLE_CSRF', true), + + /* + |-------------------------------------------------------------------------- + | Force bytecode invalidation + |-------------------------------------------------------------------------- + | + | When using OPcache with opcache.validate_timestamps set to 0 or APC + | with apc.stat set to 0 and Twig cache enabled, clearing the template + | cache won't update the cache, set to true to get around this. + | + */ + + 'forceBytecodeInvalidation' => true, + + /* + |-------------------------------------------------------------------------- + | Twig Strict Variables + |-------------------------------------------------------------------------- + | + | If strict_variables is disabled, Twig will silently ignore invalid + | variables (variables and or attributes/methods that do not exist) and + | replace them with a null value. When enabled, Twig throws an exception + | instead. If set to null, it is enabled when debug mode (app.debug) is + | enabled. + | + */ + + 'enableTwigStrictVariables' => false, + + /* + |-------------------------------------------------------------------------- + | Base Directory Restriction + |-------------------------------------------------------------------------- + | + | Restricts loading backend template and config files to within the base + | directory of the application. + | + | WARNING: This should always be enabled for security reasons. However, in + | some cases you may need to disable this; for instance when developing + | plugins that are stored elsewhere in the filesystem for organizational + | reasons and then symlinked into the application plugins/ directory. + | + | NEVER have this disabled in production. + | + */ + + 'restrictBaseDir' => true, + + /* + |-------------------------------------------------------------------------- + | Backend Service Worker + |-------------------------------------------------------------------------- + | + | Allow plugins to run Service Workers in the backend. + | + | WARNING: This should always be disabled for security reasons as Service + | Workers can be hijacked and used to run XSS into the backend. Turning + | this feature on can create a conflict if you have a frontend Service + | Worker running. The 'scope' needs to be correctly set and not have a + | duplicate subfolder structure on the frontend, otherwise it will run + | on both the frontend and backend of your website. + | + | true - allow service workers to run in the backend + | + | false - disallow service workers to run in the backend + | + */ + + 'enableBackendServiceWorkers' => false, + +]; diff --git a/config/cookie.php b/config/cookie.php new file mode 100644 index 0000000..9b624ae --- /dev/null +++ b/config/cookie.php @@ -0,0 +1,21 @@ + [ + // 'my_cookie', + ], + +]; diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000..b75280b --- /dev/null +++ b/config/database.php @@ -0,0 +1,148 @@ + PDO::FETCH_CLASS, + + /* + |-------------------------------------------------------------------------- + | Default Database Connection Name + |-------------------------------------------------------------------------- + | + | Here you may specify which of the database connections below you wish + | to use as your default connection for all database work. Of course + | you may use many connections at once using the Database library. + | + */ + + 'default' => env('DB_CONNECTION', 'mysql'), + + /* + |-------------------------------------------------------------------------- + | Database Connections + |-------------------------------------------------------------------------- + | + | Here are each of the database connections setup for your application. + | Of course, examples of configuring each database platform that is + | supported by Laravel is shown below to make development simple. + | + | + | All database work in Laravel is done through the PHP PDO facilities + | so make sure you have the driver for your particular database of + | choice installed on your machine before you begin development. + | + */ + + 'connections' => [ + + 'sqlite' => [ + 'driver' => 'sqlite', + 'database' => env('DB_DATABASE', 'storage/database.sqlite'), + 'prefix' => '', + ], + + 'mysql' => [ + 'driver' => 'mysql', + 'engine' => 'InnoDB', + 'host' => env('DB_HOST', '192.168.1.2'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'orient'), + 'username' => env('DB_USERNAME', ''), + 'password' => env('DB_PASSWORD', ''), + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', + 'varcharmax' => 191, + ], + + 'pgsql' => [ + 'driver' => 'pgsql', + 'host' => env('DB_HOST', 'localhost'), + 'port' => env('DB_PORT', 5432), + 'database' => env('DB_DATABASE', 'database'), + 'username' => env('DB_USERNAME', ''), + 'password' => env('DB_PASSWORD', ''), + 'charset' => 'utf8', + 'prefix' => '', + 'schema' => 'public', + ], + + 'sqlsrv' => [ + 'driver' => 'sqlsrv', + 'host' => env('DB_HOST', 'localhost'), + 'port' => env('DB_PORT', 5432), + 'database' => env('DB_DATABASE', 'database'), + 'username' => env('DB_USERNAME', ''), + 'password' => env('DB_PASSWORD', ''), + 'prefix' => '', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Migration Repository Table + |-------------------------------------------------------------------------- + | + | This table keeps track of all the migrations that have already run for + | your application. Using this information, we can determine which of + | the migrations on disk have not actually be run in the databases. + | + */ + + 'migrations' => 'migrations', + + /* + |-------------------------------------------------------------------------- + | Redis Databases + |-------------------------------------------------------------------------- + | + | Redis is an open source, fast, and advanced key-value store that also + | provides a richer set of commands than a typical key-value systems + | such as APC or Memcached. Laravel makes it easy to dig right in. + | + */ + + 'redis' => [ + + 'client' => 'predis', + 'cluster' => false, + + 'default' => [ + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'password' => env('REDIS_PASSWORD', null), + 'port' => env('REDIS_PORT', 6379), + 'database' => 0, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Use DB configuration for testing + |-------------------------------------------------------------------------- + | + | When running plugin tests OctoberCMS by default uses SQLite in memory. + | You can override this behavior by setting `useConfigForTesting` to true. + | + | After that OctoberCMS will take DB parameters from the config. + | If file `/config/testing/database.php` exists, config will be read from it, + | but remember that when not specified it will use parameters specified in + | `/config/database.php`. + | + */ + + 'useConfigForTesting' => env('DB_USE_CONFIG_FOR_TESTING', false), + +]; diff --git a/config/dev/.gitignore b/config/dev/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/config/dev/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/config/develop.php b/config/develop.php new file mode 100644 index 0000000..8edf577 --- /dev/null +++ b/config/develop.php @@ -0,0 +1,46 @@ + false, + + /* + |-------------------------------------------------------------------------- + | Allow deep-level symlinks + |-------------------------------------------------------------------------- + | + | October CMS, by default, will allow symlinks within the first level of + | subdirectories. When this feature is enabled, the system will allow + | symlinks to be used at any directory level. This can be useful for + | symlinking individual plugins or themes. + | + | Please note that this has a negative effect on performance. This feature + | abides by "cms.restrictBaseDir" - if enabled, symlinks cannot point to + | resources outside of the root folder. + | + | true - allow symlinks at any level + | + | false - only allow symlinks at the first level of subdirectories (default) + | + */ + + 'allowDeepSymlinks' => false, + +]; diff --git a/config/environment.php b/config/environment.php new file mode 100644 index 0000000..5249b15 --- /dev/null +++ b/config/environment.php @@ -0,0 +1,35 @@ + 'development', + + /* + |-------------------------------------------------------------------------- + | Environment Multitenancy + |-------------------------------------------------------------------------- + | + | You may specify a different environment according to the hostname that + | is provided with the HTTP request. This is useful if you want to use + | different configuration, such as database and theme, per hostname. + | + */ + + 'hosts' => [ + + 'localhost' => 'dev', + + ], + +]; diff --git a/config/filesystems.php b/config/filesystems.php new file mode 100644 index 0000000..ba80d27 --- /dev/null +++ b/config/filesystems.php @@ -0,0 +1,71 @@ + 'local', + + /* + |-------------------------------------------------------------------------- + | Default Cloud Filesystem Disk + |-------------------------------------------------------------------------- + | + | Many applications store files both locally and in the cloud. For this + | reason, you may specify a default "cloud" driver here. This driver + | will be bound as the Cloud disk implementation in the container. + | + */ + + 'cloud' => 's3', + + /* + |-------------------------------------------------------------------------- + | Filesystem Disks + |-------------------------------------------------------------------------- + | + | Here you may configure as many filesystem "disks" as you wish, and you + | may even configure multiple disks of the same driver. Defaults have + | been setup for each driver as an example of the required options. + | + */ + + 'disks' => [ + + 'local' => [ + 'driver' => 'local', + 'root' => storage_path('app'), + 'url' => '/storage/app', + ], + + 's3' => [ + 'driver' => 's3', + 'key' => 'your-key', + 'secret' => 'your-secret', + 'region' => 'your-region', + 'bucket' => 'your-bucket', + ], + + 'rackspace' => [ + 'driver' => 'rackspace', + 'username' => 'your-username', + 'key' => 'your-key', + 'container' => 'your-container', + 'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/', + 'region' => 'IAD', + ], + + ], + +]; diff --git a/config/hashing.php b/config/hashing.php new file mode 100644 index 0000000..8425770 --- /dev/null +++ b/config/hashing.php @@ -0,0 +1,52 @@ + 'bcrypt', + + /* + |-------------------------------------------------------------------------- + | Bcrypt Options + |-------------------------------------------------------------------------- + | + | Here you may specify the configuration options that should be used when + | passwords are hashed using the Bcrypt algorithm. This will allow you + | to control the amount of time it takes to hash the given password. + | + */ + + 'bcrypt' => [ + 'rounds' => env('BCRYPT_ROUNDS', 10), + ], + + /* + |-------------------------------------------------------------------------- + | Argon Options + |-------------------------------------------------------------------------- + | + | Here you may specify the configuration options that should be used when + | passwords are hashed using the Argon algorithm. These will allow you + | to control the amount of time it takes to hash the given password. + | + */ + + 'argon' => [ + 'memory' => 1024, + 'threads' => 2, + 'time' => 2, + ], + +]; diff --git a/config/logging.php b/config/logging.php new file mode 100644 index 0000000..900d481 --- /dev/null +++ b/config/logging.php @@ -0,0 +1,91 @@ + env('LOG_CHANNEL', 'single'), + + /* + |-------------------------------------------------------------------------- + | Log Channels + |-------------------------------------------------------------------------- + | + | Here you may configure the log channels for your application. Out of + | the box, Laravel uses the Monolog PHP logging library. This gives + | you a variety of powerful log handlers / formatters to utilize. + | + | Available Drivers: "single", "daily", "slack", "syslog", + | "errorlog", "monolog", + | "custom", "stack" + | + */ + + 'channels' => [ + 'stack' => [ + 'driver' => 'stack', + 'channels' => ['daily'], + 'ignore_exceptions' => false, + ], + + 'single' => [ + 'driver' => 'single', + 'path' => storage_path('logs/system.log'), + 'level' => 'debug', + ], + + 'daily' => [ + 'driver' => 'daily', + 'path' => storage_path('logs/system.log'), + 'level' => 'debug', + 'days' => 14, + ], + + 'slack' => [ + 'driver' => 'slack', + 'url' => env('LOG_SLACK_WEBHOOK_URL'), + 'username' => 'October CMS Log', + 'emoji' => ':boom:', + 'level' => 'critical', + ], + + 'papertrail' => [ + 'driver' => 'monolog', + 'level' => 'debug', + 'handler' => \Monolog\Handler\SyslogUdpHandler::class, + 'handler_with' => [ + 'host' => env('PAPERTRAIL_URL'), + 'port' => env('PAPERTRAIL_PORT'), + ], + ], + + 'stderr' => [ + 'driver' => 'monolog', + 'handler' => \Monolog\Handler\StreamHandler::class, + 'formatter' => env('LOG_STDERR_FORMATTER'), + 'with' => [ + 'stream' => 'php://stderr', + ], + ], + + 'syslog' => [ + 'driver' => 'syslog', + 'level' => 'debug', + ], + + 'errorlog' => [ + 'driver' => 'errorlog', + 'level' => 'debug', + ], + ], + +]; diff --git a/config/mail.php b/config/mail.php new file mode 100644 index 0000000..88ca768 --- /dev/null +++ b/config/mail.php @@ -0,0 +1,115 @@ + env('MAIL_DRIVER', 'smtp'), + + /* + |-------------------------------------------------------------------------- + | SMTP Host Address + |-------------------------------------------------------------------------- + | + | Here you may provide the host address of the SMTP server used by your + | applications. A default option is provided that is compatible with + | the Mailgun mail service which will provide reliable deliveries. + | + */ + + 'host' => env('MAIL_HOST', 'smtp.mailgun.org'), + + /* + |-------------------------------------------------------------------------- + | SMTP Host Port + |-------------------------------------------------------------------------- + | + | This is the SMTP port used by your application to deliver e-mails to + | users of the application. Like the host we have set this value to + | stay compatible with the Mailgun e-mail application by default. + | + */ + + 'port' => env('MAIL_PORT', 587), + + /* + |-------------------------------------------------------------------------- + | Global "From" Address + |-------------------------------------------------------------------------- + | + | You may wish for all e-mails sent by your application to be sent from + | the same address. Here, you may specify a name and address that is + | used globally for all e-mails that are sent by your application. + | + */ + + 'from' => [ + 'address' => 'noreply@domain.tld', + 'name' => 'OctoberCMS', + ], + + /* + |-------------------------------------------------------------------------- + | E-Mail Encryption Protocol + |-------------------------------------------------------------------------- + | + | Here you may specify the encryption protocol that should be used when + | the application send e-mail messages. A sensible default using the + | transport layer security protocol should provide great security. + | + */ + + 'encryption' => env('MAIL_ENCRYPTION', 'tls'), + + /* + |-------------------------------------------------------------------------- + | SMTP Server Username + |-------------------------------------------------------------------------- + | + | If your SMTP server requires a username for authentication, you should + | set it here. This will get used to authenticate with your server on + | connection. You may also set the "password" value below this one. + | + */ + + 'username' => env('MAIL_USERNAME', null), + + /* + |-------------------------------------------------------------------------- + | SMTP Server Password + |-------------------------------------------------------------------------- + | + | Here you may set the password required by your SMTP server to send out + | messages from your application. This will be given to the server on + | connection so that the application will be able to send messages. + | + */ + + 'password' => env('MAIL_PASSWORD', null), + + /* + |-------------------------------------------------------------------------- + | Sendmail System Path + |-------------------------------------------------------------------------- + | + | When using the "sendmail" driver to send e-mails, we will need to know + | the path to where Sendmail lives on this server. A default path has + | been provided here, which will work well on most of your systems. + | + */ + + 'sendmail' => '/usr/sbin/sendmail -bs', + +]; diff --git a/config/queue.php b/config/queue.php new file mode 100644 index 0000000..cd409c5 --- /dev/null +++ b/config/queue.php @@ -0,0 +1,93 @@ + env('QUEUE_CONNECTION', 'sync'), + + /* + |-------------------------------------------------------------------------- + | Queue Connections + |-------------------------------------------------------------------------- + | + | Here you may configure the connection information for each server that + | is used by your application. A default configuration has been added + | for each back-end shipped with Laravel. You are free to add more. + | + */ + + 'connections' => [ + + 'sync' => [ + 'driver' => 'sync', + ], + + 'database' => [ + 'driver' => 'database', + 'table' => 'jobs', + 'queue' => 'default', + 'expire' => 60, + ], + + 'beanstalkd' => [ + 'driver' => 'beanstalkd', + 'host' => 'localhost', + 'queue' => 'default', + 'ttr' => 60, + ], + + 'sqs' => [ + 'driver' => 'sqs', + 'key' => 'your-public-key', + 'secret' => 'your-secret-key', + 'queue' => 'your-queue-url', + 'region' => 'us-east-1', + ], + + 'iron' => [ + 'driver' => 'iron', + 'host' => 'mq-aws-us-east-1.iron.io', + 'token' => 'your-token', + 'project' => 'your-project-id', + 'queue' => 'your-queue-name', + 'encrypt' => true, + ], + + 'redis' => [ + 'driver' => 'redis', + 'queue' => 'default', + 'expire' => 60, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Failed Queue Jobs + |-------------------------------------------------------------------------- + | + | These options configure the behavior of failed queue job logging so you + | can control which database and table are used to store the jobs that + | have failed. You may change them to any database / table you wish. + | + */ + + 'failed' => [ + 'database' => 'mysql', + 'table' => 'failed_jobs', + ], + +]; diff --git a/config/services.php b/config/services.php new file mode 100644 index 0000000..4b12e4f --- /dev/null +++ b/config/services.php @@ -0,0 +1,46 @@ + [ + 'domain' => '', + 'secret' => '', + 'endpoint' => 'api.mailgun.net', // api.eu.mailgun.net for EU + ], + + 'mandrill' => [ + 'secret' => '', + ], + + 'postmark' => [ + 'token' => '', + ], + + 'ses' => [ + 'key' => '', + 'secret' => '', + 'region' => 'us-east-1', + ], + + 'sparkpost' => [ + 'secret' => '', + ], + + 'stripe' => [ + 'model' => 'User', + 'secret' => '', + ], + +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000..a76b354 --- /dev/null +++ b/config/session.php @@ -0,0 +1,199 @@ + env('SESSION_DRIVER', 'file'), + + /* + |-------------------------------------------------------------------------- + | Session Lifetime + |-------------------------------------------------------------------------- + | + | Here you may specify the number of minutes that you wish the session + | to be allowed to remain idle for it is expired. If you want them + | to immediately expire when the browser closes, set it to zero. + | + */ + + 'lifetime' => 120, + + 'expire_on_close' => false, + + /* + |-------------------------------------------------------------------------- + | Session Encryption + |-------------------------------------------------------------------------- + | + | This option allows you to easily specify that all of your session data + | should be encrypted before it is stored. All encryption will be run + | automatically by Laravel and you can use the Session like normal. + | + */ + + 'encrypt' => false, + + /* + |-------------------------------------------------------------------------- + | Session File Location + |-------------------------------------------------------------------------- + | + | When using the native session driver, we need a location where session + | files may be stored. A default has been set for you but a different + | location may be specified. This is only needed for file sessions. + | + */ + + 'files' => storage_path('framework/sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Database Connection + |-------------------------------------------------------------------------- + | + | When using the "database" or "redis" session drivers, you may specify a + | connection that should be used to manage these sessions. This should + | correspond to a connection in your database configuration options. + | + */ + + 'connection' => null, + + /* + |-------------------------------------------------------------------------- + | Session Database Table + |-------------------------------------------------------------------------- + | + | When using the "database" session driver, you may specify the table we + | should use to manage the sessions. Of course, a sensible default is + | provided for you; however, you are free to change this as needed. + | + */ + + 'table' => 'sessions', + + /* + |-------------------------------------------------------------------------- + | Session Sweeping Lottery + |-------------------------------------------------------------------------- + | + | Some session drivers must manually sweep their storage location to get + | rid of old sessions from storage. Here are the chances that it will + | happen on a given request. By default, the odds are 2 out of 100. + | + */ + + 'lottery' => [2, 100], + + /* + |-------------------------------------------------------------------------- + | Session Cookie Name + |-------------------------------------------------------------------------- + | + | Here you may change the name of the cookie used to identify a session + | instance by ID. The name specified here will get used every time a + | new session cookie is created by the framework for every driver. + | + */ + + 'cookie' => 'october_session', + + /* + |-------------------------------------------------------------------------- + | Session Cookie Path + |-------------------------------------------------------------------------- + | + | The session cookie path determines the path for which the cookie will + | be regarded as available. Typically, this will be the root path of + | your application but you are free to change this when necessary. + | + */ + + 'path' => '/', + + /* + |-------------------------------------------------------------------------- + | Session Cookie Domain + |-------------------------------------------------------------------------- + | + | Here you may change the domain of the cookie used to identify a session + | in your application. This will determine which domains the cookie is + | available to in your application. A sensible default has been set. + | + */ + + 'domain' => null, + + /* + |-------------------------------------------------------------------------- + | HTTP Access Only + |-------------------------------------------------------------------------- + | + | Setting this value to true will prevent JavaScript from accessing the + | value of the cookie and the cookie will only be accessible through + | the HTTP protocol. You are free to modify this option if needed. + | + */ + + 'http_only' => true, + + /* + |-------------------------------------------------------------------------- + | HTTPS Only Cookies + |-------------------------------------------------------------------------- + | + | By setting this option to true, session cookies will only be sent back + | to the server if the browser has a HTTPS connection. This will keep + | the cookie from being sent to you if it can not be done securely. + | + */ + + 'secure' => false, + + /* + |-------------------------------------------------------------------------- + | Same-Site Cookies + |-------------------------------------------------------------------------- + | + | This option determines how your cookies behave when cross-site requests + | take place and can be used to mitigate CSRF attacks. + | + | Cookies that match the domain of the current site, i.e. what's displayed + | in the browser's address bar, are referred to as first-party cookies. + | Similarly, cookies from domains other than the current site are referred + | to as third-party cookies. + | + | Cookies without a SameSite attribute will be treated as `SameSite=Lax`, + | meaning the default behaviour will be to restrict cookies to first party + | contexts only. + | + | Cookies for cross-site usage must specify `same_site` as 'None' and `secure` + | as `true` to work correctly. + | + | Lax - Cookies are allowed to be sent with top-level navigations and will + | be sent along with GET request initiated by third party website. + | This is the default value in modern browsers. + | + | Strict - Cookies will only be sent in a first-party context and not be + | sent along with requests initiated by third party websites. + | + | Supported: "Lax", "Strict" and "None" + | + */ + + 'same_site' => 'Lax', + +]; diff --git a/config/testing/cms.php b/config/testing/cms.php new file mode 100644 index 0000000..209006f --- /dev/null +++ b/config/testing/cms.php @@ -0,0 +1,124 @@ + 'test', + + /* + |-------------------------------------------------------------------------- + | Time to live for parsed CMS objects. + |-------------------------------------------------------------------------- + | + | Specifies the number of minutes the CMS object cache lives. After the interval + | is expired item are re-cached. Note that items are re-cached automatically when + | the corresponding template file is modified. + | + */ + + 'parsedPageCacheTTL' => 1440, + + /* + |-------------------------------------------------------------------------- + | Determines if the routing caching is enabled. + |-------------------------------------------------------------------------- + | + | If the caching is enabled, the page URL map is saved in the cache. If a page + | URL was changed on the disk, the old URL value could be still saved in the cache. + | To update the cache the back-end Clear Cache feature should be used. It is recommended + | to disable the caching during the development, and enable it in the production mode. + | + */ + + 'enableRoutesCache' => true, + + /* + |-------------------------------------------------------------------------- + | Time to live for the URL map. + |-------------------------------------------------------------------------- + | + | The URL map used in the CMS page routing process. By default + | the map is updated every time when a page is saved in the back-end or when the + | interval, in minutes, specified with the urlMapCacheTTL parameter expires. + | + */ + + 'urlCacheTtl' => 1, + + /* + |-------------------------------------------------------------------------- + | Determines if the asset caching is enabled. + |-------------------------------------------------------------------------- + | + | If the caching is enabled, combined assets are cached. If a asset file + | is changed on the disk, the old file contents could be still saved in the cache. + | To update the cache the back-end Clear Cache feature should be used. It is recommended + | to disable the caching during the development, and enable it in the production mode. + | + */ + + 'enableAssetCache' => false, + + /* + |-------------------------------------------------------------------------- + | Disables Twig caching for unit tests + |-------------------------------------------------------------------------- + */ + + 'twigNoCache' => true, + + /* + |-------------------------------------------------------------------------- + | Convert Line Endings + |-------------------------------------------------------------------------- + | + | Determines if October should convert line endings from the windows style + | \r\n to the unix style \n. + | + */ + + 'convertLineEndings' => true, + + /* + |-------------------------------------------------------------------------- + | Local plugins path + |-------------------------------------------------------------------------- + | + | Specifies the absolute local plugins path. + | + */ + + 'pluginsPathLocal' => base_path('tests/fixtures/plugins'), + + /* + |-------------------------------------------------------------------------- + | Local themes path + |-------------------------------------------------------------------------- + | + | Specifies the absolute local themes path. + | + */ + + 'themesPathLocal' => base_path('tests/fixtures/themes'), + + /* + |-------------------------------------------------------------------------- + | Cross Site Request Forgery (CSRF) Protection + |-------------------------------------------------------------------------- + | + | If the CSRF protection is enabled, all "postback" requests are checked + | for a valid security token. + | + */ + + 'enableCsrfProtection' => false, + +]; diff --git a/config/view.php b/config/view.php new file mode 100644 index 0000000..9128d73 --- /dev/null +++ b/config/view.php @@ -0,0 +1,34 @@ + [ + // Default Laravel Blade template location + // realpath(base_path('resources/views')) + ], + + /* + |-------------------------------------------------------------------------- + | Compiled View Path + |-------------------------------------------------------------------------- + | + | This option determines where all the compiled Blade templates will be + | stored for your application. Typically, this is within the storage + | directory. However, as usual, you are free to change this value. + | + */ + + 'compiled' => realpath(storage_path('framework/views')), + +]; diff --git a/hhm_07_02.sql b/hhm_07_02.sql new file mode 100644 index 0000000..86f8a8f --- /dev/null +++ b/hhm_07_02.sql @@ -0,0 +1,1417 @@ +-- ------------------------------------------------------------- +-- TablePlus 4.7.1(428) +-- +-- https://tableplus.com/ +-- +-- Database: hhm +-- Generation Time: 2023-02-07 02:18:48.7520 +-- ------------------------------------------------------------- + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + + +DROP TABLE IF EXISTS `ahmadfatoni_apigenerator_data`; +CREATE TABLE `ahmadfatoni_apigenerator_data` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL, + `endpoint` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL, + `model` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL, + `description` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `custom_format` text COLLATE utf8mb4_unicode_ci, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `backend_access_log`; +CREATE TABLE `backend_access_log` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `user_id` int unsigned NOT NULL, + `ip_address` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `backend_user_groups`; +CREATE TABLE `backend_user_groups` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + `code` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `is_new_user_default` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `name_unique` (`name`), + KEY `code_index` (`code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `backend_user_preferences`; +CREATE TABLE `backend_user_preferences` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `user_id` int unsigned NOT NULL, + `namespace` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `group` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `item` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + PRIMARY KEY (`id`), + KEY `user_item_index` (`user_id`,`namespace`,`group`,`item`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `backend_user_roles`; +CREATE TABLE `backend_user_roles` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `code` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `permissions` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `is_system` tinyint(1) NOT NULL DEFAULT '0', + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `role_unique` (`name`), + KEY `role_code_index` (`code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `backend_user_throttle`; +CREATE TABLE `backend_user_throttle` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `user_id` int unsigned DEFAULT NULL, + `ip_address` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `attempts` int NOT NULL DEFAULT '0', + `last_attempt_at` timestamp NULL DEFAULT NULL, + `is_suspended` tinyint(1) NOT NULL DEFAULT '0', + `suspended_at` timestamp NULL DEFAULT NULL, + `is_banned` tinyint(1) NOT NULL DEFAULT '0', + `banned_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `backend_user_throttle_user_id_index` (`user_id`), + KEY `backend_user_throttle_ip_address_index` (`ip_address`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `backend_users`; +CREATE TABLE `backend_users` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `first_name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `last_name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `login` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `email` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `password` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `activation_code` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `persist_code` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `reset_password_code` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `permissions` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `is_activated` tinyint(1) NOT NULL DEFAULT '0', + `role_id` int unsigned DEFAULT NULL, + `activated_at` timestamp NULL DEFAULT NULL, + `last_login` timestamp NULL DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + `deleted_at` timestamp NULL DEFAULT NULL, + `is_superuser` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `login_unique` (`login`), + UNIQUE KEY `email_unique` (`email`), + KEY `act_code_index` (`activation_code`), + KEY `reset_code_index` (`reset_password_code`), + KEY `admin_role_index` (`role_id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `backend_users_groups`; +CREATE TABLE `backend_users_groups` ( + `user_id` int unsigned NOT NULL, + `user_group_id` int unsigned NOT NULL, + PRIMARY KEY (`user_id`,`user_group_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `cache`; +CREATE TABLE `cache` ( + `key` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `value` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `expiration` int NOT NULL, + UNIQUE KEY `cache_key_unique` (`key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `cms_theme_data`; +CREATE TABLE `cms_theme_data` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `theme` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `data` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `cms_theme_data_theme_index` (`theme`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `cms_theme_logs`; +CREATE TABLE `cms_theme_logs` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `theme` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `template` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `old_template` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `old_content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `user_id` int DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `cms_theme_logs_type_index` (`type`), + KEY `cms_theme_logs_theme_index` (`theme`), + KEY `cms_theme_logs_user_id_index` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `cms_theme_templates`; +CREATE TABLE `cms_theme_templates` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `source` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `path` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `file_size` int unsigned NOT NULL, + `updated_at` datetime DEFAULT NULL, + `deleted_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `cms_theme_templates_source_index` (`source`), + KEY `cms_theme_templates_path_index` (`path`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `deferred_bindings`; +CREATE TABLE `deferred_bindings` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `master_type` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `master_field` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `slave_type` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `slave_id` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `pivot_data` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `session_key` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `is_bind` tinyint(1) NOT NULL DEFAULT '1', + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `deferred_bindings_master_type_index` (`master_type`), + KEY `deferred_bindings_master_field_index` (`master_field`), + KEY `deferred_bindings_slave_type_index` (`slave_type`), + KEY `deferred_bindings_slave_id_index` (`slave_id`), + KEY `deferred_bindings_session_key_index` (`session_key`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `failed_jobs`; +CREATE TABLE `failed_jobs` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `connection` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `queue` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `payload` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `exception` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `failed_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `jobs`; +CREATE TABLE `jobs` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `queue` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `payload` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `attempts` tinyint unsigned NOT NULL, + `reserved_at` int unsigned DEFAULT NULL, + `available_at` int unsigned NOT NULL, + `created_at` int unsigned NOT NULL, + PRIMARY KEY (`id`), + KEY `jobs_queue_reserved_at_index` (`queue`,`reserved_at`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `martin_forms_records`; +CREATE TABLE `martin_forms_records` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `group` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '(Empty)', + `form_data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `ip` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `unread` tinyint(1) NOT NULL DEFAULT '1', + `deleted_at` timestamp NULL DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `migrations`; +CREATE TABLE `migrations` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `migration` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `batch` int NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `rainlab_blog_categories`; +CREATE TABLE `rainlab_blog_categories` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `slug` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `code` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `parent_id` int unsigned DEFAULT NULL, + `nest_left` int DEFAULT NULL, + `nest_right` int DEFAULT NULL, + `nest_depth` int DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `rainlab_blog_categories_slug_index` (`slug`), + KEY `rainlab_blog_categories_parent_id_index` (`parent_id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `rainlab_blog_posts`; +CREATE TABLE `rainlab_blog_posts` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `user_id` int unsigned DEFAULT NULL, + `title` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `slug` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `excerpt` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `content_html` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `published_at` timestamp NULL DEFAULT NULL, + `published` tinyint(1) NOT NULL DEFAULT '0', + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + `metadata` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `powerseo_title` text COLLATE utf8mb4_unicode_ci, + `powerseo_description` text COLLATE utf8mb4_unicode_ci, + `powerseo_keywords` text COLLATE utf8mb4_unicode_ci, + `powerseo_canonical_url` text COLLATE utf8mb4_unicode_ci, + `powerseo_redirect_url` text COLLATE utf8mb4_unicode_ci, + `powerseo_robot_index` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `powerseo_robot_follow` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `featured` tinyint(1) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `rainlab_blog_posts_user_id_index` (`user_id`), + KEY `rainlab_blog_posts_slug_index` (`slug`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `rainlab_blog_posts_categories`; +CREATE TABLE `rainlab_blog_posts_categories` ( + `post_id` int unsigned NOT NULL, + `category_id` int unsigned NOT NULL, + PRIMARY KEY (`post_id`,`category_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `rainlab_translate_attributes`; +CREATE TABLE `rainlab_translate_attributes` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `locale` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `model_id` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `model_type` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `attribute_data` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + PRIMARY KEY (`id`), + KEY `rainlab_translate_attributes_locale_index` (`locale`), + KEY `rainlab_translate_attributes_model_id_index` (`model_id`), + KEY `rainlab_translate_attributes_model_type_index` (`model_type`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `rainlab_translate_indexes`; +CREATE TABLE `rainlab_translate_indexes` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `locale` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `model_id` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `model_type` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `item` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `value` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + PRIMARY KEY (`id`), + KEY `rainlab_translate_indexes_locale_index` (`locale`), + KEY `rainlab_translate_indexes_model_id_index` (`model_id`), + KEY `rainlab_translate_indexes_model_type_index` (`model_type`), + KEY `rainlab_translate_indexes_item_index` (`item`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `rainlab_translate_locales`; +CREATE TABLE `rainlab_translate_locales` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `code` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `is_default` tinyint(1) NOT NULL DEFAULT '0', + `is_enabled` tinyint(1) NOT NULL DEFAULT '0', + `sort_order` int NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `rainlab_translate_locales_code_index` (`code`), + KEY `rainlab_translate_locales_name_index` (`name`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `rainlab_translate_messages`; +CREATE TABLE `rainlab_translate_messages` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `code` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `message_data` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `found` tinyint(1) NOT NULL DEFAULT '1', + PRIMARY KEY (`id`), + KEY `rainlab_translate_messages_code_index` (`code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `sessions`; +CREATE TABLE `sessions` ( + `id` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `payload` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `last_activity` int DEFAULT NULL, + `user_id` int unsigned DEFAULT NULL, + `ip_address` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `user_agent` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + UNIQUE KEY `sessions_id_unique` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `system_event_logs`; +CREATE TABLE `system_event_logs` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `level` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `details` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `system_event_logs_level_index` (`level`) +) ENGINE=InnoDB AUTO_INCREMENT=306 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `system_files`; +CREATE TABLE `system_files` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `disk_name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `file_name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `file_size` int NOT NULL, + `content_type` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `title` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `field` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `attachment_id` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `attachment_type` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `is_public` tinyint(1) NOT NULL DEFAULT '1', + `sort_order` int DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `system_files_field_index` (`field`), + KEY `system_files_attachment_id_index` (`attachment_id`), + KEY `system_files_attachment_type_index` (`attachment_type`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `system_mail_layouts`; +CREATE TABLE `system_mail_layouts` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `code` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `content_html` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `content_text` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `content_css` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `is_locked` tinyint(1) NOT NULL DEFAULT '0', + `options` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `system_mail_partials`; +CREATE TABLE `system_mail_partials` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `code` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `content_html` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `content_text` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `is_custom` tinyint(1) NOT NULL DEFAULT '0', + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `system_mail_templates`; +CREATE TABLE `system_mail_templates` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `code` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `subject` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `content_html` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `content_text` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `layout_id` int DEFAULT NULL, + `is_custom` tinyint(1) NOT NULL DEFAULT '0', + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `system_mail_templates_layout_id_index` (`layout_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `system_parameters`; +CREATE TABLE `system_parameters` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `namespace` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `group` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `item` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + PRIMARY KEY (`id`), + KEY `item_index` (`namespace`,`group`,`item`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `system_plugin_history`; +CREATE TABLE `system_plugin_history` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `code` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `version` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `detail` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `created_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `system_plugin_history_code_index` (`code`), + KEY `system_plugin_history_type_index` (`type`) +) ENGINE=InnoDB AUTO_INCREMENT=443 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `system_plugin_versions`; +CREATE TABLE `system_plugin_versions` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `code` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `version` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `is_disabled` tinyint(1) NOT NULL DEFAULT '0', + `is_frozen` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `system_plugin_versions_code_index` (`code`) +) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `system_request_logs`; +CREATE TABLE `system_request_logs` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `status_code` int DEFAULT NULL, + `url` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `referer` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `count` int NOT NULL DEFAULT '0', + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `system_revisions`; +CREATE TABLE `system_revisions` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `user_id` int unsigned DEFAULT NULL, + `field` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `cast` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `old_value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `new_value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `revisionable_type` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `revisionable_id` int NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `system_revisions_revisionable_id_revisionable_type_index` (`revisionable_id`,`revisionable_type`), + KEY `system_revisions_user_id_index` (`user_id`), + KEY `system_revisions_field_index` (`field`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `system_settings`; +CREATE TABLE `system_settings` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `item` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `value` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + PRIMARY KEY (`id`), + KEY `system_settings_item_index` (`item`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `vdomah_blogviews_views`; +CREATE TABLE `vdomah_blogviews_views` ( + `views` int NOT NULL, + `post_id` int unsigned NOT NULL, + PRIMARY KEY (`post_id`), + KEY `vdomah_blogviews_views_post_id_index` (`post_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +INSERT INTO `ahmadfatoni_apigenerator_data` (`id`, `name`, `endpoint`, `model`, `description`, `custom_format`) VALUES +(1, 'Categories', 'api/v1/categories', 'RainLab\\Blog\\Models\\Category', 'Blog Cats', ''), +(2, 'Posts', 'api/v1/posts', 'RainLab\\Blog\\Models\\Post', 'Blog Posts', ''); + +INSERT INTO `backend_access_log` (`id`, `user_id`, `ip_address`, `created_at`, `updated_at`) VALUES +(1, 1, '127.0.0.1', '2022-10-24 04:12:42', '2022-10-24 04:12:42'); + +INSERT INTO `backend_user_throttle` (`id`, `user_id`, `ip_address`, `attempts`, `last_attempt_at`, `is_suspended`, `suspended_at`, `is_banned`, `banned_at`) VALUES +(1, 1, '127.0.0.1', 0, NULL, 0, NULL, 0, NULL); + +INSERT INTO `backend_users` (`id`, `first_name`, `last_name`, `login`, `email`, `password`, `activation_code`, `persist_code`, `reset_password_code`, `permissions`, `is_activated`, `role_id`, `activated_at`, `last_login`, `created_at`, `updated_at`, `deleted_at`, `is_superuser`) VALUES +(1, 'Admin', 'Person', 'admin', 'admin@domain.tld', '$2y$10$fGfsIo38M1WniqiIBeWtIe5jRnbAlufPqvbHZcIo45PZmvu/FIagS', NULL, '$2y$10$t/gbpSsY2rQzFcXD.UygduuexyU5YXOuY3TDldEnZz6m3CU2THvXy', NULL, '', 1, 2, NULL, '2022-10-24 04:12:42', '2022-06-24 12:15:58', '2022-10-24 04:12:42', NULL, 1); + +INSERT INTO `deferred_bindings` (`id`, `master_type`, `master_field`, `slave_type`, `slave_id`, `pivot_data`, `session_key`, `is_bind`, `created_at`, `updated_at`) VALUES +(1, 'RainLab\\Blog\\Models\\Post', 'featured_images', 'System\\Models\\File', '1', NULL, 'Q2caqBJnAlIsKvtqeaaTcIzMqSmCdtohKErx3FIt', 1, '2023-02-06 17:59:47', '2023-02-06 17:59:47'), +(3, 'RainLab\\Blog\\Models\\Post', 'featured_images', 'System\\Models\\File', '3', NULL, 'Q2caqBJnAlIsKvtqeaaTcIzMqSmCdtohKErx3FIt', 1, '2023-02-06 17:59:47', '2023-02-06 17:59:47'); + +INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES +(1, '2013_10_01_000001_Db_Deferred_Bindings', 1), +(2, '2013_10_01_000002_Db_System_Files', 1), +(3, '2013_10_01_000003_Db_System_Plugin_Versions', 1), +(4, '2013_10_01_000004_Db_System_Plugin_History', 1), +(5, '2013_10_01_000005_Db_System_Settings', 1), +(6, '2013_10_01_000006_Db_System_Parameters', 1), +(7, '2013_10_01_000007_Db_System_Add_Disabled_Flag', 1), +(8, '2013_10_01_000008_Db_System_Mail_Templates', 1), +(9, '2013_10_01_000009_Db_System_Mail_Layouts', 1), +(10, '2014_10_01_000010_Db_Jobs', 1), +(11, '2014_10_01_000011_Db_System_Event_Logs', 1), +(12, '2014_10_01_000012_Db_System_Request_Logs', 1), +(13, '2014_10_01_000013_Db_System_Sessions', 1), +(14, '2015_10_01_000014_Db_System_Mail_Layout_Rename', 1), +(15, '2015_10_01_000015_Db_System_Add_Frozen_Flag', 1), +(16, '2015_10_01_000016_Db_Cache', 1), +(17, '2015_10_01_000017_Db_System_Revisions', 1), +(18, '2015_10_01_000018_Db_FailedJobs', 1), +(19, '2016_10_01_000019_Db_System_Plugin_History_Detail_Text', 1), +(20, '2016_10_01_000020_Db_System_Timestamp_Fix', 1), +(21, '2017_08_04_121309_Db_Deferred_Bindings_Add_Index_Session', 1), +(22, '2017_10_01_000021_Db_System_Sessions_Update', 1), +(23, '2017_10_01_000022_Db_Jobs_FailedJobs_Update', 1), +(24, '2017_10_01_000023_Db_System_Mail_Partials', 1), +(25, '2017_10_23_000024_Db_System_Mail_Layouts_Add_Options_Field', 1), +(26, '2021_10_01_000025_Db_Add_Pivot_Data_To_Deferred_Bindings', 1), +(27, '2013_10_01_000001_Db_Backend_Users', 2), +(28, '2013_10_01_000002_Db_Backend_User_Groups', 2), +(29, '2013_10_01_000003_Db_Backend_Users_Groups', 2), +(30, '2013_10_01_000004_Db_Backend_User_Throttle', 2), +(31, '2014_01_04_000005_Db_Backend_User_Preferences', 2), +(32, '2014_10_01_000006_Db_Backend_Access_Log', 2), +(33, '2014_10_01_000007_Db_Backend_Add_Description_Field', 2), +(34, '2015_10_01_000008_Db_Backend_Add_Superuser_Flag', 2), +(35, '2016_10_01_000009_Db_Backend_Timestamp_Fix', 2), +(36, '2017_10_01_000010_Db_Backend_User_Roles', 2), +(37, '2018_12_16_000011_Db_Backend_Add_Deleted_At', 2), +(38, '2014_10_01_000001_Db_Cms_Theme_Data', 3), +(39, '2016_10_01_000002_Db_Cms_Timestamp_Fix', 3), +(40, '2017_10_01_000003_Db_Cms_Theme_Logs', 3), +(41, '2018_11_01_000001_Db_Cms_Theme_Templates', 3); + +INSERT INTO `rainlab_blog_categories` (`id`, `name`, `slug`, `code`, `description`, `parent_id`, `nest_left`, `nest_right`, `nest_depth`, `created_at`, `updated_at`) VALUES +(1, 'Uncategorized', 'uncategorized', NULL, '', NULL, 3, 4, 0, '2022-10-24 04:13:20', '2023-02-06 20:59:09'), +(2, 'Category test', 'category-test', NULL, '', NULL, 1, 2, 0, '2023-02-06 18:27:03', '2023-02-06 20:59:09'); + +INSERT INTO `rainlab_blog_posts` (`id`, `user_id`, `title`, `slug`, `excerpt`, `content`, `content_html`, `published_at`, `published`, `created_at`, `updated_at`, `metadata`, `powerseo_title`, `powerseo_description`, `powerseo_keywords`, `powerseo_canonical_url`, `powerseo_redirect_url`, `powerseo_robot_index`, `powerseo_robot_follow`, `featured`) VALUES +(1, 1, 'First blog post', 'first-blog-post', 'The first ever blog post is here. It might be a good idea to update this post with some more relevant content.', 'This is your first ever **blog post**! It might be a good idea to update this post with some more relevant content.\r\n\r\nYou can edit this content by selecting **Blog** from the administration back-end menu.\r\n\r\n*Enjoy the good times!*', '

This is your first ever blog post! It might be a good idea to update this post with some more relevant content.

\n

You can edit this content by selecting Blog from the administration back-end menu.

\n

Enjoy the good times!

', '2022-10-24 04:13:20', 1, '2022-10-24 04:13:20', '2023-02-06 18:27:18', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0), +(2, 1, 'Second Post', 'second-post', 'dfgdfg', 'sfdgdfgdfgdfgdfgdfg', '

sfdgdfgdfgdfgdfgdfg

', '2023-02-06 00:00:00', 1, '2023-02-06 19:03:46', '2023-02-06 20:48:40', NULL, 'asd', 'jhbjhb', 'jhbjhb', NULL, NULL, 'index', 'follow', 1); + +INSERT INTO `rainlab_blog_posts_categories` (`post_id`, `category_id`) VALUES +(1, 1), +(1, 2), +(2, 2); + +INSERT INTO `rainlab_translate_attributes` (`id`, `locale`, `model_id`, `model_type`, `attribute_data`) VALUES +(1, 'en', '2', 'RainLab\\Blog\\Models\\Post', '{\"title\":\"second en\",\"slug\":\"second-en\",\"content\":\"\",\"content_html\":\"\",\"excerpt\":\"\"}'), +(2, 'tm', '2', 'RainLab\\Blog\\Models\\Post', '{\"title\":\"second tm\",\"slug\":\"second-tm\",\"content\":\"\",\"content_html\":\"\",\"excerpt\":\"\"}'), +(3, 'en', '1', 'RainLab\\Blog\\Models\\Post', '{\"title\":\"blog first en\",\"slug\":\"blog-first-en\",\"content\":\"eng post\",\"content_html\":\"

eng post<\\/p>\",\"excerpt\":\"test en\"}'), +(4, 'tm', '1', 'RainLab\\Blog\\Models\\Post', '{\"title\":\"\",\"slug\":\"\",\"content\":\"tm post\",\"content_html\":\"

tm post<\\/p>\",\"excerpt\":\"\"}'), +(5, 'en', '1', 'RainLab\\Blog\\Models\\Category', '{\"name\":\"en uncat\",\"slug\":\"en-uncat\",\"description\":\"\"}'), +(6, 'tm', '1', 'RainLab\\Blog\\Models\\Category', '{\"name\":\"\",\"slug\":\"\",\"description\":\"\"}'), +(7, 'en', '2', 'RainLab\\Blog\\Models\\Category', '{\"name\":\"test en cat\",\"slug\":\"test-en-cat\",\"description\":\"\"}'), +(8, 'tm', '2', 'RainLab\\Blog\\Models\\Category', '{\"name\":\"\",\"slug\":\"\",\"description\":\"\"}'); + +INSERT INTO `rainlab_translate_indexes` (`id`, `locale`, `model_id`, `model_type`, `item`, `value`) VALUES +(1, 'en', '2', 'RainLab\\Blog\\Models\\Post', 'slug', 'second-en'), +(2, 'tm', '2', 'RainLab\\Blog\\Models\\Post', 'slug', 'second-tm'), +(3, 'en', '1', 'RainLab\\Blog\\Models\\Category', 'slug', 'en-uncat'), +(4, 'en', '2', 'RainLab\\Blog\\Models\\Category', 'slug', 'test-en-cat'), +(5, 'en', '1', 'RainLab\\Blog\\Models\\Post', 'slug', 'blog-first-en'); + +INSERT INTO `rainlab_translate_locales` (`id`, `code`, `name`, `is_default`, `is_enabled`, `sort_order`) VALUES +(1, 'en', 'English', 0, 1, 1), +(2, 'ru', 'Russian', 1, 1, 2), +(3, 'tm', 'Turkmen', 0, 1, 3); + +INSERT INTO `system_event_logs` (`id`, `level`, `message`, `details`, `created_at`, `updated_at`) VALUES +(1, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:43:25', '2023-02-06 16:43:25'), +(2, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:44:25', '2023-02-06 16:44:25'), +(3, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:45:26', '2023-02-06 16:45:26'), +(4, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:46:26', '2023-02-06 16:46:26'), +(5, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:47:26', '2023-02-06 16:47:26'), +(6, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:48:26', '2023-02-06 16:48:26'), +(7, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:49:26', '2023-02-06 16:49:26'), +(8, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:50:26', '2023-02-06 16:50:26'), +(9, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:51:26', '2023-02-06 16:51:26'), +(10, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:52:26', '2023-02-06 16:52:26'), +(11, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:53:26', '2023-02-06 16:53:26'), +(12, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:54:26', '2023-02-06 16:54:26'), +(13, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:55:26', '2023-02-06 16:55:26'), +(14, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:56:26', '2023-02-06 16:56:26'), +(15, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:57:26', '2023-02-06 16:57:26'), +(16, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:58:25', '2023-02-06 16:58:25'), +(17, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 16:59:26', '2023-02-06 16:59:26'), +(18, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:00:25', '2023-02-06 17:00:25'), +(19, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:01:26', '2023-02-06 17:01:26'), +(20, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:02:25', '2023-02-06 17:02:25'), +(21, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:03:25', '2023-02-06 17:03:25'), +(22, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:04:25', '2023-02-06 17:04:25'), +(23, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:05:25', '2023-02-06 17:05:25'), +(24, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:06:25', '2023-02-06 17:06:25'), +(25, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:07:25', '2023-02-06 17:07:25'), +(26, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:08:25', '2023-02-06 17:08:25'), +(27, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:09:25', '2023-02-06 17:09:25'), +(28, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:10:25', '2023-02-06 17:10:25'), +(29, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:11:25', '2023-02-06 17:11:25'), +(30, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:12:25', '2023-02-06 17:12:25'), +(31, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:13:25', '2023-02-06 17:13:25'), +(32, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:14:25', '2023-02-06 17:14:25'), +(33, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:15:25', '2023-02-06 17:15:25'), +(34, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:16:25', '2023-02-06 17:16:25'), +(35, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:17:26', '2023-02-06 17:17:26'), +(36, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:18:25', '2023-02-06 17:18:25'), +(37, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:19:26', '2023-02-06 17:19:26'), +(38, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:20:25', '2023-02-06 17:20:25'), +(39, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:21:25', '2023-02-06 17:21:25'), +(40, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:22:25', '2023-02-06 17:22:25'), +(41, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:23:25', '2023-02-06 17:23:25'), +(42, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:24:25', '2023-02-06 17:24:25'), +(43, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:25:25', '2023-02-06 17:25:25'), +(44, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:26:26', '2023-02-06 17:26:26'), +(45, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:27:26', '2023-02-06 17:27:26'), +(46, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:28:26', '2023-02-06 17:28:26'), +(47, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:29:26', '2023-02-06 17:29:26'), +(48, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:30:26', '2023-02-06 17:30:26'), +(49, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:31:25', '2023-02-06 17:31:25'), +(50, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:32:25', '2023-02-06 17:32:25'), +(51, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:33:25', '2023-02-06 17:33:25'), +(52, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:34:26', '2023-02-06 17:34:26'), +(53, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:35:25', '2023-02-06 17:35:25'), +(54, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:36:25', '2023-02-06 17:36:25'), +(55, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:37:25', '2023-02-06 17:37:25'), +(56, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:38:26', '2023-02-06 17:38:26'), +(57, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:39:26', '2023-02-06 17:39:26'), +(58, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:40:26', '2023-02-06 17:40:26'), +(59, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:41:25', '2023-02-06 17:41:25'), +(60, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:42:26', '2023-02-06 17:42:26'), +(61, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:43:26', '2023-02-06 17:43:26'), +(62, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:44:26', '2023-02-06 17:44:26'), +(63, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:45:26', '2023-02-06 17:45:26'), +(64, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:46:26', '2023-02-06 17:46:26'), +(65, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:47:26', '2023-02-06 17:47:26'), +(66, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:48:26', '2023-02-06 17:48:26'), +(67, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:49:26', '2023-02-06 17:49:26'), +(68, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:50:26', '2023-02-06 17:50:26'), +(69, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:51:26', '2023-02-06 17:51:26'), +(70, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:52:26', '2023-02-06 17:52:26'), +(71, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:53:26', '2023-02-06 17:53:26'), +(72, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:54:26', '2023-02-06 17:54:26'), +(73, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:55:26', '2023-02-06 17:55:26'), +(74, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:56:26', '2023-02-06 17:56:26'), +(75, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:57:26', '2023-02-06 17:57:26'), +(76, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:58:26', '2023-02-06 17:58:26'), +(77, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 17:59:26', '2023-02-06 17:59:26'), +(78, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:00:26', '2023-02-06 18:00:26'), +(79, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:01:26', '2023-02-06 18:01:26'), +(80, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:02:26', '2023-02-06 18:02:26'), +(81, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:03:26', '2023-02-06 18:03:26'), +(82, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:04:26', '2023-02-06 18:04:26'), +(83, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:05:26', '2023-02-06 18:05:26'), +(84, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:06:26', '2023-02-06 18:06:26'), +(85, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:07:26', '2023-02-06 18:07:26'), +(86, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:08:26', '2023-02-06 18:08:26'), +(87, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:09:26', '2023-02-06 18:09:26'), +(88, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:10:26', '2023-02-06 18:10:26'), +(89, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:11:26', '2023-02-06 18:11:26'), +(90, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:12:26', '2023-02-06 18:12:26'), +(91, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:13:26', '2023-02-06 18:13:26'), +(92, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:14:26', '2023-02-06 18:14:26'), +(93, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:15:26', '2023-02-06 18:15:26'), +(94, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:16:26', '2023-02-06 18:16:26'), +(95, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:17:26', '2023-02-06 18:17:26'), +(96, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:18:26', '2023-02-06 18:18:26'), +(97, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:19:26', '2023-02-06 18:19:26'), +(98, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:20:26', '2023-02-06 18:20:26'), +(99, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:21:26', '2023-02-06 18:21:26'), +(100, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:22:26', '2023-02-06 18:22:26'), +(101, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:23:26', '2023-02-06 18:23:26'), +(102, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:24:26', '2023-02-06 18:24:26'), +(103, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:25:26', '2023-02-06 18:25:26'), +(104, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:26:26', '2023-02-06 18:26:26'), +(105, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:27:26', '2023-02-06 18:27:26'), +(106, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:28:26', '2023-02-06 18:28:26'), +(107, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:29:26', '2023-02-06 18:29:26'), +(108, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:30:26', '2023-02-06 18:30:26'), +(109, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:31:26', '2023-02-06 18:31:26'), +(110, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:32:26', '2023-02-06 18:32:26'), +(111, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:33:26', '2023-02-06 18:33:26'), +(112, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:34:26', '2023-02-06 18:34:26'), +(113, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:35:26', '2023-02-06 18:35:26'), +(114, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Too few arguments to function AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController::show(), 1 passed in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php on line 48 and exactly 2 expected in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php:56\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(48): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->show(\'1\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'show\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#22 {main}', '[]', '2023-02-06 18:36:14', '2023-02-06 18:36:14'), +(115, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:36:26', '2023-02-06 18:36:26'), +(116, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:37:26', '2023-02-06 18:37:26'), +(117, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:38:26', '2023-02-06 18:38:26'), +(118, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:39:26', '2023-02-06 18:39:26'), +(119, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:40:26', '2023-02-06 18:40:26'), +(120, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:41:26', '2023-02-06 18:41:26'), +(121, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:42:26', '2023-02-06 18:42:26'), +(122, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:43:26', '2023-02-06 18:43:26'), +(123, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:44:26', '2023-02-06 18:44:26'), +(124, 'error', 'PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column \'path\' in \'field list\' in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:82\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php(82): PDO->prepare(\'select `id`, `p...\', Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(331): Doctrine\\DBAL\\Driver\\PDOConnection->prepare(\'select `id`, `p...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(662): Illuminate\\Database\\Connection->Illuminate\\Database\\{closure}(\'select `id`, `p...\', Array)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(629): Illuminate\\Database\\Connection->runQueryCallback(\'select `id`, `p...\', Array, Object(Closure))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(338): Illuminate\\Database\\Connection->run(\'select `id`, `p...\', Array, Object(Closure))\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2159): Illuminate\\Database\\Connection->select(\'select `id`, `p...\', Array, true)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2147): Illuminate\\Database\\Query\\Builder->runSelect()\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2619): Illuminate\\Database\\Query\\Builder->Illuminate\\Database\\Query\\{closure}()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2148): Illuminate\\Database\\Query\\Builder->onceWithColumns(Array, Object(Closure))\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(130): Illuminate\\Database\\Query\\Builder->get(Array)\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(100): October\\Rain\\Database\\QueryBuilder->getDuplicateCached(Array)\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(546): October\\Rain\\Database\\QueryBuilder->get(Array)\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(530): Illuminate\\Database\\Eloquent\\Builder->getModels(Array)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(155): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(144): Illuminate\\Database\\Eloquent\\Relations\\Relation->get()\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(594): Illuminate\\Database\\Eloquent\\Relations\\Relation->getEager()\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(563): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelation(Array, \'featured_images\', Object(Closure))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(531): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelations(Array)\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(143): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php(359): October\\Rain\\Database\\Builder->paginate(15, 1)\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(46): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#23 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index()\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(123): call_user_func_array(Array, Array)\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#45 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#46 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#47 {main}\n\nNext Doctrine\\DBAL\\Driver\\PDO\\Exception: SQLSTATE[42S22]: Column not found: 1054 Unknown column \'path\' in \'field list\' in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDO/Exception.php:18\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php(87): Doctrine\\DBAL\\Driver\\PDO\\Exception::new(Object(PDOException))\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(331): Doctrine\\DBAL\\Driver\\PDOConnection->prepare(\'select `id`, `p...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(662): Illuminate\\Database\\Connection->Illuminate\\Database\\{closure}(\'select `id`, `p...\', Array)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(629): Illuminate\\Database\\Connection->runQueryCallback(\'select `id`, `p...\', Array, Object(Closure))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(338): Illuminate\\Database\\Connection->run(\'select `id`, `p...\', Array, Object(Closure))\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2159): Illuminate\\Database\\Connection->select(\'select `id`, `p...\', Array, true)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2147): Illuminate\\Database\\Query\\Builder->runSelect()\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2619): Illuminate\\Database\\Query\\Builder->Illuminate\\Database\\Query\\{closure}()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2148): Illuminate\\Database\\Query\\Builder->onceWithColumns(Array, Object(Closure))\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(130): Illuminate\\Database\\Query\\Builder->get(Array)\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(100): October\\Rain\\Database\\QueryBuilder->getDuplicateCached(Array)\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(546): October\\Rain\\Database\\QueryBuilder->get(Array)\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(530): Illuminate\\Database\\Eloquent\\Builder->getModels(Array)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(155): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(144): Illuminate\\Database\\Eloquent\\Relations\\Relation->get()\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(594): Illuminate\\Database\\Eloquent\\Relations\\Relation->getEager()\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(563): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelation(Array, \'featured_images\', Object(Closure))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(531): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelations(Array)\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(143): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php(359): October\\Rain\\Database\\Builder->paginate(15, 1)\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(46): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#23 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index()\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(123): call_user_func_array(Array, Array)\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#45 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#46 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#47 {main}\n\nNext Illuminate\\Database\\QueryException: SQLSTATE[42S22]: Column not found: 1054 Unknown column \'path\' in \'field list\' (SQL: select `id`, `path`, `sort_order` from `system_files` where `system_files`.`attachment_id` in (1) and `system_files`.`attachment_type` = RainLab\\Blog\\Models\\Post and `field` = featured_images order by `sort_order` asc) in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php:669\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(629): Illuminate\\Database\\Connection->runQueryCallback(\'select `id`, `p...\', Array, Object(Closure))\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(338): Illuminate\\Database\\Connection->run(\'select `id`, `p...\', Array, Object(Closure))\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2159): Illuminate\\Database\\Connection->select(\'select `id`, `p...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2147): Illuminate\\Database\\Query\\Builder->runSelect()\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2619): Illuminate\\Database\\Query\\Builder->Illuminate\\Database\\Query\\{closure}()\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2148): Illuminate\\Database\\Query\\Builder->onceWithColumns(Array, Object(Closure))\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(130): Illuminate\\Database\\Query\\Builder->get(Array)\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(100): October\\Rain\\Database\\QueryBuilder->getDuplicateCached(Array)\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(546): October\\Rain\\Database\\QueryBuilder->get(Array)\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(530): Illuminate\\Database\\Eloquent\\Builder->getModels(Array)\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(155): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(144): Illuminate\\Database\\Eloquent\\Relations\\Relation->get()\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(594): Illuminate\\Database\\Eloquent\\Relations\\Relation->getEager()\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(563): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelation(Array, \'featured_images\', Object(Closure))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(531): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelations(Array)\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(143): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php(359): October\\Rain\\Database\\Builder->paginate(15, 1)\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(46): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#20 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index()\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(123): call_user_func_array(Array, Array)\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#44 {main}', '[]', '2023-02-06 18:45:05', '2023-02-06 18:45:05'), +(125, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:45:26', '2023-02-06 18:45:26'), +(126, 'error', 'PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column \'path\' in \'field list\' in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:82\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php(82): PDO->prepare(\'select `id`, `s...\', Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(331): Doctrine\\DBAL\\Driver\\PDOConnection->prepare(\'select `id`, `s...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(662): Illuminate\\Database\\Connection->Illuminate\\Database\\{closure}(\'select `id`, `s...\', Array)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(629): Illuminate\\Database\\Connection->runQueryCallback(\'select `id`, `s...\', Array, Object(Closure))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(338): Illuminate\\Database\\Connection->run(\'select `id`, `s...\', Array, Object(Closure))\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2159): Illuminate\\Database\\Connection->select(\'select `id`, `s...\', Array, true)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2147): Illuminate\\Database\\Query\\Builder->runSelect()\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2619): Illuminate\\Database\\Query\\Builder->Illuminate\\Database\\Query\\{closure}()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2148): Illuminate\\Database\\Query\\Builder->onceWithColumns(Array, Object(Closure))\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(130): Illuminate\\Database\\Query\\Builder->get(Array)\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(100): October\\Rain\\Database\\QueryBuilder->getDuplicateCached(Array)\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(546): October\\Rain\\Database\\QueryBuilder->get(Array)\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(530): Illuminate\\Database\\Eloquent\\Builder->getModels(Array)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(155): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(144): Illuminate\\Database\\Eloquent\\Relations\\Relation->get()\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(594): Illuminate\\Database\\Eloquent\\Relations\\Relation->getEager()\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(563): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelation(Array, \'featured_images\', Object(Closure))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(531): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelations(Array)\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(143): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php(359): October\\Rain\\Database\\Builder->paginate(15, 1)\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(46): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#23 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index()\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(123): call_user_func_array(Array, Array)\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#45 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#46 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#47 {main}\n\nNext Doctrine\\DBAL\\Driver\\PDO\\Exception: SQLSTATE[42S22]: Column not found: 1054 Unknown column \'path\' in \'field list\' in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDO/Exception.php:18\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php(87): Doctrine\\DBAL\\Driver\\PDO\\Exception::new(Object(PDOException))\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(331): Doctrine\\DBAL\\Driver\\PDOConnection->prepare(\'select `id`, `s...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(662): Illuminate\\Database\\Connection->Illuminate\\Database\\{closure}(\'select `id`, `s...\', Array)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(629): Illuminate\\Database\\Connection->runQueryCallback(\'select `id`, `s...\', Array, Object(Closure))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(338): Illuminate\\Database\\Connection->run(\'select `id`, `s...\', Array, Object(Closure))\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2159): Illuminate\\Database\\Connection->select(\'select `id`, `s...\', Array, true)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2147): Illuminate\\Database\\Query\\Builder->runSelect()\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2619): Illuminate\\Database\\Query\\Builder->Illuminate\\Database\\Query\\{closure}()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2148): Illuminate\\Database\\Query\\Builder->onceWithColumns(Array, Object(Closure))\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(130): Illuminate\\Database\\Query\\Builder->get(Array)\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(100): October\\Rain\\Database\\QueryBuilder->getDuplicateCached(Array)\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(546): October\\Rain\\Database\\QueryBuilder->get(Array)\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(530): Illuminate\\Database\\Eloquent\\Builder->getModels(Array)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(155): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(144): Illuminate\\Database\\Eloquent\\Relations\\Relation->get()\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(594): Illuminate\\Database\\Eloquent\\Relations\\Relation->getEager()\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(563): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelation(Array, \'featured_images\', Object(Closure))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(531): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelations(Array)\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(143): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php(359): October\\Rain\\Database\\Builder->paginate(15, 1)\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(46): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#23 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index()\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(123): call_user_func_array(Array, Array)\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#45 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#46 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#47 {main}\n\nNext Illuminate\\Database\\QueryException: SQLSTATE[42S22]: Column not found: 1054 Unknown column \'path\' in \'field list\' (SQL: select `id`, `sort_order`, `path` from `system_files` where `system_files`.`attachment_id` in (1) and `system_files`.`attachment_type` = RainLab\\Blog\\Models\\Post and `field` = featured_images order by `sort_order` asc) in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php:669\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(629): Illuminate\\Database\\Connection->runQueryCallback(\'select `id`, `s...\', Array, Object(Closure))\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(338): Illuminate\\Database\\Connection->run(\'select `id`, `s...\', Array, Object(Closure))\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2159): Illuminate\\Database\\Connection->select(\'select `id`, `s...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2147): Illuminate\\Database\\Query\\Builder->runSelect()\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2619): Illuminate\\Database\\Query\\Builder->Illuminate\\Database\\Query\\{closure}()\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2148): Illuminate\\Database\\Query\\Builder->onceWithColumns(Array, Object(Closure))\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(130): Illuminate\\Database\\Query\\Builder->get(Array)\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(100): October\\Rain\\Database\\QueryBuilder->getDuplicateCached(Array)\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(546): October\\Rain\\Database\\QueryBuilder->get(Array)\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(530): Illuminate\\Database\\Eloquent\\Builder->getModels(Array)\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(155): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(144): Illuminate\\Database\\Eloquent\\Relations\\Relation->get()\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(594): Illuminate\\Database\\Eloquent\\Relations\\Relation->getEager()\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(563): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelation(Array, \'featured_images\', Object(Closure))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(531): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelations(Array)\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(143): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php(359): October\\Rain\\Database\\Builder->paginate(15, 1)\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(46): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#20 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index()\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(123): call_user_func_array(Array, Array)\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#44 {main}', '[]', '2023-02-06 18:46:01', '2023-02-06 18:46:01'), +(127, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:46:26', '2023-02-06 18:46:26'), +(128, 'error', 'PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column \'path\' in \'field list\' in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:82\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php(82): PDO->prepare(\'select `id`, `p...\', Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(331): Doctrine\\DBAL\\Driver\\PDOConnection->prepare(\'select `id`, `p...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(662): Illuminate\\Database\\Connection->Illuminate\\Database\\{closure}(\'select `id`, `p...\', Array)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(629): Illuminate\\Database\\Connection->runQueryCallback(\'select `id`, `p...\', Array, Object(Closure))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(338): Illuminate\\Database\\Connection->run(\'select `id`, `p...\', Array, Object(Closure))\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2159): Illuminate\\Database\\Connection->select(\'select `id`, `p...\', Array, true)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2147): Illuminate\\Database\\Query\\Builder->runSelect()\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2619): Illuminate\\Database\\Query\\Builder->Illuminate\\Database\\Query\\{closure}()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2148): Illuminate\\Database\\Query\\Builder->onceWithColumns(Array, Object(Closure))\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(130): Illuminate\\Database\\Query\\Builder->get(Array)\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(100): October\\Rain\\Database\\QueryBuilder->getDuplicateCached(Array)\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(546): October\\Rain\\Database\\QueryBuilder->get(Array)\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(530): Illuminate\\Database\\Eloquent\\Builder->getModels(Array)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(155): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(144): Illuminate\\Database\\Eloquent\\Relations\\Relation->get()\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(594): Illuminate\\Database\\Eloquent\\Relations\\Relation->getEager()\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(563): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelation(Array, \'featured_images\', Object(Closure))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(531): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelations(Array)\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(143): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php(359): October\\Rain\\Database\\Builder->paginate(15, 1)\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(46): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#23 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index()\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(123): call_user_func_array(Array, Array)\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#45 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#46 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#47 {main}\n\nNext Doctrine\\DBAL\\Driver\\PDO\\Exception: SQLSTATE[42S22]: Column not found: 1054 Unknown column \'path\' in \'field list\' in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDO/Exception.php:18\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php(87): Doctrine\\DBAL\\Driver\\PDO\\Exception::new(Object(PDOException))\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(331): Doctrine\\DBAL\\Driver\\PDOConnection->prepare(\'select `id`, `p...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(662): Illuminate\\Database\\Connection->Illuminate\\Database\\{closure}(\'select `id`, `p...\', Array)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(629): Illuminate\\Database\\Connection->runQueryCallback(\'select `id`, `p...\', Array, Object(Closure))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(338): Illuminate\\Database\\Connection->run(\'select `id`, `p...\', Array, Object(Closure))\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2159): Illuminate\\Database\\Connection->select(\'select `id`, `p...\', Array, true)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2147): Illuminate\\Database\\Query\\Builder->runSelect()\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2619): Illuminate\\Database\\Query\\Builder->Illuminate\\Database\\Query\\{closure}()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2148): Illuminate\\Database\\Query\\Builder->onceWithColumns(Array, Object(Closure))\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(130): Illuminate\\Database\\Query\\Builder->get(Array)\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(100): October\\Rain\\Database\\QueryBuilder->getDuplicateCached(Array)\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(546): October\\Rain\\Database\\QueryBuilder->get(Array)\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(530): Illuminate\\Database\\Eloquent\\Builder->getModels(Array)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(155): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(144): Illuminate\\Database\\Eloquent\\Relations\\Relation->get()\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(594): Illuminate\\Database\\Eloquent\\Relations\\Relation->getEager()\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(563): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelation(Array, \'featured_images\', Object(Closure))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(531): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelations(Array)\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(143): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php(359): October\\Rain\\Database\\Builder->paginate(15, 1)\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(46): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#23 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index()\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(123): call_user_func_array(Array, Array)\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#45 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#46 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#47 {main}\n\nNext Illuminate\\Database\\QueryException: SQLSTATE[42S22]: Column not found: 1054 Unknown column \'path\' in \'field list\' (SQL: select `id`, `path` from `system_files` where `system_files`.`attachment_id` in (1) and `system_files`.`attachment_type` = RainLab\\Blog\\Models\\Post and `field` = featured_images order by `sort_order` asc) in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php:669\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(629): Illuminate\\Database\\Connection->runQueryCallback(\'select `id`, `p...\', Array, Object(Closure))\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Connection.php(338): Illuminate\\Database\\Connection->run(\'select `id`, `p...\', Array, Object(Closure))\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2159): Illuminate\\Database\\Connection->select(\'select `id`, `p...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2147): Illuminate\\Database\\Query\\Builder->runSelect()\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2619): Illuminate\\Database\\Query\\Builder->Illuminate\\Database\\Query\\{closure}()\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2148): Illuminate\\Database\\Query\\Builder->onceWithColumns(Array, Object(Closure))\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(130): Illuminate\\Database\\Query\\Builder->get(Array)\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/QueryBuilder.php(100): October\\Rain\\Database\\QueryBuilder->getDuplicateCached(Array)\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(546): October\\Rain\\Database\\QueryBuilder->get(Array)\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(530): Illuminate\\Database\\Eloquent\\Builder->getModels(Array)\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(155): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php(144): Illuminate\\Database\\Eloquent\\Relations\\Relation->get()\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(594): Illuminate\\Database\\Eloquent\\Relations\\Relation->getEager()\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(563): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelation(Array, \'featured_images\', Object(Closure))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(531): Illuminate\\Database\\Eloquent\\Builder->eagerLoadRelations(Array)\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(143): Illuminate\\Database\\Eloquent\\Builder->get(Array)\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php(359): October\\Rain\\Database\\Builder->paginate(15, 1)\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(46): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#20 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index()\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(123): call_user_func_array(Array, Array)\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#44 {main}', '[]', '2023-02-06 18:46:33', '2023-02-06 18:46:33'), +(129, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:47:26', '2023-02-06 18:47:26'); +INSERT INTO `system_event_logs` (`id`, `level`, `message`, `details`, `created_at`, `updated_at`) VALUES +(130, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:48:26', '2023-02-06 18:48:26'), +(131, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:49:26', '2023-02-06 18:49:26'), +(132, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:50:26', '2023-02-06 18:50:26'), +(133, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:51:26', '2023-02-06 18:51:26'), +(134, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:52:26', '2023-02-06 18:52:26'), +(135, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:53:26', '2023-02-06 18:53:26'), +(136, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:54:26', '2023-02-06 18:54:26'), +(137, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:55:26', '2023-02-06 18:55:26'), +(138, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Class \'RainLab\\Blog\\Classes\\ImageResource\' not found in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/classes/PostResource.php:24\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(60): RainLab\\Blog\\Classes\\PostResource->toArray(Object(Illuminate\\Http\\Request))\n#1 [internal function]: Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(RainLab\\Blog\\Classes\\PostResource), 0)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Collection.php(638): array_map(Object(Closure), Array, Array)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(61): Illuminate\\Support\\Collection->map(Object(Closure))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(100): Illuminate\\Support\\HigherOrderCollectionProxy->__call(\'toArray\', Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(94): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toArray(Object(Illuminate\\Http\\Request))\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php(19): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve(Object(Illuminate\\Http\\Request))\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(132): Illuminate\\Http\\Resources\\Json\\PaginatedResourceResponse->toResponse(Object(Illuminate\\Http\\Request))\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(112): Illuminate\\Http\\Resources\\Json\\ResourceCollection->preparePaginatedResponse(Object(Illuminate\\Http\\Request))\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(189): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(69): Illuminate\\Http\\Resources\\Json\\JsonResource->response()\n#11 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(138): call_user_func_array(Array, Array)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#35 {main}', '[]', '2023-02-06 18:55:55', '2023-02-06 18:55:55'), +(139, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:56:26', '2023-02-06 18:56:26'), +(140, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:57:26', '2023-02-06 18:57:26'), +(141, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Class \'RainLab\\Blog\\Classes\\ImageResource\' not found in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/classes/PostResource.php:24\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(60): RainLab\\Blog\\Classes\\PostResource->toArray(Object(Illuminate\\Http\\Request))\n#1 [internal function]: Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(RainLab\\Blog\\Classes\\PostResource), 0)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Collection.php(638): array_map(Object(Closure), Array, Array)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(61): Illuminate\\Support\\Collection->map(Object(Closure))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(100): Illuminate\\Support\\HigherOrderCollectionProxy->__call(\'toArray\', Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(94): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toArray(Object(Illuminate\\Http\\Request))\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php(19): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve(Object(Illuminate\\Http\\Request))\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(132): Illuminate\\Http\\Resources\\Json\\PaginatedResourceResponse->toResponse(Object(Illuminate\\Http\\Request))\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(112): Illuminate\\Http\\Resources\\Json\\ResourceCollection->preparePaginatedResponse(Object(Illuminate\\Http\\Request))\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(189): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(69): Illuminate\\Http\\Resources\\Json\\JsonResource->response()\n#11 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(138): call_user_func_array(Array, Array)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#35 {main}', '[]', '2023-02-06 18:57:50', '2023-02-06 18:57:50'), +(142, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Class \'RainLab\\Blog\\Classes\\ImageResource\' not found in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/classes/PostResource.php:24\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(60): RainLab\\Blog\\Classes\\PostResource->toArray(Object(Illuminate\\Http\\Request))\n#1 [internal function]: Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(RainLab\\Blog\\Classes\\PostResource), 0)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Collection.php(638): array_map(Object(Closure), Array, Array)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(61): Illuminate\\Support\\Collection->map(Object(Closure))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(100): Illuminate\\Support\\HigherOrderCollectionProxy->__call(\'toArray\', Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(94): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toArray(Object(Illuminate\\Http\\Request))\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php(19): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve(Object(Illuminate\\Http\\Request))\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(132): Illuminate\\Http\\Resources\\Json\\PaginatedResourceResponse->toResponse(Object(Illuminate\\Http\\Request))\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(112): Illuminate\\Http\\Resources\\Json\\ResourceCollection->preparePaginatedResponse(Object(Illuminate\\Http\\Request))\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(189): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(69): Illuminate\\Http\\Resources\\Json\\JsonResource->response()\n#11 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(138): call_user_func_array(Array, Array)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#35 {main}', '[]', '2023-02-06 18:58:05', '2023-02-06 18:58:05'), +(143, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:58:26', '2023-02-06 18:58:26'), +(144, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function format() on null in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/classes/ImageResource.php:23\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(60): RainLab\\Blog\\Classes\\ImageResource->toArray(Object(Illuminate\\Http\\Request))\n#1 [internal function]: Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(RainLab\\Blog\\Classes\\ImageResource), 0)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Collection.php(638): array_map(Object(Closure), Array, Array)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(61): Illuminate\\Support\\Collection->map(Object(Closure))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(100): Illuminate\\Support\\HigherOrderCollectionProxy->__call(\'toArray\', Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(94): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toArray(Object(Illuminate\\Http\\Request))\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(211): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve(Object(Illuminate\\Http\\Request))\n#7 [internal function]: Illuminate\\Http\\Resources\\Json\\JsonResource->jsonSerialize()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(71): json_encode(Array, 0)\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/symfony/http-foundation/JsonResponse.php(54): Illuminate\\Http\\JsonResponse->setData(Array)\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(31): Symfony\\Component\\HttpFoundation\\JsonResponse->__construct(Array, 200, Array)\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php(99): Illuminate\\Http\\JsonResponse->__construct(Array, 200, Array, 0)\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php(26): Illuminate\\Routing\\ResponseFactory->json(Array, 200)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(132): Illuminate\\Http\\Resources\\Json\\PaginatedResourceResponse->toResponse(Object(Illuminate\\Http\\Request))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(112): Illuminate\\Http\\Resources\\Json\\ResourceCollection->preparePaginatedResponse(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(189): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(69): Illuminate\\Http\\Resources\\Json\\JsonResource->response()\n#17 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(138): call_user_func_array(Array, Array)\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#41 {main}', '[]', '2023-02-06 18:59:24', '2023-02-06 18:59:24'), +(145, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 18:59:26', '2023-02-06 18:59:26'), +(146, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function format() on null in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/classes/ImageResource.php:23\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(60): RainLab\\Blog\\Classes\\ImageResource->toArray(Object(Illuminate\\Http\\Request))\n#1 [internal function]: Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(RainLab\\Blog\\Classes\\ImageResource), 0)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Collection.php(638): array_map(Object(Closure), Array, Array)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(61): Illuminate\\Support\\Collection->map(Object(Closure))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(100): Illuminate\\Support\\HigherOrderCollectionProxy->__call(\'toArray\', Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(94): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toArray(Object(Illuminate\\Http\\Request))\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(211): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve(Object(Illuminate\\Http\\Request))\n#7 [internal function]: Illuminate\\Http\\Resources\\Json\\JsonResource->jsonSerialize()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(71): json_encode(Array, 0)\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/symfony/http-foundation/JsonResponse.php(54): Illuminate\\Http\\JsonResponse->setData(Array)\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(31): Symfony\\Component\\HttpFoundation\\JsonResponse->__construct(Array, 200, Array)\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php(99): Illuminate\\Http\\JsonResponse->__construct(Array, 200, Array, 0)\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php(26): Illuminate\\Routing\\ResponseFactory->json(Array, 200)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(132): Illuminate\\Http\\Resources\\Json\\PaginatedResourceResponse->toResponse(Object(Illuminate\\Http\\Request))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(112): Illuminate\\Http\\Resources\\Json\\ResourceCollection->preparePaginatedResponse(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(189): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(69): Illuminate\\Http\\Resources\\Json\\JsonResource->response()\n#17 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(138): call_user_func_array(Array, Array)\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#41 {main}', '[]', '2023-02-06 18:59:30', '2023-02-06 18:59:30'), +(147, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:00:26', '2023-02-06 19:00:26'), +(148, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function first() on null in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/CollectsResources.php:29\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(52): Illuminate\\Http\\Resources\\Json\\ResourceCollection->collectResource(NULL)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/AnonymousResourceCollection.php(25): Illuminate\\Http\\Resources\\Json\\ResourceCollection->__construct(NULL)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(78): Illuminate\\Http\\Resources\\Json\\AnonymousResourceCollection->__construct(NULL, \'RainLab\\\\Blog\\\\Cl...\')\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/classes/ImageResource.php(24): Illuminate\\Http\\Resources\\Json\\JsonResource::collection(NULL)\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(60): RainLab\\Blog\\Classes\\ImageResource->toArray(Object(Illuminate\\Http\\Request))\n#5 [internal function]: Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(RainLab\\Blog\\Classes\\ImageResource), 0)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Collection.php(638): array_map(Object(Closure), Array, Array)\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(61): Illuminate\\Support\\Collection->map(Object(Closure))\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(100): Illuminate\\Support\\HigherOrderCollectionProxy->__call(\'toArray\', Array)\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(94): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toArray(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(211): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve(Object(Illuminate\\Http\\Request))\n#11 [internal function]: Illuminate\\Http\\Resources\\Json\\JsonResource->jsonSerialize()\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(71): json_encode(Array, 0)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/symfony/http-foundation/JsonResponse.php(54): Illuminate\\Http\\JsonResponse->setData(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(31): Symfony\\Component\\HttpFoundation\\JsonResponse->__construct(Array, 200, Array)\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php(99): Illuminate\\Http\\JsonResponse->__construct(Array, 200, Array, 0)\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php(26): Illuminate\\Routing\\ResponseFactory->json(Array, 200)\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(132): Illuminate\\Http\\Resources\\Json\\PaginatedResourceResponse->toResponse(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(112): Illuminate\\Http\\Resources\\Json\\ResourceCollection->preparePaginatedResponse(Object(Illuminate\\Http\\Request))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(189): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse(Object(Illuminate\\Http\\Request))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(69): Illuminate\\Http\\Resources\\Json\\JsonResource->response()\n#21 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(138): call_user_func_array(Array, Array)\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#45 {main}', '[]', '2023-02-06 19:00:37', '2023-02-06 19:00:37'), +(149, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function first() on null in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/CollectsResources.php:29\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(52): Illuminate\\Http\\Resources\\Json\\ResourceCollection->collectResource(NULL)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/AnonymousResourceCollection.php(25): Illuminate\\Http\\Resources\\Json\\ResourceCollection->__construct(NULL)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(78): Illuminate\\Http\\Resources\\Json\\AnonymousResourceCollection->__construct(NULL, \'RainLab\\\\Blog\\\\Cl...\')\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/classes/ImageResource.php(24): Illuminate\\Http\\Resources\\Json\\JsonResource::collection(NULL)\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(60): RainLab\\Blog\\Classes\\ImageResource->toArray(Object(Illuminate\\Http\\Request))\n#5 [internal function]: Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(RainLab\\Blog\\Classes\\ImageResource), 0)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Collection.php(638): array_map(Object(Closure), Array, Array)\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(61): Illuminate\\Support\\Collection->map(Object(Closure))\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(100): Illuminate\\Support\\HigherOrderCollectionProxy->__call(\'toArray\', Array)\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(94): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toArray(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(211): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve(Object(Illuminate\\Http\\Request))\n#11 [internal function]: Illuminate\\Http\\Resources\\Json\\JsonResource->jsonSerialize()\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(71): json_encode(Array, 0)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/symfony/http-foundation/JsonResponse.php(54): Illuminate\\Http\\JsonResponse->setData(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(31): Symfony\\Component\\HttpFoundation\\JsonResponse->__construct(Array, 200, Array)\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php(99): Illuminate\\Http\\JsonResponse->__construct(Array, 200, Array, 0)\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php(26): Illuminate\\Routing\\ResponseFactory->json(Array, 200)\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(132): Illuminate\\Http\\Resources\\Json\\PaginatedResourceResponse->toResponse(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(112): Illuminate\\Http\\Resources\\Json\\ResourceCollection->preparePaginatedResponse(Object(Illuminate\\Http\\Request))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(189): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse(Object(Illuminate\\Http\\Request))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(69): Illuminate\\Http\\Resources\\Json\\JsonResource->response()\n#21 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(138): call_user_func_array(Array, Array)\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#45 {main}', '[]', '2023-02-06 19:00:48', '2023-02-06 19:00:48'), +(150, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:01:26', '2023-02-06 19:01:26'), +(151, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:02:26', '2023-02-06 19:02:26'), +(152, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function first() on null in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/CollectsResources.php:29\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(52): Illuminate\\Http\\Resources\\Json\\ResourceCollection->collectResource(NULL)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/AnonymousResourceCollection.php(25): Illuminate\\Http\\Resources\\Json\\ResourceCollection->__construct(NULL)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(78): Illuminate\\Http\\Resources\\Json\\AnonymousResourceCollection->__construct(NULL, \'RainLab\\\\Blog\\\\Cl...\')\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/classes/ImageResource.php(24): Illuminate\\Http\\Resources\\Json\\JsonResource::collection(NULL)\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(60): RainLab\\Blog\\Classes\\ImageResource->toArray(Object(Illuminate\\Http\\Request))\n#5 [internal function]: Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(RainLab\\Blog\\Classes\\ImageResource), 0)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Collection.php(638): array_map(Object(Closure), Array, Array)\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(61): Illuminate\\Support\\Collection->map(Object(Closure))\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(100): Illuminate\\Support\\HigherOrderCollectionProxy->__call(\'toArray\', Array)\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(94): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toArray(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(211): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve(Object(Illuminate\\Http\\Request))\n#11 [internal function]: Illuminate\\Http\\Resources\\Json\\JsonResource->jsonSerialize()\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(71): json_encode(Array, 0)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/symfony/http-foundation/JsonResponse.php(54): Illuminate\\Http\\JsonResponse->setData(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(31): Symfony\\Component\\HttpFoundation\\JsonResponse->__construct(Array, 200, Array)\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php(99): Illuminate\\Http\\JsonResponse->__construct(Array, 200, Array, 0)\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php(26): Illuminate\\Routing\\ResponseFactory->json(Array, 200)\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(132): Illuminate\\Http\\Resources\\Json\\PaginatedResourceResponse->toResponse(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(112): Illuminate\\Http\\Resources\\Json\\ResourceCollection->preparePaginatedResponse(Object(Illuminate\\Http\\Request))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(189): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse(Object(Illuminate\\Http\\Request))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(70): Illuminate\\Http\\Resources\\Json\\JsonResource->response()\n#21 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(139): call_user_func_array(Array, Array)\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#45 {main}', '[]', '2023-02-06 19:02:58', '2023-02-06 19:02:58'), +(153, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:03:26', '2023-02-06 19:03:26'), +(154, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function first() on null in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/CollectsResources.php:29\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(52): Illuminate\\Http\\Resources\\Json\\ResourceCollection->collectResource(NULL)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/AnonymousResourceCollection.php(25): Illuminate\\Http\\Resources\\Json\\ResourceCollection->__construct(NULL)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(78): Illuminate\\Http\\Resources\\Json\\AnonymousResourceCollection->__construct(NULL, \'RainLab\\\\Blog\\\\Cl...\')\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/classes/ImageResource.php(24): Illuminate\\Http\\Resources\\Json\\JsonResource::collection(NULL)\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(60): RainLab\\Blog\\Classes\\ImageResource->toArray(Object(Illuminate\\Http\\Request))\n#5 [internal function]: Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(RainLab\\Blog\\Classes\\ImageResource), 0)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Collection.php(638): array_map(Object(Closure), Array, Array)\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(61): Illuminate\\Support\\Collection->map(Object(Closure))\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(100): Illuminate\\Support\\HigherOrderCollectionProxy->__call(\'toArray\', Array)\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(94): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toArray(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(211): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve(Object(Illuminate\\Http\\Request))\n#11 [internal function]: Illuminate\\Http\\Resources\\Json\\JsonResource->jsonSerialize()\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(71): json_encode(Array, 0)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/symfony/http-foundation/JsonResponse.php(54): Illuminate\\Http\\JsonResponse->setData(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(31): Symfony\\Component\\HttpFoundation\\JsonResponse->__construct(Array, 200, Array)\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php(99): Illuminate\\Http\\JsonResponse->__construct(Array, 200, Array, 0)\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php(26): Illuminate\\Routing\\ResponseFactory->json(Array, 200)\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(132): Illuminate\\Http\\Resources\\Json\\PaginatedResourceResponse->toResponse(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(112): Illuminate\\Http\\Resources\\Json\\ResourceCollection->preparePaginatedResponse(Object(Illuminate\\Http\\Request))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(189): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse(Object(Illuminate\\Http\\Request))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(70): Illuminate\\Http\\Resources\\Json\\JsonResource->response()\n#21 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(139): call_user_func_array(Array, Array)\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#45 {main}', '[]', '2023-02-06 19:03:54', '2023-02-06 19:03:54'), +(155, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function first() on null in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/CollectsResources.php:29\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(52): Illuminate\\Http\\Resources\\Json\\ResourceCollection->collectResource(NULL)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/AnonymousResourceCollection.php(25): Illuminate\\Http\\Resources\\Json\\ResourceCollection->__construct(NULL)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(78): Illuminate\\Http\\Resources\\Json\\AnonymousResourceCollection->__construct(NULL, \'RainLab\\\\Blog\\\\Cl...\')\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/classes/ImageResource.php(24): Illuminate\\Http\\Resources\\Json\\JsonResource::collection(NULL)\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(60): RainLab\\Blog\\Classes\\ImageResource->toArray(Object(Illuminate\\Http\\Request))\n#5 [internal function]: Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(RainLab\\Blog\\Classes\\ImageResource), 0)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Collection.php(638): array_map(Object(Closure), Array, Array)\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(61): Illuminate\\Support\\Collection->map(Object(Closure))\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(100): Illuminate\\Support\\HigherOrderCollectionProxy->__call(\'toArray\', Array)\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(94): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toArray(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(211): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve(Object(Illuminate\\Http\\Request))\n#11 [internal function]: Illuminate\\Http\\Resources\\Json\\JsonResource->jsonSerialize()\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(71): json_encode(Array, 0)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/symfony/http-foundation/JsonResponse.php(54): Illuminate\\Http\\JsonResponse->setData(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(31): Symfony\\Component\\HttpFoundation\\JsonResponse->__construct(Array, 200, Array)\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php(99): Illuminate\\Http\\JsonResponse->__construct(Array, 200, Array, 0)\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php(26): Illuminate\\Routing\\ResponseFactory->json(Array, 200)\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(132): Illuminate\\Http\\Resources\\Json\\PaginatedResourceResponse->toResponse(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(112): Illuminate\\Http\\Resources\\Json\\ResourceCollection->preparePaginatedResponse(Object(Illuminate\\Http\\Request))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(189): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse(Object(Illuminate\\Http\\Request))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(70): Illuminate\\Http\\Resources\\Json\\JsonResource->response()\n#21 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(139): call_user_func_array(Array, Array)\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#45 {main}', '[]', '2023-02-06 19:03:59', '2023-02-06 19:03:59'), +(156, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:04:26', '2023-02-06 19:04:26'), +(157, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:05:26', '2023-02-06 19:05:26'), +(158, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:06:26', '2023-02-06 19:06:26'), +(159, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:07:26', '2023-02-06 19:07:26'), +(160, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:08:26', '2023-02-06 19:08:26'), +(161, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function first() on null in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/CollectsResources.php:29\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(52): Illuminate\\Http\\Resources\\Json\\ResourceCollection->collectResource(NULL)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/AnonymousResourceCollection.php(25): Illuminate\\Http\\Resources\\Json\\ResourceCollection->__construct(NULL)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(78): Illuminate\\Http\\Resources\\Json\\AnonymousResourceCollection->__construct(NULL, \'RainLab\\\\Blog\\\\Cl...\')\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/classes/ImageResource.php(24): Illuminate\\Http\\Resources\\Json\\JsonResource::collection(NULL)\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(60): RainLab\\Blog\\Classes\\ImageResource->toArray(Object(Illuminate\\Http\\Request))\n#5 [internal function]: Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(RainLab\\Blog\\Classes\\ImageResource), 0)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Collection.php(638): array_map(Object(Closure), Array, Array)\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(61): Illuminate\\Support\\Collection->map(Object(Closure))\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(100): Illuminate\\Support\\HigherOrderCollectionProxy->__call(\'toArray\', Array)\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(94): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toArray(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(211): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve(Object(Illuminate\\Http\\Request))\n#11 [internal function]: Illuminate\\Http\\Resources\\Json\\JsonResource->jsonSerialize()\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(71): json_encode(Array, 0)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/symfony/http-foundation/JsonResponse.php(54): Illuminate\\Http\\JsonResponse->setData(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(31): Symfony\\Component\\HttpFoundation\\JsonResponse->__construct(Array, 200, Array)\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php(99): Illuminate\\Http\\JsonResponse->__construct(Array, 200, Array, 0)\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php(26): Illuminate\\Routing\\ResponseFactory->json(Array, 200)\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(132): Illuminate\\Http\\Resources\\Json\\PaginatedResourceResponse->toResponse(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(112): Illuminate\\Http\\Resources\\Json\\ResourceCollection->preparePaginatedResponse(Object(Illuminate\\Http\\Request))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(189): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse(Object(Illuminate\\Http\\Request))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(42): Illuminate\\Http\\Resources\\Json\\JsonResource->response()\n#21 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(116): call_user_func_array(Array, Array)\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#45 {main}', '[]', '2023-02-06 19:09:05', '2023-02-06 19:09:05'), +(162, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function first() on null in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/CollectsResources.php:29\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(52): Illuminate\\Http\\Resources\\Json\\ResourceCollection->collectResource(NULL)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/AnonymousResourceCollection.php(25): Illuminate\\Http\\Resources\\Json\\ResourceCollection->__construct(NULL)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(78): Illuminate\\Http\\Resources\\Json\\AnonymousResourceCollection->__construct(NULL, \'RainLab\\\\Blog\\\\Cl...\')\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/classes/ImageResource.php(24): Illuminate\\Http\\Resources\\Json\\JsonResource::collection(NULL)\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(60): RainLab\\Blog\\Classes\\ImageResource->toArray(Object(Illuminate\\Http\\Request))\n#5 [internal function]: Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(RainLab\\Blog\\Classes\\ImageResource), 0)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Collection.php(638): array_map(Object(Closure), Array, Array)\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(61): Illuminate\\Support\\Collection->map(Object(Closure))\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(100): Illuminate\\Support\\HigherOrderCollectionProxy->__call(\'toArray\', Array)\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(94): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toArray(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(211): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve(Object(Illuminate\\Http\\Request))\n#11 [internal function]: Illuminate\\Http\\Resources\\Json\\JsonResource->jsonSerialize()\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(71): json_encode(Array, 0)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/symfony/http-foundation/JsonResponse.php(54): Illuminate\\Http\\JsonResponse->setData(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(31): Symfony\\Component\\HttpFoundation\\JsonResponse->__construct(Array, 200, Array)\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php(99): Illuminate\\Http\\JsonResponse->__construct(Array, 200, Array, 0)\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php(26): Illuminate\\Routing\\ResponseFactory->json(Array, 200)\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(132): Illuminate\\Http\\Resources\\Json\\PaginatedResourceResponse->toResponse(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(112): Illuminate\\Http\\Resources\\Json\\ResourceCollection->preparePaginatedResponse(Object(Illuminate\\Http\\Request))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(189): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse(Object(Illuminate\\Http\\Request))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(42): Illuminate\\Http\\Resources\\Json\\JsonResource->response()\n#21 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(116): call_user_func_array(Array, Array)\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#45 {main}', '[]', '2023-02-06 19:09:17', '2023-02-06 19:09:17'), +(163, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function first() on null in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/CollectsResources.php:29\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(52): Illuminate\\Http\\Resources\\Json\\ResourceCollection->collectResource(NULL)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/AnonymousResourceCollection.php(25): Illuminate\\Http\\Resources\\Json\\ResourceCollection->__construct(NULL)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(78): Illuminate\\Http\\Resources\\Json\\AnonymousResourceCollection->__construct(NULL, \'RainLab\\\\Blog\\\\Cl...\')\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/classes/ImageResource.php(24): Illuminate\\Http\\Resources\\Json\\JsonResource::collection(NULL)\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(60): RainLab\\Blog\\Classes\\ImageResource->toArray(Object(Illuminate\\Http\\Request))\n#5 [internal function]: Illuminate\\Support\\HigherOrderCollectionProxy->Illuminate\\Support\\{closure}(Object(RainLab\\Blog\\Classes\\ImageResource), 0)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Collection.php(638): array_map(Object(Closure), Array, Array)\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php(61): Illuminate\\Support\\Collection->map(Object(Closure))\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(100): Illuminate\\Support\\HigherOrderCollectionProxy->__call(\'toArray\', Array)\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(94): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toArray(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(211): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve(Object(Illuminate\\Http\\Request))\n#11 [internal function]: Illuminate\\Http\\Resources\\Json\\JsonResource->jsonSerialize()\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(71): json_encode(Array, 0)\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/symfony/http-foundation/JsonResponse.php(54): Illuminate\\Http\\JsonResponse->setData(Array)\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(31): Symfony\\Component\\HttpFoundation\\JsonResponse->__construct(Array, 200, Array)\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php(99): Illuminate\\Http\\JsonResponse->__construct(Array, 200, Array, 0)\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php(26): Illuminate\\Routing\\ResponseFactory->json(Array, 200)\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(132): Illuminate\\Http\\Resources\\Json\\PaginatedResourceResponse->toResponse(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(112): Illuminate\\Http\\Resources\\Json\\ResourceCollection->preparePaginatedResponse(Object(Illuminate\\Http\\Request))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(189): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse(Object(Illuminate\\Http\\Request))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(42): Illuminate\\Http\\Resources\\Json\\JsonResource->response()\n#21 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(116): call_user_func_array(Array, Array)\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#27 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#28 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#29 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#30 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#31 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#32 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#33 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#34 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#35 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#36 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#37 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#38 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#39 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#40 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#41 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#42 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#43 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#44 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#45 {main}', '[]', '2023-02-06 19:09:20', '2023-02-06 19:09:20'), +(164, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:09:26', '2023-02-06 19:09:26'), +(165, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:10:26', '2023-02-06 19:10:26'), +(166, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:11:26', '2023-02-06 19:11:26'), +(167, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:12:26', '2023-02-06 19:12:26'), +(168, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:13:26', '2023-02-06 19:13:26'), +(169, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:14:26', '2023-02-06 19:14:26'), +(170, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:15:26', '2023-02-06 19:15:26'), +(171, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:16:26', '2023-02-06 19:16:26'), +(172, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:17:26', '2023-02-06 19:17:26'), +(173, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:18:26', '2023-02-06 19:18:26'), +(174, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:19:26', '2023-02-06 19:19:26'), +(175, 'error', 'BadMethodCallException: Method October\\Rain\\Database\\Collection::paginate does not exist. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Traits/Macroable.php:103\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php(23): Illuminate\\Support\\Collection->__call(\'paginate\', Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pagination/AbstractPaginator.php(657): Illuminate\\Pagination\\AbstractPaginator->forwardCallTo(Object(October\\Rain\\Database\\Collection), \'paginate\', Array)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(49): Illuminate\\Pagination\\AbstractPaginator->__call(\'paginate\', Array)\n#3 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(123): call_user_func_array(Array, Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#27 {main}', '[]', '2023-02-06 19:20:24', '2023-02-06 19:20:24'), +(176, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:20:26', '2023-02-06 19:20:26'), +(177, 'error', 'BadMethodCallException: Method October\\Rain\\Database\\Collection::paginate does not exist. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Traits/Macroable.php:103\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php(23): Illuminate\\Support\\Collection->__call(\'paginate\', Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pagination/AbstractPaginator.php(657): Illuminate\\Pagination\\AbstractPaginator->forwardCallTo(Object(October\\Rain\\Database\\Collection), \'paginate\', Array)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(49): Illuminate\\Pagination\\AbstractPaginator->__call(\'paginate\', Array)\n#3 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(123): call_user_func_array(Array, Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#27 {main}', '[]', '2023-02-06 19:20:38', '2023-02-06 19:20:38'), +(178, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:21:26', '2023-02-06 19:21:26'), +(179, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:22:26', '2023-02-06 19:22:26'), +(180, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:23:26', '2023-02-06 19:23:26'), +(181, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:24:26', '2023-02-06 19:24:26'), +(182, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:25:26', '2023-02-06 19:25:26'), +(183, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:26:26', '2023-02-06 19:26:26'), +(184, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:27:26', '2023-02-06 19:27:26'), +(185, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:28:26', '2023-02-06 19:28:26'), +(186, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:29:26', '2023-02-06 19:29:26'), +(187, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:30:26', '2023-02-06 19:30:26'), +(188, 'error', 'BadMethodCallException: Method October\\Rain\\Database\\Collection::response does not exist. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Traits/Macroable.php:103\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php(23): Illuminate\\Support\\Collection->__call(\'response\', Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pagination/AbstractPaginator.php(657): Illuminate\\Pagination\\AbstractPaginator->forwardCallTo(Object(October\\Rain\\Database\\Collection), \'response\', Array)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(47): Illuminate\\Pagination\\AbstractPaginator->__call(\'response\', Array)\n#3 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(121): call_user_func_array(Array, Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#27 {main}', '[]', '2023-02-06 19:31:05', '2023-02-06 19:31:05'), +(189, 'error', 'BadMethodCallException: Method October\\Rain\\Database\\Collection::response does not exist. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Traits/Macroable.php:103\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php(23): Illuminate\\Support\\Collection->__call(\'response\', Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pagination/AbstractPaginator.php(657): Illuminate\\Pagination\\AbstractPaginator->forwardCallTo(Object(October\\Rain\\Database\\Collection), \'response\', Array)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(47): Illuminate\\Pagination\\AbstractPaginator->__call(\'response\', Array)\n#3 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(121): call_user_func_array(Array, Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#27 {main}', '[]', '2023-02-06 19:31:24', '2023-02-06 19:31:24'), +(190, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:31:26', '2023-02-06 19:31:26'), +(191, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:32:26', '2023-02-06 19:32:26'), +(192, 'error', 'BadMethodCallException: Method October\\Rain\\Database\\Collection::response does not exist. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Traits/Macroable.php:103\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php(23): Illuminate\\Support\\Collection->__call(\'response\', Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pagination/AbstractPaginator.php(657): Illuminate\\Pagination\\AbstractPaginator->forwardCallTo(Object(October\\Rain\\Database\\Collection), \'response\', Array)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(49): Illuminate\\Pagination\\AbstractPaginator->__call(\'response\', Array)\n#3 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(125): call_user_func_array(Array, Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#27 {main}', '[]', '2023-02-06 19:33:26', '2023-02-06 19:33:26'), +(193, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:33:26', '2023-02-06 19:33:26'), +(194, 'error', 'ErrorException: count(): Parameter must be an array or an object that implements Countable in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/helpers/Helpers.php:11\nStack trace:\n#0 [internal function]: Illuminate\\Foundation\\Bootstrap\\HandleExceptions->handleError(2, \'count(): Parame...\', \'/Users/tmstore/...\', 11, Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/helpers/Helpers.php(11): count(Object(Illuminate\\Http\\JsonResponse))\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(51): AhmadFatoni\\ApiGenerator\\Helpers\\Helpers->apiArrayResponseBuilder(200, \'success\', Object(Illuminate\\Http\\JsonResponse))\n#3 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(125): call_user_func_array(Array, Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#27 {main}', '[]', '2023-02-06 19:34:13', '2023-02-06 19:34:13'), +(195, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:34:26', '2023-02-06 19:34:26'), +(196, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:35:26', '2023-02-06 19:35:26'), +(197, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:36:26', '2023-02-06 19:36:26'), +(198, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:37:26', '2023-02-06 19:37:26'), +(199, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:38:26', '2023-02-06 19:38:26'), +(200, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:39:26', '2023-02-06 19:39:26'), +(201, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:40:26', '2023-02-06 19:40:26'), +(202, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:41:26', '2023-02-06 19:41:26'), +(203, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:42:26', '2023-02-06 19:42:26'), +(204, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:43:26', '2023-02-06 19:43:26'), +(205, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:44:26', '2023-02-06 19:44:26'), +(206, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:45:26', '2023-02-06 19:45:26'), +(207, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:46:26', '2023-02-06 19:46:26'), +(208, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:47:26', '2023-02-06 19:47:26'), +(209, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:48:26', '2023-02-06 19:48:26'), +(210, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:49:26', '2023-02-06 19:49:26'), +(211, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:50:26', '2023-02-06 19:50:26'), +(212, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:51:26', '2023-02-06 19:51:26'), +(213, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:52:26', '2023-02-06 19:52:26'), +(214, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:53:26', '2023-02-06 19:53:26'), +(215, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:54:26', '2023-02-06 19:54:26'), +(216, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:55:26', '2023-02-06 19:55:26'), +(217, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:56:26', '2023-02-06 19:56:26'), +(218, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:57:26', '2023-02-06 19:57:26'), +(219, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:58:26', '2023-02-06 19:58:26'), +(220, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 19:59:26', '2023-02-06 19:59:26'), +(221, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:00:26', '2023-02-06 20:00:26'), +(222, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:01:26', '2023-02-06 20:01:26'), +(223, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:02:26', '2023-02-06 20:02:26'), +(224, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:03:26', '2023-02-06 20:03:26'), +(225, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:04:26', '2023-02-06 20:04:26'), +(226, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:05:26', '2023-02-06 20:05:26'), +(227, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:06:26', '2023-02-06 20:06:26'), +(228, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:07:26', '2023-02-06 20:07:26'); +INSERT INTO `system_event_logs` (`id`, `level`, `message`, `details`, `created_at`, `updated_at`) VALUES +(229, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:08:26', '2023-02-06 20:08:26'), +(230, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:09:26', '2023-02-06 20:09:26'), +(231, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:10:26', '2023-02-06 20:10:26'), +(232, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:11:26', '2023-02-06 20:11:26'), +(233, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:12:26', '2023-02-06 20:12:26'), +(234, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:13:27', '2023-02-06 20:13:27'), +(235, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:14:26', '2023-02-06 20:14:26'), +(236, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:15:27', '2023-02-06 20:15:27'), +(237, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:16:26', '2023-02-06 20:16:26'), +(238, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:17:27', '2023-02-06 20:17:27'), +(239, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:18:27', '2023-02-06 20:18:27'), +(240, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:19:27', '2023-02-06 20:19:27'), +(241, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:20:27', '2023-02-06 20:20:27'), +(242, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:21:27', '2023-02-06 20:21:27'), +(243, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:22:27', '2023-02-06 20:22:27'), +(244, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:23:27', '2023-02-06 20:23:27'), +(245, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:24:27', '2023-02-06 20:24:27'), +(246, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:25:26', '2023-02-06 20:25:26'), +(247, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:26:26', '2023-02-06 20:26:26'), +(248, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:27:27', '2023-02-06 20:27:27'), +(249, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:28:27', '2023-02-06 20:28:27'), +(250, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:29:26', '2023-02-06 20:29:26'), +(251, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:30:27', '2023-02-06 20:30:27'), +(252, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:31:26', '2023-02-06 20:31:26'), +(253, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:32:27', '2023-02-06 20:32:27'), +(254, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:33:26', '2023-02-06 20:33:26'), +(255, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:34:27', '2023-02-06 20:34:27'), +(256, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:35:27', '2023-02-06 20:35:27'), +(257, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:36:26', '2023-02-06 20:36:26'), +(258, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:37:27', '2023-02-06 20:37:27'), +(259, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:38:27', '2023-02-06 20:38:27'), +(260, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:39:26', '2023-02-06 20:39:26'), +(261, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:40:27', '2023-02-06 20:40:27'), +(262, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:41:27', '2023-02-06 20:41:27'), +(263, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:42:27', '2023-02-06 20:42:27'), +(264, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:43:27', '2023-02-06 20:43:27'), +(265, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:44:27', '2023-02-06 20:44:27'), +(266, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:45:27', '2023-02-06 20:45:27'), +(267, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:46:26', '2023-02-06 20:46:26'), +(268, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:47:27', '2023-02-06 20:47:27'), +(269, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:48:27', '2023-02-06 20:48:27'), +(270, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:49:27', '2023-02-06 20:49:27'), +(271, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:50:27', '2023-02-06 20:50:27'), +(272, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:51:27', '2023-02-06 20:51:27'), +(273, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function format() on string in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php:286\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(53): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#3 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(99): call_user_func_array(Array, Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#27 {main}', '[]', '2023-02-06 20:52:02', '2023-02-06 20:52:02'), +(274, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:52:27', '2023-02-06 20:52:27'), +(275, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function format() on string in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php:289\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(53): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#3 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(99): call_user_func_array(Array, Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#27 {main}', '[]', '2023-02-06 20:52:46', '2023-02-06 20:52:46'), +(276, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function format() on string in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php:286\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(53): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#3 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(99): call_user_func_array(Array, Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#27 {main}', '[]', '2023-02-06 20:53:19', '2023-02-06 20:53:19'), +(277, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:53:27', '2023-02-06 20:53:27'), +(278, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function format() on string in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php:288\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(53): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#3 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(99): call_user_func_array(Array, Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#27 {main}', '[]', '2023-02-06 20:53:35', '2023-02-06 20:53:35'), +(279, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to a member function format() on int in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php:288\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(53): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#3 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(99): call_user_func_array(Array, Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#27 {main}', '[]', '2023-02-06 20:53:43', '2023-02-06 20:53:43'), +(280, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:54:27', '2023-02-06 20:54:27'), +(281, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:55:27', '2023-02-06 20:55:27'), +(282, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:56:26', '2023-02-06 20:56:26'), +(283, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:57:27', '2023-02-06 20:57:27'), +(284, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:58:26', '2023-02-06 20:58:26'), +(285, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 20:59:27', '2023-02-06 20:59:27'), +(286, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:00:26', '2023-02-06 21:00:26'), +(287, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:01:27', '2023-02-06 21:01:27'), +(288, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:02:26', '2023-02-06 21:02:26'), +(289, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:03:27', '2023-02-06 21:03:27'), +(290, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:04:27', '2023-02-06 21:04:27'), +(291, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:05:27', '2023-02-06 21:05:27'), +(292, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:06:26', '2023-02-06 21:06:26'), +(293, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:07:27', '2023-02-06 21:07:27'), +(294, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:08:27', '2023-02-06 21:08:27'), +(295, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:09:27', '2023-02-06 21:09:27'), +(296, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Call to undefined function RainLab\\Blog\\Models\\leftJoin() in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/rainlab/blog/models/Post.php:288\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(987): RainLab\\Blog\\Models\\Post->scopeListFrontEnd(Object(October\\Rain\\Database\\Builder), Array)\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Database/Builder.php(274): Illuminate\\Database\\Eloquent\\Builder->callScope(Array, Array)\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(57): October\\Rain\\Database\\Builder->__call(\'listFrontEnd\', Array)\n#3 [internal function]: AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->index(Object(Illuminate\\Http\\Request))\n#4 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/plugins/ahmadfatoni/apigenerator/controllers/api/PostsController.php(103): call_user_func_array(Array, Array)\n#5 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController->callAction(\'index\', Array)\n#6 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(AhmadFatoni\\ApiGenerator\\Controllers\\API\\PostsController), \'index\')\n#7 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()\n#8 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Routing\\Route->run()\n#9 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))\n#10 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#11 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#12 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#13 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#14 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Router/CoreRouter.php(20): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#15 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): October\\Rain\\Router\\CoreRouter->dispatch(Object(Illuminate\\Http\\Request))\n#16 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))\n#17 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#18 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Foundation/Http/Middleware/CheckForMaintenanceMode.php(25): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#20 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/october/rain/src/Http/Middleware/TrustHosts.php(46): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#21 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): October\\Rain\\Http\\Middleware\\TrustHosts->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#22 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))\n#23 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#24 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#25 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/index.php(43): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#26 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/server.php(17): require_once(\'/Users/tmstore/...\')\n#27 {main}', '[]', '2023-02-06 21:09:42', '2023-02-06 21:09:42'), +(297, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:10:27', '2023-02-06 21:10:27'), +(298, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:11:27', '2023-02-06 21:11:27'), +(299, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:12:27', '2023-02-06 21:12:27'), +(300, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:13:26', '2023-02-06 21:13:26'), +(301, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:14:27', '2023-02-06 21:14:27'), +(302, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:15:27', '2023-02-06 21:15:27'), +(303, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:16:26', '2023-02-06 21:16:26'), +(304, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:17:27', '2023-02-06 21:17:27'), +(305, 'error', 'Symfony\\Component\\Debug\\Exception\\FatalErrorException: Uncaught Illuminate\\Contracts\\Container\\BindingResolutionException: Target [Illuminate\\Contracts\\Auth\\Access\\Gate] is not instantiable. in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(812): Illuminate\\Container\\Container->notInstantiable(\'Illuminate\\\\Cont...\')\n#1 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(681): Illuminate\\Container\\Container->build(\'Illuminate\\\\Cont...\')\n#2 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(785): Illuminate\\Container\\Container->resolve(\'Illuminate\\\\Cont...\', Array, true)\n#3 /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\\Foundation\\Application->resolve(\'Illuminate\\\\Cont...\', in /Users/tmstore/Desktop/tps2022/HHM/backend_hhm/vendor/laravel/framework/src/Illuminate/Container/Container.php:978\nStack trace:\n#0 {main}', '[]', '2023-02-06 21:18:27', '2023-02-06 21:18:27'); + +INSERT INTO `system_files` (`id`, `disk_name`, `file_name`, `file_size`, `content_type`, `title`, `description`, `field`, `attachment_id`, `attachment_type`, `is_public`, `sort_order`, `created_at`, `updated_at`) VALUES +(1, '63e140133dfe5027400425.jpeg', 'WB06153T8.jpeg', 29878, 'image/jpeg', NULL, NULL, NULL, NULL, NULL, 1, 3, '2023-02-06 17:59:47', '2023-02-06 17:59:51'), +(3, '63e1401398240393494881.jpeg', 'WB0C89H44.jpeg', 33709, 'image/jpeg', NULL, NULL, NULL, NULL, NULL, 1, 2, '2023-02-06 17:59:47', '2023-02-06 17:59:51'), +(4, '63e1468586c29445782254.jpeg', 'WB06153T8.jpeg', 29878, 'image/jpeg', NULL, NULL, 'featured_images', '1', 'RainLab\\Blog\\Models\\Post', 1, 4, '2023-02-06 18:27:17', '2023-02-06 18:27:18'), +(5, '63e14685a9a4d999829792.jpeg', 'WB0385285.jpeg', 32941, 'image/jpeg', NULL, NULL, 'featured_images', '1', 'RainLab\\Blog\\Models\\Post', 1, 5, '2023-02-06 18:27:17', '2023-02-06 18:27:18'), +(6, '63e14685c2995067586787.jpeg', 'WB0C89H44.jpeg', 33709, 'image/jpeg', NULL, NULL, 'featured_images', '1', 'RainLab\\Blog\\Models\\Post', 1, 6, '2023-02-06 18:27:17', '2023-02-06 18:27:18'), +(7, '63e14f0a5df63581610268.jpeg', 'WB0385285.jpeg', 32941, 'image/jpeg', NULL, NULL, 'featured_images', '2', 'RainLab\\Blog\\Models\\Post', 1, 2, '2023-02-06 19:03:38', '2023-02-06 21:05:03'), +(8, '63e14f0a99ffe517262260.jpeg', 'WB0C89H44.jpeg', 33709, 'image/jpeg', NULL, NULL, 'featured_images', '2', 'RainLab\\Blog\\Models\\Post', 1, 1, '2023-02-06 19:03:38', '2023-02-06 21:05:03'), +(9, '63e14f0ab2bcc730115913.jpeg', 'WB06153T8.jpeg', 29878, 'image/jpeg', NULL, NULL, 'featured_images', '2', 'RainLab\\Blog\\Models\\Post', 1, 3, '2023-02-06 19:03:38', '2023-02-06 21:05:03'); + +INSERT INTO `system_parameters` (`id`, `namespace`, `group`, `item`, `value`) VALUES +(1, 'system', 'update', 'count', '0'), +(2, 'system', 'update', 'retry', '1675788173'); + +INSERT INTO `system_plugin_history` (`id`, `code`, `type`, `version`, `detail`, `created_at`) VALUES +(1, 'October.Demo', 'comment', '1.0.1', 'First version of Demo', '2022-10-23 16:11:38'), +(2, 'RainLab.Blog', 'script', '1.0.1', 'create_posts_table.php', '2022-10-24 04:13:20'), +(3, 'RainLab.Blog', 'script', '1.0.1', 'create_categories_table.php', '2022-10-24 04:13:20'), +(4, 'RainLab.Blog', 'script', '1.0.1', 'seed_all_tables.php', '2022-10-24 04:13:20'), +(5, 'RainLab.Blog', 'comment', '1.0.1', 'Initialize plugin.', '2022-10-24 04:13:20'), +(6, 'RainLab.Blog', 'comment', '1.0.2', 'Added the processed HTML content column to the posts table.', '2022-10-24 04:13:20'), +(7, 'RainLab.Blog', 'comment', '1.0.3', 'Category component has been merged with Posts component.', '2022-10-24 04:13:20'), +(8, 'RainLab.Blog', 'comment', '1.0.4', 'Improvements to the Posts list management UI.', '2022-10-24 04:13:20'), +(9, 'RainLab.Blog', 'comment', '1.0.5', 'Removes the Author column from blog post list.', '2022-10-24 04:13:20'), +(10, 'RainLab.Blog', 'comment', '1.0.6', 'Featured images now appear in the Post component.', '2022-10-24 04:13:20'), +(11, 'RainLab.Blog', 'comment', '1.0.7', 'Added support for the Static Pages menus.', '2022-10-24 04:13:20'), +(12, 'RainLab.Blog', 'comment', '1.0.8', 'Added total posts to category list.', '2022-10-24 04:13:20'), +(13, 'RainLab.Blog', 'comment', '1.0.9', 'Added support for the Sitemap plugin.', '2022-10-24 04:13:20'), +(14, 'RainLab.Blog', 'comment', '1.0.10', 'Added permission to prevent users from seeing posts they did not create.', '2022-10-24 04:13:20'), +(15, 'RainLab.Blog', 'comment', '1.0.11', 'Deprecate \"idParam\" component property in favour of \"slug\" property.', '2022-10-24 04:13:20'), +(16, 'RainLab.Blog', 'comment', '1.0.12', 'Fixes issue where images cannot be uploaded caused by latest Markdown library.', '2022-10-24 04:13:20'), +(17, 'RainLab.Blog', 'comment', '1.0.13', 'Fixes problem with providing pages to Sitemap and Pages plugins.', '2022-10-24 04:13:20'), +(18, 'RainLab.Blog', 'comment', '1.0.14', 'Add support for CSRF protection feature added to core.', '2022-10-24 04:13:20'), +(19, 'RainLab.Blog', 'comment', '1.1.0', 'Replaced the Post editor with the new core Markdown editor.', '2022-10-24 04:13:20'), +(20, 'RainLab.Blog', 'comment', '1.1.1', 'Posts can now be imported and exported.', '2022-10-24 04:13:20'), +(21, 'RainLab.Blog', 'comment', '1.1.2', 'Posts are no longer visible if the published date has not passed.', '2022-10-24 04:13:20'), +(22, 'RainLab.Blog', 'comment', '1.1.3', 'Added a New Post shortcut button to the blog menu.', '2022-10-24 04:13:20'), +(23, 'RainLab.Blog', 'script', '1.2.0', 'categories_add_nested_fields.php', '2022-10-24 04:13:20'), +(24, 'RainLab.Blog', 'comment', '1.2.0', 'Categories now support nesting.', '2022-10-24 04:13:20'), +(25, 'RainLab.Blog', 'comment', '1.2.1', 'Post slugs now must be unique.', '2022-10-24 04:13:20'), +(26, 'RainLab.Blog', 'comment', '1.2.2', 'Fixes issue on new installs.', '2022-10-24 04:13:20'), +(27, 'RainLab.Blog', 'comment', '1.2.3', 'Minor user interface update.', '2022-10-24 04:13:20'), +(28, 'RainLab.Blog', 'script', '1.2.4', 'update_timestamp_nullable.php', '2022-10-24 04:13:20'), +(29, 'RainLab.Blog', 'comment', '1.2.4', 'Database maintenance. Updated all timestamp columns to be nullable.', '2022-10-24 04:13:20'), +(30, 'RainLab.Blog', 'comment', '1.2.5', 'Added translation support for blog posts.', '2022-10-24 04:13:20'), +(31, 'RainLab.Blog', 'comment', '1.2.6', 'The published field can now supply a time with the date.', '2022-10-24 04:13:20'), +(32, 'RainLab.Blog', 'comment', '1.2.7', 'Introduced a new RSS feed component.', '2022-10-24 04:13:20'), +(33, 'RainLab.Blog', 'comment', '1.2.8', 'Fixes issue with translated `content_html` attribute on blog posts.', '2022-10-24 04:13:20'), +(34, 'RainLab.Blog', 'comment', '1.2.9', 'Added translation support for blog categories.', '2022-10-24 04:13:20'), +(35, 'RainLab.Blog', 'comment', '1.2.10', 'Added translation support for post slugs.', '2022-10-24 04:13:20'), +(36, 'RainLab.Blog', 'comment', '1.2.11', 'Fixes bug where excerpt is not translated.', '2022-10-24 04:13:20'), +(37, 'RainLab.Blog', 'comment', '1.2.12', 'Description field added to category form.', '2022-10-24 04:13:20'), +(38, 'RainLab.Blog', 'comment', '1.2.13', 'Improved support for Static Pages menus, added a blog post and all blog posts.', '2022-10-24 04:13:20'), +(39, 'RainLab.Blog', 'comment', '1.2.14', 'Added post exception property to the post list component, useful for showing related posts.', '2022-10-24 04:13:20'), +(40, 'RainLab.Blog', 'comment', '1.2.15', 'Back-end navigation sort order updated.', '2022-10-24 04:13:20'), +(41, 'RainLab.Blog', 'comment', '1.2.16', 'Added `nextPost` and `previousPost` to the blog post component.', '2022-10-24 04:13:20'), +(42, 'RainLab.Blog', 'comment', '1.2.17', 'Improved the next and previous logic to sort by the published date.', '2022-10-24 04:13:20'), +(43, 'RainLab.Blog', 'comment', '1.2.18', 'Minor change to internals.', '2022-10-24 04:13:20'), +(44, 'RainLab.Blog', 'comment', '1.2.19', 'Improved support for Build 420+', '2022-10-24 04:13:20'), +(45, 'RainLab.Blog', 'script', '1.3.0', 'posts_add_metadata.php', '2022-10-24 04:13:20'), +(46, 'RainLab.Blog', 'comment', '1.3.0', 'Added metadata column for plugins to store data in', '2022-10-24 04:13:20'), +(47, 'RainLab.Blog', 'comment', '1.3.1', 'Fixed metadata column not being jsonable', '2022-10-24 04:13:20'), +(48, 'RainLab.Blog', 'comment', '1.3.2', 'Allow custom slug name for components, add 404 handling for missing blog posts, allow exporting of blog images.', '2022-10-24 04:13:20'), +(49, 'RainLab.Blog', 'comment', '1.3.3', 'Fixed \'excluded categories\' filter from being run when value is empty.', '2022-10-24 04:13:20'), +(50, 'RainLab.Blog', 'comment', '1.3.4', 'Allow post author to be specified. Improved translations.', '2022-10-24 04:13:20'), +(51, 'RainLab.Blog', 'comment', '1.3.5', 'Fixed missing user info from breaking initial seeder in migrations. Fixed a PostgreSQL issue with blog exports.', '2022-10-24 04:13:20'), +(52, 'RainLab.Blog', 'comment', '1.3.6', 'Improved French translations.', '2022-10-24 04:13:20'), +(53, 'RainLab.Blog', 'comment', '1.4.0', 'Stability improvements. Rollback custom slug names for components', '2022-10-24 04:13:20'), +(54, 'RainLab.Blog', 'comment', '1.4.1', 'Fixes potential security issue with unsafe Markdown. Allow blog bylines to be translated.', '2022-10-24 04:13:20'), +(55, 'RainLab.Blog', 'comment', '1.4.2', 'Fix 404 redirects for missing blog posts. Assign current category to the listed posts when using the Posts component on a page with the category parameter available.', '2022-10-24 04:13:20'), +(56, 'RainLab.Blog', 'comment', '1.4.3', 'Fixes incompatibility with locale switching when plugin is used in conjunction with the Translate plugin. Fixes undefined category error.', '2022-10-24 04:13:20'), +(57, 'RainLab.Blog', 'comment', '1.4.4', 'Rollback translated bylines, please move or override the default component markup instead.', '2022-10-24 04:13:20'), +(58, 'RainLab.Blog', 'comment', '1.5.0', 'Implement support for October CMS v2.0', '2022-10-24 04:13:20'), +(59, 'RainLab.Blog', 'comment', '1.5.1', 'Fixes interaction with Translate plugin', '2022-10-24 04:13:20'), +(60, 'RainLab.Blog', 'comment', '1.5.2', 'Minor styling improvements', '2022-10-24 04:13:20'), +(61, 'RainLab.Blog', 'comment', '1.5.3', 'Adds setting to use legacy markdown editor', '2022-10-24 04:13:20'), +(62, 'RainLab.Blog', 'comment', '1.5.4', 'Compatibility with October CMS v2.2', '2022-10-24 04:13:20'), +(63, 'RainLab.Blog', 'comment', '1.5.6', 'Compatibility with October CMS v3.0', '2022-10-24 04:13:20'), +(64, 'RainLab.Blog', 'comment', '1.6.0', 'Adds preview CMS page to settings and preview button to posts page', '2022-10-24 04:13:20'), +(65, 'RainLab.Blog', 'comment', '1.6.1', 'Fixes JS error when uploading images in newer versions', '2022-10-24 04:13:20'), +(66, 'RainLab.Blog', 'comment', '1.6.2', 'Fixes content_html attribute compatibility with Translate', '2022-10-24 04:13:20'), +(67, 'RainLab.Pages', 'comment', '1.0.1', 'Implemented the static pages management and the Static Page component.', '2022-10-24 04:13:47'), +(68, 'RainLab.Pages', 'comment', '1.0.2', 'Fixed the page preview URL.', '2022-10-24 04:13:47'), +(69, 'RainLab.Pages', 'comment', '1.0.3', 'Implemented menus.', '2022-10-24 04:13:47'), +(70, 'RainLab.Pages', 'comment', '1.0.4', 'Implemented the content block management and placeholder support.', '2022-10-24 04:13:47'), +(71, 'RainLab.Pages', 'comment', '1.0.5', 'Added support for the Sitemap plugin.', '2022-10-24 04:13:47'), +(72, 'RainLab.Pages', 'comment', '1.0.6', 'Minor updates to the internal API.', '2022-10-24 04:13:47'), +(73, 'RainLab.Pages', 'comment', '1.0.7', 'Added the Snippets feature.', '2022-10-24 04:13:47'), +(74, 'RainLab.Pages', 'comment', '1.0.8', 'Minor improvements to the code.', '2022-10-24 04:13:47'), +(75, 'RainLab.Pages', 'comment', '1.0.9', 'Fixes issue where Snippet tab is missing from the Partials form.', '2022-10-24 04:13:47'), +(76, 'RainLab.Pages', 'comment', '1.0.10', 'Add translations for various locales.', '2022-10-24 04:13:47'), +(77, 'RainLab.Pages', 'comment', '1.0.11', 'Fixes issue where placeholders tabs were missing from Page form.', '2022-10-24 04:13:47'), +(78, 'RainLab.Pages', 'comment', '1.0.12', 'Implement Media Manager support.', '2022-10-24 04:13:47'), +(79, 'RainLab.Pages', 'script', '1.1.0', 'snippets_rename_viewbag_properties.php', '2022-10-24 04:13:47'), +(80, 'RainLab.Pages', 'comment', '1.1.0', 'Adds meta title and description to pages. Adds |staticPage filter.', '2022-10-24 04:13:47'), +(81, 'RainLab.Pages', 'comment', '1.1.1', 'Add support for Syntax Fields.', '2022-10-24 04:13:47'), +(82, 'RainLab.Pages', 'comment', '1.1.2', 'Static Breadcrumbs component now respects the hide from navigation setting.', '2022-10-24 04:13:47'), +(83, 'RainLab.Pages', 'comment', '1.1.3', 'Minor back-end styling fix.', '2022-10-24 04:13:47'), +(84, 'RainLab.Pages', 'comment', '1.1.4', 'Minor fix to the StaticPage component API.', '2022-10-24 04:13:47'), +(85, 'RainLab.Pages', 'comment', '1.1.5', 'Fixes bug when using syntax fields.', '2022-10-24 04:13:47'), +(86, 'RainLab.Pages', 'comment', '1.1.6', 'Minor styling fix to the back-end UI.', '2022-10-24 04:13:47'), +(87, 'RainLab.Pages', 'comment', '1.1.7', 'Improved menu item form to include CSS class, open in a new window and hidden flag.', '2022-10-24 04:13:47'), +(88, 'RainLab.Pages', 'comment', '1.1.8', 'Improved the output of snippet partials when saved.', '2022-10-24 04:13:47'), +(89, 'RainLab.Pages', 'comment', '1.1.9', 'Minor update to snippet inspector internal API.', '2022-10-24 04:13:47'), +(90, 'RainLab.Pages', 'comment', '1.1.10', 'Fixes a bug where selecting a layout causes permanent unsaved changes.', '2022-10-24 04:13:47'), +(91, 'RainLab.Pages', 'comment', '1.1.11', 'Add support for repeater syntax field.', '2022-10-24 04:13:47'), +(92, 'RainLab.Pages', 'comment', '1.2.0', 'Added support for translations, UI updates.', '2022-10-24 04:13:47'), +(93, 'RainLab.Pages', 'comment', '1.2.1', 'Use nice titles when listing the content files.', '2022-10-24 04:13:48'), +(94, 'RainLab.Pages', 'comment', '1.2.2', 'Minor styling update.', '2022-10-24 04:13:48'), +(95, 'RainLab.Pages', 'comment', '1.2.3', 'Snippets can now be moved by dragging them.', '2022-10-24 04:13:48'), +(96, 'RainLab.Pages', 'comment', '1.2.4', 'Fixes a bug where the cursor is misplaced when editing text files.', '2022-10-24 04:13:48'), +(97, 'RainLab.Pages', 'comment', '1.2.5', 'Fixes a bug where the parent page is lost upon changing a page layout.', '2022-10-24 04:13:48'), +(98, 'RainLab.Pages', 'comment', '1.2.6', 'Shared view variables are now passed to static pages.', '2022-10-24 04:13:48'), +(99, 'RainLab.Pages', 'comment', '1.2.7', 'Fixes issue with duplicating properties when adding multiple snippets on the same page.', '2022-10-24 04:13:48'), +(100, 'RainLab.Pages', 'comment', '1.2.8', 'Fixes a bug where creating a content block without extension doesn\'t save the contents to file.', '2022-10-24 04:13:48'), +(101, 'RainLab.Pages', 'comment', '1.2.9', 'Add conditional support for translating page URLs.', '2022-10-24 04:13:48'), +(102, 'RainLab.Pages', 'comment', '1.2.10', 'Streamline generation of URLs to use the new Cms::url helper.', '2022-10-24 04:13:48'), +(103, 'RainLab.Pages', 'comment', '1.2.11', 'Implements repeater usage with translate plugin.', '2022-10-24 04:13:48'), +(104, 'RainLab.Pages', 'comment', '1.2.12', 'Fixes minor issue when using snippets and switching the application locale.', '2022-10-24 04:13:48'), +(105, 'RainLab.Pages', 'comment', '1.2.13', 'Fixes bug when AJAX is used on a page that does not yet exist.', '2022-10-24 04:13:48'), +(106, 'RainLab.Pages', 'comment', '1.2.14', 'Add theme logging support for changes made to menus.', '2022-10-24 04:13:48'), +(107, 'RainLab.Pages', 'comment', '1.2.15', 'Back-end navigation sort order updated.', '2022-10-24 04:13:48'), +(108, 'RainLab.Pages', 'comment', '1.2.16', 'Fixes a bug when saving a template that has been modified outside of the CMS (mtime mismatch).', '2022-10-24 04:13:48'), +(109, 'RainLab.Pages', 'comment', '1.2.17', 'Changes locations of custom fields to secondary tabs instead of the primary Settings area. New menu search ability on adding menu items', '2022-10-24 04:13:48'), +(110, 'RainLab.Pages', 'comment', '1.2.18', 'Fixes cache-invalidation issues when RainLab.Translate is not installed. Added Greek & Simplified Chinese translations. Removed deprecated calls. Allowed saving HTML in snippet properties. Added support for the MediaFinder in menu items.', '2022-10-24 04:13:48'), +(111, 'RainLab.Pages', 'comment', '1.2.19', 'Catch exception with corrupted menu file.', '2022-10-24 04:13:48'), +(112, 'RainLab.Pages', 'comment', '1.2.20', 'StaticMenu component now exposes menuName property; added pages.menu.referencesGenerated event.', '2022-10-24 04:13:48'), +(113, 'RainLab.Pages', 'comment', '1.2.21', 'Fixes a bug where last Static Menu item cannot be deleted. Improved Persian, Slovak and Turkish translations.', '2022-10-24 04:13:48'), +(114, 'RainLab.Pages', 'comment', '1.3.0', 'Added support for using Database-driven Themes when enabled in the CMS configuration.', '2022-10-24 04:13:48'), +(115, 'RainLab.Pages', 'comment', '1.3.1', 'Added ChildPages Component, prevent hidden pages from being returned via menu item resolver.', '2022-10-24 04:13:48'), +(116, 'RainLab.Pages', 'comment', '1.3.2', 'Fixes error when creating a subpage whose parent has no layout set.', '2022-10-24 04:13:48'), +(117, 'RainLab.Pages', 'comment', '1.3.3', 'Improves user experience for users with only partial access through permissions', '2022-10-24 04:13:48'), +(118, 'RainLab.Pages', 'comment', '1.3.4', 'Fix error where large menus were being truncated due to the PHP \"max_input_vars\" configuration value. Improved Slovenian translation.', '2022-10-24 04:13:48'), +(119, 'RainLab.Pages', 'comment', '1.3.5', 'Minor fix to bust the browser cache for JS assets. Prevent duplicate property fields in snippet inspector.', '2022-10-24 04:13:48'), +(120, 'RainLab.Pages', 'comment', '1.3.6', 'ChildPages component now displays localized page titles from Translate plugin.', '2022-10-24 04:13:48'), +(121, 'RainLab.Pages', 'comment', '1.3.7', 'Adds MenuPicker formwidget. Adds future support for v2.0 of October CMS.', '2022-10-24 04:13:48'), +(122, 'RainLab.Pages', 'comment', '1.4.0', 'Fixes bug when adding menu items in October CMS v2.0.', '2022-10-24 04:13:48'), +(123, 'RainLab.Pages', 'comment', '1.4.1', 'Fixes support for configuration values.', '2022-10-24 04:13:48'), +(124, 'RainLab.Pages', 'comment', '1.4.3', 'Fixes page deletion is newer platform builds.', '2022-10-24 04:13:48'), +(125, 'RainLab.Pages', 'comment', '1.4.4', 'Disable touch device detection', '2022-10-24 04:13:48'), +(126, 'RainLab.Pages', 'comment', '1.4.5', 'Minor styling improvements', '2022-10-24 04:13:48'), +(127, 'RainLab.Pages', 'comment', '1.4.6', 'Minor styling improvements', '2022-10-24 04:13:48'), +(128, 'RainLab.Pages', 'comment', '1.4.7', 'Minor layout fix in the Page editor', '2022-10-24 04:13:48'), +(129, 'RainLab.Pages', 'comment', '1.4.8', 'Fixes rich editor usage inside repeaters. Adds getProcessedMarkup event.', '2022-10-24 04:13:48'), +(130, 'RainLab.Pages', 'comment', '1.4.9', 'Fixes a lifecycle issue when switching the page layout.', '2022-10-24 04:13:48'), +(131, 'RainLab.Pages', 'comment', '1.4.10', 'Fixes maintenance mode when using static pages.', '2022-10-24 04:13:48'), +(132, 'RainLab.Pages', 'comment', '1.4.11', 'Adds type hidden to content placeholders.', '2022-10-24 04:13:48'), +(133, 'RainLab.Pages', 'comment', '1.4.12', 'Improve support with October v2.2', '2022-10-24 04:13:48'), +(134, 'RainLab.Pages', 'comment', '1.5.0', 'Improve support with October v3.0', '2022-10-24 04:13:48'), +(135, 'RainLab.Pages', 'comment', '1.5.4', 'Compatibility updates', '2022-10-24 04:13:48'), +(136, 'RainLab.Pages', 'comment', '1.5.5', 'Fixes media finder added to menu in October v2', '2022-10-24 04:13:48'), +(137, 'RainLab.Translate', 'script', '1.0.1', 'create_messages_table.php', '2022-10-24 04:14:14'), +(138, 'RainLab.Translate', 'script', '1.0.1', 'create_attributes_table.php', '2022-10-24 04:14:14'), +(139, 'RainLab.Translate', 'script', '1.0.1', 'create_locales_table.php', '2022-10-24 04:14:15'), +(140, 'RainLab.Translate', 'comment', '1.0.1', 'First version of Translate', '2022-10-24 04:14:15'), +(141, 'RainLab.Translate', 'comment', '1.0.2', 'Languages and Messages can now be deleted.', '2022-10-24 04:14:15'), +(142, 'RainLab.Translate', 'comment', '1.0.3', 'Minor updates for latest October release.', '2022-10-24 04:14:15'), +(143, 'RainLab.Translate', 'comment', '1.0.4', 'Locale cache will clear when updating a language.', '2022-10-24 04:14:15'), +(144, 'RainLab.Translate', 'comment', '1.0.5', 'Add Spanish language and fix plugin config.', '2022-10-24 04:14:15'), +(145, 'RainLab.Translate', 'comment', '1.0.6', 'Minor improvements to the code.', '2022-10-24 04:14:15'), +(146, 'RainLab.Translate', 'comment', '1.0.7', 'Fixes major bug where translations are skipped entirely!', '2022-10-24 04:14:15'), +(147, 'RainLab.Translate', 'comment', '1.0.8', 'Minor bug fixes.', '2022-10-24 04:14:15'), +(148, 'RainLab.Translate', 'comment', '1.0.9', 'Fixes an issue where newly created models lose their translated values.', '2022-10-24 04:14:15'), +(149, 'RainLab.Translate', 'comment', '1.0.10', 'Minor fix for latest build.', '2022-10-24 04:14:15'), +(150, 'RainLab.Translate', 'comment', '1.0.11', 'Fix multilingual rich editor when used in stretch mode.', '2022-10-24 04:14:15'), +(151, 'RainLab.Translate', 'comment', '1.1.0', 'Introduce compatibility with RainLab.Pages plugin.', '2022-10-24 04:14:15'), +(152, 'RainLab.Translate', 'comment', '1.1.1', 'Minor UI fix to the language picker.', '2022-10-24 04:14:15'), +(153, 'RainLab.Translate', 'comment', '1.1.2', 'Add support for translating Static Content files.', '2022-10-24 04:14:15'), +(154, 'RainLab.Translate', 'comment', '1.1.3', 'Improved support for the multilingual rich editor.', '2022-10-24 04:14:15'), +(155, 'RainLab.Translate', 'comment', '1.1.4', 'Adds new multilingual markdown editor.', '2022-10-24 04:14:15'), +(156, 'RainLab.Translate', 'comment', '1.1.5', 'Minor update to the multilingual control API.', '2022-10-24 04:14:15'), +(157, 'RainLab.Translate', 'comment', '1.1.6', 'Minor improvements in the message editor.', '2022-10-24 04:14:15'), +(158, 'RainLab.Translate', 'comment', '1.1.7', 'Fixes bug not showing content when first loading multilingual textarea controls.', '2022-10-24 04:14:15'), +(159, 'RainLab.Translate', 'comment', '1.2.0', 'CMS pages now support translating the URL.', '2022-10-24 04:14:15'), +(160, 'RainLab.Translate', 'comment', '1.2.1', 'Minor update in the rich editor and code editor language control position.', '2022-10-24 04:14:15'), +(161, 'RainLab.Translate', 'comment', '1.2.2', 'Static Pages now support translating the URL.', '2022-10-24 04:14:15'), +(162, 'RainLab.Translate', 'comment', '1.2.3', 'Fixes Rich Editor when inserting a page link.', '2022-10-24 04:14:15'), +(163, 'RainLab.Translate', 'script', '1.2.4', 'create_indexes_table.php', '2022-10-24 04:14:15'), +(164, 'RainLab.Translate', 'comment', '1.2.4', 'Translatable attributes can now be declared as indexes.', '2022-10-24 04:14:15'), +(165, 'RainLab.Translate', 'comment', '1.2.5', 'Adds new multilingual repeater form widget.', '2022-10-24 04:14:15'), +(166, 'RainLab.Translate', 'comment', '1.2.6', 'Fixes repeater usage with static pages plugin.', '2022-10-24 04:14:15'), +(167, 'RainLab.Translate', 'comment', '1.2.7', 'Fixes placeholder usage with static pages plugin.', '2022-10-24 04:14:15'), +(168, 'RainLab.Translate', 'comment', '1.2.8', 'Improvements to code for latest October build compatibility.', '2022-10-24 04:14:15'), +(169, 'RainLab.Translate', 'comment', '1.2.9', 'Fixes context for translated strings when used with Static Pages.', '2022-10-24 04:14:15'), +(170, 'RainLab.Translate', 'comment', '1.2.10', 'Minor UI fix to the multilingual repeater.', '2022-10-24 04:14:15'), +(171, 'RainLab.Translate', 'comment', '1.2.11', 'Fixes translation not working with partials loaded via AJAX.', '2022-10-24 04:14:15'), +(172, 'RainLab.Translate', 'comment', '1.2.12', 'Add support for translating the new grouped repeater feature.', '2022-10-24 04:14:15'), +(173, 'RainLab.Translate', 'comment', '1.3.0', 'Added search to the translate messages page.', '2022-10-24 04:14:15'), +(174, 'RainLab.Translate', 'script', '1.3.1', 'builder_table_update_rainlab_translate_locales.php', '2022-10-24 04:14:15'), +(175, 'RainLab.Translate', 'script', '1.3.1', 'seed_all_tables.php', '2022-10-24 04:14:15'), +(176, 'RainLab.Translate', 'comment', '1.3.1', 'Added reordering to languages', '2022-10-24 04:14:15'), +(177, 'RainLab.Translate', 'comment', '1.3.2', 'Improved compatibility with RainLab.Pages, added ability to scan Mail Messages for translatable variables.', '2022-10-24 04:14:15'), +(178, 'RainLab.Translate', 'comment', '1.3.3', 'Fix to the locale picker session handling in Build 420 onwards.', '2022-10-24 04:14:15'), +(179, 'RainLab.Translate', 'comment', '1.3.4', 'Add alternate hreflang elements and adds prefixDefaultLocale setting.', '2022-10-24 04:14:15'), +(180, 'RainLab.Translate', 'comment', '1.3.5', 'Fix MLRepeater bug when switching locales.', '2022-10-24 04:14:15'), +(181, 'RainLab.Translate', 'comment', '1.3.6', 'Fix Middleware to use the prefixDefaultLocale setting introduced in 1.3.4', '2022-10-24 04:14:15'), +(182, 'RainLab.Translate', 'comment', '1.3.7', 'Fix config reference in LocaleMiddleware', '2022-10-24 04:14:15'), +(183, 'RainLab.Translate', 'comment', '1.3.8', 'Keep query string when switching locales', '2022-10-24 04:14:15'), +(184, 'RainLab.Translate', 'comment', '1.4.0', 'Add importer and exporter for messages', '2022-10-24 04:14:15'), +(185, 'RainLab.Translate', 'comment', '1.4.1', 'Updated Hungarian translation. Added Arabic translation. Fixed issue where default texts are overwritten by import. Fixed issue where the language switcher for repeater fields would overlap with the first repeater row.', '2022-10-24 04:14:15'), +(186, 'RainLab.Translate', 'comment', '1.4.2', 'Add multilingual MediaFinder', '2022-10-24 04:14:15'), +(187, 'RainLab.Translate', 'comment', '1.4.3', '!!! Please update OctoberCMS to Build 444 before updating this plugin. Added ability to translate CMS Pages fields (e.g. title, description, meta-title, meta-description)', '2022-10-24 04:14:15'), +(188, 'RainLab.Translate', 'comment', '1.4.4', 'Minor improvements to compatibility with Laravel framework.', '2022-10-24 04:14:15'), +(189, 'RainLab.Translate', 'comment', '1.4.5', 'Fixed issue when using the language switcher', '2022-10-24 04:14:15'), +(190, 'RainLab.Translate', 'comment', '1.5.0', 'Compatibility fix with Build 451', '2022-10-24 04:14:15'), +(191, 'RainLab.Translate', 'comment', '1.6.0', 'Make File Upload widget properties translatable. Merge Repeater core changes into MLRepeater widget. Add getter method to retrieve original translate data.', '2022-10-24 04:14:15'), +(192, 'RainLab.Translate', 'comment', '1.6.1', 'Add ability for models to provide translated computed data, add option to disable locale prefix routing', '2022-10-24 04:14:15'), +(193, 'RainLab.Translate', 'comment', '1.6.2', 'Implement localeUrl filter, add per-locale theme configuration support', '2022-10-24 04:14:15'), +(194, 'RainLab.Translate', 'comment', '1.6.3', 'Add eager loading for translations, restore support for accessors & mutators', '2022-10-24 04:14:15'), +(195, 'RainLab.Translate', 'comment', '1.6.4', 'Fixes PHP 7.4 compatibility', '2022-10-24 04:14:15'), +(196, 'RainLab.Translate', 'comment', '1.6.5', 'Fixes compatibility issue when other plugins use a custom model morph map', '2022-10-24 04:14:15'), +(197, 'RainLab.Translate', 'script', '1.6.6', 'migrate_morphed_attributes.php', '2022-10-24 04:14:15'), +(198, 'RainLab.Translate', 'comment', '1.6.6', 'Introduce migration to patch existing translations using morph map', '2022-10-24 04:14:15'), +(199, 'RainLab.Translate', 'script', '1.6.7', 'migrate_morphed_indexes.php', '2022-10-24 04:14:15'), +(200, 'RainLab.Translate', 'comment', '1.6.7', 'Introduce migration to patch existing indexes using morph map', '2022-10-24 04:14:15'), +(201, 'RainLab.Translate', 'comment', '1.6.8', 'Add support for transOrderBy; Add translation support for ThemeData; Update russian localization.', '2022-10-24 04:14:15'), +(202, 'RainLab.Translate', 'comment', '1.6.9', 'Clear Static Page menu cache after saving the model; CSS fix for Text/Textarea input fields language selector.', '2022-10-24 04:14:15'), +(203, 'RainLab.Translate', 'script', '1.6.10', 'update_messages_table.php', '2022-10-24 04:14:15'), +(204, 'RainLab.Translate', 'comment', '1.6.10', 'Add option to purge deleted messages when scanning messages, Add Scan error column on Messages page, Fix translations that were lost when clicking locale twice while holding ctrl key, Fix error with nested fields default locale value, Escape Message translate params value.', '2022-10-24 04:14:15'), +(205, 'RainLab.Translate', 'comment', '1.7.0', '!!! Breaking change for the Message::trans() method (params are now escaped), fix message translation documentation, fix string translation key for scan errors column header.', '2022-10-24 04:14:15'), +(206, 'RainLab.Translate', 'comment', '1.7.1', 'Fix YAML issue with previous tag/release.', '2022-10-24 04:14:15'), +(207, 'RainLab.Translate', 'comment', '1.7.2', 'Fix regex when \"|_\" filter is followed by another filter, Try locale without country before returning default translation, Allow exporting default locale, Fire \'rainlab.translate.themeScanner.afterScan\' event in the theme scanner for extendability.', '2022-10-24 04:14:15'), +(208, 'RainLab.Translate', 'comment', '1.7.3', 'Make plugin ready for Laravel 6 update, Add support for translating RainLab.Pages MenuItem properties (requires RainLab.Pages v1.3.6), Restore multilingual button position for textarea, Fix translatableAttributes.', '2022-10-24 04:14:15'), +(209, 'RainLab.Translate', 'comment', '1.7.4', 'Faster version of transWhere, Mail templates/views can now be localized, Fix messages table layout on mobile, Fix scopeTransOrderBy duplicates, Polish localization updates, Turkish localization updates, Add Greek language localization.', '2022-10-24 04:14:15'), +(210, 'RainLab.Translate', 'comment', '1.8.0', 'Adds initial support for October v2.0', '2022-10-24 04:14:15'), +(211, 'RainLab.Translate', 'comment', '1.8.1', 'Minor bugfix', '2022-10-24 04:14:15'), +(212, 'RainLab.Translate', 'comment', '1.8.2', 'Fixes translated file models and theme data for v2.0. The parent model must implement translatable behavior for their related file models to be translated.', '2022-10-24 04:14:15'), +(213, 'RainLab.Translate', 'comment', '1.8.4', 'Fixes the multilingual mediafinder to work with the media module.', '2022-10-24 04:14:15'), +(214, 'RainLab.Translate', 'comment', '1.8.6', 'Fixes invisible checkboxes when scanning for messages.', '2022-10-24 04:14:15'), +(215, 'RainLab.Translate', 'comment', '1.8.7', 'Fixes Markdown editor translation.', '2022-10-24 04:14:15'), +(216, 'RainLab.Translate', 'comment', '1.8.8', 'Fixes Laravel compatibility in custom Repeater.', '2022-10-24 04:14:15'), +(217, 'RainLab.Translate', 'comment', '1.9.0', 'Restores ability to translate URLs with CMS Editor in October v2.0', '2022-10-24 04:14:15'), +(218, 'RainLab.Translate', 'comment', '1.9.1', 'Minor styling improvements', '2022-10-24 04:14:15'), +(219, 'RainLab.Translate', 'comment', '1.9.2', 'Fixes issue creating new content in CMS Editor', '2022-10-24 04:14:15'), +(220, 'RainLab.Translate', 'comment', '1.9.3', 'Improves support when using child themes', '2022-10-24 04:14:15'), +(221, 'RainLab.Translate', 'comment', '1.10.0', 'Adds new multilingual nested form widget. Adds withFallbackLocale method.', '2022-10-24 04:14:15'), +(222, 'RainLab.Translate', 'comment', '1.10.1', 'Improve support with October v2.0', '2022-10-24 04:14:15'), +(223, 'RainLab.Translate', 'comment', '1.10.2', 'Improve support with October v2.2', '2022-10-24 04:14:15'), +(224, 'RainLab.Translate', 'comment', '1.10.3', 'Multilingual control improvements', '2022-10-24 04:14:15'), +(225, 'RainLab.Translate', 'comment', '1.10.4', 'Improve media finder support with October v2.2', '2022-10-24 04:14:15'), +(226, 'RainLab.Translate', 'comment', '1.10.5', 'Fixes media finder when only 1 locale is available', '2022-10-24 04:14:15'), +(227, 'RainLab.Translate', 'comment', '1.11.0', 'Update to latest Media Finder changes in October v2.2', '2022-10-24 04:14:15'), +(228, 'RainLab.Translate', 'comment', '1.11.1', 'Improve support with October v3.0', '2022-10-24 04:14:15'), +(229, 'RainLab.Translate', 'comment', '1.12.0', 'Adds scopeTransWhereNoFallback method', '2022-10-24 04:14:15'), +(230, 'Indikator.DevTools', 'comment', '1.0.0', 'First version of Developer Tools.', '2022-10-24 04:14:44'), +(231, 'Indikator.DevTools', 'comment', '1.1.0', 'Edit plugins with the code editor.', '2022-10-24 04:14:44'), +(232, 'Indikator.DevTools', 'comment', '1.1.1', 'Translate some English texts.', '2022-10-24 04:14:44'), +(233, 'Indikator.DevTools', 'comment', '1.1.2', 'Fixed the Create file issue.', '2022-10-24 04:14:44'), +(234, 'Indikator.DevTools', 'comment', '1.1.3', 'Added new icon for main navigation.', '2022-10-24 04:14:44'), +(235, 'Indikator.DevTools', 'comment', '1.1.4', 'Show the PHP\'s configuration.', '2022-10-24 04:14:44'), +(236, 'Indikator.DevTools', 'comment', '1.1.5', 'Minor code improvements and bugfix.', '2022-10-24 04:14:44'), +(237, 'Indikator.DevTools', 'comment', '1.1.6', 'The top menu icon shows again.', '2022-10-24 04:14:44'), +(238, 'Indikator.DevTools', 'comment', '1.1.7', 'Fixed the Create folder issue.', '2022-10-24 04:14:44'), +(239, 'Indikator.DevTools', 'comment', '1.1.8', '!!! Updated for October 420+.', '2022-10-24 04:14:44'), +(240, 'Indikator.DevTools', 'comment', '1.1.9', 'Updated the main navigation icon.', '2022-10-24 04:14:44'), +(241, 'Indikator.DevTools', 'comment', '1.1.9', 'Added last modified date.', '2022-10-24 04:14:44'), +(242, 'Indikator.DevTools', 'comment', '1.2.0', 'The syntax highlighting works again!', '2022-10-24 04:14:44'), +(243, 'Indikator.DevTools', 'comment', '1.2.1', 'Help links open in a new window.', '2022-10-24 04:14:44'), +(244, 'Indikator.DevTools', 'comment', '1.2.2', 'Fixed the dependency bug in asset list.', '2022-10-24 04:14:44'), +(245, 'Indikator.DevTools', 'comment', '1.2.3', 'The file delete operation works again.', '2022-10-24 04:14:44'), +(246, 'RainLab.Builder', 'comment', '1.0.1', 'Initialize plugin.', '2022-10-24 04:15:19'), +(247, 'RainLab.Builder', 'comment', '1.0.2', 'Fixes the problem with selecting a plugin. Minor localization corrections. Configuration files in the list and form behaviors are now autocomplete.', '2022-10-24 04:15:19'), +(248, 'RainLab.Builder', 'comment', '1.0.3', 'Improved handling of the enum data type.', '2022-10-24 04:15:19'), +(249, 'RainLab.Builder', 'comment', '1.0.4', 'Added user permissions to work with the Builder.', '2022-10-24 04:15:19'), +(250, 'RainLab.Builder', 'comment', '1.0.5', 'Fixed permissions registration.', '2022-10-24 04:15:19'), +(251, 'RainLab.Builder', 'comment', '1.0.6', 'Fixed front-end record ordering in the Record List component.', '2022-10-24 04:15:19'), +(252, 'RainLab.Builder', 'comment', '1.0.7', 'Builder settings are now protected with user permissions. The database table column list is scrollable now. Minor code cleanup.', '2022-10-24 04:15:19'), +(253, 'RainLab.Builder', 'comment', '1.0.8', 'Added the Reorder Controller behavior.', '2022-10-24 04:15:19'), +(254, 'RainLab.Builder', 'comment', '1.0.9', 'Minor API and UI updates.', '2022-10-24 04:15:19'), +(255, 'RainLab.Builder', 'comment', '1.0.10', 'Minor styling update.', '2022-10-24 04:15:19'), +(256, 'RainLab.Builder', 'comment', '1.0.11', 'Fixed a bug where clicking placeholder in a repeater would open Inspector. Fixed a problem with saving forms with repeaters in tabs. Minor style fix.', '2022-10-24 04:15:19'), +(257, 'RainLab.Builder', 'comment', '1.0.12', 'Added support for the Trigger property to the Media Finder widget configuration. Names of form fields and list columns definition files can now contain underscores.', '2022-10-24 04:15:19'), +(258, 'RainLab.Builder', 'comment', '1.0.13', 'Minor styling fix on the database editor.', '2022-10-24 04:15:19'), +(259, 'RainLab.Builder', 'comment', '1.0.14', 'Added support for published_at timestamp field', '2022-10-24 04:15:19'), +(260, 'RainLab.Builder', 'comment', '1.0.15', 'Fixed a bug where saving a localization string in Inspector could cause a JavaScript error. Added support for Timestamps and Soft Deleting for new models.', '2022-10-24 04:15:19'), +(261, 'RainLab.Builder', 'comment', '1.0.16', 'Fixed a bug when saving a form with the Repeater widget in a tab could create invalid fields in the form\'s outside area. Added a check that prevents creating localization strings inside other existing strings.', '2022-10-24 04:15:19'), +(262, 'RainLab.Builder', 'comment', '1.0.17', 'Added support Trigger attribute support for RecordFinder and Repeater form widgets.', '2022-10-24 04:15:19'), +(263, 'RainLab.Builder', 'comment', '1.0.18', 'Fixes a bug where \'::class\' notations in a model class definition could prevent the model from appearing in the Builder model list. Added emptyOption property support to the dropdown form control.', '2022-10-24 04:15:19'), +(264, 'RainLab.Builder', 'comment', '1.0.19', 'Added a feature allowing to add all database columns to a list definition. Added max length validation for database table and column names.', '2022-10-24 04:15:19'), +(265, 'RainLab.Builder', 'comment', '1.0.20', 'Fixes a bug where form the builder could trigger the \"current.hasAttribute is not a function\" error.', '2022-10-24 04:15:19'), +(266, 'RainLab.Builder', 'comment', '1.0.21', 'Back-end navigation sort order updated.', '2022-10-24 04:15:19'), +(267, 'RainLab.Builder', 'comment', '1.0.22', 'Added scopeValue property to the RecordList component.', '2022-10-24 04:15:19'), +(268, 'RainLab.Builder', 'comment', '1.0.23', 'Added support for balloon-selector field type, added Brazilian Portuguese translation, fixed some bugs', '2022-10-24 04:15:19'), +(269, 'RainLab.Builder', 'comment', '1.0.24', 'Added support for tag list field type, added read only toggle for fields. Prevent plugins from using reserved PHP keywords for class names and namespaces', '2022-10-24 04:15:19'), +(270, 'RainLab.Builder', 'comment', '1.0.25', 'Allow editing of migration code in the \"Migration\" popup when saving changes in the database editor.', '2022-10-24 04:15:19'), +(271, 'RainLab.Builder', 'comment', '1.0.26', 'Allow special default values for columns and added new \"Add ID column\" button to database editor.', '2022-10-24 04:15:19'), +(272, 'RainLab.Builder', 'comment', '1.0.27', 'Added ability to use \'scope\' in a form relation field, added ability to change the sort order of versions and added additional properties for repeater widget in form builder. Added Polish translation.', '2022-10-24 04:15:19'), +(273, 'RainLab.Builder', 'comment', '1.0.28', 'Fixes support for PHP 8', '2022-10-24 04:15:19'), +(274, 'RainLab.Builder', 'comment', '1.0.29', 'Disable touch device detection', '2022-10-24 04:15:19'), +(275, 'RainLab.Builder', 'comment', '1.0.30', 'Minor styling improvements', '2022-10-24 04:15:19'), +(276, 'RainLab.Builder', 'comment', '1.0.31', 'Added support for more rich editor and file upload properties', '2022-10-24 04:15:19'), +(277, 'RainLab.Builder', 'comment', '1.0.32', 'Minor styling improvements', '2022-10-24 04:15:19'), +(278, 'RainLab.Builder', 'comment', '1.1.0', 'Adds feature for adding database fields to a form definition.', '2022-10-24 04:15:19'), +(279, 'RainLab.Builder', 'comment', '1.1.1', 'Adds DBAL timestamp column type. Adds database prefix support. Fixes various bugs.', '2022-10-24 04:15:19'), +(280, 'RainLab.Builder', 'comment', '1.1.2', 'Compatibility with October CMS v2.2', '2022-10-24 04:15:19'), +(281, 'RainLab.Builder', 'comment', '1.1.3', 'Adds comment support to database tables.', '2022-10-24 04:15:19'), +(282, 'RainLab.Builder', 'comment', '1.1.4', 'Fixes duplication bug saving backend menu permissions.', '2022-10-24 04:15:19'), +(283, 'RainLab.Builder', 'comment', '1.2.0', 'Improve support with October v3.0', '2022-10-24 04:15:19'), +(284, 'RainLab.Builder', 'comment', '1.2.2', 'Compatibility updates.', '2022-10-24 04:15:19'), +(285, 'RainLab.Builder', 'comment', '1.2.3', 'Fixes issue when removing items from permissions and menus.', '2022-10-24 04:15:19'), +(286, 'RainLab.Builder', 'comment', '1.2.5', 'Fixes validator conflict with other plugins.', '2022-10-24 04:15:19'), +(287, 'Martin.Forms', 'script', '1.0.0', 'create_records_table.php', '2022-10-24 04:21:36'), +(288, 'Martin.Forms', 'comment', '1.0.0', 'First version of Magic Forms', '2022-10-24 04:21:36'), +(289, 'Martin.Forms', 'comment', '1.0.1', 'Added CSRF protection', '2022-10-24 04:21:36'), +(290, 'Martin.Forms', 'comment', '1.1.0', 'Added reCAPTCHA', '2022-10-24 04:21:36'), +(291, 'Martin.Forms', 'comment', '1.1.1', 'Fix when using reCAPTCHA + allowed fields', '2022-10-24 04:21:36'), +(292, 'Martin.Forms', 'script', '1.1.2', 'add_group_field.php', '2022-10-24 04:21:36'), +(293, 'Martin.Forms', 'comment', '1.1.2', 'Filter forms records', '2022-10-24 04:21:36'), +(294, 'Martin.Forms', 'comment', '1.1.2', 'Search inside stored data', '2022-10-24 04:21:36'), +(295, 'Martin.Forms', 'comment', '1.1.2', 'Organize your forms on custom groups', '2022-10-24 04:21:36'), +(296, 'Martin.Forms', 'comment', '1.2.0', 'Export stored data in CSV format', '2022-10-24 04:21:36'), +(297, 'Martin.Forms', 'comment', '1.2.1', 'Auto-response email on form submit', '2022-10-24 04:21:36'), +(298, 'Martin.Forms', 'comment', '1.2.1', 'Added Turkish language', '2022-10-24 04:21:36'), +(299, 'Martin.Forms', 'comment', '1.2.2', 'Override notifications and auto-response email subjects', '2022-10-24 04:21:36'), +(300, 'Martin.Forms', 'comment', '1.2.3', 'New option to reset form after successfully submit', '2022-10-24 04:21:36'), +(301, 'Martin.Forms', 'comment', '1.2.3', 'Fixed Empty AJAX Form template', '2022-10-24 04:21:36'), +(302, 'Martin.Forms', 'comment', '1.2.3', 'Support for Translate plugin', '2022-10-24 04:21:36'), +(303, 'Martin.Forms', 'comment', '1.2.3', 'Added plugin documentation', '2022-10-24 04:21:36'), +(304, 'Martin.Forms', 'comment', '1.2.4', 'Added detailed reCAPTCHA help', '2022-10-24 04:21:36'), +(305, 'Martin.Forms', 'comment', '1.3.0', 'AJAX file uploads', '2022-10-24 04:21:36'), +(306, 'Martin.Forms', 'comment', '1.3.1', 'Added lang pt-br', '2022-10-24 04:21:36'), +(307, 'Martin.Forms', 'comment', '1.3.2', 'Fixed multiples reCAPTCHAs on same page', '2022-10-24 04:21:36'), +(308, 'Martin.Forms', 'comment', '1.3.3', 'Fixed record detail page when form data contains an array', '2022-10-24 04:21:36'), +(309, 'Martin.Forms', 'comment', '1.3.3', 'Updated documentations', '2022-10-24 04:21:36'), +(310, 'Martin.Forms', 'comment', '1.3.4', 'New \"Anonymize IP\" option', '2022-10-24 04:21:36'), +(311, 'Martin.Forms', 'comment', '1.3.5', 'New option \"Redirect on successful submit\"', '2022-10-24 04:21:36'), +(312, 'Martin.Forms', 'comment', '1.3.6', 'French translation', '2022-10-24 04:21:36'), +(313, 'Martin.Forms', 'comment', '1.3.6', 'Support Translate plugin on reCAPTCHA', '2022-10-24 04:21:36'), +(314, 'Martin.Forms', 'comment', '1.3.6', 'reCAPTCHA validation enhancements', '2022-10-24 04:21:36'), +(315, 'Martin.Forms', 'comment', '1.3.7', 'Displaying errors with fields (inline errors)', '2022-10-24 04:21:36'), +(316, 'Martin.Forms', 'comment', '1.3.7', 'Show uploads as list', '2022-10-24 04:21:36'), +(317, 'Martin.Forms', 'comment', '1.3.8', 'Fixed handling arrays (radio inputs) in notification email', '2022-10-24 04:21:36'), +(318, 'Martin.Forms', 'comment', '1.3.9', 'Use custom mail templates', '2022-10-24 04:21:36'), +(319, 'Martin.Forms', 'comment', '1.3.9', 'Execute custom JavaScript on form success or error', '2022-10-24 04:21:36'), +(320, 'Martin.Forms', 'comment', '1.4.0', 'Added Events (please, refer to docs) [thanks to therealkevinard]', '2022-10-24 04:21:36'), +(321, 'Martin.Forms', 'comment', '1.4.1', 'New option \"Reply To\"', '2022-10-24 04:21:36'), +(322, 'Martin.Forms', 'comment', '1.4.2', 'Escape HTML characters on the view records page [thanks to Andre]', '2022-10-24 04:21:36'), +(323, 'Martin.Forms', 'comment', '1.4.2', 'New option to sanitize form data (check security docs for more info)', '2022-10-24 04:21:36'), +(324, 'Martin.Forms', 'comment', '1.4.2', 'Added option to send blind carbon copy in notifications email', '2022-10-24 04:21:36'), +(325, 'Martin.Forms', 'script', '1.4.3', 'add_unread_field.php', '2022-10-24 04:21:36'), +(326, 'Martin.Forms', 'comment', '1.4.3', 'Fixes related to October Build 420', '2022-10-24 04:21:36'), +(327, 'Martin.Forms', 'comment', '1.4.3', 'Added \"Unread Records\" counter', '2022-10-24 04:21:36'), +(328, 'Martin.Forms', 'comment', '1.4.3', 'Fixed errors when only BCC addresses are supplied', '2022-10-24 04:21:36'), +(329, 'Martin.Forms', 'comment', '1.4.3', 'New setting \"hide navigation item\"', '2022-10-24 04:21:36'), +(330, 'Martin.Forms', 'comment', '1.4.4', 'Use custom partials for Success and Error messages', '2022-10-24 04:21:36'), +(331, 'Martin.Forms', 'comment', '1.4.4.1', 'Fix with notifications emails', '2022-10-24 04:21:36'), +(332, 'Martin.Forms', 'comment', '1.4.5', 'Mail class code refactoring', '2022-10-24 04:21:36'), +(333, 'Martin.Forms', 'comment', '1.4.5', 'Access submited data on auto-response email template', '2022-10-24 04:21:36'), +(334, 'Martin.Forms', 'comment', '1.4.5.1', 'Store form data without escaping unicode [thanks to panakour]', '2022-10-24 04:21:36'), +(335, 'Martin.Forms', 'comment', '1.4.6', 'New option to skip saving forms data on database.', '2022-10-24 04:21:36'), +(336, 'Martin.Forms', 'comment', '1.4.6', 'Possibility to change the text on the remove file popup [thanks to ShiroeSama]', '2022-10-24 04:21:36'), +(337, 'Martin.Forms', 'comment', '1.4.6.1', 'Changed database field from json to text to support MySQL 5.5', '2022-10-24 04:21:36'), +(338, 'Martin.Forms', 'comment', '1.4.7', 'you can use your form variables on notification mail subject [thanks to Alex360hd]', '2022-10-24 04:21:36'), +(339, 'Martin.Forms', 'comment', '1.4.7', 'fix custom subject on email template [Thanks to matteotrubini]', '2022-10-24 04:21:36'), +(340, 'Martin.Forms', 'comment', '1.4.7', 'fix email bug when not storing on db [Thanks JurekRaben]', '2022-10-24 04:21:36'), +(341, 'Martin.Forms', 'comment', '1.4.7', 'skip url redirect validation [Thanks to EleRam]', '2022-10-24 04:21:36'), +(342, 'Martin.Forms', 'comment', '1.4.8', 'added GDPR cleanup feature [thanks to Alex360hd]', '2022-10-24 04:21:36'), +(343, 'Martin.Forms', 'comment', '1.4.9', 'fix on replaceToken function when replacement is null [thanks to leonaze]', '2022-10-24 04:21:36'), +(344, 'Martin.Forms', 'comment', '1.4.9.1', 'fix a nullable type error on PHP 7.0', '2022-10-24 04:21:36'), +(345, 'Martin.Forms', 'comment', '1.4.9.2', 'bugfix when a form field array has more than 2 levels of depth', '2022-10-24 04:21:36'), +(346, 'Martin.Forms', 'comment', '1.4.10', 'improvements related to event functionality', '2022-10-24 04:21:36'), +(347, 'Martin.Forms', 'comment', '1.4.11', 'added Laravel custom attributes to form validation [thanks to geekfil]', '2022-10-24 04:21:36'), +(348, 'Martin.Forms', 'comment', '1.4.11', 'updated french translation [thanks to FelixINX]', '2022-10-24 04:21:36'), +(349, 'Martin.Forms', 'comment', '1.4.12', 'use form variables on auto-response mail subject [thanks to jiargei]', '2022-10-24 04:21:36'), +(350, 'Martin.Forms', 'comment', '1.4.13', 'pass an array with form errors to JavaScript [thanks to multiwebinc]', '2022-10-24 04:21:36'), +(351, 'Martin.Forms', 'comment', '1.4.14', 'fixed error with empty auto-response subject', '2022-10-24 04:21:36'), +(352, 'Martin.Forms', 'comment', '1.4.15', 'enhancements related to saving record and events [thanks to boxxroom]', '2022-10-24 04:21:36'), +(353, 'Martin.Forms', 'comment', '1.4.16', 'added chinese translation [thanks to everyx]', '2022-10-24 04:21:36'), +(354, 'Martin.Forms', 'comment', '1.4.17', 'allowing sanitize to work recursively [thanks to multiwebinc]', '2022-10-24 04:21:36'), +(355, 'Martin.Forms', 'comment', '1.4.18', 'export records enhancements [thanks to Fosphatic]', '2022-10-24 04:21:36'), +(356, 'Martin.Forms', 'comment', '1.4.18', 'recaptcha locale fix [thanks to MaTToX3]', '2022-10-24 04:21:36'), +(357, 'Martin.Forms', 'comment', '1.4.19', 'added russian translation [thanks to FlusherDock1]', '2022-10-24 04:21:36'), +(358, 'Martin.Forms', 'comment', '1.4.19', 'sort records by date fix [thanks to mjauvin]', '2022-10-24 04:21:36'), +(359, 'Martin.Forms', 'comment', '1.4.20', 'added invisible reCAPTCHA [thanks to mjauvin]', '2022-10-24 04:21:36'), +(360, 'Martin.Forms', 'comment', '1.4.20', 'new option to set custom date format on emails subject', '2022-10-24 04:21:36'), +(361, 'Martin.Forms', 'comment', '1.5.0', 'fixes related to October Build 469 [thanks to mjauvin]', '2022-10-24 04:21:36'), +(362, 'Martin.Forms', 'comment', '1.5.0', 'fix when CSRF check is disabled [thanks to rechik]', '2022-10-24 04:21:36'), +(363, 'Martin.Forms', 'comment', '1.5.0', 'php linting and cleanup', '2022-10-24 04:21:36'), +(364, 'Martin.Forms', 'comment', '1.5.1', 'email templates improvemenrs [thanks to mjauvin]', '2022-10-24 04:21:36'), +(365, 'Martin.Forms', 'comment', '1.5.1', 'added german translation [thanks to Fosphatic]', '2022-10-24 04:21:36'), +(366, 'PKleindienst.BlogSearch', 'comment', '1.0.1', 'First version of Blog Search', '2023-02-06 16:58:00'), +(367, 'PKleindienst.BlogSearch', 'comment', '1.0.2', 'Fixed error with missing Translate Plugin', '2023-02-06 16:58:00'), +(368, 'PKleindienst.BlogSearch', 'comment', '1.0.3', 'Removed _ filter because it caused to much problems when Translate Plugin is missing', '2023-02-06 16:58:00'), +(369, 'PKleindienst.BlogSearch', 'comment', '1.0.4', 'Replaced POST Method with GET', '2023-02-06 16:58:00'), +(370, 'PKleindienst.BlogSearch', 'comment', '1.0.4', 'Map GET Request to :search url param', '2023-02-06 16:58:00'), +(371, 'PKleindienst.BlogSearch', 'comment', '1.0.4', 'fixed broken navigation', '2023-02-06 16:58:00'), +(372, 'PKleindienst.BlogSearch', 'comment', '1.0.5', 'fixed wrong routing', '2023-02-06 16:58:00'), +(373, 'PKleindienst.BlogSearch', 'comment', '1.0.6', 'included `excerpt` into search', '2023-02-06 16:58:00'), +(374, 'PKleindienst.BlogSearch', 'comment', '1.0.6', 'added option to add `mark` tags (hightlight) to search terms', '2023-02-06 16:58:00'), +(375, 'PKleindienst.BlogSearch', 'comment', '1.1.0', 'added category filter', '2023-02-06 16:58:00'), +(376, 'PKleindienst.BlogSearch', 'comment', '1.1.0', 'added option to exclude categories from results', '2023-02-06 16:58:00'), +(377, 'PKleindienst.BlogSearch', 'comment', '1.1.1', 'remove \'?\' from url if query is empty', '2023-02-06 16:58:00'), +(378, 'PKleindienst.BlogSearch', 'comment', '1.1.1', 'added MIT License', '2023-02-06 16:58:00'), +(379, 'PKleindienst.BlogSearch', 'comment', '1.2.0', 'added option to show only results from selected categories', '2023-02-06 16:58:00'), +(380, 'PKleindienst.BlogSearch', 'comment', '1.2.0', 'added option to disable url mapping (example.com/search?search=Foo instead of example.com/search/Foo)', '2023-02-06 16:58:00'), +(381, 'PKleindienst.BlogSearch', 'comment', '1.2.1', 'fixed bug with missing categories', '2023-02-06 16:58:00'), +(382, 'PKleindienst.BlogSearch', 'comment', '1.2.2', 'optimized query for included/excluded categories', '2023-02-06 16:58:00'), +(383, 'PKleindienst.BlogSearch', 'comment', '1.2.3', 'Fixed bug which caused included/excluded categories not being saved', '2023-02-06 16:58:00'), +(384, 'PKleindienst.BlogSearch', 'comment', '1.2.3', 'added support for Translate Plugin', '2023-02-06 16:58:00'), +(385, 'PKleindienst.BlogSearch', 'comment', '1.2.3', 'merged highlight bug fix for Cyrillic Symbols by thewizardplusplus', '2023-02-06 16:58:00'), +(386, 'PKleindienst.BlogSearch', 'comment', '1.3.0', '!!! Removed support for old Inspector Features prior to October 306', '2023-02-06 16:58:00'), +(387, 'PKleindienst.BlogSearch', 'comment', '1.4.0', 'Add homepage to plugin details by @gergo85', '2023-02-06 16:58:00'), +(388, 'PKleindienst.BlogSearch', 'comment', '1.4.0', 'Fixed pagination reference for non-default component names by @bnordland', '2023-02-06 16:58:00'), +(389, 'PKleindienst.BlogSearch', 'comment', '1.4.0', 'Fixed an issue with post filtering when a category is to be \"included\" that doesn\'t have any blog posts yet by @Harti', '2023-02-06 16:58:00'), +(390, 'Vdomah.BlogViews', 'script', '1.0.0', 'create_post_views_table.php', '2023-02-06 17:00:10'), +(391, 'Vdomah.BlogViews', 'comment', '1.0.0', 'First version of BlogViews', '2023-02-06 17:00:10'), +(392, 'Vdomah.BlogViews', 'comment', '1.0.1', 'Limit and link params fixed', '2023-02-06 17:00:10'), +(393, 'Vdomah.BlogViews', 'comment', '1.0.2', 'Added \'views\' dynamic property to Post model', '2023-02-06 17:00:10'), +(394, 'Vdomah.BlogViews', 'comment', '1.0.3', 'Improve the translation. Add MIT license. Pull request by gergo85', '2023-02-06 17:00:10'), +(395, 'Vdomah.BlogViews', 'comment', '1.0.4', 'Default value to 0 in getViewsAttribute (thanks to hambern)', '2023-02-06 17:00:10'), +(396, 'Vdomah.BlogViews', 'comment', '1.0.5', 'Add support for whatever slug url name parameter like {{ :slug_some_custom_url_parameter }}', '2023-02-06 17:00:10'), +(397, 'Vdomah.BlogViews', 'comment', '1.0.6', 'Ability to choose blog category for Popular posts', '2023-02-06 17:00:10'), +(398, 'Vdomah.BlogViews', 'comment', '1.0.7', 'Dynamic category slug url parameter. Only published posts in Popular component', '2023-02-06 17:00:10'), +(399, 'Vdomah.BlogViews', 'comment', '1.0.8', 'Fixed error using blogviews with sitemap: check if Controller instantiated before extend', '2023-02-06 17:00:10'), +(400, 'Vdomah.BlogViews', 'comment', '1.0.9', 'Get url parameters directly from Controller instance without component. Using Cookie instead of Session', '2023-02-06 17:00:10'), +(401, 'Vdomah.BlogViews', 'comment', '1.0.10', 'Fix bug when post is not found.', '2023-02-06 17:00:10'), +(402, 'Vdomah.BlogViews', 'comment', '1.0.11', 'Don\'t count web crawler bots visits.', '2023-02-06 17:00:10'), +(403, 'Vdomah.BlogViews', 'comment', '1.0.12', 'blogviews.before.track added with trackPrevent and trackBot options.', '2023-02-06 17:00:10'), +(404, 'Vdomah.BlogViews', 'comment', '1.0.13', 'Both Cookie and Session methods available to prevent doubletracking', '2023-02-06 17:00:10'), +(405, 'Vdomah.BlogViews', 'comment', '1.0.14', 'Fix: bot detection if no HTTP_USER_AGENT is present in request', '2023-02-06 17:00:10'), +(406, 'Indikator.BlogStat', 'comment', '1.0.0', 'First version of Blog Stats & Graphs.', '2023-02-06 17:01:07'), +(407, 'Indikator.BlogStat', 'comment', '1.0.1', 'Added more post statistics.', '2023-02-06 17:01:07'), +(408, 'Indikator.BlogStat', 'comment', '1.0.2', 'Minor improvements and bugfix.', '2023-02-06 17:01:07'), +(409, 'Indikator.BlogStat', 'comment', '1.0.3', 'Redesigned the report widgets.', '2023-02-06 17:01:07'), +(410, 'Indikator.BlogStat', 'comment', '1.0.4', '!!! Updated for October 420+.', '2023-02-06 17:01:07'), +(411, 'Indikator.BlogStat', 'comment', '1.0.5', 'Minor visual and code improvements.', '2023-02-06 17:01:07'), +(412, 'Indikator.BlogStat', 'comment', '1.0.6', 'Added permission to Dashboard widgets.', '2023-02-06 17:01:07'), +(413, 'AhmadFatoni.ApiGenerator', 'comment', '1.0.1', 'Initialize plugin.', '2023-02-06 17:58:49'), +(414, 'AhmadFatoni.ApiGenerator', 'comment', '1.0.2', 'Database implementation', '2023-02-06 17:58:50'), +(415, 'AhmadFatoni.ApiGenerator', 'script', '1.0.3', 'builder_table_create_ahmadfatoni_apigenerator_data.php', '2023-02-06 17:58:50'), +(416, 'AhmadFatoni.ApiGenerator', 'comment', '1.0.3', 'add builder plugin on requirements dependency', '2023-02-06 17:58:50'), +(417, 'AhmadFatoni.ApiGenerator', 'comment', '1.0.4', 'fixing bug on PHP 7', '2023-02-06 17:58:50'), +(418, 'AhmadFatoni.ApiGenerator', 'comment', '1.0.5', 'fixing bug on request delete data', '2023-02-06 17:58:50'), +(419, 'AhmadFatoni.ApiGenerator', 'comment', '1.0.6', 'fixing bug on generate endpoint', '2023-02-06 17:58:50'), +(420, 'AhmadFatoni.ApiGenerator', 'comment', '1.0.7', 'fixing bug on October CMS v1.0.456', '2023-02-06 17:58:50'), +(421, 'Tallpro.Related', 'comment', '1.0.1', 'First version of Related', '2023-02-06 18:11:00'), +(422, 'SureSoftware.PowerSEO', 'script', '1.0.1', 'create_blog_posts_table.php', '2023-02-06 20:22:42'), +(423, 'SureSoftware.PowerSEO', 'comment', '1.0.1', 'First version of Seo Extension', '2023-02-06 20:22:42'), +(424, 'SureSoftware.PowerSEO', 'comment', '1.0.2', 'Bug fixes', '2023-02-06 20:22:42'), +(425, 'SureSoftware.PowerSEO', 'comment', '1.0.3', 'Backend Settings added to configure meta tags & Open Graph tags added', '2023-02-06 20:22:42'), +(426, 'SureSoftware.PowerSEO', 'comment', '1.0.4', 'Code clean up and change path naming in settings model', '2023-02-06 20:22:42'), +(427, 'SureSoftware.PowerSEO', 'comment', '1.0.5', 'Add Turkish, Russian, cs_CZ locale', '2023-02-06 20:22:42'), +(428, 'SureSoftware.PowerSEO', 'comment', '1.0.6', 'Fix issue of SEO Settings Errors', '2023-02-06 20:22:42'), +(429, 'SureSoftware.PowerSEO', 'script', '2.0.0', 'migrate_settings.php', '2023-02-06 20:22:42'), +(430, 'SureSoftware.PowerSEO', 'comment', '2.0.0', 'Changed plugin to PowerSEO, fixed server errors and included latest changes', '2023-02-06 20:22:42'), +(431, 'SureSoftware.PowerSEO', 'script', '2.0.1', 'migrate_blogpost_seo.php', '2023-02-06 20:22:42'), +(432, 'SureSoftware.PowerSEO', 'comment', '2.0.1', 'Prefixed SEO column names to ensure uniqueness and prevent plugin conflicts', '2023-02-06 20:22:42'), +(433, 'SureSoftware.PowerSEO', 'script', '2.0.2', 'blogposts_fix.php', '2023-02-06 20:22:42'), +(434, 'SureSoftware.PowerSEO', 'comment', '2.0.2', 'Fixed issue with fresh install on non-migrated sites', '2023-02-06 20:22:42'), +(435, 'SureSoftware.PowerSEO', 'comment', '2.0.3', 'Fixed bug in SeoBlogPost robots not populating', '2023-02-06 20:22:42'), +(436, 'SureSoftware.PowerSEO', 'comment', '2.0.4', 'Fixed bug with fields showing up in the static pages repeater', '2023-02-06 20:22:42'), +(437, 'SureSoftware.PowerSEO', 'comment', '2.0.5', 'Fixed bug the TranslatableModel check not working for default locale URLs', '2023-02-06 20:22:42'), +(438, 'SureSoftware.PowerSEO', 'comment', '2.1.1', 'Added feature to show the blog \"Featured Image\" on social media (using og tags)', '2023-02-06 20:22:42'), +(439, 'SureSoftware.PowerSEO', 'comment', '2.1.1', 'Fixed bug with blog post meta titles not being set correctly', '2023-02-06 20:22:42'), +(440, 'SureSoftware.PowerSEO', 'comment', '2.1.2', 'Fixes bug with fields repeating in Rainlab.Pages repeatable sections', '2023-02-06 20:22:42'), +(441, 'RainLab.Blog', 'script', '1.6.3', 'builder_table_update_rainlab_blog_posts.php', '2023-02-06 20:43:04'), +(442, 'RainLab.Blog', 'comment', '1.6.3', 'Updated table rainlab_blog_posts', '2023-02-06 20:43:04'); + +INSERT INTO `system_plugin_versions` (`id`, `code`, `version`, `created_at`, `is_disabled`, `is_frozen`) VALUES +(1, 'October.Demo', '1.0.1', '2022-10-23 16:11:38', 0, 0), +(2, 'RainLab.Blog', '1.6.3', '2023-02-06 20:43:04', 0, 0), +(3, 'RainLab.Pages', '1.5.5', '2022-10-24 04:13:48', 0, 0), +(4, 'RainLab.Translate', '1.12.0', '2022-10-24 04:14:15', 0, 0), +(5, 'Indikator.DevTools', '1.2.3', '2022-10-24 04:14:44', 0, 0), +(6, 'RainLab.Builder', '1.2.5', '2022-10-24 04:15:19', 0, 0), +(7, 'Martin.Forms', '1.5.1', '2022-10-24 04:21:36', 0, 0), +(8, 'PKleindienst.BlogSearch', '1.4.0', '2023-02-06 16:58:00', 0, 0), +(9, 'Vdomah.BlogViews', '1.0.14', '2023-02-06 17:00:10', 0, 0), +(10, 'Indikator.BlogStat', '1.0.6', '2023-02-06 17:01:07', 0, 0), +(11, 'AhmadFatoni.ApiGenerator', '1.0.7', '2023-02-06 17:58:50', 0, 1), +(12, 'Tallpro.Related', '1.0.1', '2023-02-06 18:11:00', 0, 0), +(13, 'SureSoftware.PowerSEO', '2.1.2', '2023-02-06 20:22:42', 0, 0); + +INSERT INTO `system_settings` (`id`, `item`, `value`) VALUES +(1, 'tallpro_related_settings', '{\"number_posts\":8}'); + +INSERT INTO `vdomah_blogviews_views` (`views`, `post_id`) VALUES +(19, 1), +(5, 2); + + + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..9c4d23a --- /dev/null +++ b/index.php @@ -0,0 +1,48 @@ +make(Illuminate\Contracts\Http\Kernel::class); + +$response = $kernel->handle( + $request = Illuminate\Http\Request::capture() +); + +$response->send(); + +$kernel->terminate($request, $response); diff --git a/modules/backend/ServiceProvider.php b/modules/backend/ServiceProvider.php new file mode 100644 index 0000000..e21bda1 --- /dev/null +++ b/modules/backend/ServiceProvider.php @@ -0,0 +1,275 @@ +registerMailer(); + $this->registerAssetBundles(); + + /* + * Backend specific + */ + if (App::runningInBackend()) { + $this->registerBackendNavigation(); + $this->registerBackendReportWidgets(); + $this->registerBackendWidgets(); + $this->registerBackendPermissions(); + $this->registerBackendSettings(); + } + } + + /** + * Bootstrap the module events. + * + * @return void + */ + public function boot() + { + parent::boot('backend'); + } + + /** + * Register mail templates + */ + protected function registerMailer() + { + MailManager::instance()->registerCallback(function ($manager) { + $manager->registerMailTemplates([ + 'backend::mail.invite', + 'backend::mail.restore', + ]); + }); + } + + /** + * Register asset bundles + */ + protected function registerAssetBundles() + { + CombineAssets::registerCallback(function ($combiner) { + $combiner->registerBundle('~/modules/backend/assets/less/october.less'); + $combiner->registerBundle('~/modules/backend/assets/js/october.js'); + $combiner->registerBundle('~/modules/backend/widgets/table/assets/js/build.js'); + $combiner->registerBundle('~/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser.js'); + $combiner->registerBundle('~/modules/backend/widgets/mediamanager/assets/less/mediamanager.less'); + $combiner->registerBundle('~/modules/backend/formwidgets/codeeditor/assets/less/codeeditor.less'); + $combiner->registerBundle('~/modules/backend/formwidgets/repeater/assets/less/repeater.less'); + $combiner->registerBundle('~/modules/backend/formwidgets/codeeditor/assets/js/build.js'); + $combiner->registerBundle('~/modules/backend/formwidgets/fileupload/assets/less/fileupload.less'); + $combiner->registerBundle('~/modules/backend/formwidgets/nestedform/assets/less/nestedform.less'); + $combiner->registerBundle('~/modules/backend/formwidgets/richeditor/assets/js/build-plugins.js'); + $combiner->registerBundle('~/modules/backend/formwidgets/colorpicker/assets/less/colorpicker.less'); + $combiner->registerBundle('~/modules/backend/formwidgets/permissioneditor/assets/less/permissioneditor.less'); + $combiner->registerBundle('~/modules/backend/formwidgets/markdowneditor/assets/less/markdowneditor.less'); + $combiner->registerBundle('~/modules/backend/formwidgets/sensitive/assets/less/sensitive.less'); + + /* + * Rich Editor is protected by DRM + */ + if (file_exists(base_path('modules/backend/formwidgets/richeditor/assets/vendor/froala_drm'))) { + $combiner->registerBundle('~/modules/backend/formwidgets/richeditor/assets/less/richeditor.less'); + $combiner->registerBundle('~/modules/backend/formwidgets/richeditor/assets/js/build.js'); + } + }); + } + + /* + * Register navigation + */ + protected function registerBackendNavigation() + { + BackendMenu::registerCallback(function ($manager) { + $manager->registerMenuItems('October.Backend', [ + 'dashboard' => [ + 'label' => 'backend::lang.dashboard.menu_label', + 'icon' => 'icon-dashboard', + 'iconSvg' => 'modules/backend/assets/images/dashboard-icon.svg', + 'url' => Backend::url('backend'), + 'permissions' => ['backend.access_dashboard'], + 'order' => 10 + ], + 'media' => [ + 'label' => 'backend::lang.media.menu_label', + 'icon' => 'icon-folder', + 'iconSvg' => 'modules/backend/assets/images/media-icon.svg', + 'url' => Backend::url('backend/media'), + 'permissions' => ['media.*'], + 'order' => 200 + ] + ]); + }); + } + + /* + * Register report widgets + */ + protected function registerBackendReportWidgets() + { + WidgetManager::instance()->registerReportWidgets(function ($manager) { + $manager->registerReportWidget(\Backend\ReportWidgets\Welcome::class, [ + 'label' => 'backend::lang.dashboard.welcome.widget_title_default', + 'context' => 'dashboard' + ]); + }); + } + + /* + * Register permissions + */ + protected function registerBackendPermissions() + { + BackendAuth::registerCallback(function ($manager) { + $manager->registerPermissions('October.Backend', [ + 'backend.access_dashboard' => [ + 'label' => 'system::lang.permissions.view_the_dashboard', + 'tab' => 'system::lang.permissions.name', + ], + 'backend.manage_default_dashboard' => [ + 'label' => 'system::lang.permissions.manage_default_dashboard', + 'tab' => 'system::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + ], + 'backend.manage_users' => [ + 'label' => 'system::lang.permissions.manage_other_administrators', + 'tab' => 'system::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + ], + 'backend.impersonate_users' => [ + 'label' => 'system::lang.permissions.impersonate_users', + 'tab' => 'system::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + ], + 'backend.manage_preferences' => [ + 'label' => 'system::lang.permissions.manage_preferences', + 'tab' => 'system::lang.permissions.name', + ], + 'backend.manage_editor' => [ + 'label' => 'system::lang.permissions.manage_editor', + 'tab' => 'system::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + ], + 'backend.manage_own_editor' => [ + 'label' => 'system::lang.permissions.manage_own_editor', + 'tab' => 'system::lang.permissions.name', + ], + 'backend.manage_branding' => [ + 'label' => 'system::lang.permissions.manage_branding', + 'tab' => 'system::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + ], + 'media.manage_media' => [ + 'label' => 'backend::lang.permissions.manage_media', + 'tab' => 'system::lang.permissions.name', + ], + 'backend.allow_unsafe_markdown' => [ + 'label' => 'backend::lang.permissions.allow_unsafe_markdown', + 'tab' => 'system::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + ], + ]); + }); + } + + /* + * Register widgets + */ + protected function registerBackendWidgets() + { + WidgetManager::instance()->registerFormWidgets(function ($manager) { + $manager->registerFormWidget('Backend\FormWidgets\CodeEditor', 'codeeditor'); + $manager->registerFormWidget('Backend\FormWidgets\RichEditor', 'richeditor'); + $manager->registerFormWidget('Backend\FormWidgets\MarkdownEditor', 'markdown'); + $manager->registerFormWidget('Backend\FormWidgets\FileUpload', 'fileupload'); + $manager->registerFormWidget('Backend\FormWidgets\Relation', 'relation'); + $manager->registerFormWidget('Backend\FormWidgets\DatePicker', 'datepicker'); + $manager->registerFormWidget('Backend\FormWidgets\TimePicker', 'timepicker'); + $manager->registerFormWidget('Backend\FormWidgets\ColorPicker', 'colorpicker'); + $manager->registerFormWidget('Backend\FormWidgets\DataTable', 'datatable'); + $manager->registerFormWidget('Backend\FormWidgets\RecordFinder', 'recordfinder'); + $manager->registerFormWidget('Backend\FormWidgets\Repeater', 'repeater'); + $manager->registerFormWidget('Backend\FormWidgets\TagList', 'taglist'); + $manager->registerFormWidget('Backend\FormWidgets\MediaFinder', 'mediafinder'); + $manager->registerFormWidget('Backend\FormWidgets\NestedForm', 'nestedform'); + $manager->registerFormWidget('Backend\FormWidgets\Sensitive', 'sensitive'); + }); + } + + /* + * Register settings + */ + protected function registerBackendSettings() + { + SettingsManager::instance()->registerCallback(function ($manager) { + $manager->registerSettingItems('October.Backend', [ + 'branding' => [ + 'label' => 'backend::lang.branding.menu_label', + 'description' => 'backend::lang.branding.menu_description', + 'category' => SettingsManager::CATEGORY_SYSTEM, + 'icon' => 'icon-paint-brush', + 'class' => 'Backend\Models\BrandSetting', + 'permissions' => ['backend.manage_branding'], + 'order' => 500, + 'keywords' => 'brand style' + ], + 'editor' => [ + 'label' => 'backend::lang.editor.menu_label', + 'description' => 'backend::lang.editor.menu_description', + 'category' => SettingsManager::CATEGORY_SYSTEM, + 'icon' => 'icon-code', + 'class' => 'Backend\Models\EditorSetting', + 'permissions' => ['backend.manage_editor'], + 'order' => 500, + 'keywords' => 'html code class style' + ], + 'myaccount' => [ + 'label' => 'backend::lang.myaccount.menu_label', + 'description' => 'backend::lang.myaccount.menu_description', + 'category' => SettingsManager::CATEGORY_MYSETTINGS, + 'icon' => 'icon-user', + 'url' => Backend::url('backend/users/myaccount'), + 'order' => 500, + 'context' => 'mysettings', + 'keywords' => 'backend::lang.myaccount.menu_keywords' + ], + 'preferences' => [ + 'label' => 'backend::lang.backend_preferences.menu_label', + 'description' => 'backend::lang.backend_preferences.menu_description', + 'category' => SettingsManager::CATEGORY_MYSETTINGS, + 'icon' => 'icon-laptop', + 'url' => Backend::url('backend/preferences'), + 'permissions' => ['backend.manage_preferences'], + 'order' => 510, + 'context' => 'mysettings' + ], + 'access_logs' => [ + 'label' => 'backend::lang.access_log.menu_label', + 'description' => 'backend::lang.access_log.menu_description', + 'category' => SettingsManager::CATEGORY_LOGS, + 'icon' => 'icon-lock', + 'url' => Backend::url('backend/accesslogs'), + 'permissions' => ['system.access_logs'], + 'order' => 920 + ] + ]); + }); + } +} diff --git a/modules/backend/assets/css/dashboard/dashboard.css b/modules/backend/assets/css/dashboard/dashboard.css new file mode 100644 index 0000000..2fb878c --- /dev/null +++ b/modules/backend/assets/css/dashboard/dashboard.css @@ -0,0 +1,12 @@ +.dashboard-container > .report-container.loading { + position: absolute; + width: 100%; + height: 100%; +} +.dashboard-container > .report-container.loading .loading-indicator-container { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; +} diff --git a/modules/backend/assets/css/october.css b/modules/backend/assets/css/october.css new file mode 100644 index 0000000..5703da3 --- /dev/null +++ b/modules/backend/assets/css/october.css @@ -0,0 +1,1117 @@ +@import "../vendor/jcrop/css/jquery.Jcrop.min.css"; +@import "../../../system/assets/vendor/prettify/prettify.css"; +@import "../../../system/assets/vendor/prettify/theme-desert.css"; +@-webkit-keyframes showSweetAlert {0% {transform:scale(0.7);-webkit-transform:scale(0.7) }45% {transform:scale(1.05);-webkit-transform:scale(1.05) }80% {transform:scale(0.95);-webkit-tranform:scale(0.95) }100% {transform:scale(1);-webkit-transform:scale(1) }} +@keyframes showSweetAlert {0% {transform:scale(0.7);-webkit-transform:scale(0.7) }45% {transform:scale(1.05);-webkit-transform:scale(1.05) }80% {transform:scale(0.95);-webkit-tranform:scale(0.95) }100% {transform:scale(1);-webkit-transform:scale(1) }} +@-webkit-keyframes hideSweetAlert {0% {transform:scale(1);-webkit-transform:scale(1) }100% {transform:scale(0.5);-webkit-transform:scale(0.5) }} +@keyframes hideSweetAlert {0% {transform:scale(1);-webkit-transform:scale(1) }100% {transform:scale(0.5);-webkit-transform:scale(0.5) }} +.showSweetAlert {-webkit-animation:showSweetAlert 0.3s;animation:showSweetAlert 0.3s} +.hideSweetAlert {-webkit-animation:hideSweetAlert 0.2s;animation:hideSweetAlert 0.2s} +@-webkit-keyframes animateSuccessTip {0% {width:0;left:1px;top:19px }54% {width:0;left:1px;top:19px }70% {width:50px;left:-8px;top:37px }84% {width:17px;left:21px;top:48px }100% {width:25px;left:14px;top:45px }} +@keyframes animateSuccessTip {0% {width:0;left:1px;top:19px }54% {width:0;left:1px;top:19px }70% {width:50px;left:-8px;top:37px }84% {width:17px;left:21px;top:48px }100% {width:25px;left:14px;top:45px }} +@-webkit-keyframes animateSuccessLong {0% {width:0;right:46px;top:54px }65% {width:0;right:46px;top:54px }84% {width:55px;right:0;top:35px }100% {width:47px;right:8px;top:38px }} +@keyframes animateSuccessLong {0% {width:0;right:46px;top:54px }65% {width:0;right:46px;top:54px }84% {width:55px;right:0;top:35px }100% {width:47px;right:8px;top:38px }} +@-webkit-keyframes rotatePlaceholder {0% {transform:rotate(-45deg);-webkit-transform:rotate(-45deg) }5% {transform:rotate(-45deg);-webkit-transform:rotate(-45deg) }12% {transform:rotate(-405deg);-webkit-transform:rotate(-405deg) }100% {transform:rotate(-405deg);-webkit-transform:rotate(-405deg) }} +@keyframes rotatePlaceholder {0% {transform:rotate(-45deg);-webkit-transform:rotate(-45deg) }5% {transform:rotate(-45deg);-webkit-transform:rotate(-45deg) }12% {transform:rotate(-405deg);-webkit-transform:rotate(-405deg) }100% {transform:rotate(-405deg);-webkit-transform:rotate(-405deg) }} +.animateSuccessTip {-webkit-animation:animateSuccessTip 0.75s;animation:animateSuccessTip 0.75s} +.animateSuccessLong {-webkit-animation:animateSuccessLong 0.75s;animation:animateSuccessLong 0.75s} +.icon.success.animate::after {-webkit-animation:rotatePlaceholder 4.25s ease-in;animation:rotatePlaceholder 4.25s ease-in} +@-webkit-keyframes animateErrorIcon {0% {transform:rotateX(100deg);-webkit-transform:rotateX(100deg);opacity:0 }100% {transform:rotateX(0deg);-webkit-transform:rotateX(0deg);opacity:1 }} +@keyframes animateErrorIcon {0% {transform:rotateX(100deg);-webkit-transform:rotateX(100deg);opacity:0 }100% {transform:rotateX(0deg);-webkit-transform:rotateX(0deg);opacity:1 }} +.animateErrorIcon {-webkit-animation:animateErrorIcon 0.5s;animation:animateErrorIcon 0.5s} +@-webkit-keyframes animateXMark {0% {transform:scale(0.4);-webkit-transform:scale(0.4);margin-top:26px;opacity:0 }50% {transform:scale(0.4);-webkit-transform:scale(0.4);margin-top:26px;opacity:0 }80% {transform:scale(1.15);-webkit-transform:scale(1.15);margin-top:-6px }100% {transform:scale(1);-webkit-transform:scale(1);margin-top:0;opacity:1 }} +@keyframes animateXMark {0% {transform:scale(0.4);-webkit-transform:scale(0.4);margin-top:26px;opacity:0 }50% {transform:scale(0.4);-webkit-transform:scale(0.4);margin-top:26px;opacity:0 }80% {transform:scale(1.15);-webkit-transform:scale(1.15);margin-top:-6px }100% {transform:scale(1);-webkit-transform:scale(1);margin-top:0;opacity:1 }} +.animateXMark {-webkit-animation:animateXMark 0.5s;animation:animateXMark 0.5s} +@-webkit-keyframes pulseWarning {0% {border-color:#F8D486 }100% {border-color:#F8BB86 }} +@keyframes pulseWarning {0% {border-color:#F8D486 }100% {border-color:#F8BB86 }} +.pulseWarning {-webkit-animation:pulseWarning 0.75s infinite alternate;animation:pulseWarning 0.75s infinite alternate} +@-webkit-keyframes pulseWarningIns {0% {background-color:#F8D486 }100% {background-color:#F8BB86 }} +@keyframes pulseWarningIns {0% {background-color:#F8D486 }100% {background-color:#F8BB86 }} +.pulseWarningIns {-webkit-animation:pulseWarningIns 0.75s infinite alternate;animation:pulseWarningIns 0.75s infinite alternate} +.sweet-overlay {background-color:rgba(0,0,0,0.4);position:fixed;left:0;right:0;top:0;bottom:0;display:none;z-index:7600} +.sweet-alert {background-color:#f9f9f9;width:478px;padding:17px;border-radius:5px;text-align:center;position:fixed;left:50%;top:50%;margin-left:-256px;margin-top:-200px;overflow:hidden;display:none;z-index:8600} +@media all and (max-width:767px) {.sweet-alert {width:auto;margin-left:0;margin-right:0;left:15px;right:15px }} +.sweet-alert .icon {width:80px;height:80px;border:4px solid gray;border-radius:50%;margin:20px auto;position:relative;box-sizing:content-box} +.sweet-alert .icon.error {border-color:#952518} +.sweet-alert .icon.error .x-mark {position:relative;display:block} +.sweet-alert .icon.error .line {position:absolute;height:5px;width:47px;background-color:#ab2a1c;display:block;top:37px;border-radius:2px} +.sweet-alert .icon.error .line.left {-webkit-transform:rotate(45deg);transform:rotate(45deg);left:17px} +.sweet-alert .icon.error .line.right {-webkit-transform:rotate(-45deg);transform:rotate(-45deg);right:16px} +.sweet-alert .icon.warning {border-color:#eea236} +.sweet-alert .icon.warning .body {position:absolute;width:5px;height:47px;left:50%;top:10px;border-radius:2px;margin-left:-2px;background-color:#f0ad4e} +.sweet-alert .icon.warning .dot {position:absolute;width:7px;height:7px;border-radius:50%;margin-left:-3px;left:50%;bottom:10px;background-color:#f0ad4e} +.sweet-alert .icon.info {border-color:#46b8da} +.sweet-alert .icon.info::before {content:"";position:absolute;width:5px;height:29px;left:50%;bottom:17px;border-radius:2px;margin-left:-2px;background-color:#5bc0de} +.sweet-alert .icon.info::after {content:"";position:absolute;width:7px;height:7px;border-radius:50%;margin-left:-3px;top:19px;background-color:#5bc0de} +.sweet-alert .icon.success {border-color:#2b9854} +.sweet-alert .icon.success::before, +.sweet-alert .icon.success::after {content:'';border-radius:50%;position:absolute;width:60px;height:120px;background:white;-webkit-transform:rotate(45deg);transform:rotate(45deg)} +.sweet-alert .icon.success::before {border-radius:120px 0 0 120px;top:-7px;left:-33px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transform-origin:60px 60px;transform-origin:60px 60px} +.sweet-alert .icon.success::after {border-radius:0 120px 120px 0;top:-11px;left:30px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transform-origin:0 60px;transform-origin:0 60px} +.sweet-alert .icon.success .placeholder {width:80px;height:80px;border:4px solid rgba(49,172,95,0.2);border-radius:50%;box-sizing:content-box;position:absolute;left:-4px;top:-4px;z-index:2} +.sweet-alert .icon.success .fix {width:5px;height:90px;background-color:#f9f9f9;position:absolute;left:28px;top:8px;z-index:1;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)} +.sweet-alert .icon.success .line {height:5px;background-color:#31ac5f;display:block;border-radius:2px;position:absolute;z-index:2} +.sweet-alert .icon.success .line.tip {width:25px;left:14px;top:46px;-webkit-transform:rotate(45deg);transform:rotate(45deg)} +.sweet-alert .icon.success .line.long {width:47px;right:8px;top:38px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)} +.sweet-alert .icon.custom {background-size:contain;border-radius:0;border:none;background-position:center center;background-repeat:no-repeat} +.sweet-alert .btn-default:focus {border-color:#656d79;outline:0} +.sweet-alert .btn-success:focus {border-color:#2b9854;outline:0} +.sweet-alert .btn-info:focus {border-color:#46b8da;outline:0} +.sweet-alert .btn-danger:focus {border-color:#952518;outline:0} +.sweet-alert .btn-warning:focus {border-color:#eea236;outline:0} +.sweet-alert button::-moz-focus-inner {border:0} +.sweet-overlay {background-color:rgba(0,0,0,0.2);z-index:10499} +.sweet-alert {text-align:right;border-radius:3px;-webkit-box-shadow:0 27px 24px 0 rgba(0,0,0,0.2),0 40px 77px 0 rgba(0,0,0,0.22);box-shadow:0 27px 24px 0 rgba(0,0,0,0.2),0 40px 77px 0 rgba(0,0,0,0.22);z-index:10500} +.sweet-alert h2 {word-break:break-word;word-wrap:break-word;max-height:350px;overflow-y:auto;margin:10px 0 17px 0;color:#2b3e50;text-align:left;font-size:15px;line-height:23px} +.sweet-alert p {margin:0} +.sweet-alert p.text-muted {margin-bottom:20px;color:#555} +.control-simplelist {font-size:13px;padding:20px 20px 2px 20px;margin-bottom:20px;background:#fff;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +.control-simplelist ul {padding-left:15px} +.control-simplelist.form-control ul {margin-bottom:0} +.control-simplelist.form-control li {padding-top:5px;padding-bottom:5px} +.control-simplelist.with-icons ul, +.control-simplelist.with-checkboxes ul, +.control-simplelist.is-divided ul, +.control-simplelist.is-selectable ul {list-style-type:none;padding-left:0} +.control-simplelist.with-checkboxes li {margin-top:-5px} +.control-simplelist.with-checkboxes li:first-child {margin-top:0} +.control-simplelist.with-checkboxes li:last-child div.custom-checkbox {margin-bottom:0} +.control-simplelist.with-checkboxes li:last-child div.custom-checkbox label {margin-bottom:5px} +.control-simplelist.is-sortable li.placeholder {position:relative} +.control-simplelist.is-sortable li.placeholder:before {top:-10px;position:absolute;content:'';display:block;width:0;height:0;border-top:4.5px solid transparent;border-bottom:4.5px solid transparent;border-left:5px solid #999} +.control-simplelist.is-sortable li.dragged {position:absolute;opacity:0.5;filter:alpha(opacity=50);z-index:2000;color:#e67e22;width:auto !important} +.control-simplelist.is-scrollable {height:200px} +.control-simplelist.is-scrollable.size-tiny {min-height:250px} +.control-simplelist.is-scrollable.size-small {min-height:300px} +.control-simplelist.is-scrollable.size-large {min-height:400px} +.control-simplelist.is-scrollable.size-huge {min-height:450px} +.control-simplelist.is-scrollable.size-giant {min-height:550px} +.control-simplelist.is-divided, +.control-simplelist.is-selectable, +.control-simplelist.is-selectable-box {padding:0} +.control-simplelist.is-divided li .heading, +.control-simplelist.is-selectable li .heading, +.control-simplelist.is-selectable-box li .heading {font-size:14px;font-weight:500} +.control-simplelist.is-divided li, +.control-simplelist.is-selectable li {padding:5px 10px;border-bottom:1px solid #d4d8da} +.control-simplelist.is-divided li:last-child, +.control-simplelist.is-selectable li:last-child {border-bottom:none} +.control-simplelist.is-selectable li a {padding:5px 10px;margin:-5px -10px;display:block;color:#333} +.control-simplelist.is-selectable li:hover {background:#4ea5e0;cursor:pointer} +.control-simplelist.is-selectable li:hover, +.control-simplelist.is-selectable li:hover a {color:white} +.control-simplelist.is-selectable li:hover a {text-decoration:none} +.control-simplelist.is-selectable li.active a {background:#f0f0f0} +.control-simplelist.is-selectable li.active a:hover {background:#4ea5e0} +.control-simplelist.is-selectable-box {padding-top:15px;margin-bottom:0} +.control-simplelist.is-selectable-box li {width:155px;margin:8px;display:inline-block;text-align:center;vertical-align:top} +.control-simplelist.is-selectable-box li a {text-decoration:none;display:block;color:#333} +.control-simplelist.is-selectable-box li a .box {display:block;width:155px;height:155px;border:3px solid rgba(0,0,0,0.1);position:relative;-webkit-transition:border 0.3s ease;transition:border 0.3s ease} +.control-simplelist.is-selectable-box li a .image {display:block;width:56px;height:56px;position:absolute;top:50%;left:50%;margin-top:-28px;margin-left:-28px} +.control-simplelist.is-selectable-box li a .image >i {font-size:56px;color:rgba(0,0,0,0.25)} +.control-simplelist.is-selectable-box li a .heading {margin:7px 0;padding:0} +.control-simplelist.is-selectable-box li a .description {font-size:12px} +.control-simplelist.is-selectable-box li a:hover .box {border-color:rgba(0,0,0,0.2)} +.control-simplelist.is-selectable-box li a:hover .image >i {color:rgba(0,0,0,0.45)} +.list-preview .control-simplelist.is-selectable ul {margin-bottom:0} +.drag-noselect {-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} +.control-scrollbar {position:relative;overflow:hidden;height:100%} +.control-scrollbar >.scrollbar-scrollbar {position:absolute;z-index:100} +.control-scrollbar >.scrollbar-scrollbar .scrollbar-track {background-color:transparent;position:relative;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px} +.control-scrollbar >.scrollbar-scrollbar .scrollbar-track .scrollbar-thumb {background-color:rgba(0,0,0,0.35);-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;cursor:pointer;overflow:hidden;position:absolute} +.control-scrollbar >.scrollbar-scrollbar.disabled {display:none !important} +.control-scrollbar.vertical >.scrollbar-scrollbar {right:0;margin-right:5px;width:6px} +.control-scrollbar.vertical >.scrollbar-scrollbar .scrollbar-track {height:100%;width:6px} +.control-scrollbar.vertical >.scrollbar-scrollbar .scrollbar-track .scrollbar-thumb {height:20px;width:6px;top:0;left:0} +.control-scrollbar.vertical >.scrollbar-scrollbar:active, +.control-scrollbar.vertical >.scrollbar-scrollbar:hover {width:8px;-webkit-transition:width 0.3s;transition:width 0.3s} +.control-scrollbar.vertical >.scrollbar-scrollbar:active .scrollbar-track, +.control-scrollbar.vertical >.scrollbar-scrollbar:hover .scrollbar-track, +.control-scrollbar.vertical >.scrollbar-scrollbar:active .scrollbar-thumb, +.control-scrollbar.vertical >.scrollbar-scrollbar:hover .scrollbar-thumb {width:8px;-webkit-transition:width 0.3s;transition:width 0.3s} +.control-scrollbar.horizontal >.scrollbar-scrollbar {margin:0 0 5px;clear:both;height:6px} +.control-scrollbar.horizontal >.scrollbar-scrollbar .scrollbar-track {width:100%;height:6px} +.control-scrollbar.horizontal >.scrollbar-scrollbar .scrollbar-track .scrollbar-thumb {height:6px;margin:2px 0;left:0;top:0} +.control-scrollbar.horizontal >.scrollbar-scrollbar:active, +.control-scrollbar.horizontal >.scrollbar-scrollbar:hover {height:8px;-webkit-transition:height 0.3s;transition:height 0.3s} +.control-scrollbar.horizontal >.scrollbar-scrollbar:active .scrollbar-track, +.control-scrollbar.horizontal >.scrollbar-scrollbar:hover .scrollbar-track, +.control-scrollbar.horizontal >.scrollbar-scrollbar:active .scrollbar-thumb, +.control-scrollbar.horizontal >.scrollbar-scrollbar:hover .scrollbar-thumb {height:8px;-webkit-transition:height 0.3s;transition:height 0.3s} +html.mobile .control-scrollbar {overflow:auto;-webkit-overflow-scrolling:touch} +.no-touch .control-scrollbar >.scrollbar-scrollbar {opacity:0;-webkit-transition:opacity 0.3s;transition:opacity 0.3s} +.no-touch .control-scrollbar:active >.scrollbar-scrollbar, +.no-touch .control-scrollbar:hover >.scrollbar-scrollbar {opacity:1} +@media (max-width:768px) {.responsive-sidebar >.layout-cell:last-child .control-scrollbar {overflow:visible;height:auto }.responsive-sidebar >.layout-cell:last-child .control-scrollbar .scrollbar-scrollbar {display:none !important }} +.control-filelist p.no-data {padding:22px 0;margin:0;color:#666;font-size:14px;text-align:center;font-weight:normal;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +.control-filelist ul {padding:0;margin:0} +.control-filelist ul li {font-weight:normal;line-height:150%;position:relative;list-style:none} +.control-filelist ul li a:hover {background:#ddd} +.control-filelist ul li.active >a {background:#ddd;position:relative} +.control-filelist ul li.active >a:after {position:absolute;height:100%;width:4px;left:0;top:0;background:#e67e22;display:block;content:' '} +.control-filelist ul li a {display:block;padding:10px 45px 10px 20px;outline:none} +.control-filelist ul li a:hover, +.control-filelist ul li a:focus, +.control-filelist ul li a:active {text-decoration:none} +.control-filelist ul li a span {display:block} +.control-filelist ul li a span.title {font-weight:normal;color:#405261;font-size:14px} +.control-filelist ul li a span.description {color:#8f8f8f;font-size:12px;white-space:nowrap;font-weight:normal;overflow:hidden;text-overflow:ellipsis} +.control-filelist ul li a span.description strong {color:#405261;font-weight:normal} +.control-filelist ul li.group >h4, +.control-filelist ul li.group >div.group >h4 {font-weight:normal;font-size:14px;margin-top:0;margin-bottom:0;position:relative} +.control-filelist ul li.group >h4 a, +.control-filelist ul li.group >div.group >h4 a {padding:10px 20px 10px 53px;color:#405261;position:relative;outline:none} +.control-filelist ul li.group >h4 a:hover, +.control-filelist ul li.group >div.group >h4 a:hover {background:transparent} +.control-filelist ul li.group >h4 a:before, +.control-filelist ul li.group >div.group >h4 a:before, +.control-filelist ul li.group >h4 a:after, +.control-filelist ul li.group >div.group >h4 a:after {width:10px;height:10px;display:block;position:absolute;top:1px} +.control-filelist ul li.group >h4 a:after, +.control-filelist ul li.group >div.group >h4 a:after {left:33px;top:9px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f07b";color:#a1aab1;font-size:16px} +.control-filelist ul li.group >h4 a:before, +.control-filelist ul li.group >div.group >h4 a:before {left:20px;top:9px;color:#cfcfcf;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f0da";-webkit-transform:rotate(90deg) translate(5px,0);-ms-transform:rotate(90deg) translate(5px,0);transform:rotate(90deg) translate(5px,0);-webkit-transition:all 0.1s ease;transition:all 0.1s ease} +.control-filelist ul li.group >ul >li >a {padding-left:52px} +.control-filelist ul li.group >ul >li.group {padding-left:20px} +.control-filelist ul li.group >ul >li.group >ul >li >a {padding-left:324px;margin-left:-270px} +.control-filelist ul li.group >ul >li.group >ul >li.group >ul >li >a {padding-left:297px;margin-left:-243px} +.control-filelist ul li.group >ul >li.group >ul >li.group >ul >li.group >ul >li >a {padding-left:270px;margin-left:-216px} +.control-filelist ul li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li >a {padding-left:243px;margin-left:-189px} +.control-filelist ul li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li >a {padding-left:216px;margin-left:-162px} +.control-filelist ul li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li >a {padding-left:189px;margin-left:-135px} +.control-filelist ul li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li >a {padding-left:162px;margin-left:-108px} +.control-filelist ul li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li >a {padding-left:135px;margin-left:-81px} +.control-filelist ul li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li >a {padding-left:108px;margin-left:-54px} +.control-filelist ul li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li.group >ul >li >a {padding-left:81px;margin-left:-27px} +.control-filelist ul li.group[data-status=collapsed] >h4 a:before, +.control-filelist ul li.group[data-status=collapsed] >div.group >h4 a:before {-webkit-transform:rotate(0deg) translate(3px,0);-ms-transform:rotate(0deg) translate(3px,0);transform:rotate(0deg) translate(3px,0)} +.control-filelist ul li.group[data-status=collapsed] >ul, +.control-filelist ul li.group[data-status=collapsed] >div.subitems {display:none} +.control-filelist ul li >div.controls {position:absolute;right:19px;top:6px} +.control-filelist ul li >div.controls .dropdown {width:14px;height:21px} +.control-filelist ul li >div.controls .dropdown.open a.control {display:block !important} +.control-filelist ul li >div.controls .dropdown.open a.control:before {visibility:visible;display:block} +.control-filelist ul li >div.controls a.control {color:#405261;font-size:14px;visibility:hidden;overflow:hidden;width:14px;height:21px;display:none;text-decoration:none;cursor:pointer;padding:0;opacity:0.5;filter:alpha(opacity=50)} +.control-filelist ul li >div.controls a.control:before {visibility:visible;display:block;margin-right:0} +.control-filelist ul li >div.controls a.control:hover {opacity:1;filter:alpha(opacity=100)} +.control-filelist ul li:hover >div.controls, +.control-filelist ul li:hover >a.control {display:block !important} +.control-filelist ul li:hover >div.controls >a.control, +.control-filelist ul li:hover >a.control >a.control {display:block !important} +.control-filelist ul li .checkbox {position:absolute;top:-5px;right:0} +.control-filelist ul li .checkbox label {margin-right:0} +.control-filelist ul li .checkbox label:before {border-color:#ccc} +.control-filelist.single-line ul li a span.title {text-overflow:ellipsis;overflow:hidden;white-space:nowrap} +.control-filelist.filelist-hero ul li {background:#fff;border-bottom:none} +.control-filelist.filelist-hero ul li >a {padding:11px 45px 10px 50px;font-size:13px;border-bottom:1px solid #ecf0f1} +.control-filelist.filelist-hero ul li >a span.title {font-size:14px;font-weight:normal;color:#2b3e50} +.control-filelist.filelist-hero ul li >a span.description {font-size:13px} +.control-filelist.filelist-hero ul li >a .list-icon {position:absolute;left:14px;top:15px;font-size:22px;color:#b7c0c2} +.control-filelist.filelist-hero ul li >a:hover {background:#4ea5e0;border-bottom:1px solid #4ea5e0 !important} +.control-filelist.filelist-hero ul li >a:hover span.title, +.control-filelist.filelist-hero ul li >a:hover span.description {color:#fff !important} +.control-filelist.filelist-hero ul li >a:hover .list-icon {color:#fff !important} +.control-filelist.filelist-hero ul li >a:active {background:#3498db;border-bottom:1px solid #3498db !important} +.control-filelist.filelist-hero ul li >a:active span.title, +.control-filelist.filelist-hero ul li >a:active span.description {color:#fff !important} +.control-filelist.filelist-hero ul li >a:active .list-icon {color:#fff !important} +.control-filelist.filelist-hero ul li .checkbox {top:-2px;right:0} +.control-filelist.filelist-hero ul li.active >a {border-bottom:1px solid #ddd} +.control-filelist.filelist-hero ul li.active >a:after {top:-1px;bottom:-1px;height:auto} +.control-filelist.filelist-hero ul li.active >a >span.borders:before {content:' ';position:absolute;width:100%;height:1px;display:block;left:0;background-color:#ddd} +.control-filelist.filelist-hero ul li.active >a >span.borders:before {top:-1px} +.control-filelist.filelist-hero ul li.active >a:hover >span.borders:before {background-color:#4ea5e0} +.control-filelist.filelist-hero ul li.active >a:active >span.borders:before {background-color:#3498db} +.control-filelist.filelist-hero ul li >h4 {padding-top:7px;padding-bottom:6px;border-bottom:1px solid #ecf0f1} +.control-filelist.filelist-hero ul li >div.controls {display:none;position:absolute;right:16px;top:15px} +.control-filelist.filelist-hero ul li >div.controls >a.control {width:16px;height:23px;background:transparent;overflow:hidden;display:inline-block;color:#fff !important;padding:0} +.control-filelist.filelist-hero ul li >div.controls >a.control:before {font-size:17px} +.control-filelist.filelist-hero ul li:hover >div.controls {display:block} +.control-filelist.filelist-hero ul li.separator {position:relative;border-bottom:1px solid #95a5a6;padding:12px 15px 13px 15px} +.control-filelist.filelist-hero ul li.separator:before {z-index:31;content:'';display:block;width:0;height:0;border-left:9.5px solid transparent;border-right:9.5px solid transparent;border-top:11px solid #fff;border-bottom-width:0;position:absolute;left:13px;bottom:-8px} +.control-filelist.filelist-hero ul li.separator:after {z-index:30;content:'';display:block;width:0;height:0;border-left:8.5px solid transparent;border-right:8.5px solid transparent;border-top:9px solid #95a5a6;border-bottom-width:0;position:absolute;left:14px;bottom:-9px} +.control-filelist.filelist-hero ul li.separator h5 {color:#2b3e50;font-size:14px;margin:0;font-weight:normal;padding:0} +.control-filelist.filelist-hero ul >li.group >ul >li >a {padding-left:66px} +.control-filelist.filelist-hero.single-level ul li:hover {background:#4ea5e0} +.control-filelist.filelist-hero.single-level ul li:hover >a {background:#4ea5e0;border-bottom:1px solid #4ea5e0 !important} +.control-filelist.filelist-hero.single-level ul li:hover >a span.title, +.control-filelist.filelist-hero.single-level ul li:hover >a span.description {color:#fff !important} +.control-filelist.filelist-hero.single-level ul li:hover >a .list-icon {color:#fff !important} +.control-filelist.filelist-hero.single-level ul li:active {background:#3498db} +.control-filelist.filelist-hero.single-level ul li:active >a {background:#3498db;border-bottom:1px solid #3498db !important} +.control-filelist.filelist-hero.single-level ul li:active >a span.title, +.control-filelist.filelist-hero.single-level ul li:active >a span.description {color:#fff !important} +.control-filelist.filelist-hero.single-level ul li:active >a .list-icon {color:#fff !important} +.control-scrollpanel {position:relative;background:#ecf0f1} +.control-scrollpanel .control-scrollbar.vertical >.scrollbar-scrollbar {right:0} +.tooltip .tooltip-inner {text-align:left;padding:5px 8px} +.tooltip.in {opacity:1;filter:alpha(opacity=100)} +.oc-logo-white {background-image:url(../images/october-logo-white.svg);background-position:50% 50%;background-repeat:no-repeat;background-size:contain} +.oc-logo {background-image:url(../images/october-logo.svg);background-position:50% 50%;background-repeat:no-repeat;background-size:contain} +.layout.control-tabs.oc-logo-transparent:not(.has-tabs), +.flex-layout-column.oc-logo-transparent:not(.has-tabs), +.layout-cell.oc-logo-transparent {background-size:50% auto;background-repeat:no-repeat;background-image:url(../images/october-logo.svg);background-position:50% 50%;position:relative} +.layout.control-tabs.oc-logo-transparent:not(.has-tabs):after, +.flex-layout-column.oc-logo-transparent:not(.has-tabs):after, +.layout-cell.oc-logo-transparent:after {content:'';display:table-cell;position:absolute;left:0;top:0;height:100%;width:100%;background:rgba(249,249,249,0.7)} +.report-widget {padding:15px;background:white;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;font-size:13px} +.report-widget h3 {font-size:14px;color:#7e8c8d;text-transform:uppercase;font-weight:600;margin-top:0;margin-bottom:30px} +.report-widget .height-100 {height:100px} +.report-widget .height-200 {height:200px} +.report-widget .height-300 {height:300px} +.report-widget .height-400 {height:400px} +.report-widget .height-500 {height:500px} +.report-widget p.report-description {margin-bottom:0;margin-top:15px;font-size:12px;line-height:190%;color:#7e8c8d} +.report-widget a:not(.btn) {color:#7e8c8d;text-decoration:none} +.report-widget a:not(.btn):hover {color:#0181b9;text-decoration:none} +.report-widget p.flash-message.static {margin-bottom:0} +.report-widget .icon-circle.success {color:#31ac5f} +.report-widget .icon-circle.primary {color:#34495e} +.report-widget .icon-circle.warning {color:#f0ad4e} +.report-widget .icon-circle.danger {color:#ab2a1c} +.report-widget .icon-circle.info {color:#5bc0de} +.control-treelist ol {padding:0;margin:0;list-style:none} +.control-treelist ol ol {margin:0;margin-left:15px;padding-left:15px;border-left:1px solid #dbdee0} +.control-treelist >ol >li >div.record:before {display:none} +.control-treelist li {margin:0;padding:0} +.control-treelist li >div.record {margin:0;font-size:12px;margin-bottom:5px;position:relative;display:block} +.control-treelist li >div.record:before {color:#bdc3c7;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f111";font-size:6px;position:absolute;left:-18px;top:11px} +.control-treelist li >div.record >a.move {display:inline-block;padding:7px 0 7px 10px;text-decoration:none;color:#bdc3c7} +.control-treelist li >div.record >a.move:hover {color:#4ea5e0} +.control-treelist li >div.record >a.move:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f0c9"} +.control-treelist li >div.record >span {color:#666;display:inline-block;padding:7px 15px 7px 5px} +.control-treelist li.dragged {position:absolute;z-index:2000;width:auto !important;height:auto !important} +.control-treelist li.dragged >div.record {opacity:0.5;filter:alpha(opacity=50);background:#4ea5e0 !important} +.control-treelist li.dragged >div.record >a.move:before, +.control-treelist li.dragged >div.record >span {color:white} +.control-treelist li.dragged >div.record:before {display:none} +.control-treelist li.placeholder {display:inline-block;position:relative;background:#4ea5e0 !important;height:25px;margin-bottom:5px} +.control-treelist li.placeholder:before {display:block;position:absolute;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f053";color:#d35714;left:-10px;top:8px;z-index:2000} +.control-treeview {margin-bottom:40px} +.control-treeview ol {margin:0;padding:0;list-style:none;background:#fff} +.control-treeview ol >li {-webkit-transition:width 1s;transition:width 1s} +.control-treeview ol >li >div {font-size:14px;font-weight:normal;background:#fff;border-bottom:1px solid #ecf0f1;position:relative} +.control-treeview ol >li >div >a {color:#2b3e50;padding:11px 45px 10px 61px;display:block;line-height:150%;text-decoration:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} +.control-treeview ol >li >div:before {content:' ';background-image:url(../images/treeview-icons.png);background-position:0 -28px;background-repeat:no-repeat;background-size:42px auto;position:absolute;width:21px;height:22px;left:28px;top:15px} +.control-treeview ol >li >div span.comment {display:block;font-weight:400;color:#95a5a6;font-size:13px;margin-top:2px;overflow:hidden;text-overflow:ellipsis} +.control-treeview ol >li >div >span.expand {font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;display:none;position:absolute;width:20px;height:20px;top:19px;left:2px;cursor:pointer;color:#bdc3c7;-webkit-transition:transform 0.1s ease;transition:transform 0.1s ease} +.control-treeview ol >li >div >span.expand:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f0da";line-height:100%;font-size:15px;position:relative;left:8px;top:2px} +.control-treeview ol >li >div >span.drag-handle {font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;-webkit-transition:opacity 0.4s;transition:opacity 0.4s;position:absolute;right:9px;bottom:0;width:18px;height:19px;cursor:move;color:#bdc3c7;opacity:0;filter:alpha(opacity=0)} +.control-treeview ol >li >div >span.drag-handle:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f0c9";font-size:18px} +.control-treeview ol >li >div span.borders {font-size:0} +.control-treeview ol >li >div >ul.submenu {position:absolute;left:20px;bottom:-36.9px;padding:0;list-style:none;z-index:200;height:37px;display:none;margin-left:15px;background:transparent url(../images/treeview-submenu-tabs.png) repeat-x left -39px} +.control-treeview ol >li >div >ul.submenu:before, +.control-treeview ol >li >div >ul.submenu:after {background:transparent url(../images/treeview-submenu-tabs.png) no-repeat left top;content:' ';display:block;width:20px;height:37px;position:absolute;top:0} +.control-treeview ol >li >div >ul.submenu:before {left:-20px} +.control-treeview ol >li >div >ul.submenu:after {background-position:-100px top;right:-20px} +.control-treeview ol >li >div >ul.submenu li {font-size:12px} +.control-treeview ol >li >div >ul.submenu li a {display:block;padding:4px 3px 0 3px;color:#fff;text-decoration:none;outline:none} +.control-treeview ol >li >div >ul.submenu li a i {margin-right:5px} +.control-treeview ol >li >div:hover >ul.submenu {display:block} +.control-treeview ol >li >div:active >ul.submenu {background-position:left -116px} +.control-treeview ol >li >div:active >ul.submenu:before {background-position:left -77px} +.control-treeview ol >li >div:active >ul.submenu:after {background-position:-100px -77px} +.control-treeview ol >li >div .checkbox {position:absolute;top:-2px;right:0} +.control-treeview ol >li >div .checkbox label {margin-right:0} +.control-treeview ol >li >div .checkbox label:before {border-color:#ccc} +.control-treeview ol >li >div.popover-highlight {background-color:#4ea5e0 !important} +.control-treeview ol >li >div.popover-highlight:before {background-position:0 -80px} +.control-treeview ol >li >div.popover-highlight >a {color:#fff !important;cursor:default} +.control-treeview ol >li >div.popover-highlight span {color:#fff !important} +.control-treeview ol >li >div.popover-highlight >ul.submenu, +.control-treeview ol >li >div.popover-highlight >span.drag-handle {display:none !important} +.control-treeview ol >li.dragged div, +.control-treeview ol >li >div:hover {background-color:#4ea5e0 !important} +.control-treeview ol >li.dragged div >a, +.control-treeview ol >li >div:hover >a {color:#fff !important} +.control-treeview ol >li.dragged div:before, +.control-treeview ol >li >div:hover:before {background-position:0 -80px} +.control-treeview ol >li.dragged div:after, +.control-treeview ol >li >div:hover:after {top:0 !important;bottom:0 !important} +.control-treeview ol >li.dragged div span, +.control-treeview ol >li >div:hover span {color:#fff !important} +.control-treeview ol >li.dragged div span.drag-handle, +.control-treeview ol >li >div:hover span.drag-handle {cursor:move;opacity:1;filter:alpha(opacity=100)} +.control-treeview ol >li.dragged div span.borders, +.control-treeview ol >li >div:hover span.borders {display:none} +.control-treeview ol >li >div:active {background-color:#3498db !important} +.control-treeview ol >li >div:active >a {color:#fff !important} +.control-treeview ol >li[data-no-drag-mode] div:hover span.drag-handle {cursor:default !important;opacity:0.3 !important;filter:alpha(opacity=30) !important} +.control-treeview ol >li.dragged li.has-subitems >div:before, +.control-treeview ol >li.dragged.has-subitems >div:before {background-position:0 -52px} +.control-treeview ol >li.dragged div >ul.submenu {display:none !important} +.control-treeview ol >li >ol {padding-left:20px;padding-right:20px} +.control-treeview ol >li[data-status=collapsed] >ol {display:none} +.control-treeview ol >li.has-subitems >div:before {background-position:0 0;width:23px;height:26px;left:26px} +.control-treeview ol >li.has-subitems >div:hover:before, +.control-treeview ol >li.has-subitems >div.popover-highlight:before {background-position:0 -52px} +.control-treeview ol >li.has-subitems >div span.expand {display:block} +.control-treeview ol >li.placeholder {position:relative;opacity:0.5;filter:alpha(opacity=50)} +.control-treeview ol >li.dragged {position:absolute;z-index:2000;opacity:0.25;filter:alpha(opacity=25)} +.control-treeview ol >li.dragged >div {-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +.control-treeview ol >li.drop-target >div {background-color:#2581b8 !important} +.control-treeview ol >li.drop-target >div >a {color:#fff} +.control-treeview ol >li.drop-target >div >a >span.comment {color:#fff} +.control-treeview ol >li.drop-target >div:before {background-position:0 -80px} +.control-treeview ol >li.drop-target.has-subitems >div:before {background-position:0 -52px} +.control-treeview ol >li[data-status=expanded] >div >span.expand {-webkit-transform:rotate(90deg) translate(0,0);-ms-transform:rotate(90deg) translate(0,0);transform:rotate(90deg) translate(0,0)} +.control-treeview ol >li.drag-ghost {background-color:transparent;box-sizing:content-box} +.control-treeview ol >li.active >div {background:#ddd} +.control-treeview ol >li.active >div:after {position:absolute;width:4px;left:0;top:-1px;bottom:-1px;background:#e67e22;display:block;content:' '} +.control-treeview ol >li.active >div >span.comment, +.control-treeview ol >li.active >div >span.expand {color:#8f8f8f} +.control-treeview ol >li.active >div >span.borders:before, +.control-treeview ol >li.active >div >span.borders:after {content:' ';position:absolute;width:100%;height:1px;display:block;left:0;background-color:#ddd} +.control-treeview ol >li.active >div >span.borders:before {top:-1px} +.control-treeview ol >li.active >div >span.borders:after {bottom:-1px} +.control-treeview ol >li.no-data {padding:18px 0;margin:0;color:#666;font-size:14px;text-align:center;font-weight:400} +.control-treeview ol >li >ol >li >div {margin-left:-20px;margin-right:-20px;padding-left:71px} +.control-treeview ol >li >ol >li >div >a {margin-left:-71px;padding-left:71px} +.control-treeview ol >li >ol >li >div:before {margin-left:10px} +.control-treeview ol >li >ol >li >div >span.expand {left:12px} +.control-treeview ol >li >ol >li >ol >li >div {margin-left:-40px;margin-right:-40px;padding-left:81px} +.control-treeview ol >li >ol >li >ol >li >div >a {margin-left:-81px;padding-left:81px} +.control-treeview ol >li >ol >li >ol >li >div:before {margin-left:20px} +.control-treeview ol >li >ol >li >ol >li >div >span.expand {left:22px} +.control-treeview ol >li >ol >li >ol >li >ol >li >div {margin-left:-60px;margin-right:-60px;padding-left:91px} +.control-treeview ol >li >ol >li >ol >li >ol >li >div >a {margin-left:-91px;padding-left:91px} +.control-treeview ol >li >ol >li >ol >li >ol >li >div:before {margin-left:30px} +.control-treeview ol >li >ol >li >ol >li >ol >li >div >span.expand {left:32px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >div {margin-left:-80px;margin-right:-80px;padding-left:101px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >div >a {margin-left:-101px;padding-left:101px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >div:before {margin-left:40px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >div >span.expand {left:42px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div {margin-left:-100px;margin-right:-100px;padding-left:111px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div >a {margin-left:-111px;padding-left:111px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div:before {margin-left:50px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div >span.expand {left:52px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div {margin-left:-120px;margin-right:-120px;padding-left:121px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div >a {margin-left:-121px;padding-left:121px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div:before {margin-left:60px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div >span.expand {left:62px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div {margin-left:-140px;margin-right:-140px;padding-left:131px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div >a {margin-left:-131px;padding-left:131px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div:before {margin-left:70px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div >span.expand {left:72px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div {margin-left:-160px;margin-right:-160px;padding-left:141px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div >a {margin-left:-141px;padding-left:141px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div:before {margin-left:80px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div >span.expand {left:82px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div {margin-left:-180px;margin-right:-180px;padding-left:151px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div >a {margin-left:-151px;padding-left:151px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div:before {margin-left:90px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div >span.expand {left:92px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div {margin-left:-200px;margin-right:-200px;padding-left:161px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div >a {margin-left:-161px;padding-left:161px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div:before {margin-left:100px} +.control-treeview ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >ol >li >div >span.expand {left:102px} +.control-treeview p.no-data {padding:18px 0;margin:0;color:#666;font-size:14px;text-align:center;font-weight:400} +.control-treeview a.menu-control {display:block;margin:20px;padding:13px 15px;border:dotted 2px #ebebeb;color:#bdc3c7;font-size:12px;font-weight:600;text-transform:uppercase;border-radius:5px;vertical-align:middle} +.control-treeview a.menu-control:hover, +.control-treeview a.menu-control:focus {text-decoration:none;background-color:#4ea5e0;color:#fff;border:none;padding:15px 17px} +.control-treeview a.menu-control:active {background:#3498db;color:#fff} +.control-treeview a.menu-control i {margin-right:10px;font-size:14px} +.control-treeview.treeview-light {margin-bottom:0;margin-top:20px} +.control-treeview.treeview-light ol {background-color:transparent} +.control-treeview.treeview-light ol >li >div {background-color:transparent;border-bottom:none} +.control-treeview.treeview-light ol >li >div:before {top:15px} +.control-treeview.treeview-light ol >li >div >a {padding-top:10px;padding-bottom:10px} +.control-treeview.treeview-light ol >li >div span.expand {top:19px} +.control-treeview.treeview-light ol >li >div >span.drag-handle {top:0;right:0;bottom:auto;height:100%;width:60px;background:#2581b8;-webkit-transition:none !important;transition:none !important} +.control-treeview.treeview-light ol >li >div >span.drag-handle:before {position:absolute;left:50%;top:50%;margin-left:-6px} +.control-treeview.treeview-light ol >li >div >ul.submenu {right:60px;left:auto;bottom:auto;top:0;height:100%;margin:0;background:transparent;white-space:nowrap;font-size:0} +.control-treeview.treeview-light ol >li >div >ul.submenu:before, +.control-treeview.treeview-light ol >li >div >ul.submenu:after {display:none} +.control-treeview.treeview-light ol >li >div >ul.submenu li {height:100%;display:inline-block;background:#2581b8;border-right:1px solid #328ec8} +.control-treeview.treeview-light ol >li >div >ul.submenu li p {display:table;height:100%;padding:0;margin:0} +.control-treeview.treeview-light ol >li >div >ul.submenu li p a {display:table-cell;vertical-align:middle;height:100%;padding:0 20px;font-size:13px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} +.control-treeview.treeview-light ol >li >div >ul.submenu li p a i.control-icon {font-size:22px;margin-right:0} +body.dragging .control-treeview ol.dragging, +body.dragging .control-treeview ol.dragging ol {background:#ccc;padding-right:20px;-webkit-transition:padding 1s;transition:padding 1s} +body.dragging .control-treeview ol.dragging >li >div, +body.dragging .control-treeview ol.dragging ol >li >div {margin-right:0;-webkit-transition:margin 1s;transition:margin 1s} +body.dragging .control-treeview ol.dragging >li >div .custom-checkbox, +body.dragging .control-treeview ol.dragging ol >li >div .custom-checkbox {-webkit-transition:opacity 0.5s;transition:opacity 0.5s;opacity:0;filter:alpha(opacity=0)} +body.dragging .control-treeview.treeview-light ol.dragging >li >div, +body.dragging .control-treeview.treeview-light ol.dragging ol >li >div {background-color:#f9f9f9} +@media only screen and (min--moz-device-pixel-ratio:1.5),only screen and (-o-min-device-pixel-ratio:3/2),only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min-devicepixel-ratio:1.5),only screen and (min-resolution:1.5dppx) {.control-treeview ol >li >div:before {background-position:0 -79px;background-size:21px auto }.control-treeview ol >li.has-subitems >div:before {background-position:0 -52px }.control-treeview ol >li.has-subitems >div:hover:before,.control-treeview ol >li.has-subitems >div.popover-highlight:before {background-position:0 -102px }.control-treeview ol >li.dragged >div:before,.control-treeview ol >li.dragged li >div:before,.control-treeview ol >li >div:hover:before,.control-treeview ol >li >div.popover-highlight:before {background-position:0 -129px }.control-treeview ol >li.dragged li.has-subitems >div:before,.control-treeview ol >li.dragged.has-subitems >div:before {background-position:0 -102px }.control-treeview ol >li.drop-target >div:before {background-position:0 -129px }.control-treeview ol >li.drop-target.has-subitems >div:before {background-position:0 -102px }} +.sidenav-tree {width:300px} +.sidenav-tree .control-toolbar {padding:0} +.sidenav-tree .control-toolbar .toolbar-item {display:block} +.sidenav-tree .control-toolbar input.form-control {border:none;outline:none;padding:12px 13px 13px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:inset -3px 0 3px rgba(0,0,0,0.1);box-shadow:inset -3px 0 3px rgba(0,0,0,0.1)} +.sidenav-tree .control-toolbar input.form-control.search {background-position:right -78px} +.sidenav-tree ul {padding:0;margin:0;list-style:none} +.sidenav-tree div.scrollbar-thumb {background:rgba(0,0,0,0.2) !important} +.sidenav-tree ul.top-level >li[data-status=collapsed] >div.group h3:before {-webkit-transform:rotate(0deg) translate(2px,-2px);-ms-transform:rotate(0deg) translate(2px,-2px);transform:rotate(0deg) translate(2px,-2px)} +.sidenav-tree ul.top-level >li[data-status=collapsed] >div.group:before, +.sidenav-tree ul.top-level >li[data-status=collapsed] >div.group:after {display:none} +.sidenav-tree ul.top-level >li[data-status=collapsed] ul {display:none} +.sidenav-tree ul.top-level >li >div.group {position:relative} +.sidenav-tree ul.top-level >li >div.group h3 {background:rgba(0,0,0,0.15);color:#ecf0f1;text-transform:uppercase;font-size:15px;padding:15px 15px 15px 40px;margin:0;position:relative;cursor:pointer;font-weight:400} +.sidenav-tree ul.top-level >li >div.group h3:before {display:block;position:absolute;width:10px;height:10px;left:16px;top:15px;color:#cfcfcf;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f105";-webkit-transform:rotate(90deg) translate(5px,-3px);-ms-transform:rotate(90deg) translate(5px,-3px);transform:rotate(90deg) translate(5px,-3px);-webkit-transition:all 0.1s ease;transition:all 0.1s ease;font-size:16px} +.sidenav-tree ul.top-level >li >div.group:before, +.sidenav-tree ul.top-level >li >div.group:after {content:'';display:block;width:0;height:0;border-left:7.5px solid transparent;border-right:7.5px solid transparent;border-top:8px solid #34495e;border-bottom-width:0;position:absolute;left:15px;bottom:-8px;z-index:101} +.sidenav-tree ul.top-level >li >div.group:after {content:'';display:block;width:0;height:0;border-left:7.5px solid transparent;border-right:7.5px solid transparent;border-top:8px solid rgba(0,0,0,0.15);border-bottom-width:0} +.sidenav-tree ul.top-level >li >ul li a {display:block;position:relative;padding:18px 25px 18px 55px;background:transparent;border-bottom:1px solid rgba(0,0,0,0.15);color:#fff;text-decoration:none !important;opacity:0.65;filter:alpha(opacity=65)} +.sidenav-tree ul.top-level >li >ul li a:active, +.sidenav-tree ul.top-level >li >ul li a:hover {opacity:1;filter:alpha(opacity=100);text-decoration:none} +.sidenav-tree ul.top-level >li >ul li a i {position:absolute;left:16px;top:18px;font-size:22px} +.sidenav-tree ul.top-level >li >ul li a span {display:block;line-height:150%} +.sidenav-tree ul.top-level >li >ul li a span.header {color:#fff;font-size:15px;margin-bottom:5px} +.sidenav-tree ul.top-level >li >ul li a span.description {color:rgba(255,255,255,0.6);font-size:13px} +.sidenav-tree ul.top-level >li >ul li:hover a, +.sidenav-tree ul.top-level >li >ul li.active a {opacity:1;filter:alpha(opacity=100)} +.sidenav-tree ul.top-level >li >ul li.active {border-left:5px solid #e67e22} +.sidenav-tree ul.top-level >li >ul li.active a {color:rgba(255,255,255,0.91);padding-right:20px} +.sidenav-tree ul.top-level >li >ul li.active a span.header {color:#fff} +.sidenav-tree ul.top-level >li >ul li.active a span.description {color:rgba(255,255,255,0.91)} +.sidenav-tree .back-link {display:none} +@media (min-width:768px) {.sidenav-tree-root .sidenav-tree {width:600px }.sidenav-tree-root .sidenav-tree ul.top-level >li >ul {font-size:0;display:flex;flex-direction:row;flex-wrap:wrap;justify-content:flex-start;align-items:stretch;align-content:stretch }.sidenav-tree-root .sidenav-tree ul.top-level >li >ul >li {display:inline-block;width:300px }.sidenav-tree-root .sidenav-tree ul.top-level >li >ul >li a {height:100% }} +@media (min-width:768px) and (max-width:991px) {.sidenav-tree-root .sidenav-tree {width:100% }.sidenav-tree-root .sidenav-tree ul.top-level >li >ul >li {width:50% }} +@media (min-width:1200px) {.sidenav-tree-root .sidenav-tree {width:900px }} +@media (max-width:768px) {.sidenav-tree {width:100%;height:auto !important;display:block !important }.sidenav-tree >.layout {display:none }.sidenav-tree-root .sidenav-tree {width:100% !important;height:100% !important;display:table-cell !important }.sidenav-tree-root .sidenav-tree .back-link {display:none !important }.sidenav-tree-root .sidenav-tree >.layout {display:table !important }.sidenav-tree-root #layout-body {display:none }body.has-sidenav-tree .sidenav-tree .back-link {display:block;padding:13px 15px;background:#2b3e50;color:#bdc3c7;font-size:14px;line-height:14px;text-transform:uppercase }body.has-sidenav-tree .sidenav-tree .back-link i {display:inline-block;margin-right:10px }body.has-sidenav-tree .sidenav-tree .back-link:hover {text-decoration:none }body.has-sidenav-tree #layout-body {display:block !important }} +div.panel {padding:20px} +div.panel.no-padding {padding:0} +div.panel.no-padding-bottom {padding-bottom:0} +div.panel.padding-top {padding-top:20px} +div.panel.padding-less {padding:15px} +div.panel.transparent {background:transparent} +div.panel.border-left {border-left:1px solid #e8eaeb} +div.panel.border-right {border-right:1px solid #e8eaeb} +div.panel.border-bottom {border-bottom:1px solid #e8eaeb} +div.panel.border-top {border-top:1px solid #e8eaeb} +div.panel.triangle-down {position:relative} +div.panel.triangle-down:after {content:'';display:block;width:0;height:0;border-left:7.5px solid transparent;border-right:7.5px solid transparent;border-top:8px solid #fff;border-bottom-width:0;position:absolute;left:15px;bottom:-8px;z-index:101} +div.panel.triangle-down:before {content:'';display:block;width:0;height:0;border-left:8.5px solid transparent;border-right:8.5px solid transparent;border-top:9px solid #e8eaeb;border-bottom-width:0;position:absolute;left:14px;bottom:-9px;z-index:100} +div.panel h3.section, +div.panel >label {text-transform:uppercase;color:#95a5a6;font-size:13px;font-weight:600;margin:0 0 15px 0} +div.panel >label {margin-bottom:5px} +.nav.selector-group {font-size:13px;letter-spacing:0.01em;margin-bottom:20px} +.nav.selector-group li a {padding:7px 20px 7px 23px;color:#95a5a6} +.nav.selector-group li.active {border-left:3px solid #e6802b;padding-left:0} +.nav.selector-group li.active a {padding-left:20px;color:#2b3e50} +.nav.selector-group li i[class^="icon-"] {font-size:17px;margin-right:6px;position:relative;top:1px} +div.panel .nav.selector-group {margin:0 -20px 20px -20px} +ul.tree-path {list-style:none;padding:0;margin-bottom:0} +ul.tree-path li {display:inline-block;margin-right:1px;font-size:13px} +ul.tree-path li:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f105";display:inline-block;font-size:13px;margin-left:5px;position:relative;top:1px;color:#95a5a6} +ul.tree-path li:last-child a {cursor:default} +ul.tree-path li:last-child:after {display:none} +ul.tree-path li.go-up {font-size:12px;margin-right:7px} +ul.tree-path li.go-up a {color:#95a5a6} +ul.tree-path li.go-up a:hover {color:#0181b9} +ul.tree-path li.go-up:after {display:none} +ul.tree-path li.root a {font-weight:600;color:#405261} +ul.tree-path li a {color:#95a5a6} +ul.tree-path li a:hover {text-decoration:none} +table.name-value-list {border-collapse:collapse;font-size:13px} +table.name-value-list th, +table.name-value-list td {padding:4px 0 4px 0;vertical-align:top} +table.name-value-list tr:first-child th, +table.name-value-list tr:first-child td {padding-top:0} +table.name-value-list th {font-weight:600;color:#95a5a6;padding-right:15px;text-transform:uppercase} +table.name-value-list td {color:#2b3e50;word-wrap:break-word} +.scrollpad-scrollbar-size-tester {width:50px;height:50px;overflow-y:scroll;position:absolute;top:-200px;left:-200px} +.scrollpad-scrollbar-size-tester div {height:100px} +.scrollpad-scrollbar-size-tester::-webkit-scrollbar {width:0;height:0} +div.control-scrollpad {position:relative;width:100%;height:100%;overflow:hidden} +div.control-scrollpad >div {overflow:hidden;overflow-y:scroll;height:100%} +div.control-scrollpad >div::-webkit-scrollbar {width:0;height:0} +div.control-scrollpad[data-direction=horizontal] >div {overflow-x:scroll;overflow-y:hidden;width:100%} +div.control-scrollpad[data-direction=horizontal] >div::-webkit-scrollbar {width:auto;height:0} +div.control-scrollpad >.scrollpad-scrollbar {z-index:199;position:absolute;top:0;right:0;bottom:0;width:11px;background-color:transparent;opacity:0;overflow:hidden;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-transition:opacity 0.3s;transition:opacity 0.3s} +div.control-scrollpad >.scrollpad-scrollbar .drag-handle {position:absolute;right:2px;min-height:10px;width:7px;background-color:rgba(0,0,0,0.35);-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px} +div.control-scrollpad >.scrollpad-scrollbar:hover {opacity:0.7;filter:alpha(opacity=70);-webkit-transition:opacity 0 linear;transition:opacity 0 linear} +div.control-scrollpad >.scrollpad-scrollbar[data-visible] {opacity:0.7;filter:alpha(opacity=70)} +div.control-scrollpad >.scrollpad-scrollbar[data-hidden] {display:none} +div.control-scrollpad[data-direction=horizontal] >.scrollpad-scrollbar {top:auto;left:0;width:auto;height:11px} +div.control-scrollpad[data-direction=horizontal] >.scrollpad-scrollbar .drag-handle {right:auto;top:2px;height:7px;min-height:0;min-width:10px;width:auto} +.svg-icon-container img.svg-icon {display:none} +.svg-icon-container.svg-active-effects img.svg-icon {-webkit-filter:grayscale(100%);filter:grayscale(100%);opacity:0.6;filter:alpha(opacity=60)} +.svg-icon-container.svg-active-effects:hover img.svg-icon, +.svg-icon-container.svg-active-effects.active img.svg-icon {-webkit-filter:none;filter:none;opacity:1;filter:alpha(opacity=100)} +html.svg .svg-icon-container i.svg-replace {display:none} +@-webkit-keyframes fadeIn {0% {opacity:0 }100% {opacity:1 }} +@keyframes fadeIn {0% {opacity:0 }100% {opacity:1 }} +.fadeIn {-webkit-animation-name:fadeIn;animation-name:fadeIn} +@-webkit-keyframes fadeInDown {0% {opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0) }100% {opacity:1;-webkit-transform:none;transform:none }} +@keyframes fadeInDown {0% {opacity:0;-webkit-transform:translate3d(0,-100%,0);-ms-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0) }100% {opacity:1;-webkit-transform:none;-ms-transform:none;transform:none }} +.fadeInDown {-webkit-animation-name:fadeInDown;animation-name:fadeInDown} +@-webkit-keyframes fadeInLeft {0% {opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0) }100% {opacity:1;-webkit-transform:none;transform:none }} +@keyframes fadeInLeft {0% {opacity:0;-webkit-transform:translate3d(-100%,0,0);-ms-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0) }100% {opacity:1;-webkit-transform:none;-ms-transform:none;transform:none }} +.fadeInLeft {-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft} +@-webkit-keyframes fadeInRight {0% {opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0) }100% {opacity:1;-webkit-transform:none;transform:none }} +@keyframes fadeInRight {0% {opacity:0;-webkit-transform:translate3d(100%,0,0);-ms-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0) }100% {opacity:1;-webkit-transform:none;-ms-transform:none;transform:none }} +.fadeInRight {-webkit-animation-name:fadeInRight;animation-name:fadeInRight} +@-webkit-keyframes fadeInUp {0% {opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0) }100% {opacity:1;-webkit-transform:none;transform:none }} +@keyframes fadeInUp {0% {opacity:0;-webkit-transform:translate3d(0,100%,0);-ms-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0) }100% {opacity:1;-webkit-transform:none;-ms-transform:none;transform:none }} +.fadeInUp {-webkit-animation-name:fadeInUp;animation-name:fadeInUp} +@-webkit-keyframes fadeInUpBig {0% {opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0) }100% {opacity:1;-webkit-transform:none;transform:none }} +@-webkit-keyframes fadeOut {0% {opacity:1 }100% {opacity:0 }} +@keyframes fadeOut {0% {opacity:1 }100% {opacity:0 }} +.fadeOut {-webkit-animation-name:fadeOut;animation-name:fadeOut} +@-webkit-keyframes fadeOutDown {0% {opacity:1 }100% {opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0) }} +@keyframes fadeOutDown {0% {opacity:1 }100% {opacity:0;-webkit-transform:translate3d(0,100%,0);-ms-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0) }} +.fadeOutDown {-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown} +@-webkit-keyframes fadeOutLeft {0% {opacity:1 }100% {opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0) }} +@keyframes fadeOutLeft {0% {opacity:1 }100% {opacity:0;-webkit-transform:translate3d(-100%,0,0);-ms-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0) }} +.fadeOutLeft {-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft} +@-webkit-keyframes fadeOutRight {0% {opacity:1 }100% {opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0) }} +@keyframes fadeOutRight {0% {opacity:1 }100% {opacity:0;-webkit-transform:translate3d(100%,0,0);-ms-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0) }} +.fadeOutRight {-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight} +@-webkit-keyframes fadeOutUp {0% {opacity:1 }100% {opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0) }} +@keyframes fadeOutUp {0% {opacity:1 }100% {opacity:0;-webkit-transform:translate3d(0,-100%,0);-ms-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0) }} +.fadeOutUp {-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp} +html:not(.mobile) body.drag * {cursor:grab !important;cursor:-webkit-grab !important;cursor:-moz-grab !important} +body.dragging, +body.dragging * {cursor:move !important} +body.loading, +body.loading * {cursor:wait !important} +body.no-select {-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default !important} +html, +body {height:100%} +body {font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";background:#f9f9f9;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale} +#layout-canvas {min-height:100%;height:100%} +.control-tabs.primary-tabs >ul.nav-tabs, +.control-tabs.primary-tabs >div >ul.nav-tabs, +.control-tabs.primary-tabs >div >div >ul.nav-tabs {margin-left:-20px;margin-right:-20px} +.control-tabs.primary-tabs.tabs-no-inset >ul.nav-tabs, +.control-tabs.primary-tabs.tabs-no-inset >div >ul.nav-tabs, +.control-tabs.primary-tabs.tabs-no-inset >div >div >ul.nav-tabs {margin-left:0;margin-right:0} +.layout {display:table;table-layout:fixed;height:100%;width:100%} +.layout >.layout-row {display:table-row;vertical-align:top;height:100%} +.layout >.layout-row >.layout-cell {display:table-cell;vertical-align:top;height:100%} +.layout >.layout-row >.layout-cell.layout-container, +.layout >.layout-row >.layout-cell .layout-container, +.layout >.layout-row >.layout-cell.padded-container, +.layout >.layout-row >.layout-cell .padded-container {padding:20px 20px 0 20px} +.layout >.layout-row >.layout-cell.layout-container .container-flush, +.layout >.layout-row >.layout-cell .layout-container .container-flush, +.layout >.layout-row >.layout-cell.padded-container .container-flush, +.layout >.layout-row >.layout-cell .padded-container .container-flush {padding-top:0} +.layout >.layout-row >.layout-cell .layout-relative {position:relative;height:100%} +.layout >.layout-row >.layout-cell .layout-absolute {position:absolute;height:100%;width:100%} +.layout >.layout-row >.layout-cell.min-size {width:0} +.layout >.layout-row >.layout-cell.min-height {height:0} +.layout >.layout-row >.layout-cell.center {text-align:center} +.layout >.layout-row >.layout-cell.middle {vertical-align:middle} +.layout >.layout-row >.layout-cell.layout-container, +.layout >.layout-row >.layout-cell .layout-container, +.layout >.layout-row >.layout-cell.padded-container, +.layout >.layout-row >.layout-cell .padded-container {padding:20px 20px 0 20px} +.layout >.layout-row >.layout-cell.layout-container .container-flush, +.layout >.layout-row >.layout-cell .layout-container .container-flush, +.layout >.layout-row >.layout-cell.padded-container .container-flush, +.layout >.layout-row >.layout-cell .padded-container .container-flush {padding-top:0} +.layout >.layout-row >.layout-cell .layout-relative {position:relative;height:100%} +.layout >.layout-row >.layout-cell .layout-absolute {position:absolute;height:100%;width:100%} +.layout >.layout-row >.layout-cell.min-size {width:0} +.layout >.layout-row >.layout-cell.min-height {height:0} +.layout >.layout-row >.layout-cell.center {text-align:center} +.layout >.layout-row >.layout-cell.middle {vertical-align:middle} +.layout >.layout-row.min-size {height:0.1px} +.layout >.layout-cell {display:table-cell;vertical-align:top;height:100%} +.layout >.layout-cell.layout-container, +.layout >.layout-cell .layout-container, +.layout >.layout-cell.padded-container, +.layout >.layout-cell .padded-container {padding:20px 20px 0 20px} +.layout >.layout-cell.layout-container .container-flush, +.layout >.layout-cell .layout-container .container-flush, +.layout >.layout-cell.padded-container .container-flush, +.layout >.layout-cell .padded-container .container-flush {padding-top:0} +.layout >.layout-cell .layout-relative {position:relative;height:100%} +.layout >.layout-cell .layout-absolute {position:absolute;height:100%;width:100%} +.layout >.layout-cell.min-size {width:0} +.layout >.layout-cell.min-height {height:0} +.layout >.layout-cell.center {text-align:center} +.layout >.layout-cell.middle {vertical-align:middle} +.whiteboard {background:white} +.layout-fill-container {position:absolute;left:0;top:0;width:100%;height:100%} +[data-calculate-width] >form, +[data-calculate-width] >div {display:inline-block} +body.compact-container .layout.layout-container, +body.compact-container .layout .layout-container {padding:0 !important} +body.slim-container .layout.layout-container, +body.slim-container .layout .layout-container {padding-left:0 !important;padding-right:0 !important} +@media (max-width:768px) {.layout .hide-on-small {display:none }.layout.responsive-sidebar >.layout-cell:first-child {display:table-footer-group;height:auto }.layout.responsive-sidebar >.layout-cell:first-child .control-breadcrumb {display:none }.layout.responsive-sidebar >.layout-cell:last-child {display:table-header-group;width:auto;height:auto }.layout.responsive-sidebar >.layout-cell:last-child .layout-absolute {position:static }} +.flex-layout-column {display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:-ms-flex;display:flex;-webkit-flex-direction:column;-moz-flex-direction:column;-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column} +.flex-layout-column.full-height-strict {height:100%} +.flex-layout-column.absolute {position:absolute !important} +.flex-layout-column.fill-container {position:absolute;left:0;top:0;width:100%;height:100%} +.flex-layout-row {display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:-ms-flex;display:flex;-webkit-flex-direction:row;-moz-flex-direction:row;-webkit-box-orient:horizontal;-ms-flex-direction:row;flex-direction:row} +.flex-layout-column.justify-center, +.flex-layout-row.justify-center {-webkit-justify-content:center;-moz-justify-content:center;-ms-justify-content:center;-webkit-box-pack:center;justify-content:center} +.flex-layout-column.align-center, +.flex-layout-row.align-center {-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;align-items:center;-webkit-align-content:center;-moz-align-content:center;-webkit-box-align:center;-ms-align-content:center;align-content:center} +.flex-layout-column.full-height, +.flex-layout-row.full-height {min-height:100%} +.flex-layout-item {margin:0} +.flex-layout-item.fix {-webkit-box-flex:0;-webkit-flex:0 0 auto;-moz-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto} +.flex-layout-item.stretch {-webkit-box-flex:1;-webkit-flex:1 1 auto;-moz-flex:1 1 auto;-ms-flex:1 1 auto;flex:1 1 auto} +.flex-layout-item.stretch-constrain {-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;flex:1} +.flex-layout-item.center {-webkit-align-self:center;-moz-align-self:center;-ms-align-self:center;align-self:center} +.flex-layout-item.relative {position:relative} +.flex-layout-item.layout-container {max-width:none} +body.mainmenu-open {overflow:hidden;position:fixed} +.mainmenu-tooltip .tooltip-inner {font-size:13px;padding:6px 16px} +ul.mainmenu-nav {font-size:14px} +ul.mainmenu-nav li {} +ul.mainmenu-nav li .svg-icon {-webkit-backface-visibility:hidden;backface-visibility:hidden} +ul.mainmenu-nav li span.counter {display:block;position:absolute;top:.143em;right:0;padding:.143em .429em .214em .286em;background-color:#d9350f;color:#fff;font-size:.786em;line-height:100%;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;opacity:1;filter:alpha(opacity=100);-webkit-transform:scale(1,);-ms-transform:scale(1,);transform:scale(1,);-webkit-transition:all 0.3s;transition:all 0.3s} +ul.mainmenu-nav li span.counter.empty {opacity:0;filter:alpha(opacity=0);-webkit-transform:scale(0,);-ms-transform:scale(0,);transform:scale(0,)} +nav#layout-mainmenu {background-color:#000;padding:0 0 0 20px;line-height:0;white-space:nowrap;display:flex} +nav#layout-mainmenu a {text-decoration:none} +nav#layout-mainmenu a:focus {background:transparent} +nav#layout-mainmenu ul {margin:0;padding:0;list-style:none;float:left;white-space:nowrap;overflow:hidden} +nav#layout-mainmenu ul li {color:rgba(255,255,255,0.6);display:inline-block;vertical-align:top;position:relative;margin-right:30px} +nav#layout-mainmenu ul li a {display:inline-block;font-size:14px;color:inherit;padding:14px 0 10px} +nav#layout-mainmenu ul li a:hover {background-color:transparent} +nav#layout-mainmenu ul li a:active, +nav#layout-mainmenu ul li a:focus {text-decoration:none;color:rgba(255,255,255,0.6)} +nav#layout-mainmenu ul li a i {line-height:1;font-size:30px;vertical-align:middle} +nav#layout-mainmenu ul li a img.svg-icon {height:30px;width:30px;margin-right:10px;position:relative;top:0} +nav#layout-mainmenu ul.nav {display:inline-block} +nav#layout-mainmenu .toolbar-item {flex:1 1 auto;display:block;padding-right:0;overflow:hidden} +nav#layout-mainmenu .toolbar-item-account {flex:0 0 auto} +nav#layout-mainmenu .toolbar-item:before, +nav#layout-mainmenu .toolbar-item:after {margin-top:0} +nav#layout-mainmenu .toolbar-item:before {left:-12px} +nav#layout-mainmenu .toolbar-item:after {right:-12px} +nav#layout-mainmenu .toolbar-item.scroll-active-before:before {color:#fff} +nav#layout-mainmenu .toolbar-item.scroll-active-after:after {color:#fff} +nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-quick-action {margin:0} +nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-quick-action:first-child {margin-left:21px} +nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-quick-action i {font-size:20px} +nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-quick-action a {position:relative;padding:0 10px;top:-1px} +nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account {margin-right:0} +nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account >a {padding:0 15px 0 10px;font-size:13px;position:relative} +nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account.highlight >a {z-index:600} +nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account img.account-avatar {width:45px;height:45px} +nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account .account-name {margin-right:15px} +nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account ul {line-height:23px} +html.svg nav#layout-mainmenu img.svg-icon, +html.svg .mainmenu-collapsed img.svg-icon {display:inline-block} +nav#layout-mainmenu ul li .mainmenu-accountmenu {position:fixed;top:0;right:20px;background:#f9f9f9;z-index:600;display:none;-webkit-box-shadow:0 1px 6px rgba(0,0,0,0.12),0 1px 4px rgba(0,0,0,0.24);box-shadow:0 1px 6px rgba(0,0,0,0.12),0 1px 4px rgba(0,0,0,0.24);border-radius:3px} +nav#layout-mainmenu ul li .mainmenu-accountmenu.active {display:block} +nav#layout-mainmenu ul li .mainmenu-accountmenu:after {content:'';display:block;width:0;height:0;border-left:8.5px solid transparent;border-right:8.5px solid transparent;border-bottom:7px solid #f9f9f9;right:9px;top:-7px;position:absolute} +nav#layout-mainmenu ul li .mainmenu-accountmenu ul {float:none;display:block;overflow:visible} +nav#layout-mainmenu ul li .mainmenu-accountmenu li {padding:0;margin:0;font-weight:normal;text-align:left;display:block} +nav#layout-mainmenu ul li .mainmenu-accountmenu li a {display:block;padding:10px 30px;text-align:left;font-size:14px;color:#666} +nav#layout-mainmenu ul li .mainmenu-accountmenu li a:hover, +nav#layout-mainmenu ul li .mainmenu-accountmenu li a:focus {background:#4ea5e0;color:#fff} +nav#layout-mainmenu ul li .mainmenu-accountmenu li a:active {background:#3498db;color:#fff} +nav#layout-mainmenu ul li .mainmenu-accountmenu li:first-child a:hover:after, +nav#layout-mainmenu ul li .mainmenu-accountmenu li:first-child a:focus:after, +nav#layout-mainmenu ul li .mainmenu-accountmenu li:first-child a:active:after {content:'';display:block;width:0;height:0;border-left:8.5px solid transparent;border-right:8.5px solid transparent;border-bottom:7px solid #4ea5e0;position:absolute;right:9px;top:-7px;z-index:102} +nav#layout-mainmenu ul li .mainmenu-accountmenu li:first-child a:active:after {content:'';display:block;width:0;height:0;border-left:8.5px solid transparent;border-right:8.5px solid transparent;border-bottom:7px solid #3498db} +nav#layout-mainmenu ul li .mainmenu-accountmenu li.divider {height:1px;width:100%;background-color:#e0e0e0} +nav#layout-mainmenu.navbar-mode-inline, +nav#layout-mainmenu.navbar-mode-inline_no_icons {height:60px} +nav#layout-mainmenu.navbar-mode-inline ul.mainmenu-toolbar li.mainmenu-quick-action a, +nav#layout-mainmenu.navbar-mode-inline_no_icons ul.mainmenu-toolbar li.mainmenu-quick-action a {height:60px;line-height:60px} +nav#layout-mainmenu.navbar-mode-inline ul.mainmenu-toolbar li.mainmenu-account >a, +nav#layout-mainmenu.navbar-mode-inline_no_icons ul.mainmenu-toolbar li.mainmenu-account >a {height:60px;line-height:60px} +nav#layout-mainmenu.navbar-mode-inline ul li .mainmenu-accountmenu, +nav#layout-mainmenu.navbar-mode-inline_no_icons ul li .mainmenu-accountmenu {top:70px} +nav#layout-mainmenu.navbar-mode-inline ul.mainmenu-nav li, +nav#layout-mainmenu.navbar-mode-inline_no_icons ul.mainmenu-nav li {margin:5px 0} +nav#layout-mainmenu.navbar-mode-inline ul.mainmenu-nav li a, +nav#layout-mainmenu.navbar-mode-inline_no_icons ul.mainmenu-nav li a {padding:10px 15px} +nav#layout-mainmenu.navbar-mode-inline ul.mainmenu-nav li a .nav-icon, +nav#layout-mainmenu.navbar-mode-inline_no_icons ul.mainmenu-nav li a .nav-icon {position:relative;top:-1px;margin-right:5px;width:30px;height:30px} +nav#layout-mainmenu.navbar-mode-inline ul.mainmenu-nav li a .nav-icon i, +nav#layout-mainmenu.navbar-mode-inline_no_icons ul.mainmenu-nav li a .nav-icon i, +nav#layout-mainmenu.navbar-mode-inline ul.mainmenu-nav li a .nav-icon img, +nav#layout-mainmenu.navbar-mode-inline_no_icons ul.mainmenu-nav li a .nav-icon img {margin:0} +nav#layout-mainmenu.navbar-mode-inline ul.mainmenu-nav li a .nav-label, +nav#layout-mainmenu.navbar-mode-inline_no_icons ul.mainmenu-nav li a .nav-label {line-height:30px} +nav#layout-mainmenu.navbar-mode-inline ul.mainmenu-nav li:first-child, +nav#layout-mainmenu.navbar-mode-inline_no_icons ul.mainmenu-nav li:first-child {margin-left:-13px} +nav#layout-mainmenu.navbar-mode-inline ul.mainmenu-nav li:last-child, +nav#layout-mainmenu.navbar-mode-inline_no_icons ul.mainmenu-nav li:last-child {margin-right:0} +nav#layout-mainmenu.navbar-mode-inline_no_icons .nav-icon {display:none !important} +nav#layout-mainmenu.navbar-mode-tile {height:78px} +nav#layout-mainmenu.navbar-mode-tile ul.mainmenu-toolbar li.mainmenu-quick-action a {height:78px;line-height:78px} +nav#layout-mainmenu.navbar-mode-tile ul.mainmenu-toolbar li.mainmenu-account >a {height:78px;line-height:78px} +nav#layout-mainmenu.navbar-mode-tile ul li .mainmenu-accountmenu {top:88px} +nav#layout-mainmenu.navbar-mode-tile ul.mainmenu-nav li a {position:relative;width:65px;height:65px} +nav#layout-mainmenu.navbar-mode-tile ul.mainmenu-nav li a .nav-icon {text-align:center;display:block;position:absolute;top:50%;left:50%;margin-left:-15px;margin-top:-26.5px;width:30px;height:30px} +nav#layout-mainmenu.navbar-mode-tile ul.mainmenu-nav li a .nav-icon i, +nav#layout-mainmenu.navbar-mode-tile ul.mainmenu-nav li a .nav-icon img {margin:0} +nav#layout-mainmenu.navbar-mode-tile ul.mainmenu-nav li a .nav-label {display:block;width:100px;height:20px;line-height:20px;position:absolute;bottom:4px;left:50%;padding:0 5px;margin-left:-50px;overflow:hidden;text-overflow:ellipsis;text-align:center} +nav#layout-mainmenu.navbar-mode-tile ul.mainmenu-nav li {padding:0 15px;margin:7px 0 0} +nav#layout-mainmenu.navbar-mode-tile ul.mainmenu-nav li:first-child {margin-left:-7px} +nav#layout-mainmenu.navbar-mode-tile ul.mainmenu-nav li:hover .nav-label {width:auto;min-width:100px;text-overflow:all;overflow:visible;z-index:2} +nav#layout-mainmenu.navbar-mode-tile ul.mainmenu-nav li.active:first-child {margin-left:0} +nav#layout-mainmenu .menu-toggle {height:45px;line-height:45px;font-size:16px;display:none} +nav#layout-mainmenu .menu-toggle .menu-toggle-icon {background:#333;display:inline-block;height:45px;line-height:45px;width:45px;text-align:center;opacity:.7} +nav#layout-mainmenu .menu-toggle .menu-toggle-icon i {line-height:45px;font-size:20px;vertical-align:bottom} +nav#layout-mainmenu .menu-toggle .menu-toggle-title {margin-left:10px} +nav#layout-mainmenu .menu-toggle:hover .menu-toggle-icon {opacity:1} +body.mainmenu-open nav#layout-mainmenu .menu-toggle-icon {opacity:1} +nav#layout-mainmenu.navbar-mode-collapse {padding-left:0;height:45px} +nav#layout-mainmenu.navbar-mode-collapse ul.mainmenu-toolbar li.mainmenu-quick-action a {height:45px;line-height:45px} +nav#layout-mainmenu.navbar-mode-collapse ul.mainmenu-toolbar li.mainmenu-account >a {height:45px;line-height:45px} +nav#layout-mainmenu.navbar-mode-collapse ul li .mainmenu-accountmenu {top:55px} +nav#layout-mainmenu.navbar-mode-collapse ul.mainmenu-toolbar li.mainmenu-account >a {padding-right:0} +nav#layout-mainmenu.navbar-mode-collapse ul li .mainmenu-accountmenu:after {right:13px} +nav#layout-mainmenu.navbar-mode-collapse ul.nav {display:none} +nav#layout-mainmenu.navbar-mode-collapse .menu-toggle {display:inline-block;color:#fff !important} +@media (max-width:769px) {nav#layout-mainmenu.navbar {padding-left:0;height:45px }nav#layout-mainmenu.navbar ul.mainmenu-toolbar li.mainmenu-quick-action a {height:45px;line-height:45px }nav#layout-mainmenu.navbar ul.mainmenu-toolbar li.mainmenu-account >a {height:45px;line-height:45px }nav#layout-mainmenu.navbar ul li .mainmenu-accountmenu {top:55px }nav#layout-mainmenu.navbar ul.mainmenu-toolbar li.mainmenu-account >a {padding-right:0 }nav#layout-mainmenu.navbar ul li .mainmenu-accountmenu:after {right:13px }nav#layout-mainmenu.navbar ul.nav {display:none }nav#layout-mainmenu.navbar .menu-toggle {display:inline-block;color:#fff !important }} +.mainmenu-collapsed {position:absolute;height:100%;top:0;left:0;margin:0;background:#000} +.mainmenu-collapsed >div {display:block;height:100%} +.mainmenu-collapsed >div ul.mainmenu-nav li a {position:relative;width:65px;height:65px} +.mainmenu-collapsed >div ul.mainmenu-nav li a .nav-icon {text-align:center;display:block;position:absolute;top:50%;left:50%;margin-left:-15px;margin-top:-26.5px;width:30px;height:30px} +.mainmenu-collapsed >div ul.mainmenu-nav li a .nav-icon i, +.mainmenu-collapsed >div ul.mainmenu-nav li a .nav-icon img {margin:0} +.mainmenu-collapsed >div ul.mainmenu-nav li a .nav-label {display:block;width:100px;height:20px;line-height:20px;position:absolute;bottom:4px;left:50%;padding:0 5px;margin-left:-50px;overflow:hidden;text-overflow:ellipsis;text-align:center} +.mainmenu-collapsed >div ul.mainmenu-nav li {padding:0 15px;margin:7px 0 0} +.mainmenu-collapsed >div ul.mainmenu-nav li:first-child {margin-left:-7px} +.mainmenu-collapsed >div ul.mainmenu-nav li:hover .nav-label {width:auto;min-width:100px;text-overflow:all;overflow:visible;z-index:2} +.mainmenu-collapsed >div ul.mainmenu-nav li.active:first-child {margin-left:0} +.mainmenu-collapsed >div ul.mainmenu-nav li:first-child {margin-left:0} +.mainmenu-collapsed >div ul {margin:0;padding:5px 0 15px 15px;overflow:hidden} +.mainmenu-collapsed >div ul li {color:rgba(255,255,255,0.6);display:inline-block;vertical-align:top;position:relative;margin-right:30px} +.mainmenu-collapsed >div ul li a {display:inline-block;font-size:14px;color:inherit} +.mainmenu-collapsed >div ul li a:hover {background-color:transparent} +.mainmenu-collapsed >div ul li a:active, +.mainmenu-collapsed >div ul li a:focus {text-decoration:none;color:rgba(255,255,255,0.6)} +.mainmenu-collapsed >div ul li a i {line-height:1;font-size:30px;vertical-align:middle} +.mainmenu-collapsed >div ul li a img.svg-icon {height:30px;width:30px;position:relative;top:0} +.mainmenu-collapsed .scroll-marker {position:absolute;left:0;width:100%;height:10px;display:none} +.mainmenu-collapsed .scroll-marker:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f141";display:block;position:absolute;left:50%;margin-left:-3px;top:0;height:9px;font-size:10px;color:rgba(255,255,255,0.6)} +.mainmenu-collapsed .scroll-marker.before {top:0} +.mainmenu-collapsed .scroll-marker.after {bottom:3px} +.mainmenu-collapsed .scroll-marker.after:after {top:2px} +.mainmenu-collapsed.scroll-before .scroll-marker.before {display:block} +.mainmenu-collapsed.scroll-after .scroll-marker.after {display:block} +body.mainmenu-open .mainmenu-collapsed ul {position:absolute;left:0;top:10px;bottom:10px} +html.mobile .mainmenu-collapsed ul {overflow:auto;-webkit-overflow-scrolling:touch} +nav#layout-mainmenu.navbar ul li:hover a:active, +.mainmenu-collapsed li:hover a:active, +nav#layout-mainmenu.navbar ul li:hover a:focus, +.mainmenu-collapsed li:hover a:focus {color:#fff !important} +.touch .mainmenu-collapsed li a:hover {color:rgba(255,255,255,0.6)} +nav#layout-mainmenu.navbar ul li.highlight >a, +.mainmenu-collapsed li.highlight >a {color:#fff !important} +nav#layout-mainmenu.navbar ul li.active, +.mainmenu-collapsed li.active {color:#fff !important} +nav#layout-mainmenu.navbar ul li.active a, +.mainmenu-collapsed li.active a {color:#fff !important} +nav#layout-mainmenu.navbar ul li:hover, +.mainmenu-collapsed li:hover {color:#fff;background:transparent} +body.drag nav#layout-mainmenu.navbar ul.nav li:hover, +body.drag .mainmenu-collapsed ul li:hover {color:rgba(255,255,255,0.6)} +.layout-sidenav-container {width:120px} +#layout-sidenav {position:absolute;height:100%;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;font-size:14px} +#layout-sidenav ul {position:relative;margin:0;padding:0;height:100%;overflow:hidden} +#layout-sidenav ul li {display:block;text-align:center;position:relative} +#layout-sidenav ul li a {padding:1.429em .714em;display:block;font-size:.929em;color:rgba(255,255,255,0.6);font-weight:normal;position:relative} +#layout-sidenav ul li a:hover {text-decoration:none;background-color:transparent} +#layout-sidenav ul li a:focus {background:transparent} +#layout-sidenav ul li a i {color:rgba(255,255,255,0.6);display:block;margin-bottom:5px;font-size:2em} +#layout-sidenav ul li:first-child a {padding-top:2.143em} +#layout-sidenav ul li.active a, +#layout-sidenav ul li a:hover {color:#fff} +#layout-sidenav ul li.active a i, +#layout-sidenav ul li a:hover i {color:#fff} +#layout-sidenav ul li span.counter {display:block;position:absolute;top:1.071em;right:1.071em;padding:.143em .429em .214em .286em;background-color:#d9350f;color:#fff;font-size:.786em;line-height:100%;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;opacity:1;filter:alpha(opacity=100);-webkit-transform:scale(1,);-ms-transform:scale(1,);transform:scale(1,);-webkit-transition:all 0.3s;transition:all 0.3s} +#layout-sidenav ul li span.counter.empty {opacity:0;filter:alpha(opacity=0);-webkit-transform:scale(0,);-ms-transform:scale(0,);transform:scale(0,)} +@media (min-width:768px) and (max-width:991px) {#layout-sidenav {font-size:12px }.layout-sidenav-container {width:100px }} +@media (max-width:767px) {#layout-sidenav {font-size:10px }.layout-sidenav-container {width:80px }} +html.mobile #layout-sidenav ul {overflow:auto;-webkit-overflow-scrolling:touch} +#layout-sidenav.layout-sidenav ul.drag li:not(.active) a:hover, +.touch #layout-sidenav.layout-sidenav li:not(.active) a:hover {color:rgba(255,255,255,0.6) !important} +#layout-sidenav.layout-sidenav ul.drag li:not(.active) a:hover i, +.touch #layout-sidenav.layout-sidenav li:not(.active) a:hover i {color:rgba(255,255,255,0.6) !important} +#layout-sidenav.layout-sidenav ul.drag li:not(.active) a:hover:after, +.touch #layout-sidenav.layout-sidenav li:not(.active) a:hover:after {display:none !important} +#layout-side-panel .fix-button {position:absolute;right:-25px;top:0;display:none;width:25px;height:25px;font-size:13px;background:#ecf0f1;z-index:120;opacity:0.5;filter:alpha(opacity=50);-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0} +#layout-side-panel .fix-button i {display:block;text-align:center;margin-top:5px;color:#aaa} +#layout-side-panel .fix-button:hover {text-decoration:none;display:block;opacity:1 !important;filter:alpha(opacity=100) !important} +#layout-side-panel:hover .fix-button {display:block} +#layout-side-panel .fix-button-content-header .fix-button {top:46px} +#layout-side-panel .sidepanel-content-header {background:#d35400;color:white;font-size:15px;padding:12px 20px 13px;position:relative} +#layout-side-panel .sidepanel-content-header:after {content:'';display:block;width:0;height:0;border-left:7.5px solid transparent;border-right:7.5px solid transparent;border-top:8px solid #d35400;border-bottom-width:0;position:absolute;left:14px;bottom:-8px} +body.side-panel-not-fixed #layout-side-panel {display:none} +body.side-panel-not-fixed #layout-side-panel .fix-button {opacity:0.5;filter:alpha(opacity=50)} +body.display-side-panel #layout-side-panel {display:block;position:absolute;z-index:600;width:350px;-webkit-box-shadow:3px 0 3px 0 rgba(0,0,0,0.1);box-shadow:3px 0 3px 0 rgba(0,0,0,0.1)} +@media (min-width:992px) {body.side-panel-fix-shadow #layout-side-panel {-webkit-box-shadow:none;box-shadow:none }} +.touch #layout-side-panel .fix-button {display:none} +@media (max-width:768px) {#layout-side-panel .fix-button {display:none }} +#layout-footer {width:100%;z-index:100;height:60px;position:fixed;bottom:0;color:#666;background-color:rgba(255,255,255,0.8);border-top:1px solid #dfdfdf} +#layout-footer .brand, +#layout-footer .tagline {margin:10px;height:40px;line-height:40px} +#layout-footer .brand {float:left;font-size:16px} +#layout-footer .brand .logo {margin:0 10px} +#layout-footer .tagline {float:right} +#layout-footer .tagline p {color:#999} +body.outer {background:#2b3e50} +body.outer .layout >.layout-row.layout-head {text-align:center;background:#f9f9f9} +body.outer .layout >.layout-row.layout-head >.layout-cell {height:40%;padding:50px 0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;vertical-align:middle;position:relative} +body.outer .layout >.layout-row.layout-head >.layout-cell:after {content:'';display:block;width:0;height:0;border-left:28px solid transparent;border-right:28px solid transparent;border-top:20px solid #f9f9f9;border-bottom-width:0;position:absolute;bottom:-20px;left:50%;margin-left:-28px} +body.outer .layout >.layout-row.layout-head >.layout-cell h1.oc-logo {font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;display:inline-block;width:100%;max-width:450px;height:170px;min-height:72px} +body.outer .layout >.layout-row >.layout-cell {vertical-align:top} +body.outer .layout >.layout-row >.layout-cell .outer-form-container {margin:0 auto;width:436px;padding:40px 0} +body.outer .layout >.layout-row >.layout-cell .outer-form-container h2 {font-size:18px;margin:20px 0;color:#feffff} +body.outer .layout >.layout-row >.layout-cell .outer-form-container .horizontal-form {font-size:0;display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:-ms-flex;display:flex} +body.outer .layout >.layout-row >.layout-cell .outer-form-container .horizontal-form input {vertical-align:top;margin-right:9px;display:inline-block;border:none;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px} +body.outer .layout >.layout-row >.layout-cell .outer-form-container .horizontal-form button {background:#0181b9;text-align:center;font-size:13px;font-weight:600;height:40px;vertical-align:top;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} +body.outer .layout >.layout-row >.layout-cell .outer-form-container .remember label {color:rgba(255,255,255,0.44)} +body.outer .layout >.layout-row >.layout-cell .outer-form-container .remember input#remember {display:none} +body.outer .layout >.layout-row >.layout-cell .outer-form-container .forgot-password {margin-top:30px;font-size:13px;top:8px} +body.outer .layout >.layout-row >.layout-cell .outer-form-container .forgot-password a {color:rgba(255,255,255,0.44)} +body.outer .layout >.layout-row >.layout-cell .outer-form-container .forgot-password:before {color:rgba(255,255,255,0.44);font-size:14px;position:relative;margin-right:5px} +html.csstransitions body.outer .outer-form-container {-webkit-transition:all 0.5s ease-out;transition:all 0.5s ease-out;-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-ms-transform:scale(1,1);-o-transform:scale(1,1);transform:scale(1,1)} +html.csstransitions body.outer.preload .outer-form-container {-webkit-transform:scale(0.2,0.2);-moz-transform:scale(0.2,0.2);-ms-transform:scale(0.2,0.2);-o-transform:scale(0.2,0.2);transform:scale(0.2,0.2)} +@media (max-width:768px) {body.outer .layout >.layout-row.layout-head >.layout-cell {padding:50px 20px }body.outer .layout >.layout-row >.layout-cell .outer-form-container {width:auto;padding:40px }body.outer .layout >.layout-row >.layout-cell .outer-form-container .horizontal-form {display:block }body.outer .layout >.layout-row >.layout-cell .outer-form-container .horizontal-form input {display:block;width:100% !important;margin-bottom:20px }} +body.breadcrumb-fancy .control-breadcrumb, +.control-breadcrumb.breadcrumb-fancy {margin-bottom:0;background-color:#e67e22} +body.breadcrumb-fancy .control-breadcrumb li, +.control-breadcrumb.breadcrumb-fancy li {background-color:#d35400;color:rgba(255,255,255,0.5)} +body.breadcrumb-fancy .control-breadcrumb li a, +.control-breadcrumb.breadcrumb-fancy li a {opacity:.5;-webkit-transition:all 0.3s ease;transition:all 0.3s ease} +body.breadcrumb-fancy .control-breadcrumb li a:hover, +.control-breadcrumb.breadcrumb-fancy li a:hover {opacity:1} +body.breadcrumb-fancy .control-breadcrumb li:before, +.control-breadcrumb.breadcrumb-fancy li:before {border-left-color:#fff;opacity:.5} +body.breadcrumb-fancy .control-breadcrumb li:after, +.control-breadcrumb.breadcrumb-fancy li:after {border-left-color:#d35400} +body.breadcrumb-fancy .control-breadcrumb li:last-child, +.control-breadcrumb.breadcrumb-fancy li:last-child {background-color:#d35400} +body.breadcrumb-fancy .control-breadcrumb li:last-child:before, +.control-breadcrumb.breadcrumb-fancy li:last-child:before {opacity:1;border-left-color:#d35400} +.fancy-layout .tab-collapse-icon {position:absolute;display:block;text-decoration:none;outline:none;opacity:0.6;filter:alpha(opacity=60);-webkit-transition:all 0.3s;transition:all 0.3s;font-size:12px;color:#fff;right:11px} +.fancy-layout .tab-collapse-icon:hover {text-decoration:none;opacity:1;filter:alpha(opacity=100)} +.fancy-layout .tab-collapse-icon.primary {color:#475354;bottom:-25px;z-index:100;-webkit-transform:scale(1,-1);-moz-transform:scale(1,-1);-ms-transform:scale(1,-1);-o-transform:scale(1,-1);transform:scale(1,-1)} +.fancy-layout .tab-collapse-icon.primary i {position:relative;display:block} +.fancy-layout .control-tabs.master-tabs, +.fancy-layout.control-tabs.master-tabs {overflow:hidden} +.fancy-layout .control-tabs.master-tabs:before, +.fancy-layout.control-tabs.master-tabs:before, +.fancy-layout .control-tabs.master-tabs:after, +.fancy-layout.control-tabs.master-tabs:after {top:13px;font-size:14px;color:rgba(255,255,255,0.35)} +.fancy-layout .control-tabs.master-tabs:before, +.fancy-layout.control-tabs.master-tabs:before {left:8px} +.fancy-layout .control-tabs.master-tabs:after, +.fancy-layout.control-tabs.master-tabs:after {right:8px} +.fancy-layout .control-tabs.master-tabs.scroll-before:before, +.fancy-layout.control-tabs.master-tabs.scroll-before:before {color:#fff} +.fancy-layout .control-tabs.master-tabs.scroll-after:after, +.fancy-layout.control-tabs.master-tabs.scroll-after:after {color:#fff} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container {background:#d35400;padding-left:20px;padding-right:20px} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs {margin-left:-8px} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li {margin-left:-5px;top:1px;padding-top:3px} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li span.tab-close, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li span.tab-close {top:14px;right:-3px;left:auto;z-index:110;font-family:sans-serif} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li span.tab-close i, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li span.tab-close i {top:4px;right:1px;color:rgba(255,255,255,0.3) !important;font-style:normal;font-weight:bold;font-size:16px} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li span.tab-close i:hover, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li span.tab-close i:hover {color:#fff !important} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a {border-bottom:none;background:transparent;font-size:14px;color:rgba(255,255,255,0.35);padding:6px 0 0 24px!important;overflow:visible} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a >span.title, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a >span.title {position:relative;display:inline-block;padding:12px 5px 0 5px;height:38px;font-size:14px;z-index:100;background-color:#b9530f} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a >span.title:before, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a >span.title:before, +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a >span.title:after, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a >span.title:after {content:' ';position:absolute;width:20px;display:block;height:37px;top:0;z-index:100;background-color:#b9530f} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a >span.title:before, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a >span.title:before {left:-14px;-webkit-border-radius:8px 0 0 0;-moz-border-radius:8px 0 0 0;border-radius:8px 0 0 0;-webkit-transform:skewX(-20deg);-ms-transform:skewX(-20deg);transform:skewX(-20deg)} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a >span.title:after, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a >span.title:after {right:-14px;-webkit-border-radius:0 8px 0 0;-moz-border-radius:0 8px 0 0;border-radius:0 8px 0 0;-webkit-transform:skewX(20deg);-ms-transform:skewX(20deg);transform:skewX(20deg)} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a >span.title span, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a >span.title span {border-top:none;padding:0;margin-top:0;overflow:visible} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a:before, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a:before {z-index:110;position:absolute;top:18px;left:22px} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a[class*=icon] >span.title, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li a[class*=icon] >span.title {padding-left:18px} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li.active a, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li.active a {z-index:107;color:#fff} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li.active span.tab-close i, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li.active span.tab-close i {color:#fff} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li.active a >span.title, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li.active a >span.title {background-color:#e67e22;z-index:105} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li.active a >span.title:before, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li.active a >span.title:before {z-index:107;background-color:#e67e22} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li.active a >span.title:after, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li.active a >span.title:after {background-color:#e67e22;z-index:107} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i {top:5px;font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i:before, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f111";font-size:9px} +.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li:first-child, +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li:first-child {margin-left:0} +.fancy-layout .control-tabs.master-tabs[data-closable] >div >div.tabs-container >ul.nav-tabs >li a >span.title, +.fancy-layout.control-tabs.master-tabs[data-closable] >div >div.tabs-container >ul.nav-tabs >li a >span.title {padding-right:10px} +.fancy-layout .control-tabs.master-tabs.has-tabs:before, +.fancy-layout.control-tabs.master-tabs.has-tabs:before, +.fancy-layout .control-tabs.master-tabs.has-tabs:after, +.fancy-layout.control-tabs.master-tabs.has-tabs:after {display:block} +.fancy-layout .control-tabs.secondary-tabs:before, +.fancy-layout.control-tabs.secondary-tabs:before {left:5px} +.fancy-layout .control-tabs.secondary-tabs:after, +.fancy-layout.control-tabs.secondary-tabs:after {right:5px} +.fancy-layout .control-tabs.secondary-tabs >div >ul.nav-tabs, +.fancy-layout.control-tabs.secondary-tabs >div >ul.nav-tabs {background:#475354} +.fancy-layout .control-tabs.secondary-tabs >div >ul.nav-tabs >li, +.fancy-layout.control-tabs.secondary-tabs >div >ul.nav-tabs >li {border-right:none;padding-right:0;margin-right:0} +.fancy-layout .control-tabs.secondary-tabs >div >ul.nav-tabs >li a, +.fancy-layout.control-tabs.secondary-tabs >div >ul.nav-tabs >li a {background:transparent;border:none;padding:12px 10px 13px 10px;font-size:14px;font-weight:normal;line-height:14px;color:#919898} +.fancy-layout .control-tabs.secondary-tabs >div >ul.nav-tabs >li a span span, +.fancy-layout.control-tabs.secondary-tabs >div >ul.nav-tabs >li a span span {overflow:visible;border-top:none;margin-top:0;padding-top:0} +.fancy-layout .control-tabs.secondary-tabs >div >ul.nav-tabs >li:first-child, +.fancy-layout.control-tabs.secondary-tabs >div >ul.nav-tabs >li:first-child {padding-left:15px} +.fancy-layout .control-tabs.secondary-tabs >div >ul.nav-tabs >li.active a, +.fancy-layout.control-tabs.secondary-tabs >div >ul.nav-tabs >li.active a {color:#fff} +.fancy-layout .control-tabs.secondary-tabs .tab-collapse-icon, +.fancy-layout.control-tabs.secondary-tabs .tab-collapse-icon {position:absolute;display:block;text-decoration:none;outline:none;opacity:0.6;filter:alpha(opacity=60);-webkit-transition:all 0.3s;transition:all 0.3s;font-size:12px;color:#fff;right:11px} +.fancy-layout .control-tabs.secondary-tabs .tab-collapse-icon:hover, +.fancy-layout.control-tabs.secondary-tabs .tab-collapse-icon:hover {text-decoration:none;opacity:1;filter:alpha(opacity=100)} +.fancy-layout .control-tabs.secondary-tabs .tab-collapse-icon.primary, +.fancy-layout.control-tabs.secondary-tabs .tab-collapse-icon.primary {color:#475354;bottom:-25px;z-index:100;-webkit-transform:scale(1,-1);-moz-transform:scale(1,-1);-ms-transform:scale(1,-1);-o-transform:scale(1,-1);transform:scale(1,-1)} +.fancy-layout .control-tabs.secondary-tabs .tab-collapse-icon.primary i, +.fancy-layout.control-tabs.secondary-tabs .tab-collapse-icon.primary i {position:relative;display:block} +.fancy-layout .control-tabs.secondary-tabs .tab-collapse-icon.primary, +.fancy-layout.control-tabs.secondary-tabs .tab-collapse-icon.primary {color:#fff;top:12px;right:11px;bottom:auto} +.fancy-layout .control-tabs.secondary-tabs.primary-collapsed .tab-collapse-icon.primary, +.fancy-layout.control-tabs.secondary-tabs.primary-collapsed .tab-collapse-icon.primary {-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-ms-transform:scale(1,1);-o-transform:scale(1,1);transform:scale(1,1)} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs {background:#f9f9f9} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li {margin-left:-19px} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li:first-child, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li:first-child {margin-left:0;padding-left:8px} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a {padding:8px 16px 0 16px;font-weight:400;height:36px;color:#2b3e50;opacity:0.6;filter:alpha(opacity=60)} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a >span.title, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a >span.title {position:relative;display:inline-block;padding:8px 5px 9px 5px;font-size:14px;z-index:100;height:27px !important;background-color:transparent} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a >span.title:before, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a >span.title:before, +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a >span.title:after, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a >span.title:after {content:' ';position:absolute;background-color:white;width:15px;height:28px;top:0;z-index:100;display:none} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a >span.title:before, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a >span.title:before {left:-11px;-webkit-border-radius:8px 0 0 0;-moz-border-radius:8px 0 0 0;border-radius:8px 0 0 0;-webkit-transform:skewX(-20deg);-ms-transform:skewX(-20deg);transform:skewX(-20deg)} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a >span.title:after, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a >span.title:after {right:-11px;-webkit-border-radius:0 8px 0 0;-moz-border-radius:0 8px 0 0;border-radius:0 8px 0 0;-webkit-transform:skewX(20deg);-ms-transform:skewX(20deg);transform:skewX(20deg)} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a >span.title span, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li a >span.title span {height:18px;font-size:14px} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li.active a, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li.active a {opacity:1;filter:alpha(opacity=100)} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li.active a >span.title, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li.active a >span.title {background-color:white} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li.active a >span.title:before, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li.active a >span.title:before, +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li.active a >span.title:after, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs >div >ul.nav-tabs >li.active a >span.title:after {display:block} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs .tab-collapse-icon.primary, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs .tab-collapse-icon.primary {color:#808c8d} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed .tab-collapse-icon.primary, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed .tab-collapse-icon.primary {color:white} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed >div >ul.nav-tabs, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed >div >ul.nav-tabs {background:#e67e22} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed >div >ul.nav-tabs >li a, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed >div >ul.nav-tabs >li a {color:white} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed >div >ul.nav-tabs >li a >span.title:before, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed >div >ul.nav-tabs >li a >span.title:before, +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed >div >ul.nav-tabs >li a >span.title:after, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed >div >ul.nav-tabs >li a >span.title:after {background-color:white} +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed >div >ul.nav-tabs >li.active a, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed >div >ul.nav-tabs >li.active a {color:#2b3e50} +.fancy-layout .control-tabs.primary-tabs.master-area >div >ul.nav-tabs, +.fancy-layout.control-tabs.primary-tabs.master-area >div >ul.nav-tabs {-webkit-transition:background-color 0.5s;transition:background-color 0.5s;background:#e67e22} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs {background:#7f8c8d;margin-left:0 !important;margin-right:0 !important} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs:before, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs:before {display:none} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li {background:transparent;border-right:none;margin-right:-8px} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li:first-child, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li:first-child {margin-left:-5px} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li a, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li a {background:transparent;border:none;padding:12px 16px 0;font-size:14px;font-weight:400;color:#95a5a6} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li a span.title, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li a span.title {background:#d5d9d8;border-top:none;padding:5px 5px 3px 5px} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li a span.title:before, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li a span.title:before, +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li a span.title:after, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li a span.title:after {background:#d5d9d8;border-width:0;top:0} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li a span.title:before, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li a span.title:before {left:-20px} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li a span.title:after, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li a span.title:after {right:-20px} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li a span.title span, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li a span.title span {border-width:0;vertical-align:top} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li.active a, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li.active a {color:#808c8d} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li.active a:before, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li.active a:before {display:none} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li.active a span.title, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li.active a span.title {background:#fafafa} +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li.active a span.title:before, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li.active a span.title:before, +.fancy-layout .control-tabs.primary-tabs >div >ul.nav-tabs >li.active a span.title:after, +.fancy-layout.control-tabs.primary-tabs >div >ul.nav-tabs >li.active a span.title:after {background:#fafafa} +.fancy-layout .control-tabs.primary-tabs >.tab-content >.tab-pane, +.fancy-layout.control-tabs.primary-tabs >.tab-content >.tab-pane {padding:20px 20px 0 20px} +.fancy-layout .control-tabs.primary-tabs >.tab-content >.tab-pane.pane-compact, +.fancy-layout.control-tabs.primary-tabs >.tab-content >.tab-pane.pane-compact {padding:0} +.fancy-layout .control-tabs.primary-tabs.collapsed, +.fancy-layout.control-tabs.primary-tabs.collapsed {display:none} +.fancy-layout .control-tabs.has-tabs >div.tab-content, +.fancy-layout.control-tabs.has-tabs >div.tab-content {background:#f9f9f9} +.fancy-layout .control-tabs >div.tab-content >div.tab-pane, +.fancy-layout.control-tabs >div.tab-content >div.tab-pane {padding:0} +.fancy-layout .control-tabs >div.tab-content >div.tab-pane.padded-pane, +.fancy-layout.control-tabs >div.tab-content >div.tab-pane.padded-pane {padding:20px 20px 0 20px} +.fancy-layout .form-tabless-fields {position:relative;background:#e67e22;padding:18px 23px 0 23px;-webkit-transition:all 0.5s;transition:all 0.5s} +.fancy-layout .form-tabless-fields:before, +.fancy-layout .form-tabless-fields:after {content:" ";display:table} +.fancy-layout .form-tabless-fields:after {clear:both} +.fancy-layout .form-tabless-fields label {text-transform:uppercase;color:rgba(255,255,255,0.5);margin-bottom:0} +.fancy-layout .form-tabless-fields input[type=text] {background:transparent;border:none;color:#fff;font-size:35px;font-weight:100;height:auto;padding:0;-webkit-box-shadow:none;box-shadow:none} +.fancy-layout .form-tabless-fields input[type=text]::-moz-placeholder {color:rgba(255,255,255,0.5);opacity:1} +.fancy-layout .form-tabless-fields input[type=text]:-ms-input-placeholder {color:rgba(255,255,255,0.5)} +.fancy-layout .form-tabless-fields input[type=text]::-webkit-input-placeholder {color:rgba(255,255,255,0.5)} +.fancy-layout .form-tabless-fields input[type=text]:focus, +.fancy-layout .form-tabless-fields input[type=text]:hover {background-color:rgba(255,255,255,0.1)} +.fancy-layout .form-tabless-fields .form-group {padding-bottom:0} +.fancy-layout .form-tabless-fields .form-group.is-required >label:after {display:none} +.fancy-layout .form-tabless-fields .tab-collapse-icon {position:absolute;display:block;text-decoration:none;outline:none;opacity:0.6;filter:alpha(opacity=60);-webkit-transition:all 0.3s;transition:all 0.3s;font-size:12px;color:#fff;right:11px} +.fancy-layout .form-tabless-fields .tab-collapse-icon:hover {text-decoration:none;opacity:1;filter:alpha(opacity=100)} +.fancy-layout .form-tabless-fields .tab-collapse-icon.primary {color:#475354;bottom:-25px;z-index:100;-webkit-transform:scale(1,-1);-moz-transform:scale(1,-1);-ms-transform:scale(1,-1);-o-transform:scale(1,-1);transform:scale(1,-1)} +.fancy-layout .form-tabless-fields .tab-collapse-icon.primary i {position:relative;display:block} +.fancy-layout .form-tabless-fields .tab-collapse-icon.tabless {top:14px} +.fancy-layout .form-tabless-fields.collapsed {padding:5px 23px 0 10px} +.fancy-layout .form-tabless-fields.collapsed .tab-collapse-icon.tabless {-webkit-transform:scale(1,-1);-moz-transform:scale(1,-1);-ms-transform:scale(1,-1);-o-transform:scale(1,-1);transform:scale(1,-1)} +.fancy-layout .form-tabless-fields.collapsed .form-group:not(.collapse-visible) {display:none} +.fancy-layout .form-tabless-fields.collapsed .form-buttons {margin-left:10px;padding-bottom:0} +.fancy-layout .form-tabless-fields .loading-indicator-container .loading-indicator {background-color:#e67e22;padding:0 0 0 30px;color:rgba(255,255,255,0.5);margin-top:1px;height:90%;font-size:12px;line-height:100%} +.fancy-layout .form-tabless-fields .loading-indicator-container .loading-indicator >span {left:-10px;top:18px} +.fancy-layout .form-buttons {-webkit-transition:all 0.5s;transition:all 0.5s;padding-top:14px;padding-bottom:5px} +.fancy-layout .form-buttons .btn {padding:0;margin-right:5px;margin-top:-6px;margin-right:30px;background:transparent;color:#fff;font-weight:normal;-webkit-box-shadow:none;box-shadow:none;opacity:0.5;filter:alpha(opacity=50);-webkit-transition:all 0.3s ease;transition:all 0.3s ease} +.fancy-layout .form-buttons .btn:hover {opacity:1;filter:alpha(opacity=100)} +.fancy-layout .form-buttons .btn:last-child {margin-right:0} +.fancy-layout .form-buttons .btn[class^="oc-icon-"]:before, +.fancy-layout .form-buttons .btn[class*=" oc-icon-"]:before {opacity:1} +.fancy-layout form.oc-data-changed .btn.save {opacity:1;filter:alpha(opacity=100)} +.fancy-layout .field-codeeditor {border:none !important;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.fancy-layout .field-codeeditor .editor-code {-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.fancy-layout .field-richeditor {border:none;border-left:1px solid #d1d6d9 !important} +.fancy-layout .field-richeditor, +.fancy-layout .field-richeditor .fr-toolbar, +.fancy-layout .field-richeditor .fr-wrapper {-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border-top-right-radius:0;border-top-left-radius:0} +.fancy-layout .secondary-content-tabs .field-richeditor .fr-toolbar {background:white} +body.side-panel-not-fixed .fancy-layout .field-richeditor {border-left:none} +html.cssanimations .fancy-layout .form-tabless-fields .loading-indicator-container .loading-indicator >span {-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite;background-image:url('../../../system/assets/ui/images/loader-white.svg');background-size:20px 20px} +html.gecko .fancy-layout .control-tabs.secondary-tabs >div >ul.nav-tabs >li.active a {padding-top:13px} +.flyout-container >.flyout {overflow:hidden;width:0;left:0 !important;-webkit-transition:width 0.1s;transition:width 0.1s} +.flyout-overlay {width:100%;height:100%;top:0;z-index:5000;position:absolute;background-color:rgba(0,0,0,0);-webkit-transition:background-color 0.3s;transition:background-color 0.3s} +.flyout-toggle {position:absolute;top:20px;left:0;width:23px;height:25px;background:#2b3e50;cursor:pointer;border-bottom-right-radius:4px;border-top-right-radius:4px;color:#bdc3c7;font-size:10px} +.flyout-toggle i {margin:7px 0 0 6px;display:inline-block} +.flyout-toggle:hover i {color:#fff} +body.flyout-visible {overflow:hidden} +body.flyout-visible .flyout-overlay {background-color:rgba(0,0,0,0.3)} \ No newline at end of file diff --git a/modules/backend/assets/images/dashboard-icon.svg b/modules/backend/assets/images/dashboard-icon.svg new file mode 100644 index 0000000..eb2f25a --- /dev/null +++ b/modules/backend/assets/images/dashboard-icon.svg @@ -0,0 +1,17 @@ + + + + dashboard-icon + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/backend/assets/images/favicon.png b/modules/backend/assets/images/favicon.png new file mode 100644 index 0000000..6af9b71 Binary files /dev/null and b/modules/backend/assets/images/favicon.png differ diff --git a/modules/backend/assets/images/media-icon.svg b/modules/backend/assets/images/media-icon.svg new file mode 100644 index 0000000..a654de0 --- /dev/null +++ b/modules/backend/assets/images/media-icon.svg @@ -0,0 +1,22 @@ + + + + media-icon + Created with Sketch. + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/backend/assets/images/october-leaf.svg b/modules/backend/assets/images/october-leaf.svg new file mode 100644 index 0000000..6f4cfdb --- /dev/null +++ b/modules/backend/assets/images/october-leaf.svg @@ -0,0 +1,18 @@ + + + + october-leaf + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/modules/backend/assets/images/october-logo-text.png b/modules/backend/assets/images/october-logo-text.png new file mode 100644 index 0000000..365dfb4 Binary files /dev/null and b/modules/backend/assets/images/october-logo-text.png differ diff --git a/modules/backend/assets/images/october-logo-transparent.svg b/modules/backend/assets/images/october-logo-transparent.svg new file mode 100644 index 0000000..fd79425 --- /dev/null +++ b/modules/backend/assets/images/october-logo-transparent.svg @@ -0,0 +1,75 @@ + + + +]> + + + + + + + + + + + diff --git a/modules/backend/assets/images/october-logo-white.svg b/modules/backend/assets/images/october-logo-white.svg new file mode 100644 index 0000000..1224385 --- /dev/null +++ b/modules/backend/assets/images/october-logo-white.svg @@ -0,0 +1,75 @@ + + + +]> + + + + + + + + + + + diff --git a/modules/backend/assets/images/october-logo.svg b/modules/backend/assets/images/october-logo.svg new file mode 100644 index 0000000..b4121e4 --- /dev/null +++ b/modules/backend/assets/images/october-logo.svg @@ -0,0 +1,75 @@ + + + +]> + + + + + + + + + + + diff --git a/modules/backend/assets/images/secondary-tab-shape-content.svg b/modules/backend/assets/images/secondary-tab-shape-content.svg new file mode 100644 index 0000000..164511a --- /dev/null +++ b/modules/backend/assets/images/secondary-tab-shape-content.svg @@ -0,0 +1,16 @@ + + + +]> + + + + + + + + diff --git a/modules/backend/assets/images/tab-shape.svg b/modules/backend/assets/images/tab-shape.svg new file mode 100644 index 0000000..d90911c --- /dev/null +++ b/modules/backend/assets/images/tab-shape.svg @@ -0,0 +1,16 @@ + + + +]> + + + + + + + + + diff --git a/modules/backend/assets/images/treeview-icons.png b/modules/backend/assets/images/treeview-icons.png new file mode 100644 index 0000000..a08c70b Binary files /dev/null and b/modules/backend/assets/images/treeview-icons.png differ diff --git a/modules/backend/assets/images/treeview-submenu-tabs.png b/modules/backend/assets/images/treeview-submenu-tabs.png new file mode 100644 index 0000000..6c39867 Binary files /dev/null and b/modules/backend/assets/images/treeview-submenu-tabs.png differ diff --git a/modules/backend/assets/js/auth/auth.js b/modules/backend/assets/js/auth/auth.js new file mode 100644 index 0000000..caa70f0 --- /dev/null +++ b/modules/backend/assets/js/auth/auth.js @@ -0,0 +1,5 @@ +$(document).ready(function(){ + $(document.body).removeClass('preload') + + $('form input[type=text], form input[type=password]').first().focus() +}) \ No newline at end of file diff --git a/modules/backend/assets/js/backend.js b/modules/backend/assets/js/backend.js new file mode 100644 index 0000000..d21803d --- /dev/null +++ b/modules/backend/assets/js/backend.js @@ -0,0 +1,238 @@ +/* + * October General Utilities + */ + +/* + * Ensure the CSRF token is added to all AJAX requests. + */ + +$.ajaxPrefilter(function(options) { + var token = $('meta[name="csrf-token"]').attr('content') + + if (token) { + if (!options.headers) options.headers = {} + options.headers['X-CSRF-TOKEN'] = token + } +}) + +/* + * Path helpers + */ + +if ($.oc === undefined) + $.oc = {} + +$.oc.backendUrl = function(url) { + var backendBasePath = $('meta[name="backend-base-path"]').attr('content') + + if (!backendBasePath) + return url + + if (url.substr(0, 1) == '/') + url = url.substr(1) + + return backendBasePath + '/' + url +} + +/* + * Asset Manager + * + * Usage: assetManager.load({ css:[], js:[], img:[] }, onLoadedCallback) + */ + +AssetManager = function() { + + var o = { + + load: function(collection, callback) { + var jsList = (collection.js) ? collection.js : [], + cssList = (collection.css) ? collection.css : [], + imgList = (collection.img) ? collection.img : [] + + jsList = $.grep(jsList, function(item){ + return $('head script[src="'+item+'"]').length == 0 + }) + + cssList = $.grep(cssList, function(item){ + return $('head link[href="'+item+'"]').length == 0 + }) + + var cssCounter = 0, + jsLoaded = false, + imgLoaded = false + + if (jsList.length === 0 && cssList.length === 0 && imgList.length === 0) { + callback && callback() + return + } + + o.loadJavaScript(jsList, function(){ + jsLoaded = true + checkLoaded() + }) + + $.each(cssList, function(index, source){ + o.loadStyleSheet(source, function(){ + cssCounter++ + checkLoaded() + }) + }) + + o.loadImage(imgList, function(){ + imgLoaded = true + checkLoaded() + }) + + function checkLoaded() { + if (!imgLoaded) + return false + + if (!jsLoaded) + return false + + if (cssCounter < cssList.length) + return false + + callback && callback() + } + }, + + /* + * Loads StyleSheet files + */ + loadStyleSheet: function(source, callback) { + var cssElement = document.createElement('link') + + cssElement.setAttribute('rel', 'stylesheet') + cssElement.setAttribute('type', 'text/css') + cssElement.setAttribute('href', source) + cssElement.addEventListener('load', callback, false) + + if (typeof cssElement != 'undefined') { + document.getElementsByTagName('head')[0].appendChild(cssElement) + } + + return cssElement + }, + + /* + * Loads JavaScript files in sequence + */ + loadJavaScript: function(sources, callback) { + if (sources.length <= 0) + return callback() + + var source = sources.shift(), + jsElement = document.createElement('script'); + + jsElement.setAttribute('type', 'text/javascript') + jsElement.setAttribute('src', source) + jsElement.addEventListener('load', function() { + o.loadJavaScript(sources, callback) + }, false) + + if (typeof jsElement != 'undefined') { + document.getElementsByTagName('head')[0].appendChild(jsElement) + } + }, + + /* + * Loads Image files + */ + loadImage: function(sources, callback) { + if (sources.length <= 0) + return callback() + + var loaded = 0 + $.each(sources, function(index, source){ + var img = new Image() + img.onload = function() { + if (++loaded == sources.length && callback) + callback() + } + img.src = source + }) + } + + }; + + return o; +}; + +assetManager = new AssetManager(); + +/* + * String escape + */ +if ($.oc === undefined) + $.oc = {} + +$.oc.escapeHtmlString = function(string) { + var htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '/': '/' + }, + htmlEscaper = /[&<>"'\/]/g + + return ('' + string).replace(htmlEscaper, function(match) { + return htmlEscapes[match]; + }) +} + +/* + * Inverse Click Event (not used) + * + * Calls the handler function if the user has clicked outside the object + * and not on any of the elements in the exception list. + */ +/* +$.fn.extend({ + clickOutside: function(handler, exceptions) { + var $this = this; + + $('body').on('click', function(event) { + if (exceptions && $.inArray(event.target, exceptions) > -1) { + return; + } else if ($.contains($this[0], event.target)) { + return; + } else { + handler(event, $this); + } + }); + + return this; + } +}) +*/ + +/* + * Browser Fixes + * - If another fix using JS is necessary, move this logic to backend.fixes.js + */ + +/* + * Internet Explorer v11 + * - IE11 will not honor height 100% when overflow is used on the Y axis. + */ +if (!!window.MSInputMethodContext && !!document.documentMode) { + $(window).on('resize', function() { + fixMediaManager() + fixSidebar() + }) + + function fixMediaManager() { + var $el = $('div[data-control="media-manager"] .control-scrollpad') + $el.height($el.parent().height()) + } + + function fixSidebar() { + $('#layout-sidenav').height(Math.max( + $('#layout-body').innerHeight(), + $(window).height() - $('#layout-mainmenu').height() + )) + } +} diff --git a/modules/backend/assets/js/october-min.js b/modules/backend/assets/js/october-min.js new file mode 100644 index 0000000..41cba97 --- /dev/null +++ b/modules/backend/assets/js/october-min.js @@ -0,0 +1,1320 @@ + +(function($){$.fn.touchwipe=function(settings){var config={min_move_x:20,min_move_y:20,wipeLeft:function(){},wipeRight:function(){},wipeUp:function(){},wipeDown:function(){},preventDefaultEvents:true};if(settings)$.extend(config,settings);this.each(function(){var startX;var startY;var isMoving=false;function cancelTouch(){this.removeEventListener('touchmove',onTouchMove);startX=null;isMoving=false;} +function onTouchMove(e){if(config.preventDefaultEvents){e.preventDefault();} +if(isMoving){var x=e.touches[0].pageX;var y=e.touches[0].pageY;var dx=startX-x;var dy=startY-y;if(Math.abs(dx)>=config.min_move_x){cancelTouch();if(dx>0){config.wipeLeft();} +else{config.wipeRight();}} +else if(Math.abs(dy)>=config.min_move_y){cancelTouch();if(dy>0){config.wipeDown();} +else{config.wipeUp();}}}} +function onTouchStart(e) +{if(e.touches.length==1){startX=e.touches[0].pageX;startY=e.touches[0].pageY;isMoving=true;this.addEventListener('touchmove',onTouchMove,false);}} +if('ontouchstart'in document.documentElement){this.addEventListener('touchstart',onTouchStart,false);}});return this;};})(jQuery);(function($){var liveUpdatingTargetSelectors={};var liveUpdaterIntervalId;var liveUpdaterRunning=false;var defaultSettings={ellipsis:'...',setTitle:'never',live:false};$.fn.ellipsis=function(selector,options){var subjectElements,settings;subjectElements=$(this);if(typeof selector!=='string'){options=selector;selector=undefined;} +settings=$.extend({},defaultSettings,options);settings.selector=selector;subjectElements.each(function(){var elem=$(this);ellipsisOnElement(elem,settings);});if(settings.live){addToLiveUpdater(subjectElements.selector,settings);}else{removeFromLiveUpdater(subjectElements.selector);} +return this;};function ellipsisOnElement(containerElement,settings){var containerData=containerElement.data('jqae');if(!containerData)containerData={};var wrapperElement=containerData.wrapperElement;if(!wrapperElement){wrapperElement=containerElement.wrapInner('

').find('>div');wrapperElement.css({margin:0,padding:0,border:0});} +var wrapperElementData=wrapperElement.data('jqae');if(!wrapperElementData)wrapperElementData={};var wrapperOriginalContent=wrapperElementData.originalContent;if(wrapperOriginalContent){wrapperElement=wrapperElementData.originalContent.clone(true).data('jqae',{originalContent:wrapperOriginalContent}).replaceAll(wrapperElement);}else{wrapperElement.data('jqae',{originalContent:wrapperElement.clone(true)});} +containerElement.data('jqae',{wrapperElement:wrapperElement,containerWidth:containerElement.width(),containerHeight:containerElement.height()});var containerElementHeight=containerElement.height();var wrapperOffset=(parseInt(containerElement.css('padding-top'),10)||0)+(parseInt(containerElement.css('border-top-width'),10)||0)-(wrapperElement.offset().top-containerElement.offset().top);var deferAppendEllipsis=false;var selectedElements=wrapperElement;if(settings.selector)selectedElements=$(wrapperElement.find(settings.selector).get().reverse());selectedElements.each(function(){var selectedElement=$(this),originalText=selectedElement.text(),ellipsisApplied=false;if(wrapperElement.innerHeight()-selectedElement.innerHeight()>containerElementHeight+wrapperOffset){selectedElement.remove();}else{removeLastEmptyElements(selectedElement);if(selectedElement.contents().length){if(deferAppendEllipsis){getLastTextNode(selectedElement).get(0).nodeValue+=settings.ellipsis;deferAppendEllipsis=false;} +while(wrapperElement.innerHeight()>containerElementHeight+wrapperOffset){ellipsisApplied=ellipsisOnLastTextNode(selectedElement);if(ellipsisApplied){removeLastEmptyElements(selectedElement);if(selectedElement.contents().length){getLastTextNode(selectedElement).get(0).nodeValue+=settings.ellipsis;}else{deferAppendEllipsis=true;selectedElement.remove();break;}}else{deferAppendEllipsis=true;selectedElement.remove();break;}} +if(((settings.setTitle=='onEllipsis')&&ellipsisApplied)||(settings.setTitle=='always')){selectedElement.attr('title',originalText);}else if(settings.setTitle!='never'){selectedElement.removeAttr('title');}}}});} +function ellipsisOnLastTextNode(element){var lastTextNode=getLastTextNode(element);if(lastTextNode.length){var text=lastTextNode.get(0).nodeValue;var pos=text.lastIndexOf(' ');if(pos>-1){text=$.trim(text.substring(0,pos));lastTextNode.get(0).nodeValue=text;}else{lastTextNode.get(0).nodeValue='';} +return true;} +return false;} +function getLastTextNode(element){if(element.contents().length){var contents=element.contents();var lastNode=contents.eq(contents.length-1);if(lastNode.filter(textNodeFilter).length){return lastNode;}else{return getLastTextNode(lastNode);}}else{element.append('');var contents=element.contents();return contents.eq(contents.length-1);}} +function removeLastEmptyElements(element){if(element.contents().length){var contents=element.contents();var lastNode=contents.eq(contents.length-1);if(lastNode.filter(textNodeFilter).length){var text=lastNode.get(0).nodeValue;text=$.trim(text);if(text==''){lastNode.remove();return true;}else{return false;}}else{while(removeLastEmptyElements(lastNode)){} +if(lastNode.contents().length){return false;}else{lastNode.remove();return true;}}} +return false;} +function textNodeFilter(){return this.nodeType===3;} +function addToLiveUpdater(targetSelector,settings){liveUpdatingTargetSelectors[targetSelector]=settings;if(!liveUpdaterIntervalId){liveUpdaterIntervalId=window.setInterval(function(){doLiveUpdater();},200);}} +function removeFromLiveUpdater(targetSelector){if(liveUpdatingTargetSelectors[targetSelector]){delete liveUpdatingTargetSelectors[targetSelector];if(!liveUpdatingTargetSelectors.length){if(liveUpdaterIntervalId){window.clearInterval(liveUpdaterIntervalId);liveUpdaterIntervalId=undefined;}}}};function doLiveUpdater(){if(!liveUpdaterRunning){liveUpdaterRunning=true;for(var targetSelector in liveUpdatingTargetSelectors){$(targetSelector).each(function(){var containerElement,containerData;containerElement=$(this);containerData=containerElement.data('jqae');if((containerData.containerWidth!=containerElement.width())||(containerData.containerHeight!=containerElement.height())){ellipsisOnElement(containerElement,liveUpdatingTargetSelectors[targetSelector]);}});} +liveUpdaterRunning=false;}};})(jQuery);(function($){$.waterfall=function(){var steps=[],dfrd=$.Deferred(),pointer=0;$.each(arguments,function(i,a){steps.push(function(){var args=[].slice.apply(arguments),d;if(typeof(a)=='function'){if(!((d=a.apply(null,args))&&d.promise)){d=$.Deferred()[d===false?'reject':'resolve'](d);}}else if(a&&a.promise){d=a;}else{d=$.Deferred()[a===false?'reject':'resolve'](a);} +d.fail(function(){dfrd.reject.apply(dfrd,[].slice.apply(arguments));}).done(function(data){pointer++;args.push(data);pointer==steps.length?dfrd.resolve.apply(dfrd,args):steps[pointer].apply(null,args);});});});steps.length?steps[0]():dfrd.resolve();return dfrd;}})(jQuery);(function(factory){if(typeof define==='function'&&define.amd){define(['jquery'],factory);}else if(typeof exports==='object'){factory(require('jquery'));}else{factory(jQuery);}}(function($){var pluses=/\+/g;function encode(s){return config.raw?s:encodeURIComponent(s);} +function decode(s){return config.raw?s:decodeURIComponent(s);} +function stringifyCookieValue(value){return encode(config.json?JSON.stringify(value):String(value));} +function parseCookieValue(s){if(s.indexOf('"')===0){s=s.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,'\\');} +try{s=decodeURIComponent(s.replace(pluses,' '));return config.json?JSON.parse(s):s;}catch(e){}} +function read(s,converter){var value=config.raw?s:parseCookieValue(s);return $.isFunction(converter)?converter(value):value;} +var config=$.cookie=function(key,value,options){if(arguments.length>1&&!$.isFunction(value)){options=$.extend({},config.defaults,options);if(typeof options.expires==='number'){var days=options.expires,t=options.expires=new Date();t.setTime(+t+days*864e+5);} +return(document.cookie=[encode(key),'=',stringifyCookieValue(value),options.expires?'; expires='+options.expires.toUTCString():'',options.path?'; path='+options.path:'',options.domain?'; domain='+options.domain:'',options.secure?'; secure':''].join(''));} +var result=key?undefined:{};var cookies=document.cookie?document.cookie.split('; '):[];for(var i=0,l=cookies.length;i1?_len-1:0),_key=1;_key<_len;_key++){args[_key-1]=arguments[_key];} +for(var _iterator=callbacks,_isArray=true,_i=0,_iterator=_isArray?_iterator:_iterator[Symbol.iterator]();;){var _ref;if(_isArray){if(_i>=_iterator.length)break;_ref=_iterator[_i++];}else{_i=_iterator.next();if(_i.done)break;_ref=_i.value;} +var callback=_ref;callback.apply(this,args);}} +return this;}},{key:"off",value:function off(event,fn){if(!this._callbacks||arguments.length===0){this._callbacks={};return this;} +var callbacks=this._callbacks[event];if(!callbacks){return this;} +if(arguments.length===1){delete this._callbacks[event];return this;} +for(var i=0;i=_iterator2.length)break;_ref2=_iterator2[_i2++];}else{_i2=_iterator2.next();if(_i2.done)break;_ref2=_i2.value;} +var child=_ref2;if(/(^| )dz-message($| )/.test(child.className)){messageElement=child;child.className="dz-message";break;}} +if(!messageElement){messageElement=Dropzone.createElement("
");this.element.appendChild(messageElement);} +var span=messageElement.getElementsByTagName("span")[0];if(span){if(span.textContent!=null){span.textContent=this.options.dictFallbackMessage;}else if(span.innerText!=null){span.innerText=this.options.dictFallbackMessage;}} +return this.element.appendChild(this.getFallbackForm());},resize:function resize(file,width,height,resizeMethod){var info={srcX:0,srcY:0,srcWidth:file.width,srcHeight:file.height};var srcRatio=file.width/file.height;if(width==null&&height==null){width=info.srcWidth;height=info.srcHeight;}else if(width==null){width=height*srcRatio;}else if(height==null){height=width/srcRatio;} +width=Math.min(width,info.srcWidth);height=Math.min(height,info.srcHeight);var trgRatio=width/height;if(info.srcWidth>width||info.srcHeight>height){if(resizeMethod==='crop'){if(srcRatio>trgRatio){info.srcHeight=file.height;info.srcWidth=info.srcHeight*trgRatio;}else{info.srcWidth=file.width;info.srcHeight=info.srcWidth/trgRatio;}}else if(resizeMethod==='contain'){if(srcRatio>trgRatio){height=width/srcRatio;}else{width=height*srcRatio;}}else{throw new Error("Unknown resizeMethod '"+resizeMethod+"'");}} +info.srcX=(file.width-info.srcWidth)/2;info.srcY=(file.height-info.srcHeight)/2;info.trgWidth=width;info.trgHeight=height;return info;},transformFile:function transformFile(file,done){if((this.options.resizeWidth||this.options.resizeHeight)&&file.type.match(/image.*/)){return this.resizeImage(file,this.options.resizeWidth,this.options.resizeHeight,this.options.resizeMethod,done);}else{return done(file);}},previewTemplate:"
\n
\n
\n
\n
\n
\n
\n
\n
\n \n Check\n \n \n \n \n \n
\n
\n \n Error\n \n \n \n \n \n \n \n
\n
",drop:function drop(e){return this.element.classList.remove("dz-drag-hover");},dragstart:function dragstart(e){},dragend:function dragend(e){return this.element.classList.remove("dz-drag-hover");},dragenter:function dragenter(e){return this.element.classList.add("dz-drag-hover");},dragover:function dragover(e){return this.element.classList.add("dz-drag-hover");},dragleave:function dragleave(e){return this.element.classList.remove("dz-drag-hover");},paste:function paste(e){},reset:function reset(){return this.element.classList.remove("dz-started");},addedfile:function addedfile(file){var _this2=this;if(this.element===this.previewsContainer){this.element.classList.add("dz-started");} +if(this.previewsContainer){file.previewElement=Dropzone.createElement(this.options.previewTemplate.trim());file.previewTemplate=file.previewElement;this.previewsContainer.appendChild(file.previewElement);for(var _iterator3=file.previewElement.querySelectorAll("[data-dz-name]"),_isArray3=true,_i3=0,_iterator3=_isArray3?_iterator3:_iterator3[Symbol.iterator]();;){var _ref3;if(_isArray3){if(_i3>=_iterator3.length)break;_ref3=_iterator3[_i3++];}else{_i3=_iterator3.next();if(_i3.done)break;_ref3=_i3.value;} +var node=_ref3;node.textContent=file.name;} +for(var _iterator4=file.previewElement.querySelectorAll("[data-dz-size]"),_isArray4=true,_i4=0,_iterator4=_isArray4?_iterator4:_iterator4[Symbol.iterator]();;){if(_isArray4){if(_i4>=_iterator4.length)break;node=_iterator4[_i4++];}else{_i4=_iterator4.next();if(_i4.done)break;node=_i4.value;} +node.innerHTML=this.filesize(file.size);} +if(this.options.addRemoveLinks){file._removeLink=Dropzone.createElement(""+this.options.dictRemoveFile+"");file.previewElement.appendChild(file._removeLink);} +var removeFileEvent=function removeFileEvent(e){e.preventDefault();e.stopPropagation();if(file.status===Dropzone.UPLOADING){return Dropzone.confirm(_this2.options.dictCancelUploadConfirmation,function(){return _this2.removeFile(file);});}else{if(_this2.options.dictRemoveFileConfirmation){return Dropzone.confirm(_this2.options.dictRemoveFileConfirmation,function(){return _this2.removeFile(file);});}else{return _this2.removeFile(file);}}};for(var _iterator5=file.previewElement.querySelectorAll("[data-dz-remove]"),_isArray5=true,_i5=0,_iterator5=_isArray5?_iterator5:_iterator5[Symbol.iterator]();;){var _ref4;if(_isArray5){if(_i5>=_iterator5.length)break;_ref4=_iterator5[_i5++];}else{_i5=_iterator5.next();if(_i5.done)break;_ref4=_i5.value;} +var removeLink=_ref4;removeLink.addEventListener("click",removeFileEvent);}}},removedfile:function removedfile(file){if(file.previewElement!=null&&file.previewElement.parentNode!=null){file.previewElement.parentNode.removeChild(file.previewElement);} +return this._updateMaxFilesReachedClass();},thumbnail:function thumbnail(file,dataUrl){if(file.previewElement){file.previewElement.classList.remove("dz-file-preview");for(var _iterator6=file.previewElement.querySelectorAll("[data-dz-thumbnail]"),_isArray6=true,_i6=0,_iterator6=_isArray6?_iterator6:_iterator6[Symbol.iterator]();;){var _ref5;if(_isArray6){if(_i6>=_iterator6.length)break;_ref5=_iterator6[_i6++];}else{_i6=_iterator6.next();if(_i6.done)break;_ref5=_i6.value;} +var thumbnailElement=_ref5;thumbnailElement.alt=file.name;thumbnailElement.src=dataUrl;} +return setTimeout(function(){return file.previewElement.classList.add("dz-image-preview");},1);}},error:function error(file,message){if(file.previewElement){file.previewElement.classList.add("dz-error");if(typeof message!=="String"&&message.error){message=message.error;} +for(var _iterator7=file.previewElement.querySelectorAll("[data-dz-errormessage]"),_isArray7=true,_i7=0,_iterator7=_isArray7?_iterator7:_iterator7[Symbol.iterator]();;){var _ref6;if(_isArray7){if(_i7>=_iterator7.length)break;_ref6=_iterator7[_i7++];}else{_i7=_iterator7.next();if(_i7.done)break;_ref6=_i7.value;} +var node=_ref6;node.textContent=message;}}},errormultiple:function errormultiple(){},processing:function processing(file){if(file.previewElement){file.previewElement.classList.add("dz-processing");if(file._removeLink){return file._removeLink.innerHTML=this.options.dictCancelUpload;}}},processingmultiple:function processingmultiple(){},uploadprogress:function uploadprogress(file,progress,bytesSent){if(file.previewElement){for(var _iterator8=file.previewElement.querySelectorAll("[data-dz-uploadprogress]"),_isArray8=true,_i8=0,_iterator8=_isArray8?_iterator8:_iterator8[Symbol.iterator]();;){var _ref7;if(_isArray8){if(_i8>=_iterator8.length)break;_ref7=_iterator8[_i8++];}else{_i8=_iterator8.next();if(_i8.done)break;_ref7=_i8.value;} +var node=_ref7;node.nodeName==='PROGRESS'?node.value=progress:node.style.width=progress+"%";}}},totaluploadprogress:function totaluploadprogress(){},sending:function sending(){},sendingmultiple:function sendingmultiple(){},success:function success(file){if(file.previewElement){return file.previewElement.classList.add("dz-success");}},successmultiple:function successmultiple(){},canceled:function canceled(file){return this.emit("error",file,this.options.dictUploadCanceled);},canceledmultiple:function canceledmultiple(){},complete:function complete(file){if(file._removeLink){file._removeLink.innerHTML=this.options.dictRemoveFile;} +if(file.previewElement){return file.previewElement.classList.add("dz-complete");}},completemultiple:function completemultiple(){},maxfilesexceeded:function maxfilesexceeded(){},maxfilesreached:function maxfilesreached(){},queuecomplete:function queuecomplete(){},addedfiles:function addedfiles(){}};this.prototype._thumbnailQueue=[];this.prototype._processingThumbnail=false;}},{key:"extend",value:function extend(target){for(var _len2=arguments.length,objects=Array(_len2>1?_len2-1:0),_key2=1;_key2<_len2;_key2++){objects[_key2-1]=arguments[_key2];} +for(var _iterator9=objects,_isArray9=true,_i9=0,_iterator9=_isArray9?_iterator9:_iterator9[Symbol.iterator]();;){var _ref8;if(_isArray9){if(_i9>=_iterator9.length)break;_ref8=_iterator9[_i9++];}else{_i9=_iterator9.next();if(_i9.done)break;_ref8=_i9.value;} +var object=_ref8;for(var key in object){var val=object[key];target[key]=val;}} +return target;}}]);function Dropzone(el,options){_classCallCheck(this,Dropzone);var _this=_possibleConstructorReturn(this,(Dropzone.__proto__||Object.getPrototypeOf(Dropzone)).call(this));var fallback=void 0,left=void 0;_this.element=el;_this.version=Dropzone.version;_this.defaultOptions.previewTemplate=_this.defaultOptions.previewTemplate.replace(/\n*/g,"");_this.clickableElements=[];_this.listeners=[];_this.files=[];if(typeof _this.element==="string"){_this.element=document.querySelector(_this.element);} +if(!_this.element||_this.element.nodeType==null){throw new Error("Invalid dropzone element.");} +if(_this.element.dropzone){throw new Error("Dropzone already attached.");} +Dropzone.instances.push(_this);_this.element.dropzone=_this;var elementOptions=(left=Dropzone.optionsForElement(_this.element))!=null?left:{};_this.options=Dropzone.extend({},_this.defaultOptions,elementOptions,options!=null?options:{});if(_this.options.forceFallback||!Dropzone.isBrowserSupported()){var _ret;return _ret=_this.options.fallback.call(_this),_possibleConstructorReturn(_this,_ret);} +if(_this.options.url==null){_this.options.url=_this.element.getAttribute("action");} +if(!_this.options.url){throw new Error("No URL provided.");} +if(_this.options.acceptedFiles&&_this.options.acceptedMimeTypes){throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");} +if(_this.options.uploadMultiple&&_this.options.chunking){throw new Error('You cannot set both: uploadMultiple and chunking.');} +if(_this.options.acceptedMimeTypes){_this.options.acceptedFiles=_this.options.acceptedMimeTypes;delete _this.options.acceptedMimeTypes;} +if(_this.options.renameFilename!=null){_this.options.renameFile=function(file){return _this.options.renameFilename.call(_this,file.name,file);};} +_this.options.method=_this.options.method.toUpperCase();if((fallback=_this.getExistingFallback())&&fallback.parentNode){fallback.parentNode.removeChild(fallback);} +if(_this.options.previewsContainer!==false){if(_this.options.previewsContainer){_this.previewsContainer=Dropzone.getElement(_this.options.previewsContainer,"previewsContainer");}else{_this.previewsContainer=_this.element;}} +if(_this.options.clickable){if(_this.options.clickable===true){_this.clickableElements=[_this.element];}else{_this.clickableElements=Dropzone.getElements(_this.options.clickable,"clickable");}} +_this.init();return _this;} +_createClass(Dropzone,[{key:"getAcceptedFiles",value:function getAcceptedFiles(){return this.files.filter(function(file){return file.accepted;}).map(function(file){return file;});}},{key:"getRejectedFiles",value:function getRejectedFiles(){return this.files.filter(function(file){return!file.accepted;}).map(function(file){return file;});}},{key:"getFilesWithStatus",value:function getFilesWithStatus(status){return this.files.filter(function(file){return file.status===status;}).map(function(file){return file;});}},{key:"getQueuedFiles",value:function getQueuedFiles(){return this.getFilesWithStatus(Dropzone.QUEUED);}},{key:"getUploadingFiles",value:function getUploadingFiles(){return this.getFilesWithStatus(Dropzone.UPLOADING);}},{key:"getAddedFiles",value:function getAddedFiles(){return this.getFilesWithStatus(Dropzone.ADDED);}},{key:"getActiveFiles",value:function getActiveFiles(){return this.files.filter(function(file){return file.status===Dropzone.UPLOADING||file.status===Dropzone.QUEUED;}).map(function(file){return file;});}},{key:"init",value:function init(){var _this3=this;if(this.element.tagName==="form"){this.element.setAttribute("enctype","multipart/form-data");} +if(this.element.classList.contains("dropzone")&&!this.element.querySelector(".dz-message")){this.element.appendChild(Dropzone.createElement("
"+this.options.dictDefaultMessage+"
"));} +if(this.clickableElements.length){var setupHiddenFileInput=function setupHiddenFileInput(){if(_this3.hiddenFileInput){_this3.hiddenFileInput.parentNode.removeChild(_this3.hiddenFileInput);} +_this3.hiddenFileInput=document.createElement("input");_this3.hiddenFileInput.setAttribute("type","file");if(_this3.options.maxFiles===null||_this3.options.maxFiles>1){_this3.hiddenFileInput.setAttribute("multiple","multiple");} +_this3.hiddenFileInput.className="dz-hidden-input";if(_this3.options.acceptedFiles!==null){_this3.hiddenFileInput.setAttribute("accept",_this3.options.acceptedFiles);} +if(_this3.options.capture!==null){_this3.hiddenFileInput.setAttribute("capture",_this3.options.capture);} +_this3.hiddenFileInput.style.visibility="hidden";_this3.hiddenFileInput.style.position="absolute";_this3.hiddenFileInput.style.top="0";_this3.hiddenFileInput.style.left="0";_this3.hiddenFileInput.style.height="0";_this3.hiddenFileInput.style.width="0";Dropzone.getElement(_this3.options.hiddenInputContainer,'hiddenInputContainer').appendChild(_this3.hiddenFileInput);return _this3.hiddenFileInput.addEventListener("change",function(){var files=_this3.hiddenFileInput.files;if(files.length){for(var _iterator10=files,_isArray10=true,_i10=0,_iterator10=_isArray10?_iterator10:_iterator10[Symbol.iterator]();;){var _ref9;if(_isArray10){if(_i10>=_iterator10.length)break;_ref9=_iterator10[_i10++];}else{_i10=_iterator10.next();if(_i10.done)break;_ref9=_i10.value;} +var file=_ref9;_this3.addFile(file);}} +_this3.emit("addedfiles",files);return setupHiddenFileInput();});};setupHiddenFileInput();} +this.URL=window.URL!==null?window.URL:window.webkitURL;for(var _iterator11=this.events,_isArray11=true,_i11=0,_iterator11=_isArray11?_iterator11:_iterator11[Symbol.iterator]();;){var _ref10;if(_isArray11){if(_i11>=_iterator11.length)break;_ref10=_iterator11[_i11++];}else{_i11=_iterator11.next();if(_i11.done)break;_ref10=_i11.value;} +var eventName=_ref10;this.on(eventName,this.options[eventName]);} +this.on("uploadprogress",function(){return _this3.updateTotalUploadProgress();});this.on("removedfile",function(){return _this3.updateTotalUploadProgress();});this.on("canceled",function(file){return _this3.emit("complete",file);});this.on("complete",function(file){if(_this3.getAddedFiles().length===0&&_this3.getUploadingFiles().length===0&&_this3.getQueuedFiles().length===0){return setTimeout(function(){return _this3.emit("queuecomplete");},0);}});var noPropagation=function noPropagation(e){e.stopPropagation();if(e.preventDefault){return e.preventDefault();}else{return e.returnValue=false;}};this.listeners=[{element:this.element,events:{"dragstart":function dragstart(e){return _this3.emit("dragstart",e);},"dragenter":function dragenter(e){noPropagation(e);return _this3.emit("dragenter",e);},"dragover":function dragover(e){var efct=void 0;try{efct=e.dataTransfer.effectAllowed;}catch(error){} +e.dataTransfer.dropEffect='move'===efct||'linkMove'===efct?'move':'copy';noPropagation(e);return _this3.emit("dragover",e);},"dragleave":function dragleave(e){return _this3.emit("dragleave",e);},"drop":function drop(e){noPropagation(e);return _this3.drop(e);},"dragend":function dragend(e){return _this3.emit("dragend",e);}}}];this.clickableElements.forEach(function(clickableElement){return _this3.listeners.push({element:clickableElement,events:{"click":function click(evt){if(clickableElement!==_this3.element||evt.target===_this3.element||Dropzone.elementInside(evt.target,_this3.element.querySelector(".dz-message"))){_this3.hiddenFileInput.click();} +return true;}}});});this.enable();return this.options.init.call(this);}},{key:"destroy",value:function destroy(){this.disable();this.removeAllFiles(true);if(this.hiddenFileInput!=null?this.hiddenFileInput.parentNode:undefined){this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput);this.hiddenFileInput=null;} +delete this.element.dropzone;return Dropzone.instances.splice(Dropzone.instances.indexOf(this),1);}},{key:"updateTotalUploadProgress",value:function updateTotalUploadProgress(){var totalUploadProgress=void 0;var totalBytesSent=0;var totalBytes=0;var activeFiles=this.getActiveFiles();if(activeFiles.length){for(var _iterator12=this.getActiveFiles(),_isArray12=true,_i12=0,_iterator12=_isArray12?_iterator12:_iterator12[Symbol.iterator]();;){var _ref11;if(_isArray12){if(_i12>=_iterator12.length)break;_ref11=_iterator12[_i12++];}else{_i12=_iterator12.next();if(_i12.done)break;_ref11=_i12.value;} +var file=_ref11;totalBytesSent+=file.upload.bytesSent;totalBytes+=file.upload.total;} +totalUploadProgress=100*totalBytesSent/totalBytes;}else{totalUploadProgress=100;} +return this.emit("totaluploadprogress",totalUploadProgress,totalBytes,totalBytesSent);}},{key:"_getParamName",value:function _getParamName(n){if(typeof this.options.paramName==="function"){return this.options.paramName(n);}else{return""+this.options.paramName+(this.options.uploadMultiple?"["+n+"]":"");}}},{key:"_renameFile",value:function _renameFile(file){if(typeof this.options.renameFile!=="function"){return file.name;} +return this.options.renameFile(file);}},{key:"getFallbackForm",value:function getFallbackForm(){var existingFallback=void 0,form=void 0;if(existingFallback=this.getExistingFallback()){return existingFallback;} +var fieldsString="
";if(this.options.dictFallbackText){fieldsString+="

"+this.options.dictFallbackText+"

";} +fieldsString+="
";var fields=Dropzone.createElement(fieldsString);if(this.element.tagName!=="FORM"){form=Dropzone.createElement("
");form.appendChild(fields);}else{this.element.setAttribute("enctype","multipart/form-data");this.element.setAttribute("method",this.options.method);} +return form!=null?form:fields;}},{key:"getExistingFallback",value:function getExistingFallback(){var getFallback=function getFallback(elements){for(var _iterator13=elements,_isArray13=true,_i13=0,_iterator13=_isArray13?_iterator13:_iterator13[Symbol.iterator]();;){var _ref12;if(_isArray13){if(_i13>=_iterator13.length)break;_ref12=_iterator13[_i13++];}else{_i13=_iterator13.next();if(_i13.done)break;_ref12=_i13.value;} +var el=_ref12;if(/(^| )fallback($| )/.test(el.className)){return el;}}};var _arr=["div","form"];for(var _i14=0;_i14<_arr.length;_i14++){var tagName=_arr[_i14];var fallback;if(fallback=getFallback(this.element.getElementsByTagName(tagName))){return fallback;}}}},{key:"setupEventListeners",value:function setupEventListeners(){return this.listeners.map(function(elementListeners){return function(){var result=[];for(var event in elementListeners.events){var listener=elementListeners.events[event];result.push(elementListeners.element.addEventListener(event,listener,false));} +return result;}();});}},{key:"removeEventListeners",value:function removeEventListeners(){return this.listeners.map(function(elementListeners){return function(){var result=[];for(var event in elementListeners.events){var listener=elementListeners.events[event];result.push(elementListeners.element.removeEventListener(event,listener,false));} +return result;}();});}},{key:"disable",value:function disable(){var _this4=this;this.clickableElements.forEach(function(element){return element.classList.remove("dz-clickable");});this.removeEventListeners();this.disabled=true;return this.files.map(function(file){return _this4.cancelUpload(file);});}},{key:"enable",value:function enable(){delete this.disabled;this.clickableElements.forEach(function(element){return element.classList.add("dz-clickable");});return this.setupEventListeners();}},{key:"filesize",value:function filesize(size){var selectedSize=0;var selectedUnit="b";if(size>0){var units=['tb','gb','mb','kb','b'];for(var i=0;i=cutoff){selectedSize=size/Math.pow(this.options.filesizeBase,4-i);selectedUnit=unit;break;}} +selectedSize=Math.round(10*selectedSize)/10;} +return""+selectedSize+" "+this.options.dictFileSizeUnits[selectedUnit];}},{key:"_updateMaxFilesReachedClass",value:function _updateMaxFilesReachedClass(){if(this.options.maxFiles!=null&&this.getAcceptedFiles().length>=this.options.maxFiles){if(this.getAcceptedFiles().length===this.options.maxFiles){this.emit('maxfilesreached',this.files);} +return this.element.classList.add("dz-max-files-reached");}else{return this.element.classList.remove("dz-max-files-reached");}}},{key:"drop",value:function drop(e){if(!e.dataTransfer){return;} +this.emit("drop",e);var files=[];for(var i=0;i=_iterator14.length)break;_ref13=_iterator14[_i15++];}else{_i15=_iterator14.next();if(_i15.done)break;_ref13=_i15.value;} +var file=_ref13;this.addFile(file);}}},{key:"_addFilesFromItems",value:function _addFilesFromItems(items){var _this5=this;return function(){var result=[];for(var _iterator15=items,_isArray15=true,_i16=0,_iterator15=_isArray15?_iterator15:_iterator15[Symbol.iterator]();;){var _ref14;if(_isArray15){if(_i16>=_iterator15.length)break;_ref14=_iterator15[_i16++];}else{_i16=_iterator15.next();if(_i16.done)break;_ref14=_i16.value;} +var item=_ref14;var entry;if(item.webkitGetAsEntry!=null&&(entry=item.webkitGetAsEntry())){if(entry.isFile){result.push(_this5.addFile(item.getAsFile()));}else if(entry.isDirectory){result.push(_this5._addFilesFromDirectory(entry,entry.name));}else{result.push(undefined);}}else if(item.getAsFile!=null){if(item.kind==null||item.kind==="file"){result.push(_this5.addFile(item.getAsFile()));}else{result.push(undefined);}}else{result.push(undefined);}} +return result;}();}},{key:"_addFilesFromDirectory",value:function _addFilesFromDirectory(directory,path){var _this6=this;var dirReader=directory.createReader();var errorHandler=function errorHandler(error){return __guardMethod__(console,'log',function(o){return o.log(error);});};var readEntries=function readEntries(){return dirReader.readEntries(function(entries){if(entries.length>0){for(var _iterator16=entries,_isArray16=true,_i17=0,_iterator16=_isArray16?_iterator16:_iterator16[Symbol.iterator]();;){var _ref15;if(_isArray16){if(_i17>=_iterator16.length)break;_ref15=_iterator16[_i17++];}else{_i17=_iterator16.next();if(_i17.done)break;_ref15=_i17.value;} +var entry=_ref15;if(entry.isFile){entry.file(function(file){if(_this6.options.ignoreHiddenFiles&&file.name.substring(0,1)==='.'){return;} +file.fullPath=path+"/"+file.name;return _this6.addFile(file);});}else if(entry.isDirectory){_this6._addFilesFromDirectory(entry,path+"/"+entry.name);}} +readEntries();} +return null;},errorHandler);};return readEntries();}},{key:"accept",value:function accept(file,done){if(this.options.maxFilesize&&file.size>this.options.maxFilesize*1024*1024){return done(this.options.dictFileTooBig.replace("{{filesize}}",Math.round(file.size/1024/10.24)/100).replace("{{maxFilesize}}",this.options.maxFilesize));}else if(!Dropzone.isValidFile(file,this.options.acceptedFiles)){return done(this.options.dictInvalidFileType);}else if(this.options.maxFiles!=null&&this.getAcceptedFiles().length>=this.options.maxFiles){done(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}",this.options.maxFiles));return this.emit("maxfilesexceeded",file);}else{return this.options.accept.call(this,file,done);}}},{key:"addFile",value:function addFile(file){var _this7=this;file.upload={uuid:Dropzone.uuidv4(),progress:0,total:file.size,bytesSent:0,filename:this._renameFile(file),chunked:this.options.chunking&&(this.options.forceChunking||file.size>this.options.chunkSize),totalChunkCount:Math.ceil(file.size/this.options.chunkSize)};this.files.push(file);file.status=Dropzone.ADDED;this.emit("addedfile",file);this._enqueueThumbnail(file);return this.accept(file,function(error){if(error){file.accepted=false;_this7._errorProcessing([file],error);}else{file.accepted=true;if(_this7.options.autoQueue){_this7.enqueueFile(file);}} +return _this7._updateMaxFilesReachedClass();});}},{key:"enqueueFiles",value:function enqueueFiles(files){for(var _iterator17=files,_isArray17=true,_i18=0,_iterator17=_isArray17?_iterator17:_iterator17[Symbol.iterator]();;){var _ref16;if(_isArray17){if(_i18>=_iterator17.length)break;_ref16=_iterator17[_i18++];}else{_i18=_iterator17.next();if(_i18.done)break;_ref16=_i18.value;} +var file=_ref16;this.enqueueFile(file);} +return null;}},{key:"enqueueFile",value:function enqueueFile(file){var _this8=this;if(file.status===Dropzone.ADDED&&file.accepted===true){file.status=Dropzone.QUEUED;if(this.options.autoProcessQueue){return setTimeout(function(){return _this8.processQueue();},0);}}else{throw new Error("This file can't be queued because it has already been processed or was rejected.");}}},{key:"_enqueueThumbnail",value:function _enqueueThumbnail(file){var _this9=this;if(this.options.createImageThumbnails&&file.type.match(/image.*/)&&file.size<=this.options.maxThumbnailFilesize*1024*1024){this._thumbnailQueue.push(file);return setTimeout(function(){return _this9._processThumbnailQueue();},0);}}},{key:"_processThumbnailQueue",value:function _processThumbnailQueue(){var _this10=this;if(this._processingThumbnail||this._thumbnailQueue.length===0){return;} +this._processingThumbnail=true;var file=this._thumbnailQueue.shift();return this.createThumbnail(file,this.options.thumbnailWidth,this.options.thumbnailHeight,this.options.thumbnailMethod,true,function(dataUrl){_this10.emit("thumbnail",file,dataUrl);_this10._processingThumbnail=false;return _this10._processThumbnailQueue();});}},{key:"removeFile",value:function removeFile(file){if(file.status===Dropzone.UPLOADING){this.cancelUpload(file);} +this.files=without(this.files,file);this.emit("removedfile",file);if(this.files.length===0){return this.emit("reset");}}},{key:"removeAllFiles",value:function removeAllFiles(cancelIfNecessary){if(cancelIfNecessary==null){cancelIfNecessary=false;} +for(var _iterator18=this.files.slice(),_isArray18=true,_i19=0,_iterator18=_isArray18?_iterator18:_iterator18[Symbol.iterator]();;){var _ref17;if(_isArray18){if(_i19>=_iterator18.length)break;_ref17=_iterator18[_i19++];}else{_i19=_iterator18.next();if(_i19.done)break;_ref17=_i19.value;} +var file=_ref17;if(file.status!==Dropzone.UPLOADING||cancelIfNecessary){this.removeFile(file);}} +return null;}},{key:"resizeImage",value:function resizeImage(file,width,height,resizeMethod,callback){var _this11=this;return this.createThumbnail(file,width,height,resizeMethod,true,function(dataUrl,canvas){if(canvas==null){return callback(file);}else{var resizeMimeType=_this11.options.resizeMimeType;if(resizeMimeType==null){resizeMimeType=file.type;} +var resizedDataURL=canvas.toDataURL(resizeMimeType,_this11.options.resizeQuality);if(resizeMimeType==='image/jpeg'||resizeMimeType==='image/jpg'){resizedDataURL=ExifRestore.restore(file.dataURL,resizedDataURL);} +return callback(Dropzone.dataURItoBlob(resizedDataURL));}});}},{key:"createThumbnail",value:function createThumbnail(file,width,height,resizeMethod,fixOrientation,callback){var _this12=this;var fileReader=new FileReader();fileReader.onload=function(){file.dataURL=fileReader.result;if(file.type==="image/svg+xml"){if(callback!=null){callback(fileReader.result);} +return;} +return _this12.createThumbnailFromUrl(file,width,height,resizeMethod,fixOrientation,callback);};return fileReader.readAsDataURL(file);}},{key:"createThumbnailFromUrl",value:function createThumbnailFromUrl(file,width,height,resizeMethod,fixOrientation,callback,crossOrigin){var _this13=this;var img=document.createElement("img");if(crossOrigin){img.crossOrigin=crossOrigin;} +img.onload=function(){var loadExif=function loadExif(callback){return callback(1);};if(typeof EXIF!=='undefined'&&EXIF!==null&&fixOrientation){loadExif=function loadExif(callback){return EXIF.getData(img,function(){return callback(EXIF.getTag(this,'Orientation'));});};} +return loadExif(function(orientation){file.width=img.width;file.height=img.height;var resizeInfo=_this13.options.resize.call(_this13,file,width,height,resizeMethod);var canvas=document.createElement("canvas");var ctx=canvas.getContext("2d");canvas.width=resizeInfo.trgWidth;canvas.height=resizeInfo.trgHeight;if(orientation>4){canvas.width=resizeInfo.trgHeight;canvas.height=resizeInfo.trgWidth;} +switch(orientation){case 2:ctx.translate(canvas.width,0);ctx.scale(-1,1);break;case 3:ctx.translate(canvas.width,canvas.height);ctx.rotate(Math.PI);break;case 4:ctx.translate(0,canvas.height);ctx.scale(1,-1);break;case 5:ctx.rotate(0.5*Math.PI);ctx.scale(1,-1);break;case 6:ctx.rotate(0.5*Math.PI);ctx.translate(0,-canvas.width);break;case 7:ctx.rotate(0.5*Math.PI);ctx.translate(canvas.height,-canvas.width);ctx.scale(-1,1);break;case 8:ctx.rotate(-0.5*Math.PI);ctx.translate(-canvas.height,0);break;} +drawImageIOSFix(ctx,img,resizeInfo.srcX!=null?resizeInfo.srcX:0,resizeInfo.srcY!=null?resizeInfo.srcY:0,resizeInfo.srcWidth,resizeInfo.srcHeight,resizeInfo.trgX!=null?resizeInfo.trgX:0,resizeInfo.trgY!=null?resizeInfo.trgY:0,resizeInfo.trgWidth,resizeInfo.trgHeight);var thumbnail=canvas.toDataURL("image/png");if(callback!=null){return callback(thumbnail,canvas);}});};if(callback!=null){img.onerror=callback;} +return img.src=file.dataURL;}},{key:"processQueue",value:function processQueue(){var parallelUploads=this.options.parallelUploads;var processingLength=this.getUploadingFiles().length;var i=processingLength;if(processingLength>=parallelUploads){return;} +var queuedFiles=this.getQueuedFiles();if(!(queuedFiles.length>0)){return;} +if(this.options.uploadMultiple){return this.processFiles(queuedFiles.slice(0,parallelUploads-processingLength));}else{while(i=_iterator19.length)break;_ref18=_iterator19[_i20++];}else{_i20=_iterator19.next();if(_i20.done)break;_ref18=_i20.value;} +var file=_ref18;file.processing=true;file.status=Dropzone.UPLOADING;this.emit("processing",file);} +if(this.options.uploadMultiple){this.emit("processingmultiple",files);} +return this.uploadFiles(files);}},{key:"_getFilesWithXhr",value:function _getFilesWithXhr(xhr){var files=void 0;return files=this.files.filter(function(file){return file.xhr===xhr;}).map(function(file){return file;});}},{key:"cancelUpload",value:function cancelUpload(file){if(file.status===Dropzone.UPLOADING){var groupedFiles=this._getFilesWithXhr(file.xhr);for(var _iterator20=groupedFiles,_isArray20=true,_i21=0,_iterator20=_isArray20?_iterator20:_iterator20[Symbol.iterator]();;){var _ref19;if(_isArray20){if(_i21>=_iterator20.length)break;_ref19=_iterator20[_i21++];}else{_i21=_iterator20.next();if(_i21.done)break;_ref19=_i21.value;} +var groupedFile=_ref19;groupedFile.status=Dropzone.CANCELED;} +if(typeof file.xhr!=='undefined'){file.xhr.abort();} +for(var _iterator21=groupedFiles,_isArray21=true,_i22=0,_iterator21=_isArray21?_iterator21:_iterator21[Symbol.iterator]();;){var _ref20;if(_isArray21){if(_i22>=_iterator21.length)break;_ref20=_iterator21[_i22++];}else{_i22=_iterator21.next();if(_i22.done)break;_ref20=_i22.value;} +var _groupedFile=_ref20;this.emit("canceled",_groupedFile);} +if(this.options.uploadMultiple){this.emit("canceledmultiple",groupedFiles);}}else if(file.status===Dropzone.ADDED||file.status===Dropzone.QUEUED){file.status=Dropzone.CANCELED;this.emit("canceled",file);if(this.options.uploadMultiple){this.emit("canceledmultiple",[file]);}} +if(this.options.autoProcessQueue){return this.processQueue();}}},{key:"resolveOption",value:function resolveOption(option){if(typeof option==='function'){for(var _len3=arguments.length,args=Array(_len3>1?_len3-1:0),_key3=1;_key3<_len3;_key3++){args[_key3-1]=arguments[_key3];} +return option.apply(this,args);} +return option;}},{key:"uploadFile",value:function uploadFile(file){return this.uploadFiles([file]);}},{key:"uploadFiles",value:function uploadFiles(files){var _this14=this;this._transformFiles(files,function(transformedFiles){if(files[0].upload.chunked){var file=files[0];var transformedFile=transformedFiles[0];var startedChunkCount=0;file.upload.chunks=[];var handleNextChunk=function handleNextChunk(){var chunkIndex=0;while(file.upload.chunks[chunkIndex]!==undefined){chunkIndex++;} +if(chunkIndex>=file.upload.totalChunkCount)return;startedChunkCount++;var start=chunkIndex*_this14.options.chunkSize;var end=Math.min(start+_this14.options.chunkSize,file.size);var dataBlock={name:_this14._getParamName(0),data:transformedFile.webkitSlice?transformedFile.webkitSlice(start,end):transformedFile.slice(start,end),filename:file.upload.filename,chunkIndex:chunkIndex};file.upload.chunks[chunkIndex]={file:file,index:chunkIndex,dataBlock:dataBlock,status:Dropzone.UPLOADING,progress:0,retries:0};_this14._uploadData(files,[dataBlock]);};file.upload.finishedChunkUpload=function(chunk){var allFinished=true;chunk.status=Dropzone.SUCCESS;chunk.dataBlock=null;chunk.xhr=null;for(var i=0;i=_iterator22.length)break;_ref21=_iterator22[_i24++];}else{_i24=_iterator22.next();if(_i24.done)break;_ref21=_i24.value;} +var file=_ref21;file.xhr=xhr;} +if(files[0].upload.chunked){files[0].upload.chunks[dataBlocks[0].chunkIndex].xhr=xhr;} +var method=this.resolveOption(this.options.method,files);var url=this.resolveOption(this.options.url,files);xhr.open(method,url,true);xhr.timeout=this.resolveOption(this.options.timeout,files);xhr.withCredentials=!!this.options.withCredentials;xhr.onload=function(e){_this15._finishedUploading(files,xhr,e);};xhr.onerror=function(){_this15._handleUploadError(files,xhr);};var progressObj=xhr.upload!=null?xhr.upload:xhr;progressObj.onprogress=function(e){return _this15._updateFilesUploadProgress(files,xhr,e);};var headers={"Accept":"application/json","Cache-Control":"no-cache","X-Requested-With":"XMLHttpRequest"};if(this.options.headers){Dropzone.extend(headers,this.options.headers);} +for(var headerName in headers){var headerValue=headers[headerName];if(headerValue){xhr.setRequestHeader(headerName,headerValue);}} +var formData=new FormData();if(this.options.params){var additionalParams=this.options.params;if(typeof additionalParams==='function'){additionalParams=additionalParams.call(this,files,xhr,files[0].upload.chunked?this._getChunk(files[0],xhr):null);} +for(var key in additionalParams){var value=additionalParams[key];formData.append(key,value);}} +for(var _iterator23=files,_isArray23=true,_i25=0,_iterator23=_isArray23?_iterator23:_iterator23[Symbol.iterator]();;){var _ref22;if(_isArray23){if(_i25>=_iterator23.length)break;_ref22=_iterator23[_i25++];}else{_i25=_iterator23.next();if(_i25.done)break;_ref22=_i25.value;} +var _file=_ref22;this.emit("sending",_file,xhr,formData);} +if(this.options.uploadMultiple){this.emit("sendingmultiple",files,xhr,formData);} +this._addFormElementData(formData);for(var i=0;i=_iterator24.length)break;_ref23=_iterator24[_i26++];}else{_i26=_iterator24.next();if(_i26.done)break;_ref23=_i26.value;} +var input=_ref23;var inputName=input.getAttribute("name");var inputType=input.getAttribute("type");if(inputType)inputType=inputType.toLowerCase();if(typeof inputName==='undefined'||inputName===null)continue;if(input.tagName==="SELECT"&&input.hasAttribute("multiple")){for(var _iterator25=input.options,_isArray25=true,_i27=0,_iterator25=_isArray25?_iterator25:_iterator25[Symbol.iterator]();;){var _ref24;if(_isArray25){if(_i27>=_iterator25.length)break;_ref24=_iterator25[_i27++];}else{_i27=_iterator25.next();if(_i27.done)break;_ref24=_i27.value;} +var option=_ref24;if(option.selected){formData.append(inputName,option.value);}}}else if(!inputType||inputType!=="checkbox"&&inputType!=="radio"||input.checked){formData.append(inputName,input.value);}}}}},{key:"_updateFilesUploadProgress",value:function _updateFilesUploadProgress(files,xhr,e){var progress=void 0;if(typeof e!=='undefined'){progress=100*e.loaded/e.total;if(files[0].upload.chunked){var file=files[0];var chunk=this._getChunk(file,xhr);chunk.progress=progress;chunk.total=e.total;chunk.bytesSent=e.loaded;var fileProgress=0,fileTotal=void 0,fileBytesSent=void 0;file.upload.progress=0;file.upload.total=0;file.upload.bytesSent=0;for(var i=0;i=_iterator26.length)break;_ref25=_iterator26[_i28++];}else{_i28=_iterator26.next();if(_i28.done)break;_ref25=_i28.value;} +var _file2=_ref25;_file2.upload.progress=progress;_file2.upload.total=e.total;_file2.upload.bytesSent=e.loaded;}} +for(var _iterator27=files,_isArray27=true,_i29=0,_iterator27=_isArray27?_iterator27:_iterator27[Symbol.iterator]();;){var _ref26;if(_isArray27){if(_i29>=_iterator27.length)break;_ref26=_iterator27[_i29++];}else{_i29=_iterator27.next();if(_i29.done)break;_ref26=_i29.value;} +var _file3=_ref26;this.emit("uploadprogress",_file3,_file3.upload.progress,_file3.upload.bytesSent);}}else{var allFilesFinished=true;progress=100;for(var _iterator28=files,_isArray28=true,_i30=0,_iterator28=_isArray28?_iterator28:_iterator28[Symbol.iterator]();;){var _ref27;if(_isArray28){if(_i30>=_iterator28.length)break;_ref27=_iterator28[_i30++];}else{_i30=_iterator28.next();if(_i30.done)break;_ref27=_i30.value;} +var _file4=_ref27;if(_file4.upload.progress!==100||_file4.upload.bytesSent!==_file4.upload.total){allFilesFinished=false;} +_file4.upload.progress=progress;_file4.upload.bytesSent=_file4.upload.total;} +if(allFilesFinished){return;} +for(var _iterator29=files,_isArray29=true,_i31=0,_iterator29=_isArray29?_iterator29:_iterator29[Symbol.iterator]();;){var _ref28;if(_isArray29){if(_i31>=_iterator29.length)break;_ref28=_iterator29[_i31++];}else{_i31=_iterator29.next();if(_i31.done)break;_ref28=_i31.value;} +var _file5=_ref28;this.emit("uploadprogress",_file5,progress,_file5.upload.bytesSent);}}}},{key:"_finishedUploading",value:function _finishedUploading(files,xhr,e){var response=void 0;if(files[0].status===Dropzone.CANCELED){return;} +if(xhr.readyState!==4){return;} +if(xhr.responseType!=='arraybuffer'&&xhr.responseType!=='blob'){response=xhr.responseText;if(xhr.getResponseHeader("content-type")&&~xhr.getResponseHeader("content-type").indexOf("application/json")){try{response=JSON.parse(response);}catch(error){e=error;response="Invalid JSON response from server.";}}} +this._updateFilesUploadProgress(files);if(!(200<=xhr.status&&xhr.status<300)){this._handleUploadError(files,xhr,response);}else{if(files[0].upload.chunked){files[0].upload.finishedChunkUpload(this._getChunk(files[0],xhr));}else{this._finished(files,response,e);}}}},{key:"_handleUploadError",value:function _handleUploadError(files,xhr,response){if(files[0].status===Dropzone.CANCELED){return;} +if(files[0].upload.chunked&&this.options.retryChunks){var chunk=this._getChunk(files[0],xhr);if(chunk.retries++=_iterator30.length)break;_ref29=_iterator30[_i32++];}else{_i32=_iterator30.next();if(_i32.done)break;_ref29=_i32.value;} +var file=_ref29;this._errorProcessing(files,response||this.options.dictResponseError.replace("{{statusCode}}",xhr.status),xhr);}}},{key:"submitRequest",value:function submitRequest(xhr,formData,files){xhr.send(formData);}},{key:"_finished",value:function _finished(files,responseText,e){for(var _iterator31=files,_isArray31=true,_i33=0,_iterator31=_isArray31?_iterator31:_iterator31[Symbol.iterator]();;){var _ref30;if(_isArray31){if(_i33>=_iterator31.length)break;_ref30=_iterator31[_i33++];}else{_i33=_iterator31.next();if(_i33.done)break;_ref30=_i33.value;} +var file=_ref30;file.status=Dropzone.SUCCESS;this.emit("success",file,responseText,e);this.emit("complete",file);} +if(this.options.uploadMultiple){this.emit("successmultiple",files,responseText,e);this.emit("completemultiple",files);} +if(this.options.autoProcessQueue){return this.processQueue();}}},{key:"_errorProcessing",value:function _errorProcessing(files,message,xhr){for(var _iterator32=files,_isArray32=true,_i34=0,_iterator32=_isArray32?_iterator32:_iterator32[Symbol.iterator]();;){var _ref31;if(_isArray32){if(_i34>=_iterator32.length)break;_ref31=_iterator32[_i34++];}else{_i34=_iterator32.next();if(_i34.done)break;_ref31=_i34.value;} +var file=_ref31;file.status=Dropzone.ERROR;this.emit("error",file,message,xhr);this.emit("complete",file);} +if(this.options.uploadMultiple){this.emit("errormultiple",files,message,xhr);this.emit("completemultiple",files);} +if(this.options.autoProcessQueue){return this.processQueue();}}}],[{key:"uuidv4",value:function uuidv4(){return'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,function(c){var r=Math.random()*16|0,v=c==='x'?r:r&0x3|0x8;return v.toString(16);});}}]);return Dropzone;}(Emitter);Dropzone.initClass();Dropzone.version="5.5.1";Dropzone.options={};Dropzone.optionsForElement=function(element){if(element.getAttribute("id")){return Dropzone.options[camelize(element.getAttribute("id"))];}else{return undefined;}};Dropzone.instances=[];Dropzone.forElement=function(element){if(typeof element==="string"){element=document.querySelector(element);} +if((element!=null?element.dropzone:undefined)==null){throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone.");} +return element.dropzone;};Dropzone.autoDiscover=true;Dropzone.discover=function(){var dropzones=void 0;if(document.querySelectorAll){dropzones=document.querySelectorAll(".dropzone");}else{dropzones=[];var checkElements=function checkElements(elements){return function(){var result=[];for(var _iterator33=elements,_isArray33=true,_i35=0,_iterator33=_isArray33?_iterator33:_iterator33[Symbol.iterator]();;){var _ref32;if(_isArray33){if(_i35>=_iterator33.length)break;_ref32=_iterator33[_i35++];}else{_i35=_iterator33.next();if(_i35.done)break;_ref32=_i35.value;} +var el=_ref32;if(/(^| )dropzone($| )/.test(el.className)){result.push(dropzones.push(el));}else{result.push(undefined);}} +return result;}();};checkElements(document.getElementsByTagName("div"));checkElements(document.getElementsByTagName("form"));} +return function(){var result=[];for(var _iterator34=dropzones,_isArray34=true,_i36=0,_iterator34=_isArray34?_iterator34:_iterator34[Symbol.iterator]();;){var _ref33;if(_isArray34){if(_i36>=_iterator34.length)break;_ref33=_iterator34[_i36++];}else{_i36=_iterator34.next();if(_i36.done)break;_ref33=_i36.value;} +var dropzone=_ref33;if(Dropzone.optionsForElement(dropzone)!==false){result.push(new Dropzone(dropzone));}else{result.push(undefined);}} +return result;}();};Dropzone.blacklistedBrowsers=[/opera.*(Macintosh|Windows Phone).*version\/12/i];Dropzone.isBrowserSupported=function(){var capableBrowser=true;if(window.File&&window.FileReader&&window.FileList&&window.Blob&&window.FormData&&document.querySelector){if(!("classList"in document.createElement("a"))){capableBrowser=false;}else{for(var _iterator35=Dropzone.blacklistedBrowsers,_isArray35=true,_i37=0,_iterator35=_isArray35?_iterator35:_iterator35[Symbol.iterator]();;){var _ref34;if(_isArray35){if(_i37>=_iterator35.length)break;_ref34=_iterator35[_i37++];}else{_i37=_iterator35.next();if(_i37.done)break;_ref34=_i37.value;} +var regex=_ref34;if(regex.test(navigator.userAgent)){capableBrowser=false;continue;}}}}else{capableBrowser=false;} +return capableBrowser;};Dropzone.dataURItoBlob=function(dataURI){var byteString=atob(dataURI.split(',')[1]);var mimeString=dataURI.split(',')[0].split(':')[1].split(';')[0];var ab=new ArrayBuffer(byteString.length);var ia=new Uint8Array(ab);for(var i=0,end=byteString.length,asc=0<=end;asc?i<=end:i>=end;asc?i++:i--){ia[i]=byteString.charCodeAt(i);} +return new Blob([ab],{type:mimeString});};var without=function without(list,rejectedItem){return list.filter(function(item){return item!==rejectedItem;}).map(function(item){return item;});};var camelize=function camelize(str){return str.replace(/[\-_](\w)/g,function(match){return match.charAt(1).toUpperCase();});};Dropzone.createElement=function(string){var div=document.createElement("div");div.innerHTML=string;return div.childNodes[0];};Dropzone.elementInside=function(element,container){if(element===container){return true;} +while(element=element.parentNode){if(element===container){return true;}} +return false;};Dropzone.getElement=function(el,name){var element=void 0;if(typeof el==="string"){element=document.querySelector(el);}else if(el.nodeType!=null){element=el;} +if(element==null){throw new Error("Invalid `"+name+"` option provided. Please provide a CSS selector or a plain HTML element.");} +return element;};Dropzone.getElements=function(els,name){var el=void 0,elements=void 0;if(els instanceof Array){elements=[];try{for(var _iterator36=els,_isArray36=true,_i38=0,_iterator36=_isArray36?_iterator36:_iterator36[Symbol.iterator]();;){if(_isArray36){if(_i38>=_iterator36.length)break;el=_iterator36[_i38++];}else{_i38=_iterator36.next();if(_i38.done)break;el=_i38.value;} +elements.push(this.getElement(el,name));}}catch(e){elements=null;}}else if(typeof els==="string"){elements=[];for(var _iterator37=document.querySelectorAll(els),_isArray37=true,_i39=0,_iterator37=_isArray37?_iterator37:_iterator37[Symbol.iterator]();;){if(_isArray37){if(_i39>=_iterator37.length)break;el=_iterator37[_i39++];}else{_i39=_iterator37.next();if(_i39.done)break;el=_i39.value;} +elements.push(el);}}else if(els.nodeType!=null){elements=[els];} +if(elements==null||!elements.length){throw new Error("Invalid `"+name+"` option provided. Please provide a CSS selector, a plain HTML element or a list of those.");} +return elements;};Dropzone.confirm=function(question,accepted,rejected){if(window.confirm(question)){return accepted();}else if(rejected!=null){return rejected();}};Dropzone.isValidFile=function(file,acceptedFiles){if(!acceptedFiles){return true;} +acceptedFiles=acceptedFiles.split(",");var mimeType=file.type;var baseMimeType=mimeType.replace(/\/.*$/,"");for(var _iterator38=acceptedFiles,_isArray38=true,_i40=0,_iterator38=_isArray38?_iterator38:_iterator38[Symbol.iterator]();;){var _ref35;if(_isArray38){if(_i40>=_iterator38.length)break;_ref35=_iterator38[_i40++];}else{_i40=_iterator38.next();if(_i40.done)break;_ref35=_i40.value;} +var validType=_ref35;validType=validType.trim();if(validType.charAt(0)==="."){if(file.name.toLowerCase().indexOf(validType.toLowerCase(),file.name.length-validType.length)!==-1){return true;}}else if(/\/\*$/.test(validType)){if(baseMimeType===validType.replace(/\/.*$/,"")){return true;}}else{if(mimeType===validType){return true;}}} +return false;};if(typeof jQuery!=='undefined'&&jQuery!==null){jQuery.fn.dropzone=function(options){return this.each(function(){return new Dropzone(this,options);});};} +if(typeof module!=='undefined'&&module!==null){module.exports=Dropzone;}else{window.Dropzone=Dropzone;} +Dropzone.ADDED="added";Dropzone.QUEUED="queued";Dropzone.ACCEPTED=Dropzone.QUEUED;Dropzone.UPLOADING="uploading";Dropzone.PROCESSING=Dropzone.UPLOADING;Dropzone.CANCELED="canceled";Dropzone.ERROR="error";Dropzone.SUCCESS="success";var detectVerticalSquash=function detectVerticalSquash(img){var iw=img.naturalWidth;var ih=img.naturalHeight;var canvas=document.createElement("canvas");canvas.width=1;canvas.height=ih;var ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);var _ctx$getImageData=ctx.getImageData(1,0,1,ih),data=_ctx$getImageData.data;var sy=0;var ey=ih;var py=ih;while(py>sy){var alpha=data[(py-1)*4+3];if(alpha===0){ey=py;}else{sy=py;} +py=ey+sy>>1;} +var ratio=py/ih;if(ratio===0){return 1;}else{return ratio;}};var drawImageIOSFix=function drawImageIOSFix(ctx,img,sx,sy,sw,sh,dx,dy,dw,dh){var vertSquashRatio=detectVerticalSquash(img);return ctx.drawImage(img,sx,sy,sw,sh,dx,dy,dw,dh/vertSquashRatio);};var ExifRestore=function(){function ExifRestore(){_classCallCheck(this,ExifRestore);} +_createClass(ExifRestore,null,[{key:"initClass",value:function initClass(){this.KEY_STR='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';}},{key:"encode64",value:function encode64(input){var output='';var chr1=undefined;var chr2=undefined;var chr3='';var enc1=undefined;var enc2=undefined;var enc3=undefined;var enc4='';var i=0;while(true){chr1=input[i++];chr2=input[i++];chr3=input[i++];enc1=chr1>>2;enc2=(chr1&3)<<4|chr2>>4;enc3=(chr2&15)<<2|chr3>>6;enc4=chr3&63;if(isNaN(chr2)){enc3=enc4=64;}else if(isNaN(chr3)){enc4=64;} +output=output+this.KEY_STR.charAt(enc1)+this.KEY_STR.charAt(enc2)+this.KEY_STR.charAt(enc3)+this.KEY_STR.charAt(enc4);chr1=chr2=chr3='';enc1=enc2=enc3=enc4='';if(!(irawImageArray.length){break;}} +return segments;}},{key:"decode64",value:function decode64(input){var output='';var chr1=undefined;var chr2=undefined;var chr3='';var enc1=undefined;var enc2=undefined;var enc3=undefined;var enc4='';var i=0;var buf=[];var base64test=/[^A-Za-z0-9\+\/\=]/g;if(base64test.exec(input)){console.warn('There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, \'+\', \'/\',and \'=\'\nExpect errors in decoding.');} +input=input.replace(/[^A-Za-z0-9\+\/\=]/g,'');while(true){enc1=this.KEY_STR.indexOf(input.charAt(i++));enc2=this.KEY_STR.indexOf(input.charAt(i++));enc3=this.KEY_STR.indexOf(input.charAt(i++));enc4=this.KEY_STR.indexOf(input.charAt(i++));chr1=enc1<<2|enc2>>4;chr2=(enc2&15)<<4|enc3>>2;chr3=(enc3&3)<<6|enc4;buf.push(chr1);if(enc3!==64){buf.push(chr2);} +if(enc4!==64){buf.push(chr3);} +chr1=chr2=chr3='';enc1=enc2=enc3=enc4='';if(!(i=0){newClass=newClass.replace(' '+className+' ',' ');} +elem.className=newClass.replace(/^\s+|\s+$/g,'');}},escapeHtml=function(str){var div=document.createElement('div');div.appendChild(document.createTextNode(str));return div.innerHTML;},_show=function(elem){elem.style.opacity='';elem.style.display='block';},show=function(elems){if(elems&&!elems.length){return _show(elems);} +for(var i=0;i0){setTimeout(tick,interval);}else{elem.style.display='none';}};tick();},fireClick=function(node){if(MouseEvent){var mevt=new MouseEvent('click',{view:window,bubbles:false,cancelable:true});node.dispatchEvent(mevt);}else if(document.createEvent){var evt=document.createEvent('MouseEvents');evt.initEvent('click',false,false);node.dispatchEvent(evt);}else if(document.createEventObject){node.fireEvent('onclick');}else if(typeof node.onclick==='function'){node.onclick();}},stopEventPropagation=function(e){if(typeof e.stopPropagation==='function'){e.stopPropagation();e.preventDefault();}else if(window.event&&window.event.hasOwnProperty('cancelBubble')){window.event.cancelBubble=true;}};var previousActiveElement,previousDocumentClick,previousWindowKeyDown,lastFocusedButton;window.sweetAlertInitialize=function(){var sweetHTML='

Title

Text

',sweetWrap=document.createElement('div');sweetWrap.innerHTML=sweetHTML;document.body.appendChild(sweetWrap);} +window.sweetAlert=window.swal=function(){if(arguments[0]===undefined){window.console.error('sweetAlert expects at least 1 attribute!');return false;} +var params=extend({},defaultParams);switch(typeof arguments[0]){case'string':params.title=arguments[0];params.text=arguments[1]||'';params.type=arguments[2]||'';break;case'object':if(arguments[0].title===undefined){window.console.error('Missing "title" argument!');return false;} +params.title=arguments[0].title;params.text=arguments[0].text||defaultParams.text;params.type=arguments[0].type||defaultParams.type;params.allowOutsideClick=arguments[0].allowOutsideClick||defaultParams.allowOutsideClick;params.showCancelButton=arguments[0].showCancelButton!==undefined?arguments[0].showCancelButton:defaultParams.showCancelButton;params.showConfirmButton=arguments[0].showConfirmButton!==undefined?arguments[0].showConfirmButton:defaultParams.showConfirmButton;params.closeOnConfirm=arguments[0].closeOnConfirm!==undefined?arguments[0].closeOnConfirm:defaultParams.closeOnConfirm;params.closeOnCancel=arguments[0].closeOnCancel!==undefined?arguments[0].closeOnCancel:defaultParams.closeOnCancel;params.timer=arguments[0].timer||defaultParams.timer;params.confirmButtonText=(defaultParams.showCancelButton)?'Confirm':defaultParams.confirmButtonText;params.confirmButtonText=arguments[0].confirmButtonText||defaultParams.confirmButtonText;params.confirmButtonClass=arguments[0].confirmButtonClass||(arguments[0].type?'btn-'+arguments[0].type:null)||defaultParams.confirmButtonClass;params.cancelButtonText=arguments[0].cancelButtonText||defaultParams.cancelButtonText;params.cancelButtonClass=arguments[0].cancelButtonClass||defaultParams.cancelButtonClass;params.containerClass=arguments[0].containerClass||defaultParams.containerClass;params.titleClass=arguments[0].titleClass||defaultParams.titleClass;params.textClass=arguments[0].textClass||defaultParams.textClass;params.imageUrl=arguments[0].imageUrl||defaultParams.imageUrl;params.imageSize=arguments[0].imageSize||defaultParams.imageSize;params.doneFunction=arguments[1]||null;break;default:window.console.error('Unexpected type of argument! Expected "string" or "object", got '+typeof arguments[0]);return false;} +setParameters(params);fixVerticalPosition();openModal();var modal=getModal();var onButtonEvent=function(e){var target=e.target||e.srcElement,targetedConfirm=(target.className.indexOf('confirm')>-1),modalIsVisible=hasClass(modal,'visible'),doneFunctionExists=(params.doneFunction&&modal.getAttribute('data-has-done-function')==='true');switch(e.type){case("click"):if(targetedConfirm&&doneFunctionExists&&modalIsVisible){params.doneFunction(true);if(params.closeOnConfirm){closeModal();}}else if(doneFunctionExists&&modalIsVisible){var functionAsStr=String(params.doneFunction).replace(/\s/g,'');var functionHandlesCancel=functionAsStr.substring(0,9)==="function("&&functionAsStr.substring(9,10)!==")";if(functionHandlesCancel){params.doneFunction(false);} +if(params.closeOnCancel){closeModal();}}else{closeModal();} +break;}};var $buttons=modal.querySelectorAll('button');for(var i=0;i<$buttons.length;i++){$buttons[i].onclick=onButtonEvent;} +previousDocumentClick=document.onclick;document.onclick=function(e){var target=e.target||e.srcElement;var clickedOnModal=(modal===target),clickedOnModalChild=isDescendant(modal,e.target),modalIsVisible=hasClass(modal,'visible'),outsideClickIsAllowed=modal.getAttribute('data-allow-ouside-click')==='true';if(!clickedOnModal&&!clickedOnModalChild&&modalIsVisible&&outsideClickIsAllowed){closeModal();}};var $okButton=modal.querySelector('button.confirm'),$cancelButton=modal.querySelector('button.cancel'),$modalButtons=modal.querySelectorAll('button:not([type=hidden])');function handleKeyDown(e){var keyCode=e.keyCode||e.which;if([9,13,32,27].indexOf(keyCode)===-1){return;} +var $targetElement=e.target||e.srcElement;var btnIndex=-1;for(var i=0;i<$modalButtons.length;i++){if($targetElement===$modalButtons[i]){btnIndex=i;break;}} +if(keyCode===9){if(btnIndex===-1){$targetElement=$okButton;}else{if(btnIndex===$modalButtons.length-1){$targetElement=$modalButtons[0];}else{$targetElement=$modalButtons[btnIndex+1];}} +stopEventPropagation(e);$targetElement.focus();}else{if(keyCode===13||keyCode===32){if(btnIndex===-1){$targetElement=$okButton;}else{$targetElement=undefined;}}else if(keyCode===27&&!($cancelButton.hidden||$cancelButton.style.display==='none')){$targetElement=$cancelButton;}else{$targetElement=undefined;} +if($targetElement!==undefined){fireClick($targetElement,e);}}} +previousWindowKeyDown=window.onkeydown;window.onkeydown=handleKeyDown;function handleOnBlur(e){var $targetElement=e.target||e.srcElement,$focusElement=e.relatedTarget,modalIsVisible=hasClass(modal,'visible'),bootstrapModalIsVisible=document.querySelector('.control-popup.modal')||false;if(bootstrapModalIsVisible){return;} +if(modalIsVisible){var btnIndex=-1;if($focusElement!==null){for(var i=0;i<$modalButtons.length;i++){if($focusElement===$modalButtons[i]){btnIndex=i;break;}} +if(btnIndex===-1){$targetElement.focus();}}else{lastFocusedButton=$targetElement;}}} +$okButton.onblur=handleOnBlur;$cancelButton.onblur=handleOnBlur;window.onfocus=function(){window.setTimeout(function(){if(lastFocusedButton!==undefined){lastFocusedButton.focus();lastFocusedButton=undefined;}},0);};};window.swal.setDefaults=function(userParams){if(!userParams){throw new Error('userParams is required');} +if(typeof userParams!=='object'){throw new Error('userParams has to be a object');} +extend(defaultParams,userParams);};window.swal.close=function(){closeModal();} +function setParameters(params){var modal=getModal();var $title=modal.querySelector('h2'),$text=modal.querySelector('p'),$cancelBtn=modal.querySelector('button.cancel'),$confirmBtn=modal.querySelector('button.confirm');$title.innerHTML=escapeHtml(params.title).split("\n").join("
");$text.innerHTML=escapeHtml(params.text||'').split("\n").join("
");if(params.text){show($text);} +hide(modal.querySelectorAll('.icon'));if(params.type){var validType=false;for(var i=0;iw)&&w>0){nw=w;nh=(w/$obj.width())*$obj.height();} +if((nh>h)&&h>0){nh=h;nw=(h/$obj.height())*$obj.width();} +xscale=$obj.width()/nw;yscale=$obj.height()/nh;$obj.width(nw).height(nh);} +function unscale(c) +{return{x:c.x*xscale,y:c.y*yscale,x2:c.x2*xscale,y2:c.y2*yscale,w:c.w*xscale,h:c.h*yscale};} +function doneSelect(pos) +{var c=Coords.getFixed();if((c.w>options.minSelect[0])&&(c.h>options.minSelect[1])){Selection.enableHandles();Selection.done();}else{Selection.release();} +Tracker.setCursor(options.allowSelect?'crosshair':'default');} +function newSelection(e) +{if(options.disabled){return false;} +if(!options.allowSelect){return false;} +btndown=true;docOffset=getPos($img);Selection.disableHandles();Tracker.setCursor('crosshair');var pos=mouseAbs(e);Coords.setPressed(pos);Selection.update();Tracker.activateHandlers(selectDrag,doneSelect,e.type.substring(0,5)==='touch');KeyManager.watchKeys();e.stopPropagation();e.preventDefault();return false;} +function selectDrag(pos) +{Coords.setCurrent(pos);Selection.update();} +function newTracker() +{var trk=$('
').addClass(cssClass('tracker'));if(is_msie){trk.css({opacity:0,backgroundColor:'white'});} +return trk;} +if(typeof(obj)!=='object'){obj=$(obj)[0];} +if(typeof(opt)!=='object'){opt={};} +setOptions(opt);var img_css={border:'none',visibility:'visible',margin:0,padding:0,position:'absolute',top:0,left:0};var $origimg=$(obj),img_mode=true;if(obj.tagName=='IMG'){if($origimg[0].width!=0&&$origimg[0].height!=0){$origimg.width($origimg[0].width);$origimg.height($origimg[0].height);}else{var tempImage=new Image();tempImage.src=$origimg[0].src;$origimg.width(tempImage.width);$origimg.height(tempImage.height);} +var $img=$origimg.clone().removeAttr('id').css(img_css).show();$img.width($origimg.width());$img.height($origimg.height());$origimg.after($img).hide();}else{$img=$origimg.css(img_css).show();img_mode=false;if(options.shade===null){options.shade=true;}} +presize($img,options.boxWidth,options.boxHeight);var boundx=$img.width(),boundy=$img.height(),$div=$('
').width(boundx).height(boundy).addClass(cssClass('holder')).css({position:'relative',backgroundColor:options.bgColor}).insertAfter($origimg).append($img);if(options.addClass){$div.addClass(options.addClass);} +var $img2=$('
'),$img_holder=$('
').width('100%').height('100%').css({zIndex:310,position:'absolute',overflow:'hidden'}),$hdl_holder=$('
').width('100%').height('100%').css('zIndex',320),$sel=$('
').css({position:'absolute',zIndex:600}).dblclick(function(){var c=Coords.getFixed();options.onDblClick.call(api,c);}).insertBefore($img).append($img_holder,$hdl_holder);if(img_mode){$img2=$('').attr('src',$img.attr('src')).css(img_css).width(boundx).height(boundy),$img_holder.append($img2);} +if(ie6mode){$sel.css({overflowY:'hidden'});} +var bound=options.boundary;var $trk=newTracker().width(boundx+(bound*2)).height(boundy+(bound*2)).css({position:'absolute',top:px(-bound),left:px(-bound),zIndex:290}).mousedown(newSelection);var bgcolor=options.bgColor,bgopacity=options.bgOpacity,xlimit,ylimit,xmin,ymin,xscale,yscale,enabled=true,btndown,animating,shift_down;docOffset=getPos($img);var Touch=(function(){function hasTouchSupport(){var support={},events=['touchstart','touchmove','touchend'],el=document.createElement('div'),i;try{for(i=0;ix1+ox){ox-=ox+x1;} +if(0>y1+oy){oy-=oy+y1;} +if(boundyboundx){xx=boundx;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}}else{xx=x2;h=rwa/aspect;yy=rh<0?y1-h:y1+h;if(yy<0){yy=0;w=Math.abs((yy-y1)*aspect);xx=rw<0?x1-w:w+x1;}else if(yy>boundy){yy=boundy;w=Math.abs(yy-y1)*aspect;xx=rw<0?x1-w:w+x1;}} +if(xx>x1){if(xx-x1max_x){xx=x1+max_x;} +if(yy>y1){yy=y1+(xx-x1)/aspect;}else{yy=y1-(xx-x1)/aspect;}}else if(xxmax_x){xx=x1-max_x;} +if(yy>y1){yy=y1+(x1-xx)/aspect;}else{yy=y1-(x1-xx)/aspect;}} +if(xx<0){x1-=xx;xx=0;}else if(xx>boundx){x1-=xx-boundx;xx=boundx;} +if(yy<0){y1-=yy;yy=0;}else if(yy>boundy){y1-=yy-boundy;yy=boundy;} +return makeObj(flipCoords(x1,y1,xx,yy));} +function rebound(p) +{if(p[0]<0)p[0]=0;if(p[1]<0)p[1]=0;if(p[0]>boundx)p[0]=boundx;if(p[1]>boundy)p[1]=boundy;return[Math.round(p[0]),Math.round(p[1])];} +function flipCoords(x1,y1,x2,y2) +{var xa=x1,xb=x2,ya=y1,yb=y2;if(x2xlimit)){x2=(xsize>0)?(x1+xlimit):(x1-xlimit);} +if(ylimit&&(Math.abs(ysize)>ylimit)){y2=(ysize>0)?(y1+ylimit):(y1-ylimit);} +if(ymin/yscale&&(Math.abs(ysize)0)?(y1+ymin/yscale):(y1-ymin/yscale);} +if(xmin/xscale&&(Math.abs(xsize)0)?(x1+xmin/xscale):(x1-xmin/xscale);} +if(x1<0){x2-=x1;x1-=x1;} +if(y1<0){y2-=y1;y1-=y1;} +if(x2<0){x1-=x2;x2-=x2;} +if(y2<0){y1-=y2;y2-=y2;} +if(x2>boundx){delta=x2-boundx;x1-=delta;x2-=delta;} +if(y2>boundy){delta=y2-boundy;y1-=delta;y2-=delta;} +if(x1>boundx){delta=x1-boundy;y2-=delta;y1-=delta;} +if(y1>boundy){delta=y1-boundy;y2-=delta;y1-=delta;} +return makeObj(flipCoords(x1,y1,x2,y2));} +function makeObj(a) +{return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]};} +return{flipCoords:flipCoords,setPressed:setPressed,setCurrent:setCurrent,getOffset:getOffset,moveOffset:moveOffset,getCorner:getCorner,getFixed:getFixed};}());var Shade=(function(){var enabled=false,holder=$('
').css({position:'absolute',zIndex:240,opacity:0}),shades={top:createShade(),left:createShade().height(boundy),right:createShade().height(boundy),bottom:createShade()};function resizeShades(w,h){shades.left.css({height:px(h)});shades.right.css({height:px(h)});} +function updateAuto() +{return updateShade(Coords.getFixed());} +function updateShade(c) +{shades.top.css({left:px(c.x),width:px(c.w),height:px(c.y)});shades.bottom.css({top:px(c.y2),left:px(c.x),width:px(c.w),height:px(boundy-c.y2)});shades.right.css({left:px(c.x2),width:px(boundx-c.x2)});shades.left.css({width:px(c.x)});} +function createShade(){return $('
').css({position:'absolute',backgroundColor:options.shadeColor||options.bgColor}).appendTo(holder);} +function enableShade(){if(!enabled){enabled=true;holder.insertBefore($img);updateAuto();Selection.setBgOpacity(1,0,1);$img2.hide();setBgColor(options.shadeColor||options.bgColor,1);if(Selection.isAwake()) +{setOpacity(options.bgOpacity,1);} +else setOpacity(1,1);}} +function setBgColor(color,now){colorChangeMacro(getShades(),color,now);} +function disableShade(){if(enabled){holder.remove();$img2.show();enabled=false;if(Selection.isAwake()){Selection.setBgOpacity(options.bgOpacity,1,1);}else{Selection.setBgOpacity(1,1,1);Selection.disableHandles();} +colorChangeMacro($div,0,1);}} +function setOpacity(opacity,now){if(enabled){if(options.bgFade&&!now){holder.animate({opacity:1-opacity},{queue:false,duration:options.fadeTime});} +else holder.css({opacity:1-opacity});}} +function refreshAll(){options.shade?enableShade():disableShade();if(Selection.isAwake())setOpacity(options.bgOpacity);} +function getShades(){return holder.children();} +return{update:updateAuto,updateRaw:updateShade,getShades:getShades,setBgColor:setBgColor,enable:enableShade,disable:disableShade,resize:resizeShades,refresh:refreshAll,opacity:setOpacity};}());var Selection=(function(){var awake,hdep=370,borders={},handle={},dragbar={},seehandles=false;function insertBorder(type) +{var jq=$('
').css({position:'absolute',opacity:options.borderOpacity}).addClass(cssClass(type));$img_holder.append(jq);return jq;} +function dragDiv(ord,zi) +{var jq=$('
').mousedown(createDragger(ord)).css({cursor:ord+'-resize',position:'absolute',zIndex:zi}).addClass('ord-'+ord);if(Touch.support){jq.bind('touchstart.jcrop',Touch.createDragger(ord));} +$hdl_holder.append(jq);return jq;} +function insertHandle(ord) +{var hs=options.handleSize,div=dragDiv(ord,hdep++).css({opacity:options.handleOpacity}).addClass(cssClass('handle'));if(hs){div.width(hs).height(hs);} +return div;} +function insertDragbar(ord) +{return dragDiv(ord,hdep++).addClass('jcrop-dragbar');} +function createDragbars(li) +{var i;for(i=0;i').css({position:'fixed',left:'-120px',width:'12px'}).addClass('jcrop-keymgr'),$keywrap=$('
').css({position:'absolute',overflow:'hidden'}).append($keymgr);function watchKeys() +{if(options.keySupport){$keymgr.show();$keymgr.focus();}} +function onBlur(e) +{$keymgr.hide();} +function doNudge(e,x,y) +{if(options.allowMove){Coords.moveOffset([x,y]);Selection.updateVisible(true);} +e.preventDefault();e.stopPropagation();} +function parseKey(e) +{if(e.ctrlKey||e.metaKey){return true;} +shift_down=e.shiftKey?true:false;var nudge=shift_down?10:1;switch(e.keyCode){case 37:doNudge(e,-nudge,0);break;case 39:doNudge(e,nudge,0);break;case 38:doNudge(e,0,-nudge);break;case 40:doNudge(e,0,nudge);break;case 27:if(options.allowSelect)Selection.release();break;case 9:return true;} +return false;} +if(options.keySupport){$keymgr.keydown(parseKey).blur(onBlur);if(ie6mode||!options.fixedSupport){$keymgr.css({position:'absolute',left:'-20px'});$keywrap.append($keymgr).insertBefore($img);}else{$keymgr.insertBefore($img);}} +return{watchKeys:watchKeys};}());function setClass(cname) +{$div.removeClass().addClass(cssClass('holder')).addClass(cname);} +function animateTo(a,callback) +{var x1=a[0]/xscale,y1=a[1]/yscale,x2=a[2]/xscale,y2=a[3]/yscale;if(animating){return;} +var animto=Coords.flipCoords(x1,y1,x2,y2),c=Coords.getFixed(),initcr=[c.x,c.y,c.x2,c.y2],animat=initcr,interv=options.animationDelay,ix1=animto[0]-initcr[0],iy1=animto[1]-initcr[1],ix2=animto[2]-initcr[2],iy2=animto[3]-initcr[3],pcent=0,velocity=options.swingSpeed;x1=animat[0];y1=animat[1];x2=animat[2];y2=animat[3];Selection.animMode(true);var anim_timer;function queueAnimator(){window.setTimeout(animator,interv);} +var animator=(function(){return function(){pcent+=(100-pcent)/velocity;animat[0]=Math.round(x1+((pcent/100)*ix1));animat[1]=Math.round(y1+((pcent/100)*iy1));animat[2]=Math.round(x2+((pcent/100)*ix2));animat[3]=Math.round(y2+((pcent/100)*iy2));if(pcent>=99.8){pcent=100;} +if(pcent<100){setSelectRaw(animat);queueAnimator();}else{Selection.done();Selection.animMode(false);if(typeof(callback)==='function'){callback.call(api);}}};}());queueAnimator();} +function setSelect(rect) +{setSelectRaw([rect[0]/xscale,rect[1]/yscale,rect[2]/xscale,rect[3]/yscale]);options.onSelect.call(api,unscale(Coords.getFixed()));Selection.enableHandles();} +function setSelectRaw(l) +{Coords.setPressed([l[0],l[1]]);Coords.setCurrent([l[2],l[3]]);Selection.update();} +function tellSelect() +{return unscale(Coords.getFixed());} +function tellScaled() +{return Coords.getFixed();} +function setOptionsNew(opt) +{setOptions(opt);interfaceUpdate();} +function disableCrop() +{options.disabled=true;Selection.disableHandles();Selection.setCursor('default');Tracker.setCursor('default');} +function enableCrop() +{options.disabled=false;interfaceUpdate();} +function cancelCrop() +{Selection.done();Tracker.activateHandlers(null,null);} +function destroy() +{$(document).unbind('touchstart.jcrop-ios',Touch.fixTouchSupport);$div.remove();$origimg.show();$origimg.css('visibility','visible');$(obj).removeData('Jcrop');} +function setImage(src,callback) +{Selection.release();disableCrop();var img=new Image();img.onload=function(){var iw=img.width;var ih=img.height;var bw=options.boxWidth;var bh=options.boxHeight;$img.width(iw).height(ih);$img.attr('src',src);$img2.attr('src',src);presize($img,bw,bh);boundx=$img.width();boundy=$img.height();$img2.width(boundx).height(boundy);$trk.width(boundx+(bound*2)).height(boundy+(bound*2));$div.width(boundx).height(boundy);Shade.resize(boundx,boundy);enableCrop();if(typeof(callback)==='function'){callback.call(api);}};img.src=src;} +function colorChangeMacro($obj,color,now){var mycolor=color||options.bgColor;if(options.bgFade&&supportsColorFade()&&options.fadeTime&&!now){$obj.animate({backgroundColor:mycolor},{queue:false,duration:options.fadeTime});}else{$obj.css('backgroundColor',mycolor);}} +function interfaceUpdate(alt) +{if(options.allowResize){if(alt){Selection.enableOnly();}else{Selection.enableHandles();}}else{Selection.disableHandles();} +Tracker.setCursor(options.allowSelect?'crosshair':'default');Selection.setCursor(options.allowMove?'move':'default');if(options.hasOwnProperty('trueSize')){xscale=options.trueSize[0]/boundx;yscale=options.trueSize[1]/boundy;} +if(options.hasOwnProperty('setSelect')){setSelect(options.setSelect);Selection.done();delete(options.setSelect);} +Shade.refresh();if(options.bgColor!=bgcolor){colorChangeMacro(options.shade?Shade.getShades():$div,options.shade?(options.shadeColor||options.bgColor):options.bgColor);bgcolor=options.bgColor;} +if(bgopacity!=options.bgOpacity){bgopacity=options.bgOpacity;if(options.shade)Shade.refresh();else Selection.setBgOpacity(bgopacity);} +xlimit=options.maxSize[0]||0;ylimit=options.maxSize[1]||0;xmin=options.minSize[0]||0;ymin=options.minSize[1]||0;if(options.hasOwnProperty('outerImage')){$img.attr('src',options.outerImage);delete(options.outerImage);} +Selection.refresh();} +if(Touch.support)$trk.bind('touchstart.jcrop',Touch.newSelection);$hdl_holder.hide();interfaceUpdate(true);var api={setImage:setImage,animateTo:animateTo,setSelect:setSelect,setOptions:setOptionsNew,tellSelect:tellSelect,tellScaled:tellScaled,setClass:setClass,disable:disableCrop,enable:enableCrop,cancel:cancelCrop,release:Selection.release,destroy:destroy,focus:KeyManager.watchKeys,getBounds:function(){return[boundx*xscale,boundy*yscale];},getWidgetSize:function(){return[boundx,boundy];},getScaleFactor:function(){return[xscale,yscale];},getOptions:function(){return options;},ui:{holder:$div,selection:$sel}};if(is_msie)$div.bind('selectstart',function(){return false;});$origimg.data('Jcrop',api);return api;};$.fn.Jcrop=function(options,callback) +{var api;this.each(function(){if($(this).data('Jcrop')){if(options==='api')return $(this).data('Jcrop');else $(this).data('Jcrop').setOptions(options);} +else{if(this.tagName=='IMG') +$.Jcrop.Loader(this,function(){$(this).css({display:'block',visibility:'hidden'});api=$.Jcrop(this,options);if($.isFunction(callback))callback.call(api);});else{$(this).css({display:'block',visibility:'hidden'});api=$.Jcrop(this,options);if($.isFunction(callback))callback.call(api);}}});return this;};$.Jcrop.Loader=function(imgobj,success,error){var $img=$(imgobj),img=$img[0];function completeCheck(){if(img.complete){$img.unbind('.jcloader');if($.isFunction(success))success.call(img);} +else window.setTimeout(completeCheck,50);} +$img.bind('load.jcloader',completeCheck).bind('error.jcloader',function(e){$img.unbind('.jcloader');if($.isFunction(error))error.call(img);});if(img.complete&&$.isFunction(success)){$img.unbind('.jcloader');success.call(img);}};$.Jcrop.defaults={allowSelect:true,allowMove:true,allowResize:true,trackDocument:true,baseClass:'jcrop',addClass:null,bgColor:'black',bgOpacity:0.6,bgFade:false,borderOpacity:0.4,handleOpacity:0.5,handleSize:null,aspectRatio:0,keySupport:true,createHandles:['n','s','e','w','nw','ne','se','sw'],createDragbars:['n','s','e','w'],createBorders:['n','s','e','w'],drawBorders:true,dragEdges:true,fixedSupport:true,touchSupport:null,shade:null,boxWidth:0,boxHeight:0,boundary:2,fadeTime:400,animationDelay:20,swingSpeed:3,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){},onDblClick:function(){},onRelease:function(){}};}(jQuery));!function(){var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;(function(){function S(a){function d(e){var b=e.charCodeAt(0);if(b!==92)return b;var a=e.charAt(1);return(b=r[a])?b:"0"<=a&&a<="7"?parseInt(e.substring(1),8):a==="u"||a==="x"?parseInt(e.substring(2),16):e.charCodeAt(1)}function g(e){if(e<32)return(e<16?"\\x0":"\\x")+e.toString(16);e=String.fromCharCode(e);return e==="\\"||e==="-"||e==="]"||e==="^"?"\\"+e:e}function b(e){var b=e.substring(1,e.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),e=[],a=b[0]==="^",c=["["];a&&c.push("^");for(var a=a?1:0,f=b.length;a122||(l<65||h>90||e.push([Math.max(65,h)|32,Math.min(l,90)|32]),l<97||h>122||e.push([Math.max(97,h)&-33,Math.min(l,122)&-33]))}}e.sort(function(e,a){return e[0]-a[0]||a[1]-e[1]});b=[];f=[];for(a=0;ah[0]&&(h[1]+1>h[0]&&c.push("-"),c.push(g(h[1])));c.push("]");return c.join("")}function s(e){for(var a=e.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),c=a.length,d=[],f=0,h=0;f=2&&e==="["?a[f]=b(l):e!=="\\"&&(a[f]=l.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var x=0,m=!1,j=!1,k=0,c=a.length;k=5&&"lang-"===w.substring(0,5))&&!(t&&typeof t[1]==="string"))f=!1,w="src";f||(r[z]=w)}h=c;c+=z.length;if(f){f=t[1];var l=z.indexOf(f),B=l+f.length;t[2]&&(B=z.length-t[2].length,l=B-f.length);w=w.substring(5);H(j+h,z.substring(0,l),g,k);H(j+h+l,f,I(w,f),k);H(j+h+B,z.substring(B),g,k)}else k.push(j+h,w)}a.g=k}var b={},s;(function(){for(var g=a.concat(d),j=[],k={},c=0,i=g.length;c=0;)b[n.charAt(e)]=r;r=r[1];n=""+r;k.hasOwnProperty(n)||(j.push(r),k[n]=q)}j.push(/[\S\s]/);s=S(j)})();var x=d.length;return g}function v(a){var d=[],g=[];a.tripleQuotedStrings?d.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?d.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,q,"'\"`"]):d.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&g.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var b=a.hashComments;b&&(a.cStyleComments?(b>1?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),g.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,q])):d.push(["com",/^#[^\n\r]*/,q,"#"]));a.cStyleComments&&(g.push(["com",/^\/\/[^\n\r]*/,q]),g.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));if(b=a.regexLiterals){var s=(b=b>1?"":"\n\r")?".":"[\\S\\s]";g.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+("/(?=[^/*"+b+"])(?:[^/\\x5B\\x5C"+b+"]|\\x5C"+s+"|\\x5B(?:[^\\x5C\\x5D"+b+"]|\\x5C"+ +s+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&g.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&g.push(["kwd",RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),q]);d.push(["pln",/^\s+/,q," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");g.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",RegExp(b),q]);return C(d,g)}function J(a,d,g){function b(a){var c=a.nodeType;if(c==1&&!x.test(a.className))if("br"===a.nodeName)s(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&g){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(j.createTextNode(d),a.nextSibling),s(a),c||a.parentNode.removeChild(a)}}function s(a){function b(a,c){var d=c?a.cloneNode(!1):a,e=a.parentNode;if(e){var e=b(e,1),g=a.nextSibling;e.appendChild(d);for(var i=g;i;i=g)g=i.nextSibling,e.appendChild(i)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var x=/(?:^|\s)nocode(?:\s|$)/,m=/\r\n?|\n/,j=a.ownerDocument,k=j.createElement("li");a.firstChild;)k.appendChild(a.firstChild);for(var c=[k],i=0;i=0;){var b=d[g];F.hasOwnProperty(b)?D.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){D.console&&console.log(u&&u.stack||u)}}var D=window,y=["break,continue,do,else,for,if,return,while"],E=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],M=[E,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],N=[E,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],O=[N,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],E=[E,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],P=[y,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],Q=[y,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],W=[y,"as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"],y=[y,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],R=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,V=/\S/,X=v({keywords:[M,O,E,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",P,Q,y],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),F={};p(X,["default-code"]);p(C([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);p(C([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);p(C([],[["atv",/^[\S\s]+/]]),["uq.val"]);p(v({keywords:M,hashComments:!0,cStyleComments:!0,types:R}),["c","cc","cpp","cxx","cyc","m"]);p(v({keywords:"null,true,false"}),["json"]);p(v({keywords:O,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:R}),["cs"]);p(v({keywords:N,cStyleComments:!0}),["java"]);p(v({keywords:y,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);p(v({keywords:P,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);p(v({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:2}),["perl","pl","pm"]);p(v({keywords:Q,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);p(v({keywords:E,cStyleComments:!0,regexLiterals:!0}),["javascript","js"]);p(v({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);p(v({keywords:W,cStyleComments:!0,multilineStrings:!0}),["rc","rs","rust"]);p(C([],[["str",/^[\S\s]+/]]),["regex"]);var Y=D.PR={createSimpleLexer:C,registerLangHandler:p,sourceDecorator:v,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:D.prettyPrintOne=function(a,d,g){var b=document.createElement("div");b.innerHTML="
"+a+"
";b=b.firstChild;g&&J(b,g,!0);K({h:d,j:g,c:b,i:1});return b.innerHTML},prettyPrint:D.prettyPrint=function(a,d){function g(){for(var b=D.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;i') +this.registerHandlers()} +MediaManagerPopup.prototype.registerHandlers=function(){this.$popupRootElement.one('hide.oc.popup',this.proxy(this.onPopupHidden)) +this.$popupRootElement.one('shown.oc.popup',this.proxy(this.onPopupShown))} +MediaManagerPopup.prototype.unregisterHandlers=function(){this.$popupElement.off('popupcommand',this.proxy(this.onPopupCommand)) +this.$popupRootElement.off('popupcommand',this.proxy(this.onPopupCommand))} +MediaManagerPopup.prototype.show=function(){var data={bottomToolbar:this.options.bottomToolbar?1:0,cropAndInsertButton:this.options.cropAndInsertButton?1:0} +this.$popupRootElement.popup({extraData:data,size:'adaptive',adaptiveHeight:true,handler:this.options.alias+'::onLoadPopup'})} +MediaManagerPopup.prototype.hide=function(){if(this.$popupElement) +this.$popupElement.trigger('close.oc.popup')} +MediaManagerPopup.prototype.getMediaManagerElement=function(){return this.$popupElement.find('[data-control="media-manager"]')} +MediaManagerPopup.prototype.insertMedia=function(){var items=this.getMediaManagerElement().mediaManager('getSelectedItems') +if(this.options.onInsert!==undefined) +this.options.onInsert.call(this,items)} +MediaManagerPopup.prototype.insertCroppedImage=function(imageItem){if(this.options.onInsert!==undefined) +this.options.onInsert.call(this,[imageItem])} +MediaManagerPopup.prototype.onPopupHidden=function(event,element,popup){var mediaManager=this.getMediaManagerElement() +mediaManager.mediaManager('dispose') +mediaManager.remove() +$(document).trigger('mousedown') +this.dispose() +if(this.options.onClose!==undefined) +this.options.onClose.call(this)} +MediaManagerPopup.prototype.onPopupShown=function(event,element,popup){this.$popupElement=popup +this.$popupElement.on('popupcommand',this.proxy(this.onPopupCommand)) +this.getMediaManagerElement().mediaManager('selectFirstItem')} +MediaManagerPopup.prototype.onPopupCommand=function(ev,command,param){switch(command){case'insert':this.insertMedia() +break;case'insert-cropped':this.insertCroppedImage(param) +break;} +return false} +MediaManagerPopup.DEFAULTS={alias:undefined,bottomToolbar:true,cropAndInsertButton:false,onInsert:undefined,onClose:undefined} +$.oc.mediaManager.popup=MediaManagerPopup}(window.jQuery);if($.oc===undefined) +$.oc={} +if($.oc.langMessages===undefined) +$.oc.langMessages={} +$.oc.lang=(function(lang,messages){lang.load=function(locale){if(messages[locale]===undefined){messages[locale]={}} +lang.loadedMessages=messages[locale]} +lang.get=function(name,defaultValue){if(!name)return +var result=lang.loadedMessages +if(!defaultValue)defaultValue=name +$.each(name.split('.'),function(index,value){if(result[value]===undefined){result=defaultValue +return false} +result=result[value]}) +return result} +if(lang.locale===undefined){lang.locale=$('html').attr('lang')||'en'} +if(lang.loadedMessages===undefined){lang.load(lang.locale)} +return lang})($.oc.lang||{},$.oc.langMessages);(function($){if($.oc===undefined) +$.oc={} +$.oc.alert=function alert(message){swal({title:message,confirmButtonClass:'btn-primary'})} +$.oc.confirm=function confirm(message,callback){swal({title:message,showCancelButton:true,confirmButtonClass:'btn-primary'},callback)}})(jQuery);$(window).on('ajaxErrorMessage',function(event,message){if(!message)return +$.oc.alert(message) +event.preventDefault()}) +$(window).on('ajaxConfirmMessage',function(event,message){if(!message)return +$.oc.confirm(message,function(isConfirm){isConfirm?event.promise.resolve():event.promise.reject()}) +event.preventDefault() +return true}) +$(document).ready(function(){if(!window.swal)return +var swal=window.swal +window.sweetAlert=window.swal=function(message,callback){if(typeof message==='object'){message.confirmButtonText=message.confirmButtonText||$.oc.lang.get('alert.confirm_button_text') +message.cancelButtonText=message.cancelButtonText||$.oc.lang.get('alert.cancel_button_text')} +else{message={title:message,confirmButtonText:$.oc.lang.get('alert.confirm_button_text'),cancelButtonText:$.oc.lang.get('alert.cancel_button_text')}} +swal(message,callback)}}) ++function($){"use strict";var Base=$.oc.foundation.base,BaseProto=Base.prototype +var Scrollpad=function(element,options){this.$el=$(element) +this.scrollbarElement=null +this.dragHandleElement=null +this.scrollContentElement=null +this.contentElement=null +this.options=options +this.scrollbarSize=null +this.updateScrollbarTimer=null +this.dragOffset=null +Base.call(this) +this.init() +$.oc.foundation.controlUtils.markDisposable(element)} +Scrollpad.prototype=Object.create(BaseProto) +Scrollpad.prototype.constructor=Scrollpad +Scrollpad.prototype.dispose=function(){this.unregisterHandlers() +this.$el.get(0).removeChild(this.scrollbarElement) +this.$el.removeData('oc.scrollpad') +this.$el=null +this.scrollbarElement=null +this.dragHandleElement=null +this.scrollContentElement=null +this.contentElement=null +BaseProto.dispose.call(this)} +Scrollpad.prototype.scrollToStart=function(){var scrollAttr=this.options.direction=='vertical'?'scrollTop':'scrollLeft' +this.scrollContentElement[scrollAttr]=0} +Scrollpad.prototype.update=function(){this.updateScrollbarSize()} +Scrollpad.prototype.init=function(){this.build() +this.setScrollContentSize() +this.registerHandlers()} +Scrollpad.prototype.build=function(){var el=this.$el.get(0) +this.scrollContentElement=el.children[0] +this.contentElement=this.scrollContentElement.children[0] +this.$el.prepend('
') +this.scrollbarElement=el.querySelector('.scrollpad-scrollbar') +this.dragHandleElement=el.querySelector('.scrollpad-scrollbar > .drag-handle')} +Scrollpad.prototype.registerHandlers=function(){this.$el.on('mouseenter',this.proxy(this.onMouseEnter)) +this.$el.on('mouseleave',this.proxy(this.onMouseLeave)) +this.$el.one('dispose-control',this.proxy(this.dispose)) +this.scrollContentElement.addEventListener('scroll',this.proxy(this.onScroll)) +this.dragHandleElement.addEventListener('mousedown',this.proxy(this.onStartDrag))} +Scrollpad.prototype.unregisterHandlers=function(){this.$el.off('mouseenter',this.proxy(this.onMouseEnter)) +this.$el.off('mouseleave',this.proxy(this.onMouseLeave)) +this.$el.off('dispose-control',this.proxy(this.dispose)) +this.scrollContentElement.removeEventListener('scroll',this.proxy(this.onScroll)) +this.dragHandleElement.removeEventListener('mousedown',this.proxy(this.onStartDrag)) +document.removeEventListener('mousemove',this.proxy(this.onMouseMove)) +document.removeEventListener('mouseup',this.proxy(this.onEndDrag))} +Scrollpad.prototype.setScrollContentSize=function(){var scrollbarSize=this.getScrollbarSize() +if(this.options.direction=='vertical') +this.scrollContentElement.setAttribute('style','margin-right: -'+scrollbarSize+'px') +else +this.scrollContentElement.setAttribute('style','margin-bottom: -'+scrollbarSize+'px')} +Scrollpad.prototype.getScrollbarSize=function(){if(this.scrollbarSize!==null) +return this.scrollbarSize +var testerElement=document.createElement('div') +testerElement.setAttribute('class','scrollpad-scrollbar-size-tester') +testerElement.appendChild(document.createElement('div')) +document.body.appendChild(testerElement) +var width=testerElement.offsetWidth,innerWidth=testerElement.querySelector('div').offsetWidth +document.body.removeChild(testerElement) +if(width===innerWidth&&navigator.userAgent.toLowerCase().indexOf('firefox')>-1) +return this.scrollbarSize=17 +return this.scrollbarSize=width-innerWidth} +Scrollpad.prototype.updateScrollbarSize=function(){this.scrollbarElement.removeAttribute('data-hidden') +var contentSize=this.options.direction=='vertical'?this.contentElement.scrollHeight:this.contentElement.scrollWidth,scrollOffset=this.options.direction=='vertical'?this.scrollContentElement.scrollTop:this.scrollContentElement.scrollLeft,scrollbarSize=this.options.direction=='vertical'?this.scrollbarElement.offsetHeight:this.scrollbarElement.offsetWidth,scrollbarRatio=scrollbarSize/contentSize,handleOffset=Math.round(scrollbarRatio*scrollOffset)+2,handleSize=Math.floor(scrollbarRatio*(scrollbarSize-2))-2;if(scrollbarSize1) +dragPerc=1 +var scrollPos=dragPerc*contentSize;this.scrollContentElement[scrollAttr]=scrollPos} +Scrollpad.prototype.onEndDrag=function(ev){document.removeEventListener('mousemove',this.proxy(this.onMouseMove)) +document.removeEventListener('mouseup',this.proxy(this.onEndDrag))} +Scrollpad.DEFAULTS={direction:'vertical'} +var old=$.fn.scrollpad +$.fn.scrollpad=function(option){var args=Array.prototype.slice.call(arguments,1),result=undefined +this.each(function(){var $this=$(this) +var data=$this.data('oc.scrollpad') +var options=$.extend({},Scrollpad.DEFAULTS,$this.data(),typeof option=='object'&&option) +if(!data)$this.data('oc.scrollpad',(data=new Scrollpad(this,options))) +if(typeof option=='string')result=data[option].apply(data,args) +if(typeof result!='undefined')return false}) +return result?result:this} +$.fn.scrollpad.Constructor=Scrollpad +$.fn.scrollpad.noConflict=function(){$.fn.scrollpad=old +return this} +$(document).on('render',function(){$('div[data-control=scrollpad]').scrollpad()})}(window.jQuery);+function($){"use strict";var VerticalMenu=function(element,toggle,options){this.$el=$(element) +this.body=$('body') +this.toggle=$(toggle) +this.options=options||{} +this.options=$.extend({},VerticalMenu.DEFAULTS,this.options) +this.wrapper=$(this.options.contentWrapper) +this.breakpoint=options.breakpoint +this.menuPanel=$('
').appendTo('body').addClass(this.options.collapsedMenuClass).css('width',0) +this.menuContainer=$('
').appendTo(this.menuPanel).css('display','none') +this.menuElement=this.$el.clone().appendTo(this.menuContainer).css('width','auto') +var self=this +this.toggle.click(function(){if(!self.body.hasClass(self.options.bodyMenuOpenClass)){var wrapperWidth=self.wrapper.outerWidth() +self.menuElement.dragScroll('goToStart') +self.wrapper.css({'position':'absolute','min-width':self.wrapper.width(),'height':'100%'}) +self.body.addClass(self.options.bodyMenuOpenClass) +self.menuContainer.css('display','block') +self.wrapper.animate({'left':self.options.menuWidth},{duration:200,queue:false}) +self.menuPanel.animate({'width':self.options.menuWidth},{duration:200,queue:false,complete:function(){self.menuElement.css('width',self.options.menuWidth)}})} +else{closeMenu()} +return false}) +this.wrapper.click(function(){if(self.body.hasClass(self.options.bodyMenuOpenClass)){closeMenu() +return false}}) +$(window).resize(function(){if(self.body.hasClass(self.options.bodyMenuOpenClass)){if($(window).width()>self.breakpoint){hideMenu()}}}) +this.menuElement.dragScroll({vertical:true,useNative:true,start:function(){self.menuElement.addClass('drag')},stop:function(){self.menuElement.removeClass('drag')},scrollClassContainer:self.menuPanel,scrollMarkerContainer:self.menuContainer}) +this.menuElement.on('click',function(){if(self.menuElement.hasClass('drag')) +return false}) +function hideMenu(){self.body.removeClass(self.options.bodyMenuOpenClass) +self.wrapper.css({'position':'static','min-width':0,'right':0,'height':'100%'}) +self.menuPanel.css('width',0) +self.menuElement.css('width','auto') +self.menuContainer.css('display','none')} +function closeMenu(){self.wrapper.animate({'left':0},{duration:200,queue:false}) +self.menuPanel.animate({'width':0},{duration:200,queue:false,complete:hideMenu}) +self.menuElement.animate({'width':0},{duration:200,queue:false})}} +VerticalMenu.DEFAULTS={menuWidth:230,breakpoint:769,bodyMenuOpenClass:'mainmenu-open',collapsedMenuClass:'mainmenu-collapsed',contentWrapper:'#layout-canvas'} +var old=$.fn.verticalMenu +$.fn.verticalMenu=function(toggleSelector,option){return this.each(function(){var $this=$(this) +var data=$this.data('oc.verticalMenu') +var options=typeof option=='object'&&option +if(!data)$this.data('oc.verticalMenu',(data=new VerticalMenu(this,toggleSelector,options))) +if(typeof option=='string')data[option].call($this)})} +$.fn.verticalMenu.Constructor=VerticalMenu +$.fn.verticalMenu.noConflict=function(){$.fn.verticalMenu=old +return this}}(window.jQuery);(function($){$(document).ready(function(){$('nav.navbar').each(function(){var +navbar=$(this),nav=$('ul.nav',navbar),collapseMode=navbar.hasClass('navbar-mode-collapse'),isMobile=$('html').hasClass('mobile') +nav.verticalMenu($('a.menu-toggle',navbar),{breakpoint:collapseMode?Infinity:769}) +$('li.with-tooltip:not(.active) > a',navbar).tooltip({container:'body',placement:'bottom',template:''}).on('show.bs.tooltip',function(e){if(isMobile)e.preventDefault()}) +var dragScroll=$('[data-control=toolbar]',navbar).data('oc.dragScroll') +if(dragScroll){dragScroll.goToElement($('ul.nav > li.active',navbar),undefined,{'duration':0})}})})})(jQuery);+function($){"use strict";if($.oc===undefined) +$.oc={} +var SideNav=function(element,options){this.options=options +this.$el=$(element) +this.$list=$('ul',this.$el) +this.$items=$('li',this.$list) +this.init();} +SideNav.DEFAULTS={activeClass:'active'} +SideNav.prototype.init=function(){var self=this +this.$list.dragScroll({vertical:true,useNative:true,start:function(){self.$list.addClass('drag')},stop:function(){self.$list.removeClass('drag')},scrollClassContainer:self.$el,scrollMarkerContainer:self.$el}) +this.$list.on('click',function(){if(self.$list.hasClass('drag')){return false}})} +SideNav.prototype.unsetActiveItem=function(itemId){this.$items.removeClass(this.options.activeClass)} +SideNav.prototype.setActiveItem=function(itemId){if(!itemId){return} +this.$items.removeClass(this.options.activeClass).filter('[data-menu-item='+itemId+']').addClass(this.options.activeClass)} +SideNav.prototype.setCounter=function(itemId,value){var $counter=$('span.counter[data-menu-id="'+itemId+'"]',this.$el) +$counter.removeClass('empty') +$counter.toggleClass('empty',value==0) +$counter.text(value) +return this} +SideNav.prototype.increaseCounter=function(itemId,value){var $counter=$('span.counter[data-menu-id="'+itemId+'"]',this.$el) +var originalValue=parseInt($counter.text()) +if(isNaN(originalValue)) +originalValue=0 +var newValue=value+originalValue +$counter.toggleClass('empty',newValue==0) +$counter.text(newValue) +return this} +SideNav.prototype.dropCounter=function(itemId){this.setCounter(itemId,0) +return this} +var old=$.fn.sideNav +$.fn.sideNav=function(option){var args=Array.prototype.slice.call(arguments,1),result +this.each(function(){var $this=$(this) +var data=$this.data('oc.sideNav') +var options=$.extend({},SideNav.DEFAULTS,$this.data(),typeof option=='object'&&option) +if(!data)$this.data('oc.sideNav',(data=new SideNav(this,options))) +if(typeof option=='string')result=data[option].apply(data,args) +if(typeof result!='undefined')return false +if($.oc.sideNav===undefined) +$.oc.sideNav=data}) +return result?result:this} +$.fn.sideNav.Constructor=SideNav +$.fn.sideNav.noConflict=function(){$.fn.sideNav=old +return this} +$(document).ready(function(){$('[data-control="sidenav"]').sideNav()})}(window.jQuery);+function($){"use strict";var Base=$.oc.foundation.base,BaseProto=Base.prototype +var Scrollbar=function(element,options){var +$el=this.$el=$(element),el=$el.get(0),self=this,options=this.options=options||{},sizeName=this.sizeName=options.vertical?'height':'width',isNative=$('html').hasClass('mobile'),isTouch=this.isTouch=Modernizr.touchevents,isScrollable=this.isScrollable=false,isLocked=this.isLocked=false,eventElementName=options.vertical?'pageY':'pageX',dragStart=0,startOffset=0;$.oc.foundation.controlUtils.markDisposable(element) +Base.call(this) +this.$el.one('dispose-control',this.proxy(this.dispose)) +if(isNative){return} +this.$scrollbar=$('
').addClass('scrollbar-scrollbar') +this.$track=$('
').addClass('scrollbar-track').appendTo(this.$scrollbar) +this.$thumb=$('
').addClass('scrollbar-thumb').appendTo(this.$track) +$el.addClass('drag-scrollbar').addClass(options.vertical?'vertical':'horizontal').prepend(this.$scrollbar) +if(isTouch){this.$el.on('touchstart',function(event){var touchEvent=event.originalEvent;if(touchEvent.touches.length==1){startDrag(touchEvent.touches[0]) +event.stopPropagation()}})} +else{this.$thumb.on('mousedown',function(event){startDrag(event)}) +this.$track.on('mouseup',function(event){moveDrag(event)})} +$el.mousewheel(function(event){var offset=self.options.vertical?((event.deltaFactor*event.deltaY)*-1):(event.deltaFactor*event.deltaX) +return!scrollWheel(offset*self.options.scrollSpeed)}) +$el.on('oc.scrollbar.gotoStart',function(event){self.options.vertical?$el.scrollTop(0):$el.scrollLeft(0) +self.update() +event.stopPropagation()}) +$(window).on('resize',$.proxy(this.update,this)) +$(window).on('oc.updateUi',$.proxy(this.update,this)) +function startDrag(event){$('body').addClass('drag-noselect') +$el.trigger('oc.scrollStart') +dragStart=event[eventElementName] +startOffset=self.options.vertical?$el.scrollTop():$el.scrollLeft() +if(isTouch){$(window).on('touchmove.scrollbar',function(event){var touchEvent=event.originalEvent +if(moveDrag(touchEvent.touches[0])) +event.preventDefault();});$el.on('touchend.scrollbar',stopDrag)} +else{$(window).on('mousemove.scrollbar',function(event){moveDrag(event) +return false}) +$(window).on('mouseup.scrollbar',function(){stopDrag() +return false})}} +function moveDrag(event){self.isLocked=true;var +offset,dragTo=event[eventElementName] +if(self.isTouch){offset=dragStart-dragTo} +else{var ratio=self.getCanvasSize()/self.getViewportSize() +offset=(dragTo-dragStart)*ratio} +self.options.vertical?$el.scrollTop(startOffset+offset):$el.scrollLeft(startOffset+offset) +self.setThumbPosition() +return self.options.vertical?el.scrollTop!=startOffset:el.scrollLeft!=startOffset} +function stopDrag(){$('body').removeClass('drag-noselect') +$el.trigger('oc.scrollEnd') +$(window).off('.scrollbar')} +var isWebkit=$(document.documentElement).hasClass('webkit') +function scrollWheel(offset){startOffset=self.options.vertical?el.scrollTop:el.scrollLeft +$el.trigger('oc.scrollStart') +self.options.vertical?$el.scrollTop(startOffset+offset):$el.scrollLeft(startOffset+offset) +var scrolled=self.options.vertical?el.scrollTop!=startOffset:el.scrollLeft!=startOffset +self.setThumbPosition() +if(!isWebkit){if(self.endScrollTimeout!==undefined){clearTimeout(self.endScrollTimeout) +self.endScrollTimeout=undefined} +self.endScrollTimeout=setTimeout(function(){$el.trigger('oc.scrollEnd') +self.endScrollTimeout=undefined},50)}else{$el.trigger('oc.scrollEnd')} +return scrolled} +setTimeout(function(){self.update()},1);} +Scrollbar.prototype=Object.create(BaseProto) +Scrollbar.prototype.constructor=Scrollbar +Scrollbar.prototype.dispose=function(){this.unregisterHandlers() +BaseProto.dispose.call(this)} +Scrollbar.prototype.unregisterHandlers=function(){} +Scrollbar.DEFAULTS={vertical:true,scrollSpeed:2,animation:true,start:function(){},drag:function(){},stop:function(){}} +Scrollbar.prototype.update=function(){if(!this.$scrollbar) +return +this.$scrollbar.hide() +this.setThumbSize() +this.setThumbPosition() +this.$scrollbar.show()} +Scrollbar.prototype.setThumbSize=function(){var properties=this.calculateProperties() +this.isScrollable=!(properties.thumbSizeRatio>=1);this.$scrollbar.toggleClass('disabled',!this.isScrollable) +if(this.options.vertical){this.$track.height(properties.canvasSize) +this.$thumb.height(properties.thumbSize)} +else{this.$track.width(properties.canvasSize) +this.$thumb.width(properties.thumbSize)}} +Scrollbar.prototype.setThumbPosition=function(){var properties=this.calculateProperties() +if(this.options.vertical) +this.$thumb.css({top:properties.thumbPosition}) +else +this.$thumb.css({left:properties.thumbPosition})} +Scrollbar.prototype.calculateProperties=function(){var $el=this.$el,properties={};properties.viewportSize=this.getViewportSize() +properties.canvasSize=this.getCanvasSize() +properties.scrollAmount=(this.options.vertical)?$el.scrollTop():$el.scrollLeft() +properties.thumbSizeRatio=properties.viewportSize/properties.canvasSize +properties.thumbSize=properties.viewportSize*properties.thumbSizeRatio +properties.thumbPositionRatio=properties.scrollAmount/(properties.canvasSize-properties.viewportSize) +properties.thumbPosition=((properties.viewportSize-properties.thumbSize)*properties.thumbPositionRatio)+properties.scrollAmount +if(isNaN(properties.thumbPosition)) +properties.thumbPosition=0 +return properties;} +Scrollbar.prototype.getViewportSize=function(){return(this.options.vertical)?this.$el.height():this.$el.width();} +Scrollbar.prototype.getCanvasSize=function(){return(this.options.vertical)?this.$el.get(0).scrollHeight:this.$el.get(0).scrollWidth;} +Scrollbar.prototype.gotoElement=function(element,callback){var $el=$(element) +if(!$el.length) +return;var self=this,offset=0,animated=false,params={duration:300,queue:false,complete:function(){if(callback!==undefined) +callback()}} +if(!this.options.vertical){offset=$el.get(0).offsetLeft-this.$el.scrollLeft() +if(offset<0){this.$el.animate({'scrollLeft':$el.get(0).offsetLeft},params) +animated=true}else{offset=$el.get(0).offsetLeft+$el.outerWidth()-(this.$el.scrollLeft()+this.$el.outerWidth()) +if(offset>0){this.$el.animate({'scrollLeft':$el.get(0).offsetLeft+$el.outerWidth()-this.$el.outerWidth()},params) +animated=true}}}else{offset=$el.get(0).offsetTop-this.$el.scrollTop() +if(this.options.animation){if(offset<0){this.$el.animate({'scrollTop':$el.get(0).offsetTop},params) +animated=true}else{offset=$el.get(0).offsetTop-(this.$el.scrollTop()+this.$el.outerHeight()) +if(offset>0){this.$el.animate({'scrollTop':$el.get(0).offsetTop+$el.outerHeight()-this.$el.outerHeight()},params) +animated=true}}}else{if(offset<0){this.$el.scrollTop($el.get(0).offsetTop)}else{offset=$el.get(0).offsetTop-(this.$el.scrollTop()+this.$el.outerHeight()) +if(offset>0) +this.$el.scrollTop($el.get(0).offsetTop+$el.outerHeight()-this.$el.outerHeight())}}} +if(!animated&&callback!==undefined) +callback() +return this} +Scrollbar.prototype.dispose=function(){this.$el=null +this.$scrollbar=null +this.$track=null +this.$thumb=null} +var old=$.fn.scrollbar +$.fn.scrollbar=function(option){return this.each(function(){var $this=$(this) +var data=$this.data('oc.scrollbar') +var options=$.extend({},Scrollbar.DEFAULTS,$this.data(),typeof option=='object'&&option) +if(!data)$this.data('oc.scrollbar',(data=new Scrollbar(this,options))) +if(typeof option=='string')data[option].call($this)})} +$.fn.scrollbar.Constructor=Scrollbar +$.fn.scrollbar.noConflict=function(){$.fn.scrollbar=old +return this} +$(document).render(function(){$('[data-control=scrollbar]').scrollbar()})}(window.jQuery);+function($){"use strict";var FileList=function(element,options){this.options=options +this.$el=$(element) +this.init();} +FileList.DEFAULTS={ignoreItemClick:false} +FileList.prototype.init=function(){var self=this +this.$el.on('click','li.group > h4 > a, li.group > div.group',function(){self.toggleGroup($(this).closest('li')) +return false;});if(!this.options.ignoreItemClick){this.$el.on('click','li.item > a',function(event){var e=$.Event('open.oc.list',{relatedTarget:$(this).parent().get(0),clickEvent:event}) +self.$el.trigger(e,this) +return false})} +this.$el.on('ajaxUpdate',$.proxy(this.update,this))} +FileList.prototype.toggleGroup=function(group){var $group=$(group);$group.attr('data-status')=='expanded'?this.collapseGroup($group):this.expandGroup($group)} +FileList.prototype.collapseGroup=function(group){var +$list=$('> ul, > div.subitems',group),self=this;$list.css('overflow','hidden') +$list.animate({'height':0},{duration:100,queue:false,complete:function(){$list.css({'overflow':'visible','display':'none'}) +$(group).attr('data-status','collapsed') +$(window).trigger('resize')}}) +this.sendGroupStatusRequest(group,0);} +FileList.prototype.expandGroup=function(group){var +$list=$('> ul, > div.subitems',group),self=this;$list.css({'overflow':'hidden','display':'block','height':0}) +$list.animate({'height':$list[0].scrollHeight},{duration:100,queue:false,complete:function(){$list.css({'overflow':'visible','height':'auto'}) +$(group).attr('data-status','expanded') +$(window).trigger('resize')}}) +this.sendGroupStatusRequest(group,1);} +FileList.prototype.sendGroupStatusRequest=function(group,status){if(this.options.groupStatusHandler!==undefined){var groupId=$(group).data('group-id') +if(groupId===undefined) +groupId=$('> h4 a',group).text();$(group).request(this.options.groupStatusHandler,{data:{group:groupId,status:status}})}} +FileList.prototype.markActive=function(dataId){$('li.item',this.$el).removeClass('active') +if(dataId) +$('li.item[data-id="'+dataId+'"]',this.$el).addClass('active') +this.dataId=dataId} +FileList.prototype.update=function(){if(this.dataId!==undefined) +this.markActive(this.dataId)} +var old=$.fn.fileList +$.fn.fileList=function(option){var args=arguments;return this.each(function(){var $this=$(this) +var data=$this.data('oc.fileList') +var options=$.extend({},FileList.DEFAULTS,$this.data(),typeof option=='object'&&option) +if(!data)$this.data('oc.fileList',(data=new FileList(this,options))) +if(typeof option=='string'){var methodArgs=[];for(var i=1;i0){fixedWidth=0 +$children.each(function(){$el=$(this) +margin=$el.data('oc.layoutMargin') +if(margin===undefined){margin=parseInt($el.css('marginRight'))+parseInt($el.css('marginLeft')) +$el.data('oc.layoutMargin',margin)} +fixedWidth+=$el.get(0).offsetWidth+margin}) +$(this).width(fixedWidth) +$(this).trigger('oc.widthFixed')}})} +OctoberLayout.prototype.toggleAccountMenu=function(el){var self=this,$el=$(el),$parent=$(el).parent(),$menu=$el.next() +$el.tooltip('hide') +if($menu.hasClass('active')){self.$accountMenuOverlay.remove() +$parent.removeClass('highlight') +$menu.removeClass('active')} +else{self.$accountMenuOverlay=$('
').addClass('popover-overlay') +$(document.body).append(self.$accountMenuOverlay) +$parent.addClass('highlight') +$menu.addClass('active') +self.$accountMenuOverlay.one('click',function(){self.$accountMenuOverlay.remove() +$menu.removeClass('active') +$parent.removeClass('highlight')})}} +if($.oc===undefined) +$.oc={} +$.oc.layout=new OctoberLayout() +$(document).ready(function(){$.oc.layout.updateLayout() +window.setTimeout($.oc.layout.updateLayout,100)}) +$(window).on('resize',function(){$.oc.layout.updateLayout()}) +$(window).on('oc.updateUi',function(){$.oc.layout.updateLayout()})})(jQuery);+function($){"use strict";var SidePanelTab=function(element,options){this.options=options +this.$el=$(element) +this.init()} +SidePanelTab.prototype.init=function(){var self=this +this.tabOpenDelay=200 +this.tabOpenTimeout=undefined +this.panelOpenTimeout=undefined +this.$sideNav=$('#layout-sidenav') +this.$sideNavItems=$('ul li',this.$sideNav) +this.$sidePanelItems=$('[data-content-id]',this.$el) +this.sideNavWidth=this.$sideNavItems.outerWidth() +this.mainNavHeight=$('#layout-mainmenu').outerHeight() +this.panelVisible=false +this.visibleItemId=false +this.$fixButton=$('') +this.$fixButton.click(function(){self.fixPanel() +return false}) +$('.fix-button-container',this.$el).append(this.$fixButton) +this.$sideNavItems.click(function(){if($(this).data('no-side-panel')){return} +if(Modernizr.touchevents&&$(window).width()this.options.breakpoint&&this.panelFixed()){this.hideSidePanel()}} +SidePanelTab.prototype.updateActiveTab=function(){if($.oc.sideNav===undefined){return} +if(!this.panelVisible&&($(window).width() ul, > ol').sortable(sortableOptions)} +if($el.hasClass('is-scrollable')){$el.wrapInner($('
').addClass('control-scrollbar')) +var $scrollbar=$el.find('>.control-scrollbar:first') +$scrollbar.scrollbar()}} +SimpleList.DEFAULTS={sortableHandle:null} +var old=$.fn.simplelist +$.fn.simplelist=function(option){return this.each(function(){var $this=$(this) +var data=$this.data('oc.simplelist') +var options=$.extend({},SimpleList.DEFAULTS,$this.data(),typeof option=='object'&&option) +if(!data)$this.data('oc.simplelist',(data=new SimpleList(this,options)))})} +$.fn.simplelist.Constructor=SimpleList +$.fn.simplelist.noConflict=function(){$.fn.simplelist=old +return this} +$(document).render(function(){$('[data-control="simplelist"]').simplelist()})}(window.jQuery);+function($){"use strict";var Base=$.oc.foundation.base,BaseProto=Base.prototype +var TreeListWidget=function(element,options){this.$el=$(element) +this.options=options||{};Base.call(this) +$.oc.foundation.controlUtils.markDisposable(element) +this.init()} +TreeListWidget.prototype=Object.create(BaseProto) +TreeListWidget.prototype.constructor=TreeListWidget +TreeListWidget.prototype.init=function(){var sortableOptions={handle:this.options.handle,nested:this.options.nested,onDrop:this.proxy(this.onDrop),afterMove:this.proxy(this.onAfterMove)} +this.$el.find('> ol').sortable($.extend(sortableOptions,this.options)) +if(!this.options.nested) +this.$el.find('> ol ol').sortable($.extend(sortableOptions,this.options)) +this.$el.one('dispose-control',this.proxy(this.dispose))} +TreeListWidget.prototype.dispose=function(){this.unbind() +BaseProto.dispose.call(this)} +TreeListWidget.prototype.unbind=function(){this.$el.off('dispose-control',this.proxy(this.dispose)) +this.$el.find('> ol').sortable('destroy') +if(!this.options.nested){this.$el.find('> ol ol').sortable('destroy')} +this.$el.removeData('oc.treelist') +this.$el=null +this.options=null} +TreeListWidget.DEFAULTS={handle:null,nested:true} +TreeListWidget.prototype.onDrop=function($item,container,_super){if(!this.$el){return} +this.$el.trigger('move.oc.treelist',{item:$item,container:container}) +_super($item,container)} +TreeListWidget.prototype.onAfterMove=function($placeholder,container,$closestEl){if(!this.$el){return} +this.$el.trigger('aftermove.oc.treelist',{placeholder:$placeholder,container:container,closestEl:$closestEl})} +var old=$.fn.treeListWidget +$.fn.treeListWidget=function(option){var args=arguments,result +this.each(function(){var $this=$(this) +var data=$this.data('oc.treelist') +var options=$.extend({},TreeListWidget.DEFAULTS,$this.data(),typeof option=='object'&&option) +if(!data)$this.data('oc.treelist',(data=new TreeListWidget(this,options))) +if(typeof option=='string')result=data[option].call(data) +if(typeof result!='undefined')return false}) +return result?result:this} +$.fn.treeListWidget.Constructor=TreeListWidget +$.fn.treeListWidget.noConflict=function(){$.fn.treeListWidget=old +return this} +$(document).render(function(){$('[data-control="treelist"]').treeListWidget();})}(window.jQuery);+function($){"use strict";var SidenavTree=function(element,options){this.options=options +this.$el=$(element) +this.init()} +SidenavTree.DEFAULTS={treeName:'sidenav_tree'} +SidenavTree.prototype.init=function(){var self=this +$(document.body).addClass('has-sidenav-tree') +this.statusCookieName=this.options.treeName+'groupStatus' +this.searchCookieName=this.options.treeName+'search' +this.$searchInput=$(this.options.searchInput) +this.$el.on('click','li > div.group',function(){self.toggleGroup($(this).closest('li')) +return false}) +this.$searchInput.on('input',function(){self.handleSearchChange()}) +var searchTerm=$.cookie(this.searchCookieName) +if(searchTerm!==undefined&&searchTerm.length>0){this.$searchInput.val(searchTerm) +this.applySearch()} +var scrollbar=$('[data-control=scrollbar]',this.$el).data('oc.scrollbar'),active=$('li.active',this.$el) +if(active.length>0){scrollbar.gotoElement(active)}} +SidenavTree.prototype.toggleGroup=function(group){var $group=$(group),status=$group.attr('data-status') +status===undefined||status=='expanded'?this.collapseGroup($group):this.expandGroup($group)} +SidenavTree.prototype.collapseGroup=function(group){var +$list=$('> ul',group),self=this +$list.css('overflow','hidden') +$list.animate({'height':0},{duration:100,queue:false,complete:function(){$list.css({'overflow':'visible','display':'none'}) +$(group).attr('data-status','collapsed') +$(window).trigger('oc.updateUi') +self.saveGroupStatus($(group).data('group-code'),true)}})} +SidenavTree.prototype.expandGroup=function(group,duration){var +$list=$('> ul',group),self=this +duration=duration===undefined?100:duration +$list.css({'overflow':'hidden','height':0}) +$list.animate({'height':$list[0].scrollHeight},{duration:duration,queue:false,complete:function(){$list.css({'overflow':'visible','height':'auto','display':''}) +$(group).attr('data-status','expanded') +$(window).trigger('oc.updateUi') +self.saveGroupStatus($(group).data('group-code'),false)}})} +SidenavTree.prototype.saveGroupStatus=function(groupCode,collapsed){var collapsedGroups=$.cookie(this.statusCookieName),updatedGroups=[] +if(collapsedGroups===undefined){collapsedGroups=''} +collapsedGroups=collapsedGroups.split('|') +$.each(collapsedGroups,function(){if(groupCode!=this) +updatedGroups.push(this)}) +if(collapsed){updatedGroups.push(groupCode)} +$.cookie(this.statusCookieName,updatedGroups.join('|'),{expires:30,path:'/'})} +SidenavTree.prototype.handleSearchChange=function(){var lastValue=this.$searchInput.data('oc.lastvalue');if(lastValue!==undefined&&lastValue==this.$searchInput.val()){return} +this.$searchInput.data('oc.lastvalue',this.$searchInput.val()) +if(this.dataTrackInputTimer!==undefined){window.clearTimeout(this.dataTrackInputTimer)} +var self=this +this.dataTrackInputTimer=window.setTimeout(function(){self.applySearch()},300);$.cookie(this.searchCookieName,$.trim(this.$searchInput.val()),{expires:30,path:'/'})} +SidenavTree.prototype.applySearch=function(){var query=$.trim(this.$searchInput.val()),words=query.toLowerCase().split(' '),visibleGroups=[],visibleItems=[],self=this +if(query.length==0){$('li',this.$el).removeClass('hidden') +return} +$('ul.top-level > li',this.$el).each(function(){var $li=$(this) +if(self.textContainsWords($('div.group h3',$li).text(),words)){visibleGroups.push($li.get(0)) +$('ul li',$li).each(function(){visibleItems.push(this)})} +else{$('ul li',$li).each(function(){if(self.textContainsWords($(this).text(),words)||self.textContainsWords($(this).data('keywords'),words)){visibleGroups.push($li.get(0)) +visibleItems.push(this)}})}}) +$('ul.top-level > li',this.$el).each(function(){var $li=$(this),groupIsVisible=$.inArray(this,visibleGroups)!==-1 +$li.toggleClass('hidden',!groupIsVisible) +if(groupIsVisible) +self.expandGroup($li,0) +$('ul li',$li).each(function(){var $itemLi=$(this) +$itemLi.toggleClass('hidden',$.inArray(this,visibleItems)==-1)})}) +return false} +SidenavTree.prototype.textContainsWords=function(text,words){text=text.toLowerCase() +for(var i=0;i':'>','"':'"',"'":''','/':'/'},htmlEscaper=/[&<>"'\/]/g +return(''+string).replace(htmlEscaper,function(match){return htmlEscapes[match];})} +if(!!window.MSInputMethodContext&&!!document.documentMode){$(window).on('resize',function(){fixMediaManager() +fixSidebar()}) +function fixMediaManager(){var $el=$('div[data-control="media-manager"] .control-scrollpad') +$el.height($el.parent().height())} +function fixSidebar(){$('#layout-sidenav').height(Math.max($('#layout-body').innerHeight(),$(window).height()-$('#layout-mainmenu').height()))}} \ No newline at end of file diff --git a/modules/backend/assets/js/october.alert.js b/modules/backend/assets/js/october.alert.js new file mode 100644 index 0000000..11d9e64 --- /dev/null +++ b/modules/backend/assets/js/october.alert.js @@ -0,0 +1,90 @@ +/* + * Alerts + * + * Displays alert and confirmation dialogs + * + * JavaScript API: + * $.oc.alert() + * $.oc.confirm() + * + * Dependences: + * - Sweet Alert + * - Translations (october.lang.js) + */ +(function($){ + + if ($.oc === undefined) + $.oc = {} + + $.oc.alert = function alert(message) { + swal({ + title: message, + confirmButtonClass: 'btn-primary' + }) + } + + $.oc.confirm = function confirm(message, callback) { + + swal({ + title: message, + showCancelButton: true, + confirmButtonClass: 'btn-primary' + }, callback) + + } + +})(jQuery); + +/* + * Implement alerts with AJAX framework + */ + +$(window).on('ajaxErrorMessage', function(event, message){ + if (!message) return + + $.oc.alert(message) + + // Prevent the default alert() message + event.preventDefault() +}) + +$(window).on('ajaxConfirmMessage', function(event, message){ + if (!message) return + + $.oc.confirm(message, function(isConfirm){ + isConfirm + ? event.promise.resolve() + : event.promise.reject() + }) + + // Prevent the default confirm() message + event.preventDefault() + return true +}) + +/* + * Override "Sweet Alert" functions to translate default buttons + */ + +$(document).ready(function(){ + if (!window.swal) return + + var swal = window.swal + + window.sweetAlert = window.swal = function(message, callback) { + if (typeof message === 'object') { + // Do not override if texts are provided + message.confirmButtonText = message.confirmButtonText || $.oc.lang.get('alert.confirm_button_text') + message.cancelButtonText = message.cancelButtonText || $.oc.lang.get('alert.cancel_button_text') + } + else { + message = { + title: message, + confirmButtonText: $.oc.lang.get('alert.confirm_button_text'), + cancelButtonText: $.oc.lang.get('alert.cancel_button_text') + } + } + + swal(message, callback) + } +}) diff --git a/modules/backend/assets/js/october.datetime.js b/modules/backend/assets/js/october.datetime.js new file mode 100644 index 0000000..ae42996 --- /dev/null +++ b/modules/backend/assets/js/october.datetime.js @@ -0,0 +1,175 @@ +/* + * Date time converter. + * See moment.js for format options. + * http://momentjs.com/docs/#/displaying/format/ + * + * Usage: + * + * + * + * Alias options: + * + * time -> 6:28 AM + * timeLong -> 6:28:01 AM + * date -> 04/23/2016 + * dateMin -> 4/23/2016 + * dateLong -> April 23, 2016 + * dateLongMin -> Apr 23, 2016 + * dateTime -> April 23, 2016 6:28 AM + * dateTimeMin -> Apr 23, 2016 6:28 AM + * dateTimeLong -> Saturday, April 23, 2016 6:28 AM + * dateTimeLongMin -> Sat, Apr 23, 2016 6:29 AM + * + */ ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var DateTimeConverter = function (element, options) { + this.$el = $(element) + this.options = options || {} + + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + this.init() + } + + DateTimeConverter.prototype = Object.create(BaseProto) + DateTimeConverter.prototype.constructor = DateTimeConverter + + DateTimeConverter.prototype.init = function() { + this.initDefaults() + + this.$el.text(this.getDateTimeValue()) + + this.$el.one('dispose-control', this.proxy(this.dispose)) + } + + DateTimeConverter.prototype.initDefaults = function() { + if (!this.options.timezone) { + this.options.timezone = $('meta[name="backend-timezone"]').attr('content') + } + + if (!this.options.locale) { + this.options.locale = $('meta[name="backend-locale"]').attr('content') + } + + if (!this.options.format) { + this.options.format = 'llll' + } + + if (this.options.formatAlias) { + this.options.format = this.getFormatFromAlias(this.options.formatAlias) + } + + this.appTimezone = $('meta[name="app-timezone"]').attr('content') + if (!this.appTimezone) { + this.appTimezone = 'UTC' + } + } + + DateTimeConverter.prototype.getDateTimeValue = function() { + this.datetime = this.$el.attr('datetime') + + if (this.$el.get(0).hasAttribute('data-ignore-timezone')) { + this.appTimezone = 'UTC' + this.options.timezone = 'UTC' + } + + var momentObj = moment.tz(this.datetime, this.appTimezone), + result + + if (this.options.locale) { + momentObj = momentObj.locale(this.options.locale) + } + + if (this.options.timezone) { + momentObj = momentObj.tz(this.options.timezone) + } + + if (this.options.timeSince) { + result = momentObj.fromNow() + } + else if (this.options.timeTense) { + result = momentObj.calendar() + } + else { + result = momentObj.format(this.options.format) + } + + return result + } + + DateTimeConverter.prototype.getFormatFromAlias = function(alias) { + var map = { + time: 'LT', + timeLong: 'LTS', + date: 'L', + dateMin: 'l', + dateLong: 'LL', + dateLongMin: 'll', + dateTime: 'LLL', + dateTimeMin: 'lll', + dateTimeLong: 'LLLL', + dateTimeLongMin: 'llll' + } + + return map[alias] ? map[alias] : 'llll' + } + + DateTimeConverter.prototype.dispose = function() { + this.$el.off('dispose-control', this.proxy(this.dispose)) + this.$el.removeData('oc.dateTimeConverter') + + this.$el = null + this.options = null + + BaseProto.dispose.call(this) + } + + DateTimeConverter.DEFAULTS = { + format: null, + formatAlias: null, + timezone: null, + locale: null, + timeTense: false, + timeSince: false + } + + // PLUGIN DEFINITION + // ============================ + + var old = $.fn.dateTimeConverter + + $.fn.dateTimeConverter = function (option) { + var args = Array.prototype.slice.call(arguments, 1), items, result + + items = this.each(function () { + var $this = $(this) + var data = $this.data('oc.dateTimeConverter') + var options = $.extend({}, DateTimeConverter.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.dateTimeConverter', (data = new DateTimeConverter(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : items + } + + $.fn.dateTimeConverter.Constructor = DateTimeConverter + + $.fn.dateTimeConverter.noConflict = function () { + $.fn.dateTimeConverter = old + return this + } + + $(document).render(function (){ + $('time[data-datetime-control]').dateTimeConverter() + }) + +}(window.jQuery); diff --git a/modules/backend/assets/js/october.filelist.js b/modules/backend/assets/js/october.filelist.js new file mode 100644 index 0000000..9796372 --- /dev/null +++ b/modules/backend/assets/js/october.filelist.js @@ -0,0 +1,169 @@ +/* + * File List + * + * Creates a tree list of clickable folders and files. + * + * Data attributes: + * - data-control="filelist" - enables the file list plugin + * - data-group-status-handler - AJAX handler to execute when a group is collapsed or expanded by a user + * + * JavaScript API: + * $('#list').fileList() + * + * Events + * - open.oc.list - this event is triggered on the list element when an item is clicked. + * + * Dependences: + * - Null + */ + ++function ($) { "use strict"; + + // FILELIST CLASS DEFINITION + // ============================ + + var FileList = function(element, options) { + this.options = options + this.$el = $(element) + + this.init(); + } + + FileList.DEFAULTS = { + ignoreItemClick: false + } + + FileList.prototype.init = function (){ + var self = this + + this.$el.on('click', 'li.group > h4 > a, li.group > div.group', function() { + self.toggleGroup($(this).closest('li')) + + return false; + }); + + if (!this.options.ignoreItemClick) { + this.$el.on('click', 'li.item > a', function(event) { + var e = $.Event('open.oc.list', {relatedTarget: $(this).parent().get(0), clickEvent: event}) + self.$el.trigger(e, this) + + return false + }) + } + + this.$el.on('ajaxUpdate', $.proxy(this.update, this)) + } + + FileList.prototype.toggleGroup = function(group) { + var $group = $(group); + + $group.attr('data-status') == 'expanded' ? + this.collapseGroup($group) : + this.expandGroup($group) + } + + FileList.prototype.collapseGroup = function(group) { + var + $list = $('> ul, > div.subitems', group), + self = this; + + $list.css('overflow', 'hidden') + $list.animate({'height': 0}, { duration: 100, queue: false, complete: function() { + $list.css({ + 'overflow': 'visible', + 'display': 'none' + }) + $(group).attr('data-status', 'collapsed') + $(window).trigger('resize') + } }) + + this.sendGroupStatusRequest(group, 0); + } + + FileList.prototype.expandGroup = function(group) { + var + $list = $('> ul, > div.subitems', group), + self = this; + + $list.css({ + 'overflow': 'hidden', + 'display': 'block', + 'height': 0 + }) + $list.animate({'height': $list[0].scrollHeight}, { duration: 100, queue: false, complete: function() { + $list.css({ + 'overflow': 'visible', + 'height': 'auto' + }) + $(group).attr('data-status', 'expanded') + $(window).trigger('resize') + } }) + + this.sendGroupStatusRequest(group, 1); + } + + FileList.prototype.sendGroupStatusRequest = function(group, status) { + if (this.options.groupStatusHandler !== undefined) { + var groupId = $(group).data('group-id') + if (groupId === undefined) + groupId = $('> h4 a', group).text(); + + $(group).request(this.options.groupStatusHandler, {data: {group: groupId, status: status}}) + } + } + + FileList.prototype.markActive = function(dataId) { + $('li.item', this.$el).removeClass('active') + if (dataId) + $('li.item[data-id="'+dataId+'"]', this.$el).addClass('active') + + this.dataId = dataId + } + + FileList.prototype.update = function() { + if (this.dataId !== undefined) + this.markActive(this.dataId) + } + + // FILELIST PLUGIN DEFINITION + // ============================ + + var old = $.fn.fileList + + $.fn.fileList = function (option) { + var args = arguments; + + return this.each(function () { + var $this = $(this) + var data = $this.data('oc.fileList') + var options = $.extend({}, FileList.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) $this.data('oc.fileList', (data = new FileList(this, options))) + if (typeof option == 'string') { + var methodArgs = []; + for (var i=1; i .layout-cell'), + $flyout = this.$el.find('> .flyout') + + $('[data-control=layout-sidepanel]').sidePanelTab('hideSidePanel') + + this.removeOverlay() + + for (var i = 0; i < $cells.length; i++) { + var $cell = $($cells[i]), + width = $cell.width() + + $cell.css('width', width) + } + + this.createOverlay() + + window.setTimeout(this.proxy(this.setBodyClass), 1) + $flyout.css('width', this.options.flyoutWidth) + + this.hideToggle() + } + + Flyout.prototype.hide = function() { + var $cells = this.$el.find('> .layout-cell'), + $flyout = this.$el.find('> .flyout') + + for (var i = 0; i < $cells.length; i++) { + var $cell = $($cells[i]) + + $cell.css('width', '') + } + + $flyout.css('width', 0) + + window.setTimeout(this.proxy(this.removeBodyClass), 1) + window.setTimeout(this.proxy(this.removeOverlayAndShowToggle), 300) + } + + // FLYOUT INTERNAL METHODS + // ============================ + + Flyout.prototype.init = function() { + this.build() + } + + Flyout.prototype.build = function() { + if (this.options.flyoutToggle) { + this.buildToggle() + } + } + + Flyout.prototype.buildToggle = function() { + var $toggleContainer = $(this.options.flyoutToggle), + $toggle = $('
') + + $toggle.on('click', this.proxy(this.show)) + $toggleContainer.append($toggle) + } + + Flyout.prototype.removeToggle = function() { + var $toggle = this.getToggle() + + $toggle.off('click', this.proxy(this.show)) + $toggle.remove() + } + + Flyout.prototype.hideToggle = function() { + if (!this.options.flyoutToggle) { + return + } + + this.getToggle().hide() + } + + Flyout.prototype.showToggle = function() { + if (!this.options.flyoutToggle) { + return + } + + this.getToggle().show() + } + + Flyout.prototype.getToggle = function() { + var $toggleContainer = $(this.options.flyoutToggle) + + return $toggleContainer.find('.flyout-toggle') + } + + Flyout.prototype.setBodyClass = function() { + $(document.body).addClass('flyout-visible') + } + + Flyout.prototype.removeBodyClass = function() { + $(document.body).removeClass('flyout-visible') + } + + Flyout.prototype.createOverlay = function() { + this.$overlay = $('
') + + var position = this.$el.offset() + + this.$overlay.css({ + top: position.top, + left: this.options.flyoutWidth + }) + + this.$overlay.on('click', this.proxy(this.onOverlayClick)) + $(document.body).on('keydown', this.proxy(this.onDocumentKeydown)) + + $(document.body).append(this.$overlay) + } + + Flyout.prototype.removeOverlay = function() { + if (!this.$overlay) { + return + } + + this.$overlay.off('click', this.proxy(this.onOverlayClick)) + $(document.body).off('keydown', this.proxy(this.onDocumentKeydown)) + + this.$overlay.remove() + this.$overlay = null + } + + Flyout.prototype.removeOverlayAndShowToggle = function() { + this.removeOverlay() + this.showToggle() + } + + // EVENT HANDLERS + // ============================ + + Flyout.prototype.onOverlayClick = function() { + this.hide() + } + + Flyout.prototype.onDocumentKeydown = function(ev) { + if (ev.key === 'Escape') { + this.hide(); + } + } + + // FLYOUT PLUGIN DEFINITION + // ============================ + + Flyout.DEFAULTS = { + flyoutWidth: 400, + flyoutToggle: null + } + + var old = $.fn.flyout + + $.fn.flyout = function (option) { + var args = Array.prototype.slice.call(arguments, 1), + result = undefined + + this.each(function () { + var $this = $(this) + var data = $this.data('oc.flyout') + var options = $.extend({}, Flyout.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.flyout', (data = new Flyout(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : this + } + + $.fn.flyout.Constructor = Flyout + + // FLYOUT NO CONFLICT + // ================= + + $.fn.flyout.noConflict = function () { + $.fn.flyout = old + return this + } + + // FLYOUT DATA-API + // =============== + + // Currently flyouts don't use the document render event + // and can't be created dynamically (performance considerations). + $(document).ready(function(){ + $('div[data-control=flyout]').flyout() + }) +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/assets/js/october.js b/modules/backend/assets/js/october.js new file mode 100644 index 0000000..17fd9d3 --- /dev/null +++ b/modules/backend/assets/js/october.js @@ -0,0 +1,36 @@ +/* + * This is a bundle file, you can compile this in two ways: + * (1) Using your favorite JS combiner + * (2) Using CLI command: + * php artisan october:util compile assets + * + * @see october-min.js + * + +=require vendor/jquery.touchwipe.js +=require vendor/jquery.autoellipsis.js +=require vendor/jquery.waterfall.js +=require vendor/jquery.cookie.js +=require ../vendor/dropzone/dropzone.js +=require ../vendor/sweet-alert/sweet-alert.js +=require ../vendor/jcrop/js/jquery.Jcrop.js +=require ../../../system/assets/vendor/prettify/prettify.js +=require ../../widgets/mediamanager/assets/js/mediamanager-global.js + +=require october.lang.js +=require october.alert.js +=require october.scrollpad.js +=require october.verticalmenu.js +=require october.navbar.js +=require october.sidenav.js +=require october.scrollbar.js +=require october.filelist.js +=require october.layout.js +=require october.sidepaneltab.js +=require october.simplelist.js +=require october.treelist.js +=require october.sidenav-tree.js +=require october.datetime.js + +=require backend.js +*/ diff --git a/modules/backend/assets/js/october.lang.js b/modules/backend/assets/js/october.lang.js new file mode 100644 index 0000000..92ed770 --- /dev/null +++ b/modules/backend/assets/js/october.lang.js @@ -0,0 +1,50 @@ +/* + * Client side translations + */ + +if ($.oc === undefined) + $.oc = {} + +if ($.oc.langMessages === undefined) + $.oc.langMessages = {} + +$.oc.lang = (function(lang, messages) { + + lang.load = function(locale) { + if (messages[locale] === undefined) { + messages[locale] = {} + } + + lang.loadedMessages = messages[locale] + } + + lang.get = function(name, defaultValue) { + if (!name) return + + var result = lang.loadedMessages + + if (!defaultValue) defaultValue = name + + $.each(name.split('.'), function(index, value) { + if (result[value] === undefined) { + result = defaultValue + return false + } + + result = result[value] + }) + + return result + } + + if (lang.locale === undefined) { + lang.locale = $('html').attr('lang') || 'en' + } + + if (lang.loadedMessages === undefined) { + lang.load(lang.locale) + } + + return lang + +})($.oc.lang || {}, $.oc.langMessages); \ No newline at end of file diff --git a/modules/backend/assets/js/october.layout.js b/modules/backend/assets/js/october.layout.js new file mode 100644 index 0000000..3f0af1c --- /dev/null +++ b/modules/backend/assets/js/october.layout.js @@ -0,0 +1,84 @@ +(function($){ + var OctoberLayout = function() { + this.$accountMenuOverlay = null + } + + OctoberLayout.prototype.setPageTitle = function(title) { + var $title = $('title') + + if (this.pageTitleTemplate === undefined) + this.pageTitleTemplate = $title.data('titleTemplate') + + $title.text(this.pageTitleTemplate.replace('%s', title)) + } + + OctoberLayout.prototype.updateLayout = function(title) { + var $children, $el, fixedWidth, margin + + $('[data-calculate-width]').each(function(){ + $children = $(this).children() + + if ($children.length > 0) { + fixedWidth = 0 + + $children.each(function() { + $el = $(this) + margin = $el.data('oc.layoutMargin') + + if (margin === undefined) { + margin = parseInt($el.css('marginRight')) + parseInt($el.css('marginLeft')) + $el.data('oc.layoutMargin', margin) + } + fixedWidth += $el.get(0).offsetWidth + margin + }) + + $(this).width(fixedWidth) + $(this).trigger('oc.widthFixed') + } + }) + } + + OctoberLayout.prototype.toggleAccountMenu = function(el) { + var self = this, + $el = $(el), + $parent = $(el).parent(), + $menu = $el.next() + + $el.tooltip('hide') + + if ($menu.hasClass('active')) { + self.$accountMenuOverlay.remove() + $parent.removeClass('highlight') + $menu.removeClass('active') + } + else { + self.$accountMenuOverlay = $('
').addClass('popover-overlay') + $(document.body).append(self.$accountMenuOverlay) + $parent.addClass('highlight') + $menu.addClass('active') + + self.$accountMenuOverlay.one('click', function(){ + self.$accountMenuOverlay.remove() + $menu.removeClass('active') + $parent.removeClass('highlight') + }) + } + } + + if ($.oc === undefined) + $.oc = {} + + $.oc.layout = new OctoberLayout() + + $(document).ready(function(){ + $.oc.layout.updateLayout() + + window.setTimeout($.oc.layout.updateLayout, 100) + }) + $(window).on('resize', function() { + $.oc.layout.updateLayout() + }) + $(window).on('oc.updateUi', function() { + $.oc.layout.updateLayout() + }) +})(jQuery); \ No newline at end of file diff --git a/modules/backend/assets/js/october.navbar.js b/modules/backend/assets/js/october.navbar.js new file mode 100644 index 0000000..25c9b7d --- /dev/null +++ b/modules/backend/assets/js/october.navbar.js @@ -0,0 +1,41 @@ +/* + * Top navigation bar. Features of the bar: + * - Hide content if the display width is less than 768px. In this case the menu icon is displayed. + * When the icon is clicked, the menu content is displayed on the left side of the page. + * - If the content doesn't fit the navbar, it can be dragged left and right. + * + * Dependences: + * - DragScroll (october.dragscroll.js) + * - VerticalMenu (october.verticalmenu.js) + */ + +(function($){ + $(document).ready(function(){ + $('nav.navbar').each(function(){ + var + navbar = $(this), + nav = $('ul.nav', navbar), + collapseMode = navbar.hasClass('navbar-mode-collapse'), + isMobile = $('html').hasClass('mobile') + + nav.verticalMenu($('a.menu-toggle', navbar), { + breakpoint: collapseMode ? Infinity : 769 + }) + + $('li.with-tooltip:not(.active) > a', navbar).tooltip({ + container: 'body', + placement: 'bottom', + template: '' + }) + .on('show.bs.tooltip', function (e) { + if (isMobile) e.preventDefault() + }) + + // Scroll to the currently active nav item. + var dragScroll = $('[data-control=toolbar]', navbar).data('oc.dragScroll') + if (dragScroll) { + dragScroll.goToElement($('ul.nav > li.active', navbar), undefined, {'duration': 0}) + } + }) + }) +})(jQuery); diff --git a/modules/backend/assets/js/october.scrollbar.js b/modules/backend/assets/js/october.scrollbar.js new file mode 100644 index 0000000..c99628b --- /dev/null +++ b/modules/backend/assets/js/october.scrollbar.js @@ -0,0 +1,409 @@ +/* + * Creates a scrollbar in a container. + * + * Note the element must have a height set for vertical, + * and a width set for horizontal. + * + * Data attributes: + * - data-control="scrollbar" - enables the scrollbar plugin + * + * JavaScript API: + * $('#area').scrollbar() + * + * Dependences: + * - Mouse Wheel plugin (mousewheel.js) + */ ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var Scrollbar = function (element, options) { + + var + $el = this.$el = $(element), + el = $el.get(0), + self = this, + options = this.options = options || {}, + sizeName = this.sizeName = options.vertical ? 'height' : 'width', + isNative = $('html').hasClass('mobile'), + isTouch = this.isTouch = Modernizr.touchevents, + isScrollable = this.isScrollable = false, + isLocked = this.isLocked = false, + eventElementName = options.vertical ? 'pageY' : 'pageX', + dragStart = 0, + startOffset = 0; + + $.oc.foundation.controlUtils.markDisposable(element) + + Base.call(this) + + this.$el.one('dispose-control', this.proxy(this.dispose)) + + /* + * Native (mobile) environments use overflow auto in CSS + */ + if (isNative) { + return + } + + /* + * Create Scrollbar + */ + this.$scrollbar = $('
').addClass('scrollbar-scrollbar') + this.$track = $('
').addClass('scrollbar-track').appendTo(this.$scrollbar) + this.$thumb = $('
').addClass('scrollbar-thumb').appendTo(this.$track) + + $el + .addClass('drag-scrollbar') + .addClass(options.vertical ? 'vertical' : 'horizontal') + .prepend(this.$scrollbar) + + /* + * Bind events + */ + if (isTouch) { + this.$el.on('touchstart', function (event){ + var touchEvent = event.originalEvent; + if (touchEvent.touches.length == 1) { + startDrag(touchEvent.touches[0]) + event.stopPropagation() + } + }) + } + else { + this.$thumb.on('mousedown', function (event){ + startDrag(event) + }) + this.$track.on('mouseup', function (event){ + moveDrag(event) + }) + } + + $el.mousewheel(function (event){ + var offset = self.options.vertical + ? ((event.deltaFactor * event.deltaY) * -1) + : (event.deltaFactor * event.deltaX) + + return !scrollWheel(offset * self.options.scrollSpeed) + }) + + $el.on('oc.scrollbar.gotoStart', function(event){ + self.options.vertical + ? $el.scrollTop(0) + : $el.scrollLeft(0) + + self.update() + event.stopPropagation() + }) + + $(window).on('resize', $.proxy(this.update, this)) + $(window).on('oc.updateUi', $.proxy(this.update, this)) + + /* + * Internal event, drag has started + */ + function startDrag(event) { + $('body').addClass('drag-noselect') + $el.trigger('oc.scrollStart') + + dragStart = event[eventElementName] + startOffset = self.options.vertical ? $el.scrollTop() : $el.scrollLeft() + + if (isTouch) { + $(window).on('touchmove.scrollbar', function(event) { + var touchEvent = event.originalEvent + if (moveDrag(touchEvent.touches[0])) + event.preventDefault(); + }); + + $el.on('touchend.scrollbar', stopDrag) + } + else { + $(window).on('mousemove.scrollbar', function(event){ + moveDrag(event) + return false + }) + + $(window).on('mouseup.scrollbar', function(){ + stopDrag() + return false + }) + } + } + + /* + * Internal event, drag is active + */ + function moveDrag(event) { + self.isLocked = true; + + var + offset, + dragTo = event[eventElementName] + + // Touch devices use an inverse scrolling interface + // with a 1:1 ratio + if (self.isTouch) { + offset = dragStart - dragTo + } + // Mouse devices use a natural scrolling interface + // with a track:canvas ratio + else { + var ratio = self.getCanvasSize() / self.getViewportSize() + offset = (dragTo - dragStart) * ratio + } + + self.options.vertical + ? $el.scrollTop(startOffset + offset) + : $el.scrollLeft(startOffset + offset) + + self.setThumbPosition() + + return self.options.vertical + ? el.scrollTop != startOffset + : el.scrollLeft != startOffset + } + + /* + * Internal event, drag has ended + */ + function stopDrag() { + $('body').removeClass('drag-noselect') + $el.trigger('oc.scrollEnd') + + $(window).off('.scrollbar') + } + + /* + * Scroll wheel has moved by supplied offset + */ + + var isWebkit = $(document.documentElement).hasClass('webkit') + + function scrollWheel(offset) { + startOffset = self.options.vertical ? el.scrollTop : el.scrollLeft + $el.trigger('oc.scrollStart') + + self.options.vertical + ? $el.scrollTop(startOffset + offset) + : $el.scrollLeft(startOffset + offset) + + var scrolled = self.options.vertical + ? el.scrollTop != startOffset + : el.scrollLeft != startOffset + + self.setThumbPosition() + if (!isWebkit) { + if (self.endScrollTimeout !== undefined) { + clearTimeout(self.endScrollTimeout) + self.endScrollTimeout = undefined + } + + self.endScrollTimeout = setTimeout(function() { + $el.trigger('oc.scrollEnd') + self.endScrollTimeout = undefined + }, 50) + } else { + $el.trigger('oc.scrollEnd') + } + + return scrolled + } + + /* + * Give the DOM a second, then set the track and thumb size + */ + setTimeout(function() { self.update() }, 1); + } + + Scrollbar.prototype = Object.create(BaseProto) + Scrollbar.prototype.constructor = Scrollbar + + Scrollbar.prototype.dispose = function() { + this.unregisterHandlers() + + BaseProto.dispose.call(this) + } + + Scrollbar.prototype.unregisterHandlers = function() { + + } + + Scrollbar.DEFAULTS = { + vertical: true, + scrollSpeed: 2, + animation: true, + start: function() {}, + drag: function() {}, + stop: function() {} + } + + Scrollbar.prototype.update = function() { + if (!this.$scrollbar) + return + + this.$scrollbar.hide() + this.setThumbSize() + this.setThumbPosition() + this.$scrollbar.show() + } + + Scrollbar.prototype.setThumbSize = function() { + var properties = this.calculateProperties() + + this.isScrollable = !(properties.thumbSizeRatio >= 1); + this.$scrollbar.toggleClass('disabled', !this.isScrollable) + + if (this.options.vertical) { + this.$track.height(properties.canvasSize) + this.$thumb.height(properties.thumbSize) + } + else { + this.$track.width(properties.canvasSize) + this.$thumb.width(properties.thumbSize) + } + } + + Scrollbar.prototype.setThumbPosition = function() { + var properties = this.calculateProperties() + + if (this.options.vertical) + this.$thumb.css({top: properties.thumbPosition}) + else + this.$thumb.css({left: properties.thumbPosition}) + } + + Scrollbar.prototype.calculateProperties = function() { + + var $el = this.$el, + properties = {}; + + properties.viewportSize = this.getViewportSize() + properties.canvasSize = this.getCanvasSize() + properties.scrollAmount = (this.options.vertical) ? $el.scrollTop() : $el.scrollLeft() + + properties.thumbSizeRatio = properties.viewportSize / properties.canvasSize + properties.thumbSize = properties.viewportSize * properties.thumbSizeRatio + + properties.thumbPositionRatio = properties.scrollAmount / (properties.canvasSize - properties.viewportSize) + properties.thumbPosition = ((properties.viewportSize - properties.thumbSize) * properties.thumbPositionRatio) + properties.scrollAmount + + if (isNaN(properties.thumbPosition)) + properties.thumbPosition = 0 + + return properties; + } + + Scrollbar.prototype.getViewportSize = function() { + return (this.options.vertical) + ? this.$el.height() + : this.$el.width(); + } + + Scrollbar.prototype.getCanvasSize = function() { + return (this.options.vertical) + ? this.$el.get(0).scrollHeight + : this.$el.get(0).scrollWidth; + } + + Scrollbar.prototype.gotoElement = function(element, callback) { + var $el = $(element) + if (!$el.length) + return; + + var self = this, + offset = 0, + animated = false, + params = { + duration: 300, + queue: false, + complete: function(){ + if (callback !== undefined) + callback() + } + } + + if (!this.options.vertical) { + offset = $el.get(0).offsetLeft - this.$el.scrollLeft() + + if (offset < 0) { + this.$el.animate({'scrollLeft': $el.get(0).offsetLeft}, params) + animated = true + } else { + offset = $el.get(0).offsetLeft + $el.outerWidth() - (this.$el.scrollLeft() + this.$el.outerWidth()) + if (offset > 0) { + this.$el.animate({'scrollLeft': $el.get(0).offsetLeft + $el.outerWidth() - this.$el.outerWidth()}, params) + animated = true + } + } + } else { + offset = $el.get(0).offsetTop - this.$el.scrollTop() + + if (this.options.animation) { + if (offset < 0) { + this.$el.animate({'scrollTop': $el.get(0).offsetTop}, params) + animated = true + } else { + offset = $el.get(0).offsetTop - (this.$el.scrollTop() + this.$el.outerHeight()) + if (offset > 0) { + this.$el.animate({'scrollTop': $el.get(0).offsetTop + $el.outerHeight() - this.$el.outerHeight()}, params) + animated = true + } + } + } else { + if (offset < 0) { + this.$el.scrollTop($el.get(0).offsetTop) + } else { + offset = $el.get(0).offsetTop - (this.$el.scrollTop() + this.$el.outerHeight()) + if (offset > 0) + this.$el.scrollTop($el.get(0).offsetTop + $el.outerHeight() - this.$el.outerHeight()) + } + } + } + + if (!animated && callback !== undefined) + callback() + + return this + } + + Scrollbar.prototype.dispose = function() { + this.$el = null + this.$scrollbar = null + this.$track = null + this.$thumb = null + } + + // SCROLLBAR PLUGIN DEFINITION + // ============================ + + var old = $.fn.scrollbar + + $.fn.scrollbar = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('oc.scrollbar') + var options = $.extend({}, Scrollbar.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) $this.data('oc.scrollbar', (data = new Scrollbar(this, options))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.scrollbar.Constructor = Scrollbar + + // SCROLLBAR NO CONFLICT + // ================= + + $.fn.scrollbar.noConflict = function () { + $.fn.scrollbar = old + return this + } + + // SCROLLBAR DATA-API + // =============== + $(document).render(function(){ + $('[data-control=scrollbar]').scrollbar() + }) + +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/assets/js/october.scrollpad.js b/modules/backend/assets/js/october.scrollpad.js new file mode 100644 index 0000000..8e2be62 --- /dev/null +++ b/modules/backend/assets/js/october.scrollpad.js @@ -0,0 +1,310 @@ +/* + * ScrollPad plugin. + * + * This plugin creates a scrollable area with features similar (but more limited) + * to october.scrollbar.js, with virtual scroll bars. This plugin is more lightweight + * in terms of calculations and more responsive. It doesn't use scripting for scrolling, + * instead it uses the native scrolling and listens for the onscroll event to update + * the virtual scroll bars. + * + * The plugin is partially based on Trackpad Scroll Emulator + * https://github.com/jnicol/trackpad-scroll-emulator, cleaned up for the better CPU and + * memory (DOM references) management. + * + * Expected markup: + *
+ *
+ *
+ * The content goes here. The two wrapping + * DIV elements are required. + *
+ *
+ *
+ * + * Data attributes: + * - data-control="scrollpad" - enables the plugin. + * - data-direction="vertical|horizontal" - sets the scrolling direction. + * + * JavaScript API: + * $('#area').scrollpad({direction: 'vertical'}) + * $('#area').scrollpad('dispose') + * $('#area').scrollpad('scrollToStart') + * + * TODO: In FireFox the control in the horizontal mode displays the native scrollbars, + * because negative margin-bottom in the scrollable element doesn't work for some reason. + * Try to align the scrollable element with absolute positioning (negative right and bottom) + * instead of negative margins. + * + */ ++function ($) { "use strict"; + + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + // SCROLLPAD CLASS DEFINITION + // ============================ + + var Scrollpad = function(element, options) { + this.$el = $(element) + this.scrollbarElement = null + this.dragHandleElement = null + this.scrollContentElement = null + this.contentElement = null + this.options = options + this.scrollbarSize = null + this.updateScrollbarTimer = null + this.dragOffset = null + + Base.call(this) + + // + // Initialization + // + + this.init() + + $.oc.foundation.controlUtils.markDisposable(element) + } + + Scrollpad.prototype = Object.create(BaseProto) + Scrollpad.prototype.constructor = Scrollpad + + Scrollpad.prototype.dispose = function() { + this.unregisterHandlers() + + this.$el.get(0).removeChild(this.scrollbarElement) + this.$el.removeData('oc.scrollpad') + this.$el = null + + this.scrollbarElement = null + this.dragHandleElement = null + this.scrollContentElement = null + this.contentElement = null + + BaseProto.dispose.call(this) + } + + Scrollpad.prototype.scrollToStart = function() { + var scrollAttr = this.options.direction == 'vertical' ? 'scrollTop' : 'scrollLeft' + this.scrollContentElement[scrollAttr] = 0 + } + + Scrollpad.prototype.update = function() { + this.updateScrollbarSize() + } + + // SCROLLPAD INTERNAL METHODS + // ============================ + + Scrollpad.prototype.init = function() { + this.build() + this.setScrollContentSize() + this.registerHandlers() + } + + Scrollpad.prototype.build = function() { + var el = this.$el.get(0) + + this.scrollContentElement = el.children[0] + this.contentElement = this.scrollContentElement.children[0] + this.$el.prepend('
') + this.scrollbarElement = el.querySelector('.scrollpad-scrollbar') + this.dragHandleElement = el.querySelector('.scrollpad-scrollbar > .drag-handle') + } + + Scrollpad.prototype.registerHandlers = function() { + this.$el.on('mouseenter', this.proxy(this.onMouseEnter)) + this.$el.on('mouseleave', this.proxy(this.onMouseLeave)) + + this.$el.one('dispose-control', this.proxy(this.dispose)) + + this.scrollContentElement.addEventListener('scroll', this.proxy(this.onScroll)) + this.dragHandleElement.addEventListener('mousedown', this.proxy(this.onStartDrag)) + } + + Scrollpad.prototype.unregisterHandlers = function() { + this.$el.off('mouseenter', this.proxy(this.onMouseEnter)) + this.$el.off('mouseleave', this.proxy(this.onMouseLeave)) + this.$el.off('dispose-control', this.proxy(this.dispose)) + this.scrollContentElement.removeEventListener('scroll', this.proxy(this.onScroll)) + this.dragHandleElement.removeEventListener('mousedown', this.proxy(this.onStartDrag)) + + document.removeEventListener('mousemove', this.proxy(this.onMouseMove)) + document.removeEventListener('mouseup', this.proxy(this.onEndDrag)) + } + + Scrollpad.prototype.setScrollContentSize = function() { + var scrollbarSize = this.getScrollbarSize() + + if (this.options.direction == 'vertical') + this.scrollContentElement.setAttribute('style', 'margin-right: -' + scrollbarSize + 'px') + else + this.scrollContentElement.setAttribute('style', 'margin-bottom: -' + scrollbarSize + 'px') + } + + Scrollpad.prototype.getScrollbarSize = function() { + if (this.scrollbarSize !== null) + return this.scrollbarSize + + var testerElement = document.createElement('div') + testerElement.setAttribute('class', 'scrollpad-scrollbar-size-tester') + testerElement.appendChild(document.createElement('div')) + + document.body.appendChild(testerElement) + + var width = testerElement.offsetWidth, + innerWidth = testerElement.querySelector('div').offsetWidth + + document.body.removeChild(testerElement) + + // Some magic for FireFox, see + // https://github.com/jnicol/trackpad-scroll-emulator/blob/master/jquery.trackpad-scroll-emulator.js + if (width === innerWidth && navigator.userAgent.toLowerCase().indexOf('firefox') > -1) + return this.scrollbarSize = 17 + + return this.scrollbarSize = width - innerWidth + } + + Scrollpad.prototype.updateScrollbarSize = function() { + this.scrollbarElement.removeAttribute('data-hidden') + + var contentSize = this.options.direction == 'vertical' ? this.contentElement.scrollHeight : this.contentElement.scrollWidth, + scrollOffset = this.options.direction == 'vertical' ? this.scrollContentElement.scrollTop : this.scrollContentElement.scrollLeft, + scrollbarSize = this.options.direction == 'vertical' ? this.scrollbarElement.offsetHeight : this.scrollbarElement.offsetWidth, + scrollbarRatio = scrollbarSize / contentSize, + handleOffset = Math.round(scrollbarRatio * scrollOffset) + 2, + handleSize = Math.floor(scrollbarRatio * (scrollbarSize - 2)) - 2; + + if (scrollbarSize < contentSize) { + if (this.options.direction == 'vertical') + this.dragHandleElement.setAttribute('style', 'top: ' + handleOffset + 'px; height: ' + handleSize + 'px') + else + this.dragHandleElement.setAttribute('style', 'left: ' + handleOffset + 'px; width: ' + handleSize + 'px') + + this.scrollbarElement.removeAttribute('data-hidden') + } + else + this.scrollbarElement.setAttribute('data-hidden', true) + } + + Scrollpad.prototype.displayScrollbar = function() { + this.clearUpdateScrollbarTimer() + + this.updateScrollbarSize() + this.scrollbarElement.setAttribute('data-visible', 'true') + } + + Scrollpad.prototype.hideScrollbar = function() { + this.scrollbarElement.removeAttribute('data-visible') + } + + Scrollpad.prototype.clearUpdateScrollbarTimer = function() { + if (this.updateScrollbarTimer === null) + return + + clearTimeout(this.updateScrollbarTimer) + this.updateScrollbarTimer = null + } + + // EVENT HANDLERS + // ============================ + + Scrollpad.prototype.onMouseEnter = function() { + this.displayScrollbar() + } + + Scrollpad.prototype.onMouseLeave = function() { + this.hideScrollbar() + } + + Scrollpad.prototype.onScroll = function() { + if (this.updateScrollbarTimer !== null) + return + + this.updateScrollbarTimer = setTimeout(this.proxy(this.displayScrollbar), 10) + } + + Scrollpad.prototype.onStartDrag = function(ev) { + $.oc.foundation.event.stop(ev) + + var pageCoords = $.oc.foundation.event.pageCoordinates(ev), + eventOffset = this.options.direction == 'vertical' ? pageCoords.y : pageCoords.x, + handleCoords = $.oc.foundation.element.absolutePosition(this.dragHandleElement), + handleOffset = this.options.direction == 'vertical' ? handleCoords.top : handleCoords.left + + this.dragOffset = eventOffset - handleOffset + + document.addEventListener('mousemove', this.proxy(this.onMouseMove)) + document.addEventListener('mouseup', this.proxy(this.onEndDrag)) + } + + Scrollpad.prototype.onMouseMove = function(ev) { + $.oc.foundation.event.stop(ev) + + var eventCoordsAttr = this.options.direction == 'vertical' ? 'y' : 'x', + elementCoordsAttr = this.options.direction == 'vertical' ? 'top' : 'left', + offsetAttr = this.options.direction == 'vertical' ? 'offsetHeight' : 'offsetWidth', + scrollAttr = this.options.direction == 'vertical' ? 'scrollTop' : 'scrollLeft' + + var eventOffset = $.oc.foundation.event.pageCoordinates(ev)[eventCoordsAttr], + scrollbarOffset = $.oc.foundation.element.absolutePosition(this.scrollbarElement)[elementCoordsAttr], + dragPos = eventOffset - scrollbarOffset - this.dragOffset, + scrollbarSize = this.scrollbarElement[offsetAttr], + contentSize = this.contentElement[offsetAttr], + dragPerc = dragPos / scrollbarSize + + if (dragPerc > 1) + dragPerc = 1 + + var scrollPos = dragPerc * contentSize; + + this.scrollContentElement[scrollAttr] = scrollPos + } + + Scrollpad.prototype.onEndDrag = function(ev) { + document.removeEventListener('mousemove', this.proxy(this.onMouseMove)) + document.removeEventListener('mouseup', this.proxy(this.onEndDrag)) + } + + // SCROLLPAD PLUGIN DEFINITION + // ============================ + + Scrollpad.DEFAULTS = { + direction: 'vertical' + } + + var old = $.fn.scrollpad + + $.fn.scrollpad = function (option) { + var args = Array.prototype.slice.call(arguments, 1), + result = undefined + + this.each(function () { + var $this = $(this) + var data = $this.data('oc.scrollpad') + var options = $.extend({}, Scrollpad.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.scrollpad', (data = new Scrollpad(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : this + } + + $.fn.scrollpad.Constructor = Scrollpad + + // SCROLLPAD NO CONFLICT + // ================= + + $.fn.scrollpad.noConflict = function () { + $.fn.scrollpad = old + return this + } + + // SCROLLPAD DATA-API + // =============== + + $(document).on('render', function(){ + $('div[data-control=scrollpad]').scrollpad() + }) +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/assets/js/october.sidenav-tree.js b/modules/backend/assets/js/october.sidenav-tree.js new file mode 100644 index 0000000..4415486 --- /dev/null +++ b/modules/backend/assets/js/october.sidenav-tree.js @@ -0,0 +1,268 @@ +/* + * Side navigation tree + * + * Data attributes: + * - data-control="sidenav-tree" - enables the plugin + * - data-tree-name - unique name of the tree control. The name is used for storing user configuration in the browser cookies. + * + * JavaScript API: + * $('#tree').sidenavTree() + * + * Dependences: + * - Null + */ + ++function ($) { "use strict"; + + // SIDENAVTREE CLASS DEFINITION + // ============================ + + var SidenavTree = function(element, options) { + this.options = options + this.$el = $(element) + + this.init() + } + + SidenavTree.DEFAULTS = { + treeName: 'sidenav_tree' + } + + SidenavTree.prototype.init = function (){ + var self = this + + $(document.body).addClass('has-sidenav-tree') + + this.statusCookieName = this.options.treeName + 'groupStatus' + this.searchCookieName = this.options.treeName + 'search' + this.$searchInput = $(this.options.searchInput) + + this.$el.on('click', 'li > div.group', function() { + self.toggleGroup($(this).closest('li')) + return false + }) + + this.$searchInput.on('input', function(){ + self.handleSearchChange() + }) + + var searchTerm = $.cookie(this.searchCookieName) + if (searchTerm !== undefined && searchTerm.length > 0) { + this.$searchInput.val(searchTerm) + this.applySearch() + } + + var scrollbar = $('[data-control=scrollbar]', this.$el).data('oc.scrollbar'), + active = $('li.active', this.$el) + + if (active.length > 0) { + scrollbar.gotoElement(active) + } + } + + SidenavTree.prototype.toggleGroup = function(group) { + var $group = $(group), + status = $group.attr('data-status') + + status === undefined || status == 'expanded' + ? this.collapseGroup($group) + : this.expandGroup($group) + } + + SidenavTree.prototype.collapseGroup = function(group) { + var + $list = $('> ul', group), + self = this + + $list.css('overflow', 'hidden') + $list.animate({ 'height': 0 }, { + duration: 100, + queue: false, + complete: function() { + $list.css({ + 'overflow': 'visible', + 'display': 'none' + }) + + $(group).attr('data-status', 'collapsed') + $(window).trigger('oc.updateUi') + self.saveGroupStatus($(group).data('group-code'), true) + } + }) + } + + SidenavTree.prototype.expandGroup = function(group, duration) { + var + $list = $('> ul', group), + self = this + + duration = duration === undefined ? 100 : duration + + $list.css({ + 'overflow': 'hidden', + 'height': 0 + }) + $list.animate({'height': $list[0].scrollHeight}, { duration: duration, queue: false, complete: function() { + $list.css({ + 'overflow': 'visible', + 'height': 'auto', + 'display': '' + }) + $(group).attr('data-status', 'expanded') + $(window).trigger('oc.updateUi') + self.saveGroupStatus($(group).data('group-code'), false) + } }) + } + + SidenavTree.prototype.saveGroupStatus = function(groupCode, collapsed) { + var collapsedGroups = $.cookie(this.statusCookieName), + updatedGroups = [] + + if (collapsedGroups === undefined) { + collapsedGroups = '' + } + + collapsedGroups = collapsedGroups.split('|') + $.each(collapsedGroups, function() { + if (groupCode != this) + updatedGroups.push(this) + }) + + if (collapsed) { + updatedGroups.push(groupCode) + } + + $.cookie(this.statusCookieName, updatedGroups.join('|'), { expires: 30, path: '/' }) + } + + SidenavTree.prototype.handleSearchChange = function() { + var lastValue = this.$searchInput.data('oc.lastvalue'); + + if (lastValue !== undefined && lastValue == this.$searchInput.val()) { + return + } + + this.$searchInput.data('oc.lastvalue', this.$searchInput.val()) + + if (this.dataTrackInputTimer !== undefined) { + window.clearTimeout(this.dataTrackInputTimer) + } + + var self = this + this.dataTrackInputTimer = window.setTimeout(function(){ + self.applySearch() + }, 300); + + $.cookie(this.searchCookieName, $.trim(this.$searchInput.val()), { expires: 30, path: '/' }) + } + + SidenavTree.prototype.applySearch = function() { + var query = $.trim(this.$searchInput.val()), + words = query.toLowerCase().split(' '), + visibleGroups = [], + visibleItems = [], + self = this + + if (query.length == 0) { + $('li', this.$el).removeClass('hidden') + + return + } + + /* + * Find visible groups and items + */ + $('ul.top-level > li', this.$el).each(function() { + var $li = $(this) + + if (self.textContainsWords($('div.group h3', $li).text(), words)) { + visibleGroups.push($li.get(0)) + + $('ul li', $li).each(function(){ + visibleItems.push(this) + }) + } + else { + $('ul li', $li).each(function(){ + if (self.textContainsWords($(this).text(), words) || self.textContainsWords($(this).data('keywords'), words)) { + visibleGroups.push($li.get(0)) + visibleItems.push(this) + } + }) + } + }) + + /* + * Hide invisible groups and items + */ + $('ul.top-level > li', this.$el).each(function() { + var $li = $(this), + groupIsVisible = $.inArray(this, visibleGroups) !== -1 + + $li.toggleClass('hidden', !groupIsVisible) + if (groupIsVisible) + self.expandGroup($li, 0) + + $('ul li', $li).each(function(){ + var $itemLi = $(this) + + $itemLi.toggleClass('hidden', $.inArray(this, visibleItems) == -1) + }) + }) + + return false + } + + SidenavTree.prototype.textContainsWords = function(text, words) { + text = text.toLowerCase() + + for (var i = 0; i < words.length; i++) { + if (text.indexOf(words[i]) === -1) + return false + } + + return true + } + + // SIDENAVTREE PLUGIN DEFINITION + // ============================ + + var old = $.fn.sidenavTree + + $.fn.sidenavTree = function (option) { + var args = arguments; + + return this.each(function () { + var $this = $(this) + var data = $this.data('oc.sidenavTree') + var options = $.extend({}, SidenavTree.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) $this.data('oc.sidenavTree', (data = new SidenavTree(this, options))) + if (typeof option == 'string') { + var methodArgs = []; + for (var i=1; i') + + this.$fixButton.click(function() { + self.fixPanel() + return false + }) + $('.fix-button-container', this.$el).append(this.$fixButton) + + this.$sideNavItems.click(function() { + if ($(this).data('no-side-panel')) { + return + } + + if (Modernizr.touchevents && $(window).width() < self.options.breakpoint) { + if ($(this).data('menu-item') == self.visibleItemId && self.panelVisible) { + self.hideSidePanel() + return + } + else { + self.displaySidePanel() + } + } + + self.displayTab(this) + + return false + }) + + if (!Modernizr.touchevents) { + // The side panel now opens only when a menu item is hovered and + // when the item doesn't have the "data-no-side-panel" attribute. + // TODO: remove the comment and the code below if no issues noticed. + // self.$sideNav.mouseenter(function() { + // if ($(window).width() < self.options.breakpoint || !self.panelFixed()) { + // self.panelOpenTimeout = setTimeout(function() { + // self.displaySidePanel() + // }, self.tabOpenDelay) + // } + // }) + + self.$sideNav.mouseleave(function() { + clearTimeout(self.panelOpenTimeout) + }) + + self.$el.mouseleave(function() { + self.hideSidePanel() + }) + + self.$sideNavItems.mouseenter(function() { + if ($(window).width() < self.options.breakpoint || !self.panelFixed()) { + if ($(this).data('no-side-panel')) { + self.hideSidePanel() + return + } + + var _this = this + self.tabOpenTimeout = setTimeout(function() { + self.displaySidePanel() + self.displayTab(_this) + }, self.tabOpenDelay) + } + }) + + self.$sideNavItems.mouseleave(function() { + clearTimeout(self.tabOpenTimeout) + }) + + $(window).resize(function() { + self.updatePanelPosition() + self.updateActiveTab() + }) + } + else { + $('#layout-body').click(function() { + if (self.panelVisible) { + self.hideSidePanel() + return false + } + }) + + self.$el.on('close.oc.sidePanel', function() { + self.hideSidePanel() + }) + } + + this.updateActiveTab() + } + + SidePanelTab.prototype.displayTab = function(menuItem) { + var menuItemId = $(menuItem).data('menu-item') + + this.visibleItemId = menuItemId + + if ($.oc.sideNav !== undefined) { + $.oc.sideNav.setActiveItem(menuItemId) + } + + this.$sidePanelItems.each(function() { + var $el = $(this) + $el.toggleClass('hide', $el.data('content-id') != menuItemId) + }) + + $(window).trigger('resize') + } + + SidePanelTab.prototype.displaySidePanel = function() { + $(document.body).addClass('display-side-panel') + + this.$el.appendTo('#layout-canvas') + this.panelVisible = true + this.$el.css({ + left: this.sideNavWidth, + top: this.mainNavHeight + }) + + this.updatePanelPosition() + $(window).trigger('resize') + } + + SidePanelTab.prototype.hideSidePanel = function() { + $(document.body).removeClass('display-side-panel') + if (this.$el.next('#layout-body').length == 0) { + $('#layout-body').before(this.$el) + } + + this.panelVisible = false + + this.updateActiveTab() + } + + SidePanelTab.prototype.updatePanelPosition = function() { + if (!this.panelFixed() || Modernizr.touchevents) { + this.$el.height($(document).height() - this.mainNavHeight) + } + else { + this.$el.css('height', '') + } + + if (this.panelVisible && $(window).width() > this.options.breakpoint && this.panelFixed()) { + this.hideSidePanel() + } + } + + SidePanelTab.prototype.updateActiveTab = function() { + if ($.oc.sideNav === undefined) { + return + } + + if (!this.panelVisible && ($(window).width() < this.options.breakpoint || !this.panelFixed())) { + $.oc.sideNav.unsetActiveItem() + } + else { + $.oc.sideNav.setActiveItem(this.visibleItemId) + } + } + + SidePanelTab.prototype.panelFixed = function() { + return !($(window).width() < this.options.breakpoint) && + !$(document.body).hasClass('side-panel-not-fixed') + } + + SidePanelTab.prototype.fixPanel = function() { + $(document.body).toggleClass('side-panel-not-fixed') + + var self = this + + window.setTimeout(function() { + var fixed = self.panelFixed() + + if (fixed) { + self.updateActiveTab() + $(document.body).addClass('side-panel-fix-shadow') + } else { + $(document.body).removeClass('side-panel-fix-shadow') + self.hideSidePanel() + } + + if (typeof(localStorage) !== 'undefined') + localStorage.ocSidePanelFixed = fixed ? 1 : 0 + }, 0) + } + + SidePanelTab.DEFAULTS = { + breakpoint: 769 + } + + // PLUGIN DEFINITION + // ============================ + + var old = $.fn.sidePanelTab + + $.fn.sidePanelTab = function (option) { + return this.each(function() { + var $this = $(this) + var data = $this.data('oc.sidePanelTab') + var options = $.extend({}, SidePanelTab.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.sidePanelTab', (data = new SidePanelTab(this, options))) + if (typeof option == 'string') data[option].call(data) + }) + } + + $.fn.sidePanelTab.Constructor = SidePanelTab + + // NO CONFLICT + // ================= + + $.fn.sidePanelTab.noConflict = function() { + $.fn.sidePanelTab = old + return this + } + + // DATA-API + // ============ + + $(document).ready(function(){ + $('[data-control=layout-sidepanel]').sidePanelTab() + }) + + // STORED PREFERENCES + // ==================== + + $(document).ready(function() { + if (Modernizr.touchevents || (typeof(localStorage) !== 'undefined')) { + if (localStorage.ocSidePanelFixed == 0) { + $(document.body).addClass('side-panel-not-fixed') + $(window).trigger('resize') + } + else if (localStorage.ocSidePanelFixed == 1) { + $(document.body).removeClass('side-panel-not-fixed') + $(window).trigger('resize') + } + } + }) +}(window.jQuery); diff --git a/modules/backend/assets/js/october.simplelist.js b/modules/backend/assets/js/october.simplelist.js new file mode 100644 index 0000000..f1158c7 --- /dev/null +++ b/modules/backend/assets/js/october.simplelist.js @@ -0,0 +1,81 @@ +/* + * SimpleList control. + * + * Data attributes: + * - data-control="simplelist" - enables the simplelist plugin + * + * JavaScript API: + * $('#simplelist').simplelist() + * + * Dependences: + * - Sortable (jquery-sortable.js) + */ ++function ($) { "use strict"; + + var SimpleList = function (element, options) { + + var $el = this.$el = $(element) + + this.options = options || {} + + if ($el.hasClass('is-sortable')) { + + /* + * Make each list inside sortable + */ + var sortableOptions = { + distance: 10 + } + if (this.options.sortableHandle) + sortableOptions[handle] = this.options.sortableHandle + + $el.find('> ul, > ol').sortable(sortableOptions) + } + + if ($el.hasClass('is-scrollable')) { + + /* + * Inject a scrollbar container + */ + $el.wrapInner($('
').addClass('control-scrollbar')) + var $scrollbar = $el.find('>.control-scrollbar:first') + $scrollbar.scrollbar() + } + } + + SimpleList.DEFAULTS = { + sortableHandle: null + } + + // SIMPLE LIST PLUGIN DEFINITION + // ============================ + + var old = $.fn.simplelist + + $.fn.simplelist = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('oc.simplelist') + var options = $.extend({}, SimpleList.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.simplelist', (data = new SimpleList(this, options))) + }) + } + + $.fn.simplelist.Constructor = SimpleList + + // SIMPLE LIST NO CONFLICT + // ================= + + $.fn.simplelist.noConflict = function () { + $.fn.simplelist = old + return this + } + + // SIMPLE LIST DATA-API + // =============== + + $(document).render(function(){ + $('[data-control="simplelist"]').simplelist() + }) + +}(window.jQuery); diff --git a/modules/backend/assets/js/october.tabformexpandcontrols.js b/modules/backend/assets/js/october.tabformexpandcontrols.js new file mode 100644 index 0000000..4998869 --- /dev/null +++ b/modules/backend/assets/js/october.tabformexpandcontrols.js @@ -0,0 +1,163 @@ +/* + * Extends the fancy tabs layout with expand controls in the tab + * form sections. See main Builder page for example. + * TODO: A similar layout is used in the CMS, Pages and Builder areas, + * but only Builder uses this class. + */ ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var TabFormExpandControls = function ($tabsControlElement, options) { + this.$tabsControlElement = $tabsControlElement + this.options = $.extend(TabFormExpandControls.DEFAULTS, typeof options == 'object' && options) + this.tabsControlId = null + + Base.call(this) + this.init() + } + + TabFormExpandControls.prototype = Object.create(BaseProto) + TabFormExpandControls.prototype.constructor = TabFormExpandControls + + TabFormExpandControls.prototype.init = function() { + this.tabsControlId = this.$tabsControlElement.attr('id') + + if (!this.tabsControlId) { + throw new Error('The tab controls element should have the id attribute value.') + } + + this.registerHandlers() + } + + TabFormExpandControls.prototype.dispose = function() { + this.unregisterHandlers() + + this.$tabsControlElement = null + + BaseProto.dispose.call(this) + } + + TabFormExpandControls.prototype.registerHandlers = function() { + this.$tabsControlElement.on('initTab.oc.tab', this.proxy(this.initTab)) + this.$tabsControlElement.on('click', '[data-control="tabless-collapse-icon"]', this.proxy(this.tablessCollapseClicked)) + this.$tabsControlElement.on('click', '[data-control="primary-collapse-icon"]', this.proxy(this.primaryCollapseClicked)) + } + + TabFormExpandControls.prototype.unregisterHandlers = function() { + this.$tabsControlElement.off('initTab.oc.tab', this.proxy(this.initTab)) + this.$tabsControlElement.off('click', '[data-control="tabless-collapse-icon"]', this.proxy(this.tablessCollapseClicked)) + this.$tabsControlElement.off('click', '[data-control="primary-collapse-icon"]', this.proxy(this.primaryCollapseClicked)) + } + + TabFormExpandControls.prototype.initTab = function(ev, data) { + if ($(ev.target).attr('id') != this.tabsControlId) + return + + var $primaryPanel = this.findPrimaryPanel(data.pane), + $panel = $('.form-tabless-fields', data.pane), + $secondaryPanel = this.findSecondaryPanel(data.pane), + hasSecondaryTabs = $secondaryPanel.length > 0 + + $secondaryPanel.addClass('secondary-content-tabs') + $panel.append(this.createTablessCollapseIcon()) + + if (!hasSecondaryTabs) { + $('.tab-pane', $primaryPanel).addClass('pane-compact') + } + + $('.nav-tabs', $primaryPanel).addClass('master-area') + + if ($primaryPanel.length > 0) { + $secondaryPanel.append(this.createPrimaryCollapseIcon()) + } else { + $secondaryPanel.addClass('primary-collapsed') + } + + if (!$('a', data.tab).hasClass('new-template') && this.getLocalStorageValue('tabless', 0) == 1) { + $panel.addClass('collapsed') + } + + if (this.getLocalStorageValue('primary', 0) == 1 && hasSecondaryTabs) { + $primaryPanel.addClass('collapsed') + $secondaryPanel.addClass('primary-collapsed') + } + + if (this.options.onInitTab) { + this.options.onInitTab($('form', data.pane)) + } + } + + TabFormExpandControls.prototype.tablessCollapseClicked = function(ev) { + var $panel = $(ev.target).closest('.form-tabless-fields') + + $panel.toggleClass('collapsed') + this.setLocalStorageValue('tabless', $panel.hasClass('collapsed') ? 1 : 0) + window.setTimeout(this.proxy(this.updateUi), 500) + + ev.stopPropagation() + return false + } + + TabFormExpandControls.prototype.primaryCollapseClicked = function(ev) { + var $pane = $(ev.target).closest('.tab-pane'), + $primaryPanel = this.findPrimaryPanel($pane), + $secondaryPanel = this.findSecondaryPanel($pane) + + $primaryPanel.toggleClass('collapsed') + $secondaryPanel.toggleClass('primary-collapsed') + + this.updateUi() + this.setLocalStorageValue('primary', $primaryPanel.hasClass('collapsed') ? 1 : 0) + + return false + } + + TabFormExpandControls.prototype.updateUi = function() { + $(window).trigger('oc.updateUi') + } + + TabFormExpandControls.prototype.createTablessCollapseIcon = function() { + return $('') + } + + TabFormExpandControls.prototype.createPrimaryCollapseIcon = function() { + return $('') + } + + TabFormExpandControls.prototype.generateStorageKey = function(section) { + return 'oc' + section + this.tabsControlId.replace('-', '') + 'collapsed' + } + + TabFormExpandControls.prototype.findPrimaryPanel = function(pane) { + return $(pane).find('.control-tabs.primary-tabs') + } + + TabFormExpandControls.prototype.findSecondaryPanel = function(pane) { + return $(pane).find('.control-tabs.secondary-tabs') + } + + TabFormExpandControls.prototype.getLocalStorageValue = function(section, defaultValue) { + var key = this.generateStorageKey(section) + + if (typeof(localStorage) !== 'undefined') { + return localStorage[key] + } + + return defaultValue + } + + TabFormExpandControls.prototype.setLocalStorageValue = function(section, value) { + var key = this.generateStorageKey(section) + + if (typeof(localStorage) !== 'undefined') { + localStorage[key] = value + } + } + + TabFormExpandControls.DEFAULTS = { + onInitTab: null + } + + $.oc.tabFormExpandControls = TabFormExpandControls +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/assets/js/october.treelist.js b/modules/backend/assets/js/october.treelist.js new file mode 100644 index 0000000..c0aaa50 --- /dev/null +++ b/modules/backend/assets/js/october.treelist.js @@ -0,0 +1,133 @@ +/* + * TreeList Widget + * + * Supported options: + * - handle - class name to use as a handle + * - nested - set to false if sorting should be kept within each OL container, if using + * a handle it should be focused enough to exclude nested handles. + * + * Events: + * - move.oc.treelist - triggered when a node on the tree is moved. + * + * Dependences: + * - Sortable Plugin (october.sortable.js) + */ ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var TreeListWidget = function (element, options) { + this.$el = $(element) + this.options = options || {}; + + Base.call(this) + + $.oc.foundation.controlUtils.markDisposable(element) + this.init() + } + + TreeListWidget.prototype = Object.create(BaseProto) + TreeListWidget.prototype.constructor = TreeListWidget + + TreeListWidget.prototype.init = function() { + var sortableOptions = { + handle: this.options.handle, + nested: this.options.nested, + onDrop: this.proxy(this.onDrop), + afterMove: this.proxy(this.onAfterMove) + } + + this.$el.find('> ol').sortable($.extend(sortableOptions, this.options)) + + if (!this.options.nested) + this.$el.find('> ol ol').sortable($.extend(sortableOptions, this.options)) + + this.$el.one('dispose-control', this.proxy(this.dispose)) + } + + TreeListWidget.prototype.dispose = function() { + this.unbind() + BaseProto.dispose.call(this) + } + + TreeListWidget.prototype.unbind = function() { + this.$el.off('dispose-control', this.proxy(this.dispose)) + + this.$el.find('> ol').sortable('destroy') + + if (!this.options.nested) { + this.$el.find('> ol ol').sortable('destroy') + } + + this.$el.removeData('oc.treelist') + + this.$el = null + this.options = null + } + + TreeListWidget.DEFAULTS = { + handle: null, + nested: true + } + + // TREELIST EVENT HANDLERS + // ============================ + + TreeListWidget.prototype.onDrop = function($item, container, _super) { + // The event handler could be registered after the + // sortable is destroyed. This should be fixed later. + if (!this.$el) { + return + } + + this.$el.trigger('move.oc.treelist', { item: $item, container: container }) + _super($item, container) + } + + TreeListWidget.prototype.onAfterMove = function($placeholder, container, $closestEl) { + if (!this.$el) { + return + } + + this.$el.trigger('aftermove.oc.treelist', { placeholder: $placeholder, container: container, closestEl: $closestEl }) + } + + // TREELIST WIDGET PLUGIN DEFINITION + // ============================ + + var old = $.fn.treeListWidget + + $.fn.treeListWidget = function (option) { + var args = arguments, + result + + this.each(function () { + var $this = $(this) + var data = $this.data('oc.treelist') + var options = $.extend({}, TreeListWidget.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.treelist', (data = new TreeListWidget(this, options))) + if (typeof option == 'string') result = data[option].call(data) + if (typeof result != 'undefined') return false + }) + + return result ? result : this + } + + $.fn.treeListWidget.Constructor = TreeListWidget + + // TREELIST WIDGET NO CONFLICT + // ================= + + $.fn.treeListWidget.noConflict = function () { + $.fn.treeListWidget = old + return this + } + + // TREELIST WIDGET DATA-API + // ============== + + $(document).render(function(){ + $('[data-control="treelist"]').treeListWidget(); + }) + +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/assets/js/october.treeview.js b/modules/backend/assets/js/october.treeview.js new file mode 100644 index 0000000..f443429 --- /dev/null +++ b/modules/backend/assets/js/october.treeview.js @@ -0,0 +1,437 @@ +/* + * TreeView Widget. Represents a sortable and draggable tree view. This widget was first used in the Pages plugin, for the sidebar page tree. + * + * Data attributes: + * - data-group-status-handler - AJAX handler to execute when an item is collapsed or expanded by a user + * - data-reorder-handler - AJAX handler to execute when items are reordered + * + * Events + * - open.oc.treeview - this event is triggered on the list element when an item is clicked. + * + * Dependences: + * - Tree list (october.treelist.js) + * + */ ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var TreeView = function (element, options) { + this.$el = $(element) + this.options = options + this.$allItems = null + this.$scrollbar = null + + Base.call(this) + + $.oc.foundation.controlUtils.markDisposable(element) + this.init() + } + + TreeView.prototype = Object.create(BaseProto) + TreeView.prototype.constructor = TreeView + + TreeView.prototype.init = function () { + this.$allItems = $('li', this.$el) + this.$scrollbar = this.$el.closest('[data-control=scrollbar]') + + /* + * Init the sortable + */ + + this.initSortable() + + /* + * Create expand/collapse icons and drag handles + */ + + this.createItemControls() + + /* + * Bind the click events + */ + + this.$el.on('click.treeview', 'li > div > ul.submenu li a', this.proxy(this.onOpenSubmenu)) + this.$el.on('click.treeview', 'li > div > a', this.proxy(this.onOpen)) + this.$el.on('click.treeview', 'li span.expand', this.proxy(this.onItemExpandClick)) + + /* + * Listen for the AJAX updates and dispose the widget + */ + + this.$el.one('dispose-control', this.proxy(this.dispose)) + + /* + * Mark previously active item, if it was set + */ + var dataId = this.$el.data('oc.active-item') + if (dataId !== undefined) { + this.markActive(dataId) + } + + this.$scrollbar.on('oc.scrollEnd', this.proxy(this.onScroll)) + } + + TreeView.prototype.dispose = function() { + this.unregisterHandlers() + this.clearScrollTimeout() + + this.options = null + this.$el.removeData('oc.treeView') + this.$el = null + this.$allItems = null + this.$scrollbar = null + + BaseProto.dispose.call(this) + } + + TreeView.prototype.unregisterHandlers = function() { + this.$scrollbar.off('oc.scrollEnd', this.proxy(this.onScroll)) + this.$el.off('.treeview') + this.$el.off('move.oc.treelist', this.proxy(this.onNodeMove)) + this.$el.off('aftermove.oc.treelist', this.proxy(this.onAfterNodeMove)) + this.$el.off('dispose-control', this.proxy(this.dispose)) + } + + TreeView.prototype.createItemControls = function() { + $('li', this.$el).each(function() { + var $container = $('> div', this), + $expand = $('> span.expand', $container) + + if ($expand.length > 0) + return + + $expand = $('Expand') + + $container.prepend($expand) + + if (!$('.drag-handle', $container).length) + $container.append($('Drag')) + + $container.append($('')) + + if ($(this).attr('data-no-drag-mode') !== undefined) + $('span.drag-handle', this).attr('title', 'Dragging is disabled when the Search is active') + }) + } + + TreeView.prototype.collapseGroup = function($group) { + var $subitems = $('> ol', $group) + + $subitems.css({ + 'overflow': 'hidden' + }) + + $subitems.animate({'height': 0}, { duration: 100, queue: false, complete: function() { + $subitems.css({ + 'overflow': 'visible', + 'display': 'none', + 'height' : 'auto' + }) + $group.attr('data-status', 'collapsed') + $(window).trigger('resize') + } }) + + this.sendGroupStatusRequest($group, 0) + } + + TreeView.prototype.expandGroup = function($group) { + var $subitems = $('> ol', $group) + + $subitems.css({ + 'overflow': 'hidden', + 'display': 'block', + 'height': 0 + }) + + $group.attr('data-status', 'expanded') + $subitems.animate({'height': $subitems[0].scrollHeight}, { duration: 100, queue: false, complete: function() { + $subitems.css({ + 'overflow': 'visible', + 'height': 'auto' + }) + $(window).trigger('resize') + } }) + + this.sendGroupStatusRequest($group, 1); + } + + TreeView.prototype.fixSubItems = function() { + $('li', this.$el).each(function(){ + var $li = $(this), + $subitems = $('> ol > li', $li) + $li.toggleClass('has-subitems', $subitems.length > 0) + }) + } + + TreeView.prototype.toggleGroup = function(group) { + var $group = $(group); + + $group.attr('data-status') == 'expanded' + ? this.collapseGroup($group) + : this.expandGroup($group) + } + + TreeView.prototype.sendGroupStatusRequest = function($group, status) { + if (this.options.groupStatusHandler !== undefined) { + var groupId = $group.data('group-id') + + $group.request(this.options.groupStatusHandler, {data: {group: groupId, status: status}}) + } + } + + TreeView.prototype.sendReorderRequest = function() { + if (this.options.reorderHandler === undefined) + return + + var groups = {} + + function iterator($container, node) { + $('> li', $container).each(function(){ + var subnodes = {} + iterator($('> ol', this), subnodes) + + node[$(this).data('groupId')] = subnodes + }) + } + + iterator($('> ol', this.$el), groups) + + this.$el.request(this.options.reorderHandler, {data: {structure: JSON.stringify(groups)}}) + } + + TreeView.prototype.initSortable = function() { + var $noDragItems = $('[data-no-drag-mode]', this.$el) + + if ($noDragItems.length > 0) + return + + if (this.$el.data('oc.treelist')) + this.$el.treeListWidget('unbind') + + this.$el.treeListWidget({ + tweakCursorAdjustment: this.proxy(this.tweakCursorAdjustment), + isValidTarget: this.proxy(this.isValidTarget), + useAnimation: false, + usePlaceholderClone: true, + handle: 'span.drag-handle', + onDrag: this.proxy(this.onDrag), + tolerance: -20 // Give 20px of carry between containers + }) + + this.$el.on('move.oc.treelist', this.proxy(this.onNodeMove)) + this.$el.on('aftermove.oc.treelist', this.proxy(this.onAfterNodeMove)) + } + + TreeView.prototype.markActive = function(dataId) { + $('li', this.$el).removeClass('active') + + if (dataId) + $('li[data-id="'+dataId+'"]', this.$el).addClass('active') + + this.$el.data('oc.active-item', dataId) + } + + // It seems the method is not used anymore as we re-create the control + // instead of updating it. Remove later if nothing weird is noticed. + // -ab Apr 26 2015 + // + TreeView.prototype.update = function() { + this.$allItems = $('li', this.$el) + this.createItemControls() + //this.initSortable() + + var dataId = this.$el.data('oc.active-item') + if (dataId !== undefined) { + this.markActive(dataId) + } + } + + TreeView.prototype.handleMovedNode = function() { + this.$el.trigger('change') + this.$allItems.removeClass('drop-target') + this.fixSubItems() + this.sendReorderRequest() + } + + TreeView.prototype.tweakCursorAdjustment = function(adjustment) { + if (!adjustment) { + return adjustment + } + + if (this.$scrollbar.length > 0) { + adjustment.top -= this.$scrollbar.scrollTop() + } + + return adjustment + } + + TreeView.prototype.isValidTarget = function($item, container) { + return $(container.el).closest('li').attr('data-status') != 'collapsed' + } + + TreeView.DEFAULTS = { + + } + + // TREEVIEW EVENT HANDLERS + // ============================ + + TreeView.prototype.onOpenSubmenu = function(ev) { + var e = $.Event('submenu.oc.treeview', {relatedTarget: ev.currentTarget, clickEvent: ev}) + this.$el.trigger(e, this) + + return false + } + + TreeView.prototype.onOpen = function(ev) { + var e = $.Event('open.oc.treeview', {relatedTarget: $(ev.currentTarget).closest('li').get(0), clickEvent: ev}) + this.$el.trigger(e, ev.currentTarget) + + return false + } + + TreeView.prototype.onNodeMove = function() { + setTimeout(this.proxy(this.handleMovedNode), 50) + } + + TreeView.prototype.onAfterNodeMove = function(ev, data) { + this.$allItems.removeClass('drop-target') + data.container.el.closest('li').addClass('drop-target') + } + + TreeView.prototype.onItemExpandClick = function(ev) { + this.toggleGroup($(ev.currentTarget).closest('li')) + return false + } + + // TREEVIEW SCROLL ON DRAG + // ============================ + + TreeView.prototype.onScroll = function () { + if (!$('body').hasClass('dragging')) { + return + } + + var changed = this.lastScrollPos - this.$scrollbar.scrollTop() + + this.$el.children('ol').each(function() { + var sortable = $(this).data('oc.sortable') + sortable.refresh() + sortable.cursorAdjustment.top += changed // Keep cursor adjustment in sync with scroll + }); + + this.dragCallback() + + this.lastScrollPos = this.$scrollbar.scrollTop() + } + + TreeView.prototype.onDrag = function ($item, position, _super, event) { + this.lastScrollPos = this.$scrollbar.scrollTop() + + this.dragCallback = function() { + _super($item, position, null, event) + }; + + this.clearScrollTimeout() + this.dragCallback() + + if (!this.$scrollbar || this.$scrollbar.length === 0) + return + + if (position.top < 0) { + this.scrollOffset = -10 + Math.floor(position.top / 5) + } + else if (position.top > this.$scrollbar.height()) { + this.scrollOffset = 10 + Math.ceil((position.top - this.$scrollbar.height()) / 5) + } + else { + return + } + + this.dragScroll() + } + + TreeView.prototype.scrollMax = function() { + return this.$el.height() - this.$scrollbar.height() + } + + TreeView.prototype.dragScroll = function() { + var startScrollTop = this.$scrollbar.scrollTop() + var changed + + this.scrollTimeout = null + + this.$scrollbar.scrollTop(Math.min(startScrollTop + this.scrollOffset, this.scrollMax())) + + changed = this.$scrollbar.scrollTop() - startScrollTop + if (changed === 0) { + return + } + + this.$el.children('ol').each(function() { + var sortable = $(this).data('oc.sortable') + sortable.refresh() + sortable.cursorAdjustment.top -= changed // Keep cursor adjustment in sync with scroll + }); + + this.dragCallback() + + this.$scrollbar.data('oc.scrollbar').setThumbPosition() // Update scrollbar position + + this.scrollTimeout = window.setTimeout(this.proxy(this.dragScroll), 100) + } + + TreeView.prototype.clearScrollTimeout = function() { + if (this.scrollTimeout) { + window.clearTimeout(this.scrollTimeout) + this.scrollTimeout = null + } + } + + // TREEVIEW PLUGIN DEFINITION + // ============================ + + var old = $.fn.treeView + + $.fn.treeView = function (option) { + var args = arguments + + return this.each(function () { + var $this = $(this) + var data = $this.data('oc.treeView') + var options = $.extend({}, TreeView.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.treeView', (data = new TreeView(this, options))) + + if (typeof option == 'string' && data) { + var methodArgs = []; + for (var i=1; i
').appendTo('body').addClass(this.options.collapsedMenuClass).css('width', 0) + this.menuContainer = $('
').appendTo(this.menuPanel).css('display', 'none') + this.menuElement = this.$el.clone().appendTo(this.menuContainer).css('width', 'auto') + + var self = this + + /* + * Handle the menu toggle click + */ + this.toggle.click(function() { + if (!self.body.hasClass(self.options.bodyMenuOpenClass)) { + var wrapperWidth = self.wrapper.outerWidth() + + self.menuElement.dragScroll('goToStart') + + self.wrapper.css({ + 'position': 'absolute', + 'min-width': self.wrapper.width(), + 'height': '100%' + }) + self.body.addClass(self.options.bodyMenuOpenClass) + self.menuContainer.css('display', 'block') + + self.wrapper.animate({'left': self.options.menuWidth}, { duration: 200, queue: false }) + self.menuPanel.animate({'width': self.options.menuWidth}, { + duration: 200, + queue: false, + complete: function() { + self.menuElement.css('width', self.options.menuWidth) + } + }) + } + else { + closeMenu() + } + + return false + }) + + this.wrapper.click(function() { + if (self.body.hasClass(self.options.bodyMenuOpenClass)) { + closeMenu() + return false + } + }) + + /* + * Disable the menu if the window is wider than the breakpoint width + */ + $(window).resize(function() { + if (self.body.hasClass(self.options.bodyMenuOpenClass)) { + if ($(window).width() > self.breakpoint) { + hideMenu() + } + } + }) + + /* + * Make the menu draggable + */ + this.menuElement.dragScroll({ + vertical: true, + useNative: true, + start: function(){self.menuElement.addClass('drag')}, + stop: function(){self.menuElement.removeClass('drag')}, + scrollClassContainer: self.menuPanel, + scrollMarkerContainer: self.menuContainer + }) + + this.menuElement.on('click', function() { + // Do not handle menu item clicks while dragging + if (self.menuElement.hasClass('drag')) + return false + }) + + /* + * Internal event, completely hides the menu + */ + function hideMenu() { + self.body.removeClass(self.options.bodyMenuOpenClass) + self.wrapper.css({ + 'position': 'static', + 'min-width': 0, + 'right': 0, + 'height': '100%' + }) + self.menuPanel.css('width', 0) + self.menuElement.css('width', 'auto') + self.menuContainer.css('display', 'none') + } + + /* + * Internal event, smoothly collapses the menu + */ + function closeMenu() { + self.wrapper.animate({'left': 0}, { duration: 200, queue: false}) + self.menuPanel.animate({'width': 0}, { duration: 200, queue: false, complete: hideMenu }) + self.menuElement.animate({'width': 0}, { duration: 200, queue: false }) + } + } + + VerticalMenu.DEFAULTS = { + menuWidth: 230, + breakpoint: 769, + bodyMenuOpenClass: 'mainmenu-open', + collapsedMenuClass: 'mainmenu-collapsed', + contentWrapper: '#layout-canvas' + } + + // VERTICAL MENU PLUGIN DEFINITION + // ============================ + + var old = $.fn.verticalMenu + + $.fn.verticalMenu = function (toggleSelector, option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('oc.verticalMenu') + var options = typeof option == 'object' && option + + if (!data) $this.data('oc.verticalMenu', (data = new VerticalMenu(this, toggleSelector, options))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.verticalMenu.Constructor = VerticalMenu + + // VERTICAL MENU NO CONFLICT + // ================= + + $.fn.verticalMenu.noConflict = function () { + $.fn.verticalMenu = old + return this + } + +}(window.jQuery); diff --git a/modules/backend/assets/js/preferences/preferences.js b/modules/backend/assets/js/preferences/preferences.js new file mode 100644 index 0000000..9e55335 --- /dev/null +++ b/modules/backend/assets/js/preferences/preferences.js @@ -0,0 +1,71 @@ +$(document).ready(function() { + + var editorEl = $('#editorpreferencesCodeeditor'), + editor = editorEl.codeEditor('getEditorObject'), + session = editor.getSession(), + renderer = editor.renderer + + editorEl.height($('#editorSettingsForm').height() - 23) + + $('#Form-field-Preference-editor_theme').on('change', function() { + editorEl.codeEditor('setTheme', $(this).val()) + }) + + $('#Form-field-Preference-editor_font_size').on('change', function() { + editor.setFontSize(parseInt($(this).val())) + }) + + $('#Form-field-Preference-editor_word_wrap').on('change', function() { + editorEl.codeEditor('setWordWrap', $(this).val()) + }) + + $('#Form-field-Preference-editor_code_folding').on('change', function() { + session.setFoldStyle($(this).val()) + }) + + $('#Form-field-Preference-editor_autocompletion').on('change', function() { + editor.setOption('enableBasicAutocompletion', false) + editor.setOption('enableLiveAutocompletion', false) + + var val = $(this).val() + if (val == 'basic') { + editor.setOption('enableBasicAutocompletion', true) + } + else if (val == 'live') { + editor.setOption('enableLiveAutocompletion', true) + } + }) + + $('#Form-field-Preference-editor_tab_size').on('change', function() { + session.setTabSize($(this).val()) + }) + + $('#Form-field-Preference-editor_show_invisibles').on('change', function() { + editor.setShowInvisibles($(this).is(':checked')) + }) + + $('#Form-field-Preference-editor_enable_snippets').on('change', function() { + editor.setOption('enableSnippets', $(this).is(':checked')) + }) + + $('#Form-field-Preference-editor_display_indent_guides').on('change', function() { + editor.setDisplayIndentGuides($(this).is(':checked')) + }) + + $('#Form-field-Preference-editor_show_print_margin').on('change', function() { + editor.setShowPrintMargin($(this).is(':checked')) + }) + + $('#Form-field-Preference-editor_highlight_active_line').on('change', function() { + editor.setHighlightActiveLine($(this).is(':checked')) + }) + + $('#Form-field-Preference-editor_use_hard_tabs').on('change', function() { + session.setUseSoftTabs(!$(this).is(':checked')) + }) + + $('#Form-field-Preference-editor_show_gutter').on('change', function() { + renderer.setShowGutter($(this).is(':checked')) + }) + +}) diff --git a/modules/backend/assets/js/vendor/jquery-and-migrate.min.js b/modules/backend/assets/js/vendor/jquery-and-migrate.min.js new file mode 100644 index 0000000..a549ff1 --- /dev/null +++ b/modules/backend/assets/js/vendor/jquery-and-migrate.min.js @@ -0,0 +1,220 @@ +/*! jQuery v3.4.0 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.0",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ae(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ne(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ne(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n=void 0,r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n}else r&&(Q.set(this,i,k.event.trigger(k.extend(r.shift(),k.Event.prototype),r,this)),e.stopImmediatePropagation())}})):k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0= 0; + }(t); + return n !== a && r("jQuery.isNumeric() should not be called on constructed objects"), + a; + }, a(e, "holdReady", e.holdReady, "jQuery.holdReady is deprecated"), a(e, "unique", e.uniqueSort, "jQuery.unique is deprecated; use jQuery.uniqueSort"), + n(e.expr, "filters", e.expr.pseudos, "jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"), + n(e.expr, ":", e.expr.pseudos, "jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos"); + var p = e.ajax; + e.ajax = function() { + var e = p.apply(this, arguments); + return e.promise && (a(e, "success", e.done, "jQXHR.success is deprecated and removed"), + a(e, "error", e.fail, "jQXHR.error is deprecated and removed"), a(e, "complete", e.always, "jQXHR.complete is deprecated and removed")), + e; + }; + var f = e.fn.removeAttr, y = e.fn.toggleClass, m = /\S+/g; + e.fn.removeAttr = function(t) { + var n = this; + return e.each(t.match(m), function(t, a) { + e.expr.match.bool.test(a) && (r("jQuery.fn.removeAttr no longer sets boolean properties: " + a), + n.prop(a, !1)); + }), f.apply(this, arguments); + }, e.fn.toggleClass = function(t) { + return void 0 !== t && "boolean" != typeof t ? y.apply(this, arguments) : (r("jQuery.fn.toggleClass( boolean ) is deprecated"), + this.each(function() { + var r = this.getAttribute && this.getAttribute("class") || ""; + r && e.data(this, "__className__", r), this.setAttribute && this.setAttribute("class", r || !1 === t ? "" : e.data(this, "__className__") || ""); + })); + }; + var h = !1; + e.swap && e.each([ "height", "width", "reliableMarginRight" ], function(t, r) { + var n = e.cssHooks[r] && e.cssHooks[r].get; + n && (e.cssHooks[r].get = function() { + var e; + return h = !0, e = n.apply(this, arguments), h = !1, e; + }); + }), e.swap = function(e, t, n, a) { + var o, i, s = {}; + h || r("jQuery.swap() is undocumented and deprecated"); + for (i in t) s[i] = e.style[i], e.style[i] = t[i]; + o = n.apply(e, a || []); + for (i in t) e.style[i] = s[i]; + return o; + }; + var g = e.data; + e.data = function(t, n, a) { + var o; + if (n && "object" == typeof n && 2 === arguments.length) { + o = e.hasData(t) && g.call(this, t); + var i = {}; + for (var s in n) s !== e.camelCase(s) ? (r("jQuery.data() always sets/gets camelCased names: " + s), + o[s] = n[s]) : i[s] = n[s]; + return g.call(this, t, i), n; + } + return n && "string" == typeof n && n !== e.camelCase(n) && (o = e.hasData(t) && g.call(this, t)) && n in o ? (r("jQuery.data() always sets/gets camelCased names: " + n), + arguments.length > 2 && (o[n] = a), o[n]) : g.apply(this, arguments); + }; + var v = e.Tween.prototype.run, j = function(e) { + return e; + }; + e.Tween.prototype.run = function() { + e.easing[this.easing].length > 1 && (r("'jQuery.easing." + this.easing.toString() + "' should use only one argument"), + e.easing[this.easing] = j), v.apply(this, arguments); + }, e.fx.interval = e.fx.interval || 13, t.requestAnimationFrame && n(e.fx, "interval", e.fx.interval, "jQuery.fx.interval is deprecated"); + var Q = e.fn.load, b = e.event.add, w = e.event.fix; + e.event.props = [], e.event.fixHooks = {}, n(e.event.props, "concat", e.event.props.concat, "jQuery.event.props.concat() is deprecated and removed"), + e.event.fix = function(t) { + var n, a = t.type, o = this.fixHooks[a], i = e.event.props; + if (i.length) for (r("jQuery.event.props are deprecated and removed: " + i.join()); i.length; ) e.event.addProp(i.pop()); + if (o && !o._migrated_ && (o._migrated_ = !0, r("jQuery.event.fixHooks are deprecated and removed: " + a), + (i = o.props) && i.length)) for (;i.length; ) e.event.addProp(i.pop()); + return n = w.call(this, t), o && o.filter ? o.filter(n, t) : n; + }, e.event.add = function(e, n) { + return e === t && "load" === n && "complete" === t.document.readyState && r("jQuery(window).on('load'...) called after load event occurred"), + b.apply(this, arguments); + }, e.each([ "load", "unload", "error" ], function(t, n) { + e.fn[n] = function() { + var e = Array.prototype.slice.call(arguments, 0); + return "load" === n && "string" == typeof e[0] ? Q.apply(this, e) : (r("jQuery.fn." + n + "() is deprecated"), + e.splice(0, 0, n), arguments.length ? this.on.apply(this, e) : (this.triggerHandler.apply(this, e), + this)); + }; + }), e.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "), function(t, n) { + e.fn[n] = function(e, t) { + return r("jQuery.fn." + n + "() event shorthand is deprecated"), arguments.length > 0 ? this.on(n, null, e, t) : this.trigger(n); + }; + }), e(function() { + e(t.document).triggerHandler("ready"); + }), e.event.special.ready = { + setup: function() { + this === t.document && r("'ready' event is deprecated"); + } + }, e.fn.extend({ + bind: function(e, t, n) { + return r("jQuery.fn.bind() is deprecated"), this.on(e, null, t, n); + }, + unbind: function(e, t) { + return r("jQuery.fn.unbind() is deprecated"), this.off(e, null, t); + }, + delegate: function(e, t, n, a) { + return r("jQuery.fn.delegate() is deprecated"), this.on(t, e, n, a); + }, + undelegate: function(e, t, n) { + return r("jQuery.fn.undelegate() is deprecated"), 1 === arguments.length ? this.off(e, "**") : this.off(t, e || "**", n); + }, + hover: function(e, t) { + return r("jQuery.fn.hover() is deprecated"), this.on("mouseenter", e).on("mouseleave", t || e); + } + }); + var x = e.fn.offset; + e.fn.offset = function() { + var n, a = this[0], o = { + top: 0, + left: 0 + }; + return a && a.nodeType ? (n = (a.ownerDocument || t.document).documentElement, e.contains(n, a) ? x.apply(this, arguments) : (r("jQuery.fn.offset() requires an element connected to a document"), + o)) : (r("jQuery.fn.offset() requires a valid DOM element"), o); + }; + var k = e.param; + e.param = function(t, n) { + var a = e.ajaxSettings && e.ajaxSettings.traditional; + return void 0 === n && a && (r("jQuery.param() no longer uses jQuery.ajaxSettings.traditional"), + n = a), k.call(this, t, n); + }; + var A = e.fn.andSelf || e.fn.addBack; + e.fn.andSelf = function() { + return r("jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()"), + A.apply(this, arguments); + }; + var S = e.Deferred, q = [ [ "resolve", "done", e.Callbacks("once memory"), e.Callbacks("once memory"), "resolved" ], [ "reject", "fail", e.Callbacks("once memory"), e.Callbacks("once memory"), "rejected" ], [ "notify", "progress", e.Callbacks("memory"), e.Callbacks("memory") ] ]; + return e.Deferred = function(t) { + var n = S(), a = n.promise(); + return n.pipe = a.pipe = function() { + var t = arguments; + return r("deferred.pipe() is deprecated"), e.Deferred(function(r) { + e.each(q, function(o, i) { + var s = e.isFunction(t[o]) && t[o]; + n[i[1]](function() { + var t = s && s.apply(this, arguments); + t && e.isFunction(t.promise) ? t.promise().done(r.resolve).fail(r.reject).progress(r.notify) : r[i[0] + "With"](this === a ? r.promise() : this, s ? [ t ] : arguments); + }); + }), t = null; + }).promise(); + }, t && t.call(n, n), n; + }, e.Deferred.exceptionHook = S.exceptionHook, e; +}); diff --git a/modules/backend/assets/js/vendor/jquery-migrate.min.js b/modules/backend/assets/js/vendor/jquery-migrate.min.js new file mode 100644 index 0000000..cd6d6c8 --- /dev/null +++ b/modules/backend/assets/js/vendor/jquery-migrate.min.js @@ -0,0 +1,215 @@ +/*! jQuery Migrate v3.0.1 | (c) jQuery Foundation and other contributors | jquery.org/license */ + +void 0 === jQuery.migrateMute && (jQuery.migrateMute = !0), function(e) { + "function" == typeof define && define.amd ? define([ "jquery" ], window, e) : "object" == typeof module && module.exports ? module.exports = e(require("jquery"), window) : e(jQuery, window); +}(function(e, t) { + "use strict"; + function r(r) { + var n = t.console; + o[r] || (o[r] = !0, e.migrateWarnings.push(r), n && n.warn && !e.migrateMute && (n.warn("JQMIGRATE: " + r), + e.migrateTrace && n.trace && n.trace())); + } + function n(e, t, n, a) { + Object.defineProperty(e, t, { + configurable: !0, + enumerable: !0, + get: function() { + return r(a), n; + }, + set: function(e) { + r(a), n = e; + } + }); + } + function a(e, t, n, a) { + e[t] = function() { + return r(a), n.apply(this, arguments); + }; + } + e.migrateVersion = "3.0.1", function() { + var r = /^[12]\./; + t.console && t.console.log && (e && !r.test(e.fn.jquery) || t.console.log("JQMIGRATE: jQuery 3.0.0+ REQUIRED"), + e.migrateWarnings && t.console.log("JQMIGRATE: Migrate plugin loaded multiple times"), + t.console.log("JQMIGRATE: Migrate is installed" + (e.migrateMute ? "" : " with logging active") + ", version " + e.migrateVersion)); + }(); + var o = {}; + e.migrateWarnings = [], void 0 === e.migrateTrace && (e.migrateTrace = !0), e.migrateReset = function() { + o = {}, e.migrateWarnings.length = 0; + }, "BackCompat" === t.document.compatMode && r("jQuery is not compatible with Quirks Mode"); + var i = e.fn.init, s = e.isNumeric, u = e.find, c = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/, l = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g; + e.fn.init = function(e) { + var t = Array.prototype.slice.call(arguments); + return "string" == typeof e && "#" === e && (r("jQuery( '#' ) is not a valid selector"), + t[0] = []), i.apply(this, t); + }, e.fn.init.prototype = e.fn, e.find = function(e) { + var n = Array.prototype.slice.call(arguments); + if ("string" == typeof e && c.test(e)) try { + t.document.querySelector(e); + } catch (a) { + e = e.replace(l, function(e, t, r, n) { + return "[" + t + r + '"' + n + '"]'; + }); + try { + t.document.querySelector(e), r("Attribute selector with '#' must be quoted: " + n[0]), + n[0] = e; + } catch (e) { + r("Attribute selector with '#' was not fixed: " + n[0]); + } + } + return u.apply(this, n); + }; + var d; + for (d in u) Object.prototype.hasOwnProperty.call(u, d) && (e.find[d] = u[d]); + e.fn.size = function() { + return r("jQuery.fn.size() is deprecated and removed; use the .length property"), + this.length; + }, e.parseJSON = function() { + return r("jQuery.parseJSON is deprecated; use JSON.parse"), JSON.parse.apply(null, arguments); + }, e.isNumeric = function(t) { + var n = s(t), a = function(t) { + var r = t && t.toString(); + return !e.isArray(t) && r - parseFloat(r) + 1 >= 0; + }(t); + return n !== a && r("jQuery.isNumeric() should not be called on constructed objects"), + a; + }, a(e, "holdReady", e.holdReady, "jQuery.holdReady is deprecated"), a(e, "unique", e.uniqueSort, "jQuery.unique is deprecated; use jQuery.uniqueSort"), + n(e.expr, "filters", e.expr.pseudos, "jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"), + n(e.expr, ":", e.expr.pseudos, "jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos"); + var p = e.ajax; + e.ajax = function() { + var e = p.apply(this, arguments); + return e.promise && (a(e, "success", e.done, "jQXHR.success is deprecated and removed"), + a(e, "error", e.fail, "jQXHR.error is deprecated and removed"), a(e, "complete", e.always, "jQXHR.complete is deprecated and removed")), + e; + }; + var f = e.fn.removeAttr, y = e.fn.toggleClass, m = /\S+/g; + e.fn.removeAttr = function(t) { + var n = this; + return e.each(t.match(m), function(t, a) { + e.expr.match.bool.test(a) && (r("jQuery.fn.removeAttr no longer sets boolean properties: " + a), + n.prop(a, !1)); + }), f.apply(this, arguments); + }, e.fn.toggleClass = function(t) { + return void 0 !== t && "boolean" != typeof t ? y.apply(this, arguments) : (r("jQuery.fn.toggleClass( boolean ) is deprecated"), + this.each(function() { + var r = this.getAttribute && this.getAttribute("class") || ""; + r && e.data(this, "__className__", r), this.setAttribute && this.setAttribute("class", r || !1 === t ? "" : e.data(this, "__className__") || ""); + })); + }; + var h = !1; + e.swap && e.each([ "height", "width", "reliableMarginRight" ], function(t, r) { + var n = e.cssHooks[r] && e.cssHooks[r].get; + n && (e.cssHooks[r].get = function() { + var e; + return h = !0, e = n.apply(this, arguments), h = !1, e; + }); + }), e.swap = function(e, t, n, a) { + var o, i, s = {}; + h || r("jQuery.swap() is undocumented and deprecated"); + for (i in t) s[i] = e.style[i], e.style[i] = t[i]; + o = n.apply(e, a || []); + for (i in t) e.style[i] = s[i]; + return o; + }; + var g = e.data; + e.data = function(t, n, a) { + var o; + if (n && "object" == typeof n && 2 === arguments.length) { + o = e.hasData(t) && g.call(this, t); + var i = {}; + for (var s in n) s !== e.camelCase(s) ? (r("jQuery.data() always sets/gets camelCased names: " + s), + o[s] = n[s]) : i[s] = n[s]; + return g.call(this, t, i), n; + } + return n && "string" == typeof n && n !== e.camelCase(n) && (o = e.hasData(t) && g.call(this, t)) && n in o ? (r("jQuery.data() always sets/gets camelCased names: " + n), + arguments.length > 2 && (o[n] = a), o[n]) : g.apply(this, arguments); + }; + var v = e.Tween.prototype.run, j = function(e) { + return e; + }; + e.Tween.prototype.run = function() { + e.easing[this.easing].length > 1 && (r("'jQuery.easing." + this.easing.toString() + "' should use only one argument"), + e.easing[this.easing] = j), v.apply(this, arguments); + }, e.fx.interval = e.fx.interval || 13, t.requestAnimationFrame && n(e.fx, "interval", e.fx.interval, "jQuery.fx.interval is deprecated"); + var Q = e.fn.load, b = e.event.add, w = e.event.fix; + e.event.props = [], e.event.fixHooks = {}, n(e.event.props, "concat", e.event.props.concat, "jQuery.event.props.concat() is deprecated and removed"), + e.event.fix = function(t) { + var n, a = t.type, o = this.fixHooks[a], i = e.event.props; + if (i.length) for (r("jQuery.event.props are deprecated and removed: " + i.join()); i.length; ) e.event.addProp(i.pop()); + if (o && !o._migrated_ && (o._migrated_ = !0, r("jQuery.event.fixHooks are deprecated and removed: " + a), + (i = o.props) && i.length)) for (;i.length; ) e.event.addProp(i.pop()); + return n = w.call(this, t), o && o.filter ? o.filter(n, t) : n; + }, e.event.add = function(e, n) { + return e === t && "load" === n && "complete" === t.document.readyState && r("jQuery(window).on('load'...) called after load event occurred"), + b.apply(this, arguments); + }, e.each([ "load", "unload", "error" ], function(t, n) { + e.fn[n] = function() { + var e = Array.prototype.slice.call(arguments, 0); + return "load" === n && "string" == typeof e[0] ? Q.apply(this, e) : (r("jQuery.fn." + n + "() is deprecated"), + e.splice(0, 0, n), arguments.length ? this.on.apply(this, e) : (this.triggerHandler.apply(this, e), + this)); + }; + }), e.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "), function(t, n) { + e.fn[n] = function(e, t) { + return r("jQuery.fn." + n + "() event shorthand is deprecated"), arguments.length > 0 ? this.on(n, null, e, t) : this.trigger(n); + }; + }), e(function() { + e(t.document).triggerHandler("ready"); + }), e.event.special.ready = { + setup: function() { + this === t.document && r("'ready' event is deprecated"); + } + }, e.fn.extend({ + bind: function(e, t, n) { + return r("jQuery.fn.bind() is deprecated"), this.on(e, null, t, n); + }, + unbind: function(e, t) { + return r("jQuery.fn.unbind() is deprecated"), this.off(e, null, t); + }, + delegate: function(e, t, n, a) { + return r("jQuery.fn.delegate() is deprecated"), this.on(t, e, n, a); + }, + undelegate: function(e, t, n) { + return r("jQuery.fn.undelegate() is deprecated"), 1 === arguments.length ? this.off(e, "**") : this.off(t, e || "**", n); + }, + hover: function(e, t) { + return r("jQuery.fn.hover() is deprecated"), this.on("mouseenter", e).on("mouseleave", t || e); + } + }); + var x = e.fn.offset; + e.fn.offset = function() { + var n, a = this[0], o = { + top: 0, + left: 0 + }; + return a && a.nodeType ? (n = (a.ownerDocument || t.document).documentElement, e.contains(n, a) ? x.apply(this, arguments) : (r("jQuery.fn.offset() requires an element connected to a document"), + o)) : (r("jQuery.fn.offset() requires a valid DOM element"), o); + }; + var k = e.param; + e.param = function(t, n) { + var a = e.ajaxSettings && e.ajaxSettings.traditional; + return void 0 === n && a && (r("jQuery.param() no longer uses jQuery.ajaxSettings.traditional"), + n = a), k.call(this, t, n); + }; + var A = e.fn.andSelf || e.fn.addBack; + e.fn.andSelf = function() { + return r("jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()"), + A.apply(this, arguments); + }; + var S = e.Deferred, q = [ [ "resolve", "done", e.Callbacks("once memory"), e.Callbacks("once memory"), "resolved" ], [ "reject", "fail", e.Callbacks("once memory"), e.Callbacks("once memory"), "rejected" ], [ "notify", "progress", e.Callbacks("memory"), e.Callbacks("memory") ] ]; + return e.Deferred = function(t) { + var n = S(), a = n.promise(); + return n.pipe = a.pipe = function() { + var t = arguments; + return r("deferred.pipe() is deprecated"), e.Deferred(function(r) { + e.each(q, function(o, i) { + var s = e.isFunction(t[o]) && t[o]; + n[i[1]](function() { + var t = s && s.apply(this, arguments); + t && e.isFunction(t.promise) ? t.promise().done(r.resolve).fail(r.reject).progress(r.notify) : r[i[0] + "With"](this === a ? r.promise() : this, s ? [ t ] : arguments); + }); + }), t = null; + }).promise(); + }, t && t.call(n, n), n; + }, e.Deferred.exceptionHook = S.exceptionHook, e; +}); \ No newline at end of file diff --git a/modules/backend/assets/js/vendor/jquery.autoellipsis.js b/modules/backend/assets/js/vendor/jquery.autoellipsis.js new file mode 100644 index 0000000..7bd28ef --- /dev/null +++ b/modules/backend/assets/js/vendor/jquery.autoellipsis.js @@ -0,0 +1,447 @@ +/*! + + Copyright (c) 2011 Peter van der Spek + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + */ + + +(function($) { + + /** + * Hash containing mapping of selectors to settings hashes for target selectors that should be live updated. + * + * @type {Object.} + * @private + */ + var liveUpdatingTargetSelectors = {}; + + /** + * Interval ID for live updater. Contains interval ID when the live updater interval is active, or is undefined + * otherwise. + * + * @type {number} + * @private + */ + var liveUpdaterIntervalId; + + /** + * Boolean indicating whether the live updater is running. + * + * @type {boolean} + * @private + */ + var liveUpdaterRunning = false; + + /** + * Set of default settings. + * + * @type {Object.} + * @private + */ + var defaultSettings = { + ellipsis: '...', + setTitle: 'never', + live: false + }; + + /** + * Perform ellipsis on selected elements. + * + * @param {string} selector the inner selector of elements that ellipsis may work on. Inner elements not referred to by this + * selector are left untouched. + * @param {Object.=} options optional options to override default settings. + * @return {jQuery} the current jQuery object for chaining purposes. + * @this {jQuery} the current jQuery object. + */ + $.fn.ellipsis = function(selector, options) { + var subjectElements, settings; + + subjectElements = $(this); + + // Check for options argument only. + if (typeof selector !== 'string') { + options = selector; + selector = undefined; + } + + // Create the settings from the given options and the default settings. + settings = $.extend({}, defaultSettings, options); + + // If selector is not set, work on immediate children (default behaviour). + settings.selector = selector; + + // Do ellipsis on each subject element. + subjectElements.each(function() { + var elem = $(this); + + // Do ellipsis on subject element. + ellipsisOnElement(elem, settings); + }); + + // If live option is enabled, add subject elements to live updater. Otherwise remove from live updater. + if (settings.live) { + addToLiveUpdater(subjectElements.selector, settings); + + } else { + removeFromLiveUpdater(subjectElements.selector); + } + + // Return jQuery object for chaining. + return this; + }; + + + /** + * Perform ellipsis on the given container. + * + * @param {jQuery} containerElement jQuery object containing one DOM element to perform ellipsis on. + * @param {Object.} settings the settings for this ellipsis operation. + * @private + */ + function ellipsisOnElement(containerElement, settings) { + var containerData = containerElement.data('jqae'); + if (!containerData) containerData = {}; + + // Check if wrapper div was already created and bound to the container element. + var wrapperElement = containerData.wrapperElement; + + // If not, create wrapper element. + if (!wrapperElement) { + wrapperElement = containerElement.wrapInner('
').find('>div'); + + // Wrapper div should not add extra size. + wrapperElement.css({ + margin: 0, + padding: 0, + border: 0 + }); + } + + // Check if the original wrapper element content was already bound to the wrapper element. + var wrapperElementData = wrapperElement.data('jqae'); + if (!wrapperElementData) wrapperElementData = {}; + + var wrapperOriginalContent = wrapperElementData.originalContent; + + // If so, clone the original content, re-bind the original wrapper content to the clone, and replace the + // wrapper with the clone. + if (wrapperOriginalContent) { + wrapperElement = wrapperElementData.originalContent.clone(true) + .data('jqae', {originalContent: wrapperOriginalContent}).replaceAll(wrapperElement); + + } else { + // Otherwise, clone the current wrapper element and bind it as original content to the wrapper element. + + wrapperElement.data('jqae', {originalContent: wrapperElement.clone(true)}); + } + + // Bind the wrapper element and current container width and height to the container element. Current container + // width and height are stored to detect changes to the container size. + containerElement.data('jqae', { + wrapperElement: wrapperElement, + containerWidth: containerElement.width(), + containerHeight: containerElement.height() + }); + + // Calculate with current container element height. + var containerElementHeight = containerElement.height(); + + // Calculate wrapper offset. + var wrapperOffset = (parseInt(containerElement.css('padding-top'), 10) || 0) + (parseInt(containerElement.css('border-top-width'), 10) || 0) - (wrapperElement.offset().top - containerElement.offset().top); + + // Normally the ellipsis characters are applied to the last non-empty text-node in the selected element. If the + // selected element becomes empty during ellipsis iteration, the ellipsis characters cannot be applied to that + // selected element, and must be deferred to the previous selected element. This parameter keeps track of that. + var deferAppendEllipsis = false; + + // Loop through all selected elements in reverse order. + var selectedElements = wrapperElement; + if (settings.selector) selectedElements = $(wrapperElement.find(settings.selector).get().reverse()); + + selectedElements.each(function() { + var selectedElement = $(this), + originalText = selectedElement.text(), + ellipsisApplied = false; + + // Check if we can safely remove the selected element. This saves a lot of unnecessary iterations. + if (wrapperElement.innerHeight() - selectedElement.innerHeight() > containerElementHeight + wrapperOffset) { + selectedElement.remove(); + + } else { + // Reverse recursively remove empty elements, until the element that contains a non-empty text-node. + removeLastEmptyElements(selectedElement); + + // If the selected element has not become empty, start ellipsis iterations on the selected element. + if (selectedElement.contents().length) { + + // If a deffered ellipsis is still pending, apply it now to the last text-node. + if (deferAppendEllipsis) { + getLastTextNode(selectedElement).get(0).nodeValue += settings.ellipsis; + deferAppendEllipsis = false; + } + + // Iterate until wrapper element height is less than or equal to the original container element + // height plus possible wrapperOffset. + while (wrapperElement.innerHeight() > containerElementHeight + wrapperOffset) { + // Apply ellipsis on last text node, by removing one word. + ellipsisApplied = ellipsisOnLastTextNode(selectedElement); + + // If ellipsis was succesfully applied, remove any remaining empty last elements and append the + // ellipsis characters. + if (ellipsisApplied) { + removeLastEmptyElements(selectedElement); + + // If the selected element is not empty, append the ellipsis characters. + if (selectedElement.contents().length) { + getLastTextNode(selectedElement).get(0).nodeValue += settings.ellipsis; + + } else { + // If the selected element has become empty, defer the appending of the ellipsis characters + // to the previous selected element. + deferAppendEllipsis = true; + selectedElement.remove(); + break; + } + + } else { + // If ellipsis could not be applied, defer the appending of the ellipsis characters to the + // previous selected element. + deferAppendEllipsis = true; + selectedElement.remove(); + break; + } + } + + // If the "setTitle" property is set to "onEllipsis" and the ellipsis has been applied, or if the + // property is set to "always", the add the "title" attribute with the original text. Else remove the + // "title" attribute. When the "setTitle" property is set to "never" we do not touch the "title" + // attribute. + if (((settings.setTitle == 'onEllipsis') && ellipsisApplied) || (settings.setTitle == 'always')) { + selectedElement.attr('title', originalText); + + } else if (settings.setTitle != 'never') { + selectedElement.removeAttr('title'); + } + } + } + }); + } + + /** + * Performs ellipsis on the last text node of the given element. Ellipsis is done by removing a full word. + * + * @param {jQuery} element jQuery object containing a single DOM element. + * @return {boolean} true when ellipsis has been done, false otherwise. + * @private + */ + function ellipsisOnLastTextNode(element) { + var lastTextNode = getLastTextNode(element); + + // If the last text node is found, do ellipsis on that node. + if (lastTextNode.length) { + var text = lastTextNode.get(0).nodeValue; + + // Find last space character, and remove text from there. If no space is found the full remaining text is + // removed. + var pos = text.lastIndexOf(' '); + if (pos > -1) { + text = $.trim(text.substring(0, pos)); + lastTextNode.get(0).nodeValue = text; + + } else { + lastTextNode.get(0).nodeValue = ''; + } + + return true; + } + + return false; + } + + /** + * Get last text node of the given element. + * + * @param {jQuery} element jQuery object containing a single element. + * @return {jQuery} jQuery object containing a single text node. + * @private + */ + function getLastTextNode(element) { + if (element.contents().length) { + + // Get last child node. + var contents = element.contents(); + var lastNode = contents.eq(contents.length - 1); + + // If last node is a text node, return it. + if (lastNode.filter(textNodeFilter).length) { + return lastNode; + + } else { + // Else it is an element node, and we recurse into it. + + return getLastTextNode(lastNode); + } + + } else { + // If there is no last child node, we append an empty text node and return that. Normally this should not + // happen, as we test for emptiness before calling getLastTextNode. + + element.append(''); + var contents = element.contents(); + return contents.eq(contents.length - 1); + } + } + + /** + * Remove last empty elements. This is done recursively until the last element contains a non-empty text node. + * + * @param {jQuery} element jQuery object containing a single element. + * @return {boolean} true when elements have been removed, false otherwise. + * @private + */ + function removeLastEmptyElements(element) { + if (element.contents().length) { + + // Get last child node. + var contents = element.contents(); + var lastNode = contents.eq(contents.length - 1); + + // If last child node is a text node, check for emptiness. + if (lastNode.filter(textNodeFilter).length) { + var text = lastNode.get(0).nodeValue; + text = $.trim(text); + + if (text == '') { + // If empty, remove the text node. + lastNode.remove(); + + return true; + + } else { + return false; + } + + } else { + // If the last child node is an element node, remove the last empty child nodes on that node. + while (removeLastEmptyElements(lastNode)) { + } + + // If the last child node contains no more child nodes, remove the last child node. + if (lastNode.contents().length) { + return false; + + } else { + lastNode.remove(); + + return true; + } + } + } + + return false; + } + + /** + * Filter for testing on text nodes. + * + * @return {boolean} true when this node is a text node, false otherwise. + * @this {Node} + * @private + */ + function textNodeFilter() { + return this.nodeType === 3; + } + + /** + * Add target selector to hash of target selectors. If this is the first target selector added, start the live + * updater. + * + * @param {string} targetSelector the target selector to run the live updater for. + * @param {Object.} settings the settings to apply on this target selector. + * @private + */ + function addToLiveUpdater(targetSelector, settings) { + // Store target selector with its settings. + liveUpdatingTargetSelectors[targetSelector] = settings; + + // If the live updater has not yet been started, start it now. + if (!liveUpdaterIntervalId) { + liveUpdaterIntervalId = window.setInterval(function() { + doLiveUpdater(); + }, 200); + } + } + + /** + * Remove the target selector from the hash of target selectors. It this is the last remaining target selector + * being removed, stop the live updater. + * + * @param {string} targetSelector the target selector to stop running the live updater for. + * @private + */ + function removeFromLiveUpdater(targetSelector) { + // If the hash contains the target selector, remove it. + if (liveUpdatingTargetSelectors[targetSelector]) { + delete liveUpdatingTargetSelectors[targetSelector]; + + // If no more target selectors are in the hash, stop the live updater. + if (!liveUpdatingTargetSelectors.length) { + if (liveUpdaterIntervalId) { + window.clearInterval(liveUpdaterIntervalId); + liveUpdaterIntervalId = undefined; + } + } + } + }; + + /** + * Run the live updater. The live updater is periodically run to check if its monitored target selectors require + * re-applying of the ellipsis. + * + * @private + */ + function doLiveUpdater() { + // If the live updater is already running, skip this time. We only want one instance running at a time. + if (!liveUpdaterRunning) { + liveUpdaterRunning = true; + + // Loop through target selectors. + for (var targetSelector in liveUpdatingTargetSelectors) { + $(targetSelector).each(function() { + var containerElement, containerData; + + containerElement = $(this); + containerData = containerElement.data('jqae'); + + // If container element dimensions have changed, or the container element is new, run ellipsis on + // that container element. + if ((containerData.containerWidth != containerElement.width()) || + (containerData.containerHeight != containerElement.height())) { + ellipsisOnElement(containerElement, liveUpdatingTargetSelectors[targetSelector]); + } + }); + } + + liveUpdaterRunning = false; + } + }; + +})(jQuery); \ No newline at end of file diff --git a/modules/backend/assets/js/vendor/jquery.cookie.js b/modules/backend/assets/js/vendor/jquery.cookie.js new file mode 100644 index 0000000..feb62e9 --- /dev/null +++ b/modules/backend/assets/js/vendor/jquery.cookie.js @@ -0,0 +1,117 @@ +/*! + * jQuery Cookie Plugin v1.4.1 + * https://github.com/carhartl/jquery-cookie + * + * Copyright 2006, 2014 Klaus Hartl + * Released under the MIT license + */ +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD + define(['jquery'], factory); + } else if (typeof exports === 'object') { + // CommonJS + factory(require('jquery')); + } else { + // Browser globals + factory(jQuery); + } +}(function ($) { + + var pluses = /\+/g; + + function encode(s) { + return config.raw ? s : encodeURIComponent(s); + } + + function decode(s) { + return config.raw ? s : decodeURIComponent(s); + } + + function stringifyCookieValue(value) { + return encode(config.json ? JSON.stringify(value) : String(value)); + } + + function parseCookieValue(s) { + if (s.indexOf('"') === 0) { + // This is a quoted cookie as according to RFC2068, unescape... + s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); + } + + try { + // Replace server-side written pluses with spaces. + // If we can't decode the cookie, ignore it, it's unusable. + // If we can't parse the cookie, ignore it, it's unusable. + s = decodeURIComponent(s.replace(pluses, ' ')); + return config.json ? JSON.parse(s) : s; + } catch(e) {} + } + + function read(s, converter) { + var value = config.raw ? s : parseCookieValue(s); + return $.isFunction(converter) ? converter(value) : value; + } + + var config = $.cookie = function (key, value, options) { + + // Write + + if (arguments.length > 1 && !$.isFunction(value)) { + options = $.extend({}, config.defaults, options); + + if (typeof options.expires === 'number') { + var days = options.expires, t = options.expires = new Date(); + t.setTime(+t + days * 864e+5); + } + + return (document.cookie = [ + encode(key), '=', stringifyCookieValue(value), + options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE + options.path ? '; path=' + options.path : '', + options.domain ? '; domain=' + options.domain : '', + options.secure ? '; secure' : '' + ].join('')); + } + + // Read + + var result = key ? undefined : {}; + + // To prevent the for loop in the first place assign an empty array + // in case there are no cookies at all. Also prevents odd result when + // calling $.cookie(). + var cookies = document.cookie ? document.cookie.split('; ') : []; + + for (var i = 0, l = cookies.length; i < l; i++) { + var parts = cookies[i].split('='); + var name = decode(parts.shift()); + var cookie = parts.join('='); + + if (key && key === name) { + // If second argument (value) is a function it's a converter... + result = read(cookie, value); + break; + } + + // Prevent storing a cookie that we couldn't decode. + if (!key && (cookie = read(cookie)) !== undefined) { + result[name] = cookie; + } + } + + return result; + }; + + config.defaults = {}; + + $.removeCookie = function (key, options) { + if ($.cookie(key) === undefined) { + return false; + } + + // Must not alter options, thus extending a fresh object... + $.cookie(key, '', $.extend({}, options, { expires: -1 })); + return !$.cookie(key); + }; + +})); diff --git a/modules/backend/assets/js/vendor/jquery.min.js b/modules/backend/assets/js/vendor/jquery.min.js new file mode 100644 index 0000000..c92739a --- /dev/null +++ b/modules/backend/assets/js/vendor/jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v3.4.0 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.0",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ae(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ne(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ne(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n=void 0,r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n}else r&&(Q.set(this,i,k.event.trigger(k.extend(r.shift(),k.Event.prototype),r,this)),e.stopImmediatePropagation())}})):k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0= config.min_move_x) { + cancelTouch(); + if(dx > 0) { + config.wipeLeft(); + } + else { + config.wipeRight(); + } + } + else if(Math.abs(dy) >= config.min_move_y) { + cancelTouch(); + if(dy > 0) { + config.wipeDown(); + } + else { + config.wipeUp(); + } + } + } + } + + function onTouchStart(e) + { + if (e.touches.length == 1) { + startX = e.touches[0].pageX; + startY = e.touches[0].pageY; + isMoving = true; + this.addEventListener('touchmove', onTouchMove, false); + } + } + if ('ontouchstart' in document.documentElement) { + this.addEventListener('touchstart', onTouchStart, false); + } + }); + + return this; + }; + + })(jQuery); \ No newline at end of file diff --git a/modules/backend/assets/js/vendor/jquery.waterfall.js b/modules/backend/assets/js/vendor/jquery.waterfall.js new file mode 100644 index 0000000..a27b6fb --- /dev/null +++ b/modules/backend/assets/js/vendor/jquery.waterfall.js @@ -0,0 +1,63 @@ +(function($) { +/** + * Runs functions given in arguments in series, each functions passing their results to the next one. + * Return jQuery Deferred object. + * + * @example + * $.waterfall( + * function() { return $.ajax({url : first_url}) }, + * function() { return $.ajax({url : second_url}) }, + * function() { return $.ajax({url : another_url}) } + *).fail(function() { + * console.log(arguments) + *).done(function() { + * console.log(arguments) + *}) + * + * @example2 + * event_chain = []; + * event_chain.push(function() { var deferred = $.Deferred(); deferred.resolve(); return deferred; }); + * $.waterfall.apply(this, event_chain).fail(function(){}).done(function(){}); + * + * @author Dmitry (dio) Levashov, dio@std42.ru + * @return jQuery.Deferred + */ +$.waterfall = function() { + var steps = [], + dfrd = $.Deferred(), + pointer = 0; + + $.each(arguments, function(i, a) { + steps.push(function() { + var args = [].slice.apply(arguments), d; + + if (typeof(a) == 'function') { + if (!((d = a.apply(null, args)) && d.promise)) { + d = $.Deferred()[d === false ? 'reject' : 'resolve'](d); + } + } else if (a && a.promise) { + d = a; + } else { + d = $.Deferred()[a === false ? 'reject' : 'resolve'](a); + } + + d.fail(function() { + dfrd.reject.apply(dfrd, [].slice.apply(arguments)); + }) + .done(function(data) { + pointer++; + args.push(data); + + pointer == steps.length + ? dfrd.resolve.apply(dfrd, args) + : steps[pointer].apply(null, args); + }); + }); + }); + + steps.length ? steps[0]() : dfrd.resolve(); + + return dfrd; +} + +})(jQuery); \ No newline at end of file diff --git a/modules/backend/assets/less/.gitignore b/modules/backend/assets/less/.gitignore new file mode 100644 index 0000000..2318862 --- /dev/null +++ b/modules/backend/assets/less/.gitignore @@ -0,0 +1 @@ +*.css \ No newline at end of file diff --git a/modules/backend/assets/less/controls/alert.less b/modules/backend/assets/less/controls/alert.less new file mode 100644 index 0000000..6143c46 --- /dev/null +++ b/modules/backend/assets/less/controls/alert.less @@ -0,0 +1,37 @@ +// +// Custom alerts (Based on Sweet Alert) +// -------------------------------------------------- + +.sweet-overlay { + background-color: @overlay-background; + z-index: @zindex-alert - 1; +} + +.sweet-alert { + text-align: right; + border-radius: @border-radius-base; + .box-shadow(@popup-box-shadow); + z-index: @zindex-alert; + + h2 { + word-break: break-word; + word-wrap: break-word; + max-height: 350px; + overflow-y: auto; + + margin: 10px 0 17px 0; + color: #2b3e50; + text-align: left; + font-size: 15px; + line-height: 23px; + } + + p { + margin: 0; + } + + p.text-muted { + margin-bottom: 20px; + color: #555555; + } +} diff --git a/modules/backend/assets/less/controls/common.less b/modules/backend/assets/less/controls/common.less new file mode 100644 index 0000000..542c6e3 --- /dev/null +++ b/modules/backend/assets/less/controls/common.less @@ -0,0 +1,66 @@ +// +// Common control styles +// -------------------------------------------------- + +// +// The scroll panel can host a scrollbar control. It has a right border that covers +// the scrollbar to satisfy the design requirements. +// +.control-scrollpanel { + position: relative; + background: @color-panel-light; + + .control-scrollbar { + &.vertical > .scrollbar-scrollbar {right: 0;} + } +} + +.tooltip { + .tooltip-inner { + text-align: left; + padding: 5px 8px; + } + + &.in { + .opacity(1); + } +} + +// +// Logos +// + +.oc-logo-white { + background-image: url(../images/october-logo-white.svg); + background-position: 50% 50%; + background-repeat: no-repeat; + background-size: contain; +} + +.oc-logo { + background-image: url(../images/october-logo.svg); + background-position: 50% 50%; + background-repeat: no-repeat; + background-size: contain; +} + +.layout.control-tabs.oc-logo-transparent:not(.has-tabs), +.flex-layout-column.oc-logo-transparent:not(.has-tabs), +.layout-cell.oc-logo-transparent { + background-size: 50% auto; + background-repeat: no-repeat; + background-image: url(../images/october-logo.svg); + background-position: 50% 50%; + position: relative; + + &:after { + content: ''; + display: table-cell; + position: absolute; + left: 0; + top: 0; + height: 100%; + width: 100%; + background: rgba(249,249,249,0.7); + } +} diff --git a/modules/backend/assets/less/controls/filelist.less b/modules/backend/assets/less/controls/filelist.less new file mode 100644 index 0000000..07e4a8a --- /dev/null +++ b/modules/backend/assets/less/controls/filelist.less @@ -0,0 +1,426 @@ +// +// File list control +// -------------------------------------------------- + +.control-filelist { + .listPaddings (@level, @offset-base) when (@level > 0) { + > li.group { + > ul { + > li > a { + padding-left: (@level+2)*@offset-base; + margin-left: -1*@level*@offset-base; + } + + .listPaddings(@level - 1, @offset-base); + } + } + } + .listPaddings (0, 27px) {} + + p.no-data { + padding: 22px 0; + margin: 0; + color: @color-filelist-norecords-text; + font-size: @font-size-base; + text-align: center; + font-weight: normal; + .border-radius(@border-radius-base); + } + + ul { + padding: 0; + margin: 0; + + li { + font-weight: normal; + line-height: 150%; + position: relative; + list-style: none; + + a:hover { + background: @color-list-hover; + } + + &.active > a { + background: @color-list-active; + position: relative; + &:after { + position: absolute; + height: 100%; + width: 4px; + left: 0; + top: 0; + background: @color-list-active-border; + display: block; + content: ' '; + } + } + + a { + display: block; + padding: 10px 45px 10px 20px; + outline: none; + + &:hover, &:focus, &:active {text-decoration: none;} + + span { + display: block; + + &.title { + font-weight: normal; + color: @color-text-title; + font-size: @font-size-base; + } + + &.description { + color: @color-text-description; + font-size: @font-size-base - 2; + white-space: nowrap; + font-weight: normal; + overflow: hidden; + text-overflow: ellipsis; + + strong { + color: @color-text-title; + font-weight: normal; + } + } + } + } + + &.group { + > h4, > div.group > h4 { + font-weight: normal; + font-size: @font-size-base; + margin-top: 0; + margin-bottom: 0; + position: relative; + + a { + padding: 10px 20px 10px 53px; + color: @color-text-title; + position: relative; + outline: none; + + &:hover { background: transparent; } + + &:before, &:after { + width: 10px; + height: 10px; + display: block; + position: absolute; + top: 1px; + } + + &:after { + left: 33px; + top: 9px; + .icon(@folder); + color: @color-list-icon; + font-size: 16px; + } + + &:before { + left: 20px; + top: 9px; + color: @color-list-arrow; + .icon(@caret-right); + .transform( ~'rotate(90deg) translate(5px, 0)' ); + .transition(all 0.1s ease); + } + } + } + + > ul { + > li > a { + padding-left: 52px; + } + + > li.group { + padding-left: 20px; + } + + .listPaddings(10, 27px); + } + + &[data-status=collapsed] { + > h4 a:before, > div.group > h4 a:before { + .transform(~'rotate(0deg) translate(3px, 0)'); + } + + & > ul, & > div.subitems { + display: none; + } + } + } + + > div.controls { + position: absolute; + right: 19px; + top: 6px; + + .dropdown { + width: 14px; + height: 21px; + + &.open a.control { + display: block!important; + &:before { + visibility: visible; + display: block; + } + } + } + + a.control { + color: @color-text-title; + font-size: @font-size-base; + visibility: hidden; + overflow: hidden; + width: 14px; + height: 21px; + display: none; + text-decoration: none; + cursor: pointer; + padding: 0; + .opacity(0.5); + &:before { + visibility: visible; + display: block; + margin-right: 0; + } + + &:hover { + .opacity(1); + } + } + } + + &:hover { + > div.controls, > a.control { + display: block!important; + + > a.control { + display: block!important; + } + } + } + + .checkbox { + position: absolute; + top: -5px; + right: 0; + + label { + margin-right: 0; + + &:before { + border-color: @color-filelist-cb-border; + } + } + } + } + } + + &.single-line { + ul { + li a span.title { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + } + } + + // + // Templates have emphasis + // + + &.filelist-hero { + .a-hover() { + background: @color-filelist-hero-hover-bg; + border-bottom: 1px solid @color-filelist-hero-hover-bg !important; + span.title, span.description { + color: @color-filelist-hero-hover-text !important; + } + + .list-icon { + color: @color-filelist-hero-hover-text !important; + } + } + + .a-active() { + background: @color-filelist-hero-active-bg; + border-bottom: 1px solid @color-filelist-hero-active-bg !important; + span.title, span.description { + color: @color-filelist-hero-active-text !important; + } + + .list-icon { + color: @color-filelist-hero-active-text !important; + } + } + + ul { + li { + background: @color-filelist-hero-item-bg; + border-bottom: none; + + > a { + padding: 11px 45px 10px 50px; + font-size: @font-size-base - 1; + border-bottom: 1px solid @color-panel-light; + + span.title { + font-size: @font-size-base; + font-weight: normal; + color: @color-filelist-title-hero; + } + + span.description { + font-size: @font-size-base - 1; + } + + .list-icon { + position: absolute; + left: 14px; + top: 15px; + font-size: 22px; + color: #b7c0c2; + } + + &:hover { + .a-hover(); + } + + &:active { + .a-active(); + } + } + + .checkbox { + top: -2px; + right: 0; + } + + &.active { + > a { + border-bottom: 1px solid @color-list-active; + + &:after { + top: -1px; + bottom: -1px; + height: auto; + } + + > span.borders { + &:before { + content: ' '; + position: absolute; + width: 100%; + height: 1px; + display: block; + left: 0; + background-color: @color-list-active; + } + + &:before {top: -1px;} + } + + &:hover > span.borders:before { + background-color: @color-filelist-hero-hover-bg; + } + + &:active > span.borders:before { + background-color: @color-filelist-hero-active-bg; + } + } + } + + > h4 { + padding-top: 7px; + padding-bottom: 6px; + border-bottom: 1px solid @color-panel-light; + } + + > div.controls { + display: none; + position: absolute; + right: 16px; + top: 15px; + + > a.control { + width: 16px; + height: 23px; + background: transparent; + overflow: hidden; + display: inline-block; + color: @color-filelist-hero-hover-text!important; + padding: 0; + + &:before { + font-size: 17px; + } + } + } + + &:hover > div.controls { + display: block; + } + + &.separator { + position: relative; + border-bottom: 1px solid #95a5a6; + padding: 12px 15px 13px 15px; + + &:before { + z-index: 31; + .triangle(down, 19px, 11px, white); + position: absolute; + left: 13px; + bottom: -8px; + } + + &:after { + z-index: 30; + .triangle(down, 17px, 9px, #95a5a6); + position: absolute; + left: 14px; + bottom: -9px; + } + + h5 { + color: #2b3e50; + font-size: @font-size-base; + margin: 0; + font-weight: normal; + padding: 0; + } + } + } + + > li.group { + > ul > li > a { + padding-left: 66px; + } + } + } + + &.single-level { + ul li:hover { + background: @color-filelist-hero-hover-bg; + + > a { + .a-hover(); + } + } + ul li:active { + background: @color-filelist-hero-active-bg; + + > a { + .a-active(); + } + } + } + } +} diff --git a/modules/backend/assets/less/controls/namevaluelist.less b/modules/backend/assets/less/controls/namevaluelist.less new file mode 100644 index 0000000..afd6c1e --- /dev/null +++ b/modules/backend/assets/less/controls/namevaluelist.less @@ -0,0 +1,27 @@ +table.name-value-list { + border-collapse: collapse; + font-size: 13px; + + th, td { + padding: 4px 0 4px 0; + vertical-align: top; + } + + tr:first-child { + th, td { + padding-top: 0; + } + } + + th { + font-weight: 600; + color: #95a5a6; + padding-right: 15px; + text-transform: uppercase; + } + + td { + color: #2b3e50; + word-wrap: break-word; + } +} \ No newline at end of file diff --git a/modules/backend/assets/less/controls/panels.less b/modules/backend/assets/less/controls/panels.less new file mode 100644 index 0000000..02c2312 --- /dev/null +++ b/modules/backend/assets/less/controls/panels.less @@ -0,0 +1,77 @@ +div.panel { + @panel-border-color: #e8eaeb; + + padding: 20px; + + &.no-padding { + padding: 0; + } + + &.no-padding-bottom { + padding-bottom: 0; + } + + &.padding-top { + padding-top: 20px; + } + + &.padding-less { + padding: 15px; + } + + &.transparent { + background: transparent; + } + + &.border-left { + border-left: 1px solid @panel-border-color; + } + + &.border-right { + border-right: 1px solid @panel-border-color; + } + + &.border-bottom { + border-bottom: 1px solid @panel-border-color; + } + + &.border-top { + border-top: 1px solid @panel-border-color; + } + + &.triangle-down { + position: relative; + + &:after { + .triangle(down, 15px, 8px, white); + position: absolute; + left: 15px; + bottom: -8px; + z-index: 101; + } + + &:before { + .triangle(down, 17px, 9px, #e8eaeb); + position: absolute; + left: 14px; + bottom: -9px; + z-index: 100; + } + } + + /* + * Panel sections + */ + + h3.section, > label { + text-transform: uppercase; + color: #95a5a6; + font-size: 13px; + font-weight: 600; + margin: 0 0 15px 0; + } + + > label { + margin-bottom: 5px; + } +} diff --git a/modules/backend/assets/less/controls/reportwidgets.less b/modules/backend/assets/less/controls/reportwidgets.less new file mode 100644 index 0000000..983762b --- /dev/null +++ b/modules/backend/assets/less/controls/reportwidgets.less @@ -0,0 +1,51 @@ +.report-widget { + padding: 15px; + background: white; + .box-sizing(border-box); + .border-radius(@border-radius-base); + font-size: @font-size-base - 1; + + h3 { + font-size: @font-size-base; + color: @color-report-widget-title; + text-transform: uppercase; + font-weight: 600; + margin-top: 0; + margin-bottom: 30px; + } + + .height-100 { height: 100px; } + .height-200 { height: 200px; } + .height-300 { height: 300px; } + .height-400 { height: 400px; } + .height-500 { height: 500px; } + + p.report-description { + margin-bottom: 0; + margin-top: 15px; + font-size: 12px; + line-height: 190%; + color: @color-report-widget-description; + } + + a:not(.btn) { + color: @color-report-widget-link; + text-decoration: none; + &:hover { + color: @link-color; + text-decoration: none; + } + } + + p.flash-message.static { + margin-bottom: 0; + } + + .icon-circle { + &.success { color: @brand-success; } + &.primary { color: @brand-primary; } + &.warning { color: @brand-warning; } + &.danger { color: @brand-danger; } + &.info { color: @brand-info; } + } +} \ No newline at end of file diff --git a/modules/backend/assets/less/controls/scrollbar.less b/modules/backend/assets/less/controls/scrollbar.less new file mode 100644 index 0000000..d4966e5 --- /dev/null +++ b/modules/backend/assets/less/controls/scrollbar.less @@ -0,0 +1,125 @@ +// +// Scrollbar +// -------------------------------------------------- + +.drag-noselect { + .user-select(none); +} + +@scrollbar-thumb-size: 6px; + +.control-scrollbar { + position: relative; + overflow: hidden; + height: 100%; + + >.scrollbar-scrollbar { + position: absolute; + z-index: 100; + .scrollbar-track { + background-color: @color-scrollbar-track; + position: relative; + .border-radius(5px); + + .scrollbar-thumb { + background-color: @color-scrollbar-thumb; + .border-radius(5px); + cursor: pointer; + overflow: hidden; + position: absolute; + } + } + + &.disabled { + display: none !important; + } + } + + &.vertical { + >.scrollbar-scrollbar { + right: 0; + margin-right: 5px; + width: @scrollbar-thumb-size; + .scrollbar-track { + height: 100%; + width: @scrollbar-thumb-size; + .scrollbar-thumb { + height: 20px; + width: @scrollbar-thumb-size; + top: 0; + left: 0; + } + } + + &:active, &:hover { + width: @scrollbar-thumb-size + 2px; + .transition(width .3s); + .scrollbar-track, + .scrollbar-thumb { + width: @scrollbar-thumb-size + 2px; + .transition(width .3s); + } + } + } + } + + &.horizontal { + >.scrollbar-scrollbar { + margin: 0 0 5px; + clear: both; + height: @scrollbar-thumb-size; + .scrollbar-track { + width: 100%; + height: @scrollbar-thumb-size; + .scrollbar-thumb { + height: @scrollbar-thumb-size; + margin: 2px 0; + left: 0; + top: 0; + } + } + + &:active, &:hover { + height: @scrollbar-thumb-size + 2px; + .transition(height .3s); + .scrollbar-track, + .scrollbar-thumb { + height: @scrollbar-thumb-size + 2px; + .transition(height .3s); + } + } + } + } +} + +html.mobile { + .control-scrollbar { + overflow: auto; + -webkit-overflow-scrolling: touch; + } +} + +.no-touch .control-scrollbar { + >.scrollbar-scrollbar { + opacity: 0; + .transition(opacity 0.3s); + } + + &:active >.scrollbar-scrollbar, + &:hover >.scrollbar-scrollbar {opacity: 1;} +} + +@media (max-width: @screen-sm) { + &.responsive-sidebar { + > .layout-cell:last-child { + .control-scrollbar { + overflow: visible; + height: auto; + + .scrollbar-scrollbar { + display: none!important; + } + } + } + } +} diff --git a/modules/backend/assets/less/controls/scrollpad.less b/modules/backend/assets/less/controls/scrollpad.less new file mode 100644 index 0000000..a364d54 --- /dev/null +++ b/modules/backend/assets/less/controls/scrollpad.less @@ -0,0 +1,98 @@ +.scrollpad-scrollbar-size-tester { + width: 50px; + height: 50px; + overflow-y: scroll; + position: absolute; + top: -200px; + left: -200px; + + div { + height: 100px; + } + + &::-webkit-scrollbar { + width: 0; + height: 0; + } +} + +div.control-scrollpad { + position: relative; + width: 100%; + height: 100%; + overflow: hidden; + + > div { + overflow: hidden; + overflow-y: scroll; + height: 100%; + + &::-webkit-scrollbar { + width: 0; + height: 0; + } + } + + &[data-direction=horizontal] > div { + overflow-x: scroll; + overflow-y: hidden; + width: 100%; + + &::-webkit-scrollbar { + width: auto; + height: 0; + } + } + + > .scrollpad-scrollbar { + z-index: 199; // Be careful here + position: absolute; + top: 0; + right: 0; + bottom: 0; + width: 11px; + background-color: @color-scrollbar-track; + opacity: 0; + overflow: hidden; + .border-radius(5px); + .transition(opacity 0.3s); + + .drag-handle { + position: absolute; + right: 2px; + min-height: 10px; + width: 7px; + background-color: @color-scrollbar-thumb; + .border-radius(5px); + } + + &:hover { + .opacity(.7); + .transition(opacity 0 linear); + } + + &[data-visible] { + .opacity(.7); + } + + &[data-hidden] { + display: none; + } + } + + &[data-direction=horizontal] > .scrollpad-scrollbar { + top: auto; + left: 0; + width: auto; + height: 11px; + + .drag-handle { + right: auto; + top: 2px; + height: 7px; + min-height: 0; + min-width: 10px; + width: auto; + } + } +} \ No newline at end of file diff --git a/modules/backend/assets/less/controls/selector-group.less b/modules/backend/assets/less/controls/selector-group.less new file mode 100644 index 0000000..4651cdb --- /dev/null +++ b/modules/backend/assets/less/controls/selector-group.less @@ -0,0 +1,35 @@ +.nav.selector-group { + font-size: 13px; + letter-spacing: 0.01em; + margin-bottom: 20px; + + li { + a { + padding: 7px 20px 7px 23px; + color: #95a5a6; + } + + &.active { + border-left: 3px solid #e6802b; + padding-left: 0; + + a { + padding-left: 20px; + color: #2b3e50; + } + } + + i[class^="icon-"] { + font-size: 17px; + margin-right: 6px; + position: relative; + top: 1px; + } + } +} + +div.panel { + .nav.selector-group { + margin: 0 -20px 20px -20px; + } +} \ No newline at end of file diff --git a/modules/backend/assets/less/controls/sidenav-tree.less b/modules/backend/assets/less/controls/sidenav-tree.less new file mode 100644 index 0000000..334eecb --- /dev/null +++ b/modules/backend/assets/less/controls/sidenav-tree.less @@ -0,0 +1,270 @@ +.sidenav-tree { + width: 300px; + + .control-toolbar { + padding: 0; + + .toolbar-item { + display: block; + } + + input.form-control { + border: none; + outline: none; + padding: 12px 13px 13px; + .border-radius(0); + .box-shadow(inset -3px 0 3px rgba(0,0,0,0.1)); + + &.search { + background-position: right -78px; + } + } + } + + ul { + padding: 0; + margin: 0; + list-style: none; + } + + div.scrollbar-thumb { + background: rgba(0,0,0,.2) !important; + } + + ul.top-level > li { + &[data-status=collapsed] { + > div.group { + h3:before { + .transform(~'rotate(0deg) translate(2px, -2px)'); + } + + // Hide triangle + &:before, &:after { + display: none; + } + } + + ul { + display: none; + } + } + + > div.group { + position: relative; + + h3 { + background: @color-sidebarnav-tree-group-bg; + color: @color-sidebarnav-tree-group; + text-transform: uppercase; + font-size: 15px; + padding: 15px 15px 15px 40px; + margin: 0; + position: relative; + cursor: pointer; + font-weight: 400; + + &:before { + display: block; + position: absolute; + width: 10px; + height: 10px; + left: 16px; + top: 15px; + color: @color-list-arrow; + .icon(@angle-right); + .transform(~'rotate(90deg) translate(5px, -3px)'); + .transition(all 0.1s ease); + font-size: 16px; + } + } + + // Use two triangles to achieve the darkening effect + &:before, + &:after { + .triangle(down, 15px, 8px, @brand-primary); + position: absolute; + left: 15px; + bottom: -8px; + z-index: 101; + } + + &:after { + .triangle(down, 15px, 8px, @color-sidebarnav-tree-group-bg); + } + } + + > ul { + li { + + a { + display: block; + position: relative; + padding: 18px 25px 18px 55px; + background: @color-sidebarnav-tree-inactive-bg; + border-bottom: 1px solid @color-sidebarnav-tree-group-bg; + color: @color-sidebarnav-tree-inactive-text; + text-decoration: none !important; + .opacity(.65); + + &:active, + &:hover { + .opacity(1); + text-decoration: none; + } + + i { + position: absolute; + left: 16px; + top: 18px; + font-size: 22px; + } + + span { + display: block; + line-height: 150%; + + &.header { + color: @color-sidebarnav-tree-inactive-header; + font-size: @font-size-base + 1; + margin-bottom: 5px; + } + + &.description { + color: @color-sidebarnav-tree-inactive-desc; + font-size: @font-size-base - 1; + } + } + } + + &:hover a, + &.active a { + .opacity(1); + } + + &.active { + border-left: 5px solid @brand-secondary; + + a { + color: @color-sidebarnav-tree-active-text; + padding-right: 20px; + + span.header { + color: @color-sidebarnav-tree-active-header; + } + + span.description { + color: @color-sidebarnav-tree-active-text; + } + } + } + + // &:last-child a { + // border-bottom: none; + // } + } + } + } + + .back-link { + display: none; + } +} + +@media (min-width: @screen-sm-min) { + .sidenav-tree-root .sidenav-tree { + width: 600px; + + ul.top-level > li > ul { + font-size: 0; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + align-items: stretch; + align-content: stretch; + + > li { + display: inline-block; + // flex-grow: 1; + width: 300px; + + a { + height: 100%; + } + } + } + } +} + +@media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { + .sidenav-tree-root .sidenav-tree { + width: 100%; + + ul.top-level > li > ul > li { + width: 50%; + } + } +} + +@media (min-width: @screen-lg-min) { + .sidenav-tree-root .sidenav-tree { + width: 900px; + } +} + +@media (max-width: @screen-sm) { + .sidenav-tree { + width: 100%; + height: auto !important; + display: block !important; + + > .layout { + display: none; + } + } + + .sidenav-tree-root { + .sidenav-tree { + width: 100% !important; + height: 100% !important; + display: table-cell !important; + + .back-link { + display: none !important; + } + + > .layout { + display: table !important; + } + } + + #layout-body { + display: none; + } + } + + body.has-sidenav-tree { + .sidenav-tree { + .back-link { + display: block; + padding: 13px 15px; + background: @color-sidebarnav-back-link-bg; + color: @color-sidebarnav-back-link-text; + font-size: 14px; + line-height: 14px; + text-transform: uppercase; + i { + display: inline-block; + margin-right: 10px; + } + &:hover { + text-decoration: none; + } + } + } + + #layout-body { + display: block !important; + } + } +} diff --git a/modules/backend/assets/less/controls/simplelist.less b/modules/backend/assets/less/controls/simplelist.less new file mode 100644 index 0000000..919ff49 --- /dev/null +++ b/modules/backend/assets/less/controls/simplelist.less @@ -0,0 +1,265 @@ +// +// Simple List +// -------------------------------------------------- +// Usage (bullets): +//
+//
    +//
  • Hello friend
  • +//
+//
+// +// With icons (no bullets): +//
+//
    +//
  • Hello friend
  • +//
+//
+// +// With checkboxes: +//
+//
    +//
  • +//
    +// +// +//
    +//
  • +//
+//
+// +// Divided (basic): +//
+//
    +//
  • Hello friend
  • +//
+//
+// +// Selectable: +// +// +// Selectable (box): +// +// + +.control-simplelist { + font-size: 13px; + padding: 20px 20px 2px 20px; + margin-bottom: @padding-standard; + background: @color-form-checkboxlist-background; + .border-radius(@border-radius-base); + + ul { padding-left: 15px; } + + &.form-control { + ul { margin-bottom: 0; } + li { + padding-top: 5px; + padding-bottom: 5px; + } + } + + &.with-icons, + &.with-checkboxes, + &.is-divided, + &.is-selectable { + ul { + list-style-type: none; + padding-left: 0; + } + } + + &.with-checkboxes { + li { + margin-top: -5px; + + &:first-child { + margin-top: 0; + } + + &:last-child { + div.custom-checkbox { + margin-bottom: 0; + + label { + margin-bottom: 5px; + } + } + } + } + } + + &.is-sortable { + + li.placeholder { + position: relative; + &:before { + top: -10px; + position: absolute; + .triangle(right, 5px, 9px, @color-sortable-caret); + } + } + + li.dragged { + position: absolute; + .opacity(.5); + z-index: 2000; + color: @color-sortable-active; + + width: auto !important; // Prevent browser scrollbars + } + } + + &.is-scrollable { + height: 200px; + &.size-tiny { min-height: @size-tiny + 200; } + &.size-small { min-height: @size-small + 200; } + &.size-large { min-height: @size-large + 200; } + &.size-huge { min-height: @size-huge + 200; } + &.size-giant { min-height: @size-giant + 200; } + } + + &.is-divided, + &.is-selectable, + &.is-selectable-box { + padding: 0; + + li { + .heading { + font-size: 14px; + font-weight: 500; + } + + .description {} + } + } + + &.is-divided, + &.is-selectable { + li { + padding: 5px 10px; + border-bottom: 1px solid @color-list-border; + + &:last-child { + border-bottom: none; + } + } + } + + &.is-selectable { + li { + a { + padding: 5px 10px; + margin: -5px -10px; + display: block; + color: @text-color; + } + &:hover { + background: @color-list-hover-bg; + cursor: pointer; + &, a { color: white; } + a { text-decoration: none; } + } + + &.active { + a { + background: #f0f0f0; + &:hover { + background: @color-list-hover-bg; + } + } + } + } + } + + &.is-selectable-box { + padding-top: 15px; + margin-bottom: 0; + + li { + width: 155px; + margin: 8px; + display: inline-block; + text-align: center; + vertical-align: top; + + a { + text-decoration: none; + display: block; + color: @text-color; + + .box { + display: block; + width: 155px; + height: 155px; + border: 3px solid rgba(0,0,0,.1); + position: relative; + .transition(border .3s ease); + } + + .image { + display: block; + width: 56px; + height: 56px; + position: absolute; + top: 50%; + left: 50%; + margin-top: -28px; + margin-left: -28px; + + > i { + font-size: 56px; + color: rgba(0,0,0,.25); + } + } + + .heading { + margin: 7px 0; + padding: 0; + } + + .description { + font-size: 12px; + } + + &:hover { + .box { + border-color: rgba(0,0,0,.2); + } + + .image > i { + color: rgba(0,0,0,.45); + } + } + } + } + } +} + +.list-preview .control-simplelist { + &.is-selectable { + ul { + margin-bottom: 0; + } + } +} diff --git a/modules/backend/assets/less/controls/svg-icons.less b/modules/backend/assets/less/controls/svg-icons.less new file mode 100644 index 0000000..6e82b89 --- /dev/null +++ b/modules/backend/assets/less/controls/svg-icons.less @@ -0,0 +1,33 @@ +.svg-icon-container { + img.svg-icon { + // SVG icons are invisible until SVG support is detected + // with JavaScript to reduce flickering on page load. + // This should be overridden in a specific control, + // inside html.svg {} + display: none; + } + + &.svg-active-effects { + img.svg-icon { + -webkit-filter: grayscale(100%); + filter: grayscale(100%); + .opacity(0.6); + } + + &:hover, &.active { + img.svg-icon { + -webkit-filter: none; + filter: none; + .opacity(1); + } + } + } +} + +html.svg { + .svg-icon-container { + i.svg-replace { + display: none; + } + } +} diff --git a/modules/backend/assets/less/controls/tree-path.less b/modules/backend/assets/less/controls/tree-path.less new file mode 100644 index 0000000..c2422be --- /dev/null +++ b/modules/backend/assets/less/controls/tree-path.less @@ -0,0 +1,61 @@ +ul.tree-path { + list-style: none; + padding: 0; + margin-bottom: 0; + + li { + display: inline-block; + margin-right: 1px; + font-size: 13px; + + &:after { + .icon(@angle-right); + display: inline-block; + font-size: 13px; + margin-left: 5px; + position: relative; + top: 1px; + color: #95a5a6; + } + + &:last-child { + a { + cursor: default; + } + + &:after { + display: none; + } + } + + &.go-up { + font-size: 12px; + margin-right: 7px; + + a { + color: #95a5a6; + + &:hover { + color: @link-color; + } + } + + &:after { + display: none; + } + } + + &.root a { + font-weight: 600; + color: #405261; + } + + a { + color: #95a5a6; + + &:hover { + text-decoration: none; + } + } + } +} \ No newline at end of file diff --git a/modules/backend/assets/less/controls/treelist.less b/modules/backend/assets/less/controls/treelist.less new file mode 100644 index 0000000..b0dfec8 --- /dev/null +++ b/modules/backend/assets/less/controls/treelist.less @@ -0,0 +1,93 @@ +// +// Tree List +// -------------------------------------------------- + +.control-treelist { + ol { + padding: 0; + margin: 0; + list-style: none; + + ol { + margin: 0; + margin-left: 15px; + padding-left: 15px; + border-left: 1px solid #dbdee0; + } + } + + > ol > li > div.record:before { + display: none; + } + + li { + margin: 0; + padding: 0; + > div.record { + margin: 0; + font-size: 12px; + margin-bottom: 5px; + position: relative; + display: block; + + &:before { + color: #bdc3c7; + .icon(@circle); + font-size: 6px; + position: absolute; + left: -18px; + top: 11px; + } + + > a.move { + display: inline-block; + padding: 7px 0 7px 10px; + text-decoration: none; + color: #bdc3c7; + &:hover { + color: @color-list-hover-bg; + } + &:before { .icon(@bars); } + } + > span { + color: @color-list-text; + display: inline-block; + padding: 7px 15px 7px 5px; + } + } + + &.dragged { + position: absolute; + z-index: 2000; + width: auto !important; // Prevent browser scrollbars + height: auto !important; + > div.record { + .opacity(.5); + background: @color-list-hover-bg !important; + > a.move:before, > span { color: white; } + + &:before { + display: none; + } + } + } + + &.placeholder { + display: inline-block; + position: relative; + background: @color-list-hover-bg !important; + height: 25px; + margin-bottom: 5px; + &:before { + display: block; + position: absolute; + .icon(@chevron-left); + color: #d35714; + left: -10px; + top: 8px; + z-index: 2000; + } + } + + } +} diff --git a/modules/backend/assets/less/controls/treeview.less b/modules/backend/assets/less/controls/treeview.less new file mode 100644 index 0000000..3b2b24b --- /dev/null +++ b/modules/backend/assets/less/controls/treeview.less @@ -0,0 +1,622 @@ +.control-treeview { + margin-bottom: 40px; + + .no-data() { + padding: 18px 0; + margin: 0; + color: @color-filelist-norecords-text; + font-size: @font-size-base; + text-align: center; + font-weight: 400; + } + + ol { + margin: 0; + padding: 0; + list-style: none; + background: @color-treeview-item-bg; + + > li { + .transition(width 1s); + + > div { + font-size: @font-size-base; + font-weight: normal; + background: @color-treeview-item-bg; + border-bottom: 1px solid @color-panel-light; + position: relative; + + > a { + color: @color-treeview-item-title; + padding: 11px 45px 10px 61px; + display: block; + line-height: 150%; + text-decoration: none; + .box-sizing(border-box); + } + + &:before { + content: ' '; + background-image: url(../images/treeview-icons.png); + background-position: 0px -28px; + background-repeat: no-repeat; + background-size: 42px auto; + + position: absolute; + width: 21px; + height: 22px; + left: 28px; + top: 15px; + } + + span.comment { + display: block; + font-weight: 400; + color: @color-treeview-item-comment; + font-size: @font-size-base - 1; + margin-top: 2px; + overflow: hidden; + text-overflow: ellipsis; + } + + > span.expand { + .hide-text(); + display: none; + position: absolute; + width: 20px; + height: 20px; + top: 19px; + left: 2px; + cursor: pointer; + color: @color-treeview-control; + .transition(transform 0.1s ease); + + &:before { + .icon(@caret-right); + line-height: 100%; + font-size: @font-size-base + 1; + + position: relative; + left: 8px; + top: 2px; + } + } + + > span.drag-handle { + .hide-text(); + .transition(opacity 0.4s); + + position: absolute; + right: 9px; + bottom: 0; + width: 18px; + height: 19px; + cursor: move; + color: @color-treeview-control; + .opacity(0); + + &:before { + .icon(@bars); + font-size: 18px; + } + } + + span.borders { + font-size: 0; + } + + > ul.submenu { + position: absolute; + left: 20px; + bottom: -36.9px; + padding: 0; + list-style: none; + z-index: 200; + height: 37px; + display: none; + margin-left: 15px; + + background: transparent url(../images/treeview-submenu-tabs.png) repeat-x left -39px; + + &:before, &:after { + background: transparent url(../images/treeview-submenu-tabs.png) no-repeat left top; + content: ' '; + display: block; + width: 20px; + height: 37px; + position: absolute; + top: 0; + } + + &:before { + left: -20px; + } + + &:after { + background-position: -100px top; + right: -20px; + } + + li { + font-size: @font-size-base - 2; + + a { + display: block; + padding: 4px 3px 0 3px; + color: @color-treeview-submenu-text; + text-decoration: none; + outline: none; + + i { + margin-right: 5px; + } + } + } + } + + &:hover { + > ul.submenu { + display: block; + } + } + + &:active { + > ul.submenu { + background-position: left -116px; + + &:before { + background-position: left -77px; + } + &:after { + background-position: -100px -77px; + } + } + } + + .checkbox { + position: absolute; + top: -2px; + right: 0; + + label { + margin-right: 0; + + &:before { + border-color: @color-filelist-cb-border; + } + } + } + + &.popover-highlight { + background-color: @color-treeview-hover-bg !important; + + &:before { + background-position: 0px -80px; + } + + > a { + color: @color-treeview-hover-text !important; + cursor: default; + } + + span { + color: @color-treeview-hover-text !important; + } + + > ul.submenu, > span.drag-handle { + display: none!important; + } + } + } + + &.dragged div, > div:hover { + background-color: @color-treeview-hover-bg !important; + + > a { + color: @color-treeview-hover-text !important; + } + + &:before { + background-position: 0px -80px; + } + + &:after { + top: 0 !important; + bottom: 0 !important; + } + + span { + color: @color-treeview-hover-text !important; + + &.drag-handle { + cursor: move; + .opacity(1); + } + + &.borders { + display: none; + } + } + } + + > div:active { + background-color: @color-treeview-active-bg !important; + + > a { + color: @color-treeview-active-text !important; + } + } + + &[data-no-drag-mode] div:hover { + span.drag-handle { + cursor: default!important; + .opacity(.3)!important; + } + } + + &.dragged { + li.has-subitems, &.has-subitems { + > div:before { + background-position: 0px -52px; + } + } + + div > ul.submenu { + display: none!important; + } + } + + > ol { + padding-left: 20px; + padding-right: 20px; + } + + &[data-status=collapsed] > ol { + display: none; + } + + &.has-subitems { + > div { + &:before { + background-position: 0 0; + width: 23px; + height: 26px; + left: 26px; + } + + &:hover, &.popover-highlight { + &:before { background-position: 0px -52px; } + } + + span.expand { + display: block; + } + } + } + + &.placeholder { + position: relative; + .opacity(.5); + } + + &.dragged { + position: absolute; + z-index: 2000; + .opacity(.25); + + > div { + .border-radius(3px); + } + } + + &.drop-target { + > div { + background-color: #2581b8!important; + + > a { + color: @color-treeview-hover-text; + > span.comment { + color: @color-treeview-hover-text; + } + } + + &:before { + background-position: 0px -80px; + } + } + + &.has-subitems > div:before { + background-position: 0px -52px; + } + } + + &[data-status=expanded] > div > span.expand { + .transform( ~'rotate(90deg) translate(0, 0)' ); + } + + &.drag-ghost { + background-color: transparent; + box-sizing: content-box; + } + + &.active { + > div { + background: @color-list-active; + + &:after { + position: absolute; + width: 4px; + left: 0; + top: -1px; + bottom: -1px; + background: @color-list-active-border; + display: block; + content: ' '; + } + + > span.comment, > span.expand { + color: @color-treeview-item-active-comment; + } + + > span.borders { + &:before, &:after { + content: ' '; + position: absolute; + width: 100%; + height: 1px; + display: block; + left: 0; + background-color: @color-list-active; + } + + &:before {top: -1px;} + &:after {bottom: -1px;} + } + } + } + + &.no-data { + .no-data(); + } + } + + @max-level: 10; + + .tree-view-paddings (@level) when (@level > 0) { + > li { + > ol { + > li > div { + margin-left: -20-(@max-level - @level)*20px; + margin-right: -20-(@max-level - @level)*20px; + padding-left: 61+(@max-level - @level + 1)*10px; + + > a { + margin-left: -61-(@max-level - @level + 1)*10px; + padding-left: 61+(@max-level - @level + 1)*10px; + } + + &:before { + margin-left: (@max-level - @level + 1)*10px; + } + + > span.expand { + left: 2+(@max-level - @level + 1)*10px; + } + } + + .tree-view-paddings(@level - 1); + } + } + } + + .tree-view-paddings (@max-level); + } + + p.no-data { + .no-data(); + } + + a.menu-control { + display: block; + margin: 20px; + padding: 13px 15px; + border: dotted 2px #ebebeb; + color: #bdc3c7; + font-size: @font-size-base - 2; + font-weight: 600; + text-transform: uppercase; + border-radius: 5px; + vertical-align: middle; + + &:hover, &:focus { + text-decoration: none; + background-color: @color-treeview-hover-bg; + color: @color-treeview-hover-text; + border: none; + padding: 15px 17px; + } + + &:active { + background: @color-treeview-active-bg; + color: @color-treeview-active-text; + } + + i { + margin-right: 10px; + font-size: 14px; + } + } + + /* + * Light version of the treeview - transparent background, no bottom borders, + * smaller paddings, inline submenu + */ + &.treeview-light { + margin-bottom: 0; + margin-top: 20px; + + ol { + background-color: transparent; + > li { + > div { + background-color: transparent; + border-bottom: none; + + &:before { + top: 15px; + } + + > a { + padding-top: 10px; + padding-bottom: 10px; + } + + span.expand { + top: 19px; + } + + > span.drag-handle { + top: 0; + right: 0; + bottom: auto; + height: 100%; + width: 60px; + background: @color-treeview-light-submenu-bg; + .transition(none)!important; + + &:before { + position: absolute; + left: 50%; + top: 50%; + margin-left: -6px; + } + } + + > ul.submenu { + right: 60px; + left: auto; + bottom: auto; + top: 0; + height: 100%; + margin: 0; + background: transparent; + white-space: nowrap; + font-size: 0; + + &:before, &:after { + display: none; + } + + li { + height: 100%; + display: inline-block; + background: @color-treeview-light-submenu-bg; + border-right: 1px solid @color-treeview-light-submenu-border; + + p { + display: table; + height: 100%; + padding: 0; + margin: 0; + + a { + display: table-cell; + vertical-align: middle; + height: 100%; + padding: 0 20px; + font-size: @font-size-base - 1; + .box-sizing(border-box); + + i.control-icon { + font-size: 22px; + margin-right: 0; + } + } + } + } + } + } + } + } + } +} + +// +// Sorting guides +// + +body.dragging .control-treeview { + ol.dragging, ol.dragging ol { + background: #ccc; + padding-right: 20px; + .transition(padding 1s); + + > li { + > div { + margin-right: 0; + .transition(margin 1s); + + .custom-checkbox { + .transition(opacity .5s); + .opacity(0); + } + } + } + } + + &.treeview-light { + ol.dragging, ol.dragging ol { + > li > div { + background-color: #f9f9f9; + } + } + } +} + +// +// Retina +// + +@media only screen and (min--moz-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-devicepixel-ratio: 1.5), only screen and (min-resolution: 1.5dppx) { + .control-treeview { + ol { + > li { + > div{ + &:before { + background-position: 0px -79px; + background-size: 21px auto; + } + } + + &.has-subitems > div { + &:before {background-position: 0px -52px;} + &:hover, &.popover-highlight { + &:before {background-position: 0px -102px;} + } + } + + &.dragged > div, &.dragged li > div, > div:hover, > div.popover-highlight { + &:before {background-position: 0px -129px;} + } + + &.dragged { + li.has-subitems, &.has-subitems { + > div:before { + background-position: 0px -102px; + } + } + } + + &.drop-target { + > div:before { + background-position: 0px -129px; + } + + &.has-subitems > div:before { + background-position: 0px -102px; + } + } + } + } + } +} diff --git a/modules/backend/assets/less/core/animations.less b/modules/backend/assets/less/core/animations.less new file mode 100644 index 0000000..c0f7fe0 --- /dev/null +++ b/modules/backend/assets/less/core/animations.less @@ -0,0 +1,363 @@ +// +// Fade In +// + +@-webkit-keyframes fadeIn { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +@keyframes fadeIn { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +.fadeIn { + -webkit-animation-name: fadeIn; + animation-name: fadeIn; +} + +// +// Fade In Down +// + +@-webkit-keyframes fadeInDown { + 0% { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } + + 100% { + opacity: 1; + -webkit-transform: none; + transform: none; + } +} + +@keyframes fadeInDown { + 0% { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + -ms-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } + + 100% { + opacity: 1; + -webkit-transform: none; + -ms-transform: none; + transform: none; + } +} + +.fadeInDown { + -webkit-animation-name: fadeInDown; + animation-name: fadeInDown; +} + +// +// Fade In Left +// + +@-webkit-keyframes fadeInLeft { + 0% { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } + + 100% { + opacity: 1; + -webkit-transform: none; + transform: none; + } +} + +@keyframes fadeInLeft { + 0% { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + -ms-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } + + 100% { + opacity: 1; + -webkit-transform: none; + -ms-transform: none; + transform: none; + } +} + +.fadeInLeft { + -webkit-animation-name: fadeInLeft; + animation-name: fadeInLeft; +} + +// +// Fade In Right +// + +@-webkit-keyframes fadeInRight { + 0% { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } + + 100% { + opacity: 1; + -webkit-transform: none; + transform: none; + } +} + +@keyframes fadeInRight { + 0% { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + -ms-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } + + 100% { + opacity: 1; + -webkit-transform: none; + -ms-transform: none; + transform: none; + } +} + +.fadeInRight { + -webkit-animation-name: fadeInRight; + animation-name: fadeInRight; +} + +// +// Fade In Up +// + +@-webkit-keyframes fadeInUp { + 0% { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } + + 100% { + opacity: 1; + -webkit-transform: none; + transform: none; + } +} + +@keyframes fadeInUp { + 0% { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + -ms-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } + + 100% { + opacity: 1; + -webkit-transform: none; + -ms-transform: none; + transform: none; + } +} + +.fadeInUp { + -webkit-animation-name: fadeInUp; + animation-name: fadeInUp; +} + +@-webkit-keyframes fadeInUpBig { + 0% { + opacity: 0; + -webkit-transform: translate3d(0, 2000px, 0); + transform: translate3d(0, 2000px, 0); + } + + 100% { + opacity: 1; + -webkit-transform: none; + transform: none; + } +} + +// +// Fade Out +// + +@-webkit-keyframes fadeOut { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + +@keyframes fadeOut { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + +.fadeOut { + -webkit-animation-name: fadeOut; + animation-name: fadeOut; +} + +// +// Fade Out Down +// + +@-webkit-keyframes fadeOutDown { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } +} + +@keyframes fadeOutDown { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + -ms-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } +} + +.fadeOutDown { + -webkit-animation-name: fadeOutDown; + animation-name: fadeOutDown; +} + +// +// Fade Out Left +// + +@-webkit-keyframes fadeOutLeft { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} + +@keyframes fadeOutLeft { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + -ms-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} + +.fadeOutLeft { + -webkit-animation-name: fadeOutLeft; + animation-name: fadeOutLeft; +} + +// +// Fade Out Right +// + +@-webkit-keyframes fadeOutRight { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } +} + +@keyframes fadeOutRight { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + -ms-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } +} + +.fadeOutRight { + -webkit-animation-name: fadeOutRight; + animation-name: fadeOutRight; +} + +// +// Fade Out Up +// + +@-webkit-keyframes fadeOutUp { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } +} + +@keyframes fadeOutUp { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + -ms-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } +} + +.fadeOutUp { + -webkit-animation-name: fadeOutUp; + animation-name: fadeOutUp; +} diff --git a/modules/backend/assets/less/core/boot.less b/modules/backend/assets/less/core/boot.less new file mode 100644 index 0000000..659749e --- /dev/null +++ b/modules/backend/assets/less/core/boot.less @@ -0,0 +1,11 @@ +// +// Boots the Core LESS +// +// Includes non-output LESS files such as mixins and variables +// + +// Core variables and mixins +@import "../../../../system/assets/ui/less/global.less"; + +@import "variables.less"; +@import "mixins.less"; diff --git a/modules/backend/assets/less/core/mixins.less b/modules/backend/assets/less/core/mixins.less new file mode 100644 index 0000000..e3e0d69 --- /dev/null +++ b/modules/backend/assets/less/core/mixins.less @@ -0,0 +1,165 @@ +// -------------------------------------------------- +// Flexbox LESS mixins +// The spec: http://www.w3.org/TR/css3-flexbox +// -------------------------------------------------- + +// Flexbox display +// flex or inline-flex +.flex-display() { + display: ~"-webkit-box"; + display: ~"-webkit-flex"; + display: ~"-moz-flex"; + display: ~"-ms-flexbox"; // IE10 uses -ms-flexbox + display: ~"-ms-flex"; // IE11 + display: flex; +} + +// The 'flex: 0 0 auto' shorthand +.flex-fix() { + -webkit-box-flex: 0; + -webkit-flex: 0 0 auto; + -moz-flex: 0 0 auto; + -ms-flex: 0 0 auto; + flex: 0 0 auto; +} + +// The 'flex: 1 1 auto' shorthand +.flex-stretch() { + -webkit-box-flex: 1; + -webkit-flex: 1 1 auto; + -moz-flex: 1 1 auto; + -ms-flex: 1 1 auto; + flex: 1 1 auto; +} + +// The 'flex: 1' shorthand +.flex-stretch-constrain() { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; +} + +// Flex Flow Direction Column +// - applies to: flex containers +.flex-direction-column() { + -webkit-flex-direction: column; + -moz-flex-direction: column; + -webkit-box-orient: vertical; + -ms-flex-direction: column; + flex-direction: column; +} + +// Flex Flow Direction Row +// - applies to: flex containers +.flex-direction-row() { + -webkit-flex-direction: row; + -moz-flex-direction: row; + -webkit-box-orient: horizontal; + -ms-flex-direction: row; + flex-direction: row; +} + +// Flex Line Wrapping +// - applies to: flex containers +// nowrap | wrap | wrap-reverse +.flex-wrap(@wrap: nowrap) { + -webkit-flex-wrap: @wrap; + -moz-flex-wrap: @wrap; + -ms-flex-wrap: @wrap; + flex-wrap: @wrap; +} + +// Flex Direction and Wrap +// - applies to: flex containers +// || +.flex-flow(@flow) { + -webkit-flex-flow: @flow; + -moz-flex-flow: @flow; + -ms-flex-flow: @flow; + flex-flow: @flow; +} + +// Display Order +// - applies to: flex items +// +.flex-order(@order: 0) { + -webkit-order: @order; + -moz-order: @order; + -ms-order: @order; + order: @order; +} + +// Flex grow factor +// - applies to: flex items +// +.flex-grow(@grow: 0) { + -webkit-flex-grow: @grow; + -moz-flex-grow: @grow; + -ms-flex-grow: @grow; + flex-grow: @grow; +} + +// Flex shr +// - applies to: flex itemsink factor +// +.flex-shrink(@shrink: 1) { + -webkit-flex-shrink: @shrink; + -moz-flex-shrink: @shrink; + -ms-flex-shrink: @shrink; + flex-shrink: @shrink; +} + +// Flex basis +// - the initial main size of the flex item +// - applies to: flex itemsnitial main size of the flex item +// +.flex-basis(@width: auto) { + -webkit-flex-basis: @width; + -moz-flex-basis: @width; + -ms-flex-basis: @width; + flex-basis: @width; +} + +// Axis Alignment +// - applies to: flex containers +// flex-start | flex-end | center | space-between | space-around +.justify-content(@justify: flex-start) { + -webkit-justify-content: @justify; + -moz-justify-content: @justify; + -ms-justify-content: @justify; + -webkit-box-pack: @justify; + justify-content: @justify; +} + +// Packing Flex Lines +// - applies to: multi-line flex containers +// flex-start | flex-end | center | space-between | space-around | stretch +.align-content(@align: stretch) { + -webkit-align-content: @align; + -moz-align-content: @align; + -webkit-box-align: @align; + -ms-align-content: @align; + align-content: @align; +} + +// Cross-axis Alignment +// - applies to: flex containers +// flex-start | flex-end | center | baseline | stretch +.align-items(@align: stretch) { + -webkit-align-items: @align; + -moz-align-items: @align; + -ms-align-items: @align; + align-items: @align; +} + +// Cross-axis Alignment +// - applies to: flex items +// auto | flex-start | flex-end | center | baseline | stretch +.align-self(@align: auto) { + -webkit-align-self: @align; + -moz-align-self: @align; + -ms-align-self: @align; + align-self: @align; +} \ No newline at end of file diff --git a/modules/backend/assets/less/core/variables.less b/modules/backend/assets/less/core/variables.less new file mode 100644 index 0000000..cf36e59 --- /dev/null +++ b/modules/backend/assets/less/core/variables.less @@ -0,0 +1,153 @@ +// +// Override UI variables +// -------------------------------------------------- + +@font-family-base: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + +// +// Paths +// -------------------------------------------------- + +@type-font-path: "../font"; + +// +// Colors +// -------------------------------------------------- + +@color-border: #cccccc; +@color-border-light: #e1e1e1; + +@color-mainmenu: #000000; +@color-mainmenu-inactive: rgba(255,255,255,.6); +@color-mainmenu-active: #ffffff; +@color-mainmenu-active-bg: #262626; +@color-mainmenu-collapsed: #000000; + +@color-accountmenu-bg: #f9f9f9; +@color-accountmenu-text: #666666; +@color-accountmenu-divider: #e0e0e0; + +@color-footer: rgba(255,255,255,.8); +@color-footer-border: #dfdfdf; +@color-footer-text: #666666; + +@color-sidebarnav-active-text: #ffffff; +@color-sidebarnav-active-icon: #ffffff; +@color-sidebarnav-inactive-text: rgba(255,255,255,.6); +@color-sidebarnav-inactive-icon: rgba(255,255,255,.6); +@color-sidebarnav-counter-bg: #d9350f; +@color-sidebarnav-counter-text: #ffffff; + +@color-sidebarnav-tree-group: #ecf0f1; +@color-sidebarnav-tree-group-bg: rgba(0,0,0,.15); +@color-sidebarnav-tree-inactive-header: #ffffff; +@color-sidebarnav-tree-inactive-desc: rgba(255,255,255,.6); +@color-sidebarnav-tree-inactive-text: #ffffff; +@color-sidebarnav-tree-active-header: #ffffff; +@color-sidebarnav-tree-inactive-bg: transparent; +@color-sidebarnav-tree-active-text: rgba(255,255,255,.91); +@color-sidebarnav-tree-active-marker: @brand-secondary; +@color-sidebarnav-back-link-bg: #2b3e50; +@color-sidebarnav-back-link-text: #bdc3c7; + +@color-scrollbar-track: transparent; +@color-scrollbar-thumb: rgba(0,0,0,.35); +@color-scrollpanel-border: #efefef; +@color-scrollpanel-fix-button: #aaaaaa; +@color-scrollpanel-fix-button-light: #eeeeee; +@color-scroll-indicator: #bbbbbb; + +@color-panel-light: #ECF0F1; + +@color-outer-muted-text: rgba(255,255,255,.44); +@color-outer-heading: #feffff; +@color-outer-description: #999999; +@color-outer-bg: #2b3e50; +@color-outer-header: @body-bg; +@color-outer-form-label: #666666; + +@color-breadcrumb-text-active: #9da3a7; +@color-breadcrumb-text: #9B9B9B; +@color-breadcrumb-background: #2b343d; + +@color-custom-input-icon: #666666; +@color-custom-input-border: #999999; + +@color-input-sidebar-control: #C4C4C4; + +@color-switch-input-bg: #f6f6f6; +@color-switch-input-on: #8da85e; +@color-switch-input-off: #cc3300; + +@color-custom-select-border: #b2b9be; +@color-custom-select-bg: #f6f6f6; +@color-custom-select-bg-hover: #4da7e8; + +@color-filelist-norecords-text: #666666; +@color-filelist-norecords-bg: #eeeeee; +@color-filelist-cb-border: #cccccc; +@color-filelist-title-hero: #2b3e50; +@color-filelist-hero-item-bg: #ffffff; +@color-filelist-hero-hover-bg: @highlight-hover-bg; +@color-filelist-hero-hover-text: @highlight-hover-text; +@color-filelist-hero-active-bg: @highlight-active-bg; +@color-filelist-hero-active-text: @highlight-active-text; + +@color-fancy-master-tabs-bg: #d35400; +@color-fancy-master-tabs-active-text: #ffffff; +@color-fancy-master-tabs-inactive-text: rgba(255, 255, 255, .35); +@color-fancy-master-panel-bg: #d35400; + +@color-fancy-secondary-tabs-bg: #475354; +@color-fancy-secondary-tabs-active-text: #ffffff; +@color-fancy-secondary-tabs-inactive-text: #919898; + +@color-fancy-primary-tabs-bg: #7F8C8D; +@color-fancy-primary-tabs-inactive-text: #95a5a6; +@color-fancy-primary-tabs-active-text: #808c8d; +@color-fancy-primary-tabs-active-bg: #fafafa; +@color-fancy-primary-tabs-inactive-bg: #d5d9d8; + +@color-fancy-form-tabless-fields-bg: @brand-secondary; +@color-fancy-form-label: rgba(255, 255, 255, .5); +@color-fancy-form-text: #ffffff; +@color-fancy-form-text-selection: #d35400; +@color-fancy-form-placeholder: rgba(255, 255, 255, .5); +@color-fancy-form-inactive-tab: #b9530f; + +@color-sortable-caret: #999999; +@color-sortable-active: @brand-secondary; + +@color-report-widget-title: #7e8c8d; +@color-report-widget-control-inactive: #b6b6b6; +@color-report-widget-description: @color-report-widget-title; +@color-report-widget-link: @color-report-widget-title; + +@color-treeview-item-bg: #ffffff; +@color-treeview-item-title: #2b3e50; +@color-treeview-item-comment: #95a5a6; +@color-treeview-control: #bdc3c7; +@color-treeview-hover-bg: @highlight-hover-bg; +@color-treeview-hover-text: @highlight-hover-text; +@color-treeview-active-bg: @highlight-active-bg; +@color-treeview-active-text: @highlight-active-text; +@color-treeview-item-active-comment: #8f8f8f; +@color-treeview-submenu-text: #ffffff; +@color-treeview-light-submenu-bg: #2581b8; +@color-treeview-light-submenu-border: #328ec8; + +// +// Sizes +// -------------------------------------------------- +@size-tiny: 50px; +@size-small: 100px; +@size-large: 200px; +@size-huge: 250px; +@size-giant: 350px; + +// +// Media breakpoints +// -------------------------------------------------- + +@menu-breakpoint-min: 770px; +@menu-breakpoint-max: (@menu-breakpoint-min - 1); \ No newline at end of file diff --git a/modules/backend/assets/less/dashboard/dashboard.less b/modules/backend/assets/less/dashboard/dashboard.less new file mode 100644 index 0000000..8b30885 --- /dev/null +++ b/modules/backend/assets/less/dashboard/dashboard.less @@ -0,0 +1,17 @@ +@import "../../../../backend/assets/less/core/boot.less"; + +.dashboard-container > .report-container { + &.loading { + position: absolute; + width: 100%; + height: 100%; + + .loading-indicator-container { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + } + } +} diff --git a/modules/backend/assets/less/layout/fancylayout.less b/modules/backend/assets/less/layout/fancylayout.less new file mode 100644 index 0000000..37a2587 --- /dev/null +++ b/modules/backend/assets/less/layout/fancylayout.less @@ -0,0 +1,697 @@ +body.breadcrumb-fancy .control-breadcrumb, +.control-breadcrumb.breadcrumb-fancy { + margin-bottom: 0; + + background-color: @color-fancy-form-tabless-fields-bg; + + li { + background-color: @color-fancy-master-tabs-bg; + color: rgba(255,255,255, .5); + + a { + opacity: .5; + .transition(all 0.3s ease); + &:hover { + opacity: 1; + + } + } + + &:before { + border-left-color: @color-fancy-form-text; + opacity: .5; + } + + &:after { + border-left-color: @color-fancy-master-tabs-bg; + } + + &:last-child { + background-color: @color-fancy-master-tabs-bg; + + &:before { + opacity: 1; + border-left-color: @color-fancy-master-tabs-bg; + } + } + } +} + +.fancy-layout { + // + // Fancy form tabs + // + + .tab-collapse-icon { + position: absolute; + display: block; + text-decoration: none; + outline: none; + .opacity(0.6); + .transition(all 0.3s); + font-size: 12px; + color: @color-fancy-master-tabs-active-text; + right: 11px; + + &:hover { + text-decoration: none; + .opacity(1); + } + + &.primary { + color: @color-fancy-secondary-tabs-bg; + bottom: -25px; + z-index: 100; + .scaleAxes(1, -1); + + i { + position: relative; + display: block; + } + } + } + + .control-tabs, &.control-tabs { + &.master-tabs { + overflow: hidden; + + &:before, &:after { + top: 13px; + font-size: 14px; + color: @color-fancy-master-tabs-inactive-text; + } + &:before { left: 8px; } + &:after { right: 8px; } + &.scroll-before:before { color: @color-fancy-master-tabs-active-text; } + &.scroll-after:after { color: @color-fancy-master-tabs-active-text; } + + > div > div.tabs-container { + background: @color-fancy-master-tabs-bg; + padding-left: 20px; + padding-right: 20px; + + > ul.nav-tabs { + margin-left: -8px; + > li { + margin-left: -5px; + top: 1px; + padding-top: 3px; + + span.tab-close { + top: 14px; + right: -3px; + left: auto; + z-index: 110; + font-family: sans-serif; + + i { + top: 4px; + right: 1px; + color: rgba(255, 255, 255, 0.3) !important; + font-style: normal; + font-weight: bold; + font-size: 16px; + + &:hover { color: @color-fancy-master-tabs-active-text !important; } + } + } + + a { + border-bottom: none; + background: transparent; + font-size: 14px; + color: @color-fancy-master-tabs-inactive-text; + padding: 6px 0 0 24px!important; + overflow: visible; + + > span.title { + position: relative; + display: inline-block; + padding: 12px 5px 0 5px; + height: 38px; + font-size: 14px; + z-index: 100; + background-color: @color-fancy-form-inactive-tab; + + &:before, &:after { + content: ' '; + position: absolute; + width: 20px; + display: block; + height: 37px; + top: 0; + z-index: 100; + background-color: @color-fancy-form-inactive-tab; + } + + &:before { + left: -14px; + .border-radius(8px 0 0 0); + .transform( ~'skewX(-20deg)'); + + } + + &:after { + right: -14px; + .border-radius(0 8px 0 0); + .transform( ~'skewX(20deg)'); + } + + span { + border-top: none; + padding: 0; + margin-top: 0; + overflow: visible; + } + } + + &:before { + z-index: 110; + position: absolute; + top: 18px; + left: 22px; + } + + &[class*=icon] > span.title { + padding-left: 18px; + } + } + + &.active { + a { + z-index: 107; + color: @color-fancy-master-tabs-active-text; + } + span.tab-close i { color: @color-fancy-master-tabs-active-text; } + + a > span.title { + background-color: @color-fancy-form-tabless-fields-bg; + z-index: 105; + &:before { + z-index: 107; + background-color: @color-fancy-form-tabless-fields-bg; + } + &:after { + background-color: @color-fancy-form-tabless-fields-bg; + z-index: 107; + } + } + } + + &[data-modified] { + span.tab-close i { + top: 5px; + .hide-text(); + + &:before { + .icon(@circle); + font-size: 9px; + } + } + } + + &:first-child { + margin-left: 0; + } + } + } + } + + &[data-closable] { + > div > div.tabs-container { + > ul.nav-tabs { + > li { + a > span.title { + padding-right: 10px; + } + } + } + } + } + + &.has-tabs { + &:before, &:after {display: block;} + } + } + + &.secondary-tabs { + // Target horizontal scroll indicators + &:before { + left: 5px; + } + &:after { + right: 5px; + } + > div > ul.nav-tabs { + background: @color-fancy-secondary-tabs-bg; + > li { + border-right: none; + padding-right: 0; + margin-right: 0; + a { + background: transparent; + border: none; + padding: 12px 10px 13px 10px; + font-size: 14px; + font-weight: normal; + line-height: 14px; + color: @color-fancy-secondary-tabs-inactive-text; + + span { + span { + overflow: visible; + border-top: none; + margin-top: 0; + padding-top: 0; + } + } + } + + &:first-child { + padding-left: 15px; // Will cause issues when first child is hidden + } + + &.active { + a {color: @color-fancy-secondary-tabs-active-text;} + } + } + } + + .tab-collapse-icon { + .tab-collapse-icon(); + + &.primary { + color: @color-fancy-master-tabs-active-text; + top: 12px; + right: 11px; + bottom: auto; + } + } + + &.primary-collapsed { + .tab-collapse-icon.primary { + .scaleAxes(1, 1); + } + } + + &.secondary-content-tabs { + > div > ul.nav-tabs { + background: @body-bg; + + > li { + margin-left: -19px; + + &:first-child { + margin-left: 0; + padding-left: 8px; + } + + a { + padding: 8px 16px 0 16px; + font-weight: 400; + height: 36px; + color: #2b3e50; + .opacity(0.6); + + > span.title { + position: relative; + display: inline-block; + padding: 8px 5px 9px 5px; + font-size: 14px; + z-index: 100; + height: 27px!important; + background-color: transparent; + + &:before, &:after { + content: ' '; + position: absolute; + background-color: white; + width: 15px; + height: 28px; + top: 0; + z-index: 100; + display: none; + } + + &:before { + left: -11px; + .border-radius(8px 0 0 0); + .transform( ~'skewX(-20deg)'); + } + + &:after { + right: -11px; + .border-radius(0 8px 0 0); + .transform( ~'skewX(20deg)'); + } + + span { + height: 18px; + font-size: 14px; + } + } + } + + &.active a { + .opacity(1); + + > span.title { + background-color: white; + &:before, &:after { + display: block; + } + } + } + } + } + + .tab-collapse-icon.primary { + color: #808c8d; + } + + &.primary-collapsed { + .tab-collapse-icon.primary { + color: white; + } + + > div > ul.nav-tabs { + background: @color-fancy-form-tabless-fields-bg; + + > li { + a { + color: white; + + > span.title { + &:before, &:after { + background-color: white; + } + } + } + + &.active a { + color: #2b3e50; + } + } + } + } + } + } + + &.primary-tabs { + + &.master-area { + > div > ul.nav-tabs { + .transition(background-color 0.5s); + background: @color-fancy-form-tabless-fields-bg; + } + } + + > div > ul.nav-tabs { + background: @color-fancy-primary-tabs-bg; + margin-left: 0!important; + margin-right: 0!important; + + &:before { + display: none; + } + + > li { + background: transparent; + border-right: none; + margin-right: -8px; + + &:first-child { + margin-left: -5px; + } + + a { + background: transparent; + border: none; + padding: 12px 16px 0px; + font-size: 14px; + font-weight: 400; + color: @color-fancy-primary-tabs-inactive-text; + + span.title { + background: @color-fancy-primary-tabs-inactive-bg; + border-top: none; + padding: 5px 5px 3px 5px; + + &:before, &:after { + background: @color-fancy-primary-tabs-inactive-bg; + border-width: 0; + top: 0; + } + + &:before { + left: -20px; + } + + &:after { + right: -20px; + } + + span { + border-width: 0; + vertical-align: top; + } + } + } + + &.active { + a { + color: @color-fancy-primary-tabs-active-text; + &:before { + display: none; + } + + span.title { + background: @color-fancy-primary-tabs-active-bg; + + &:before, &:after { + background: @color-fancy-primary-tabs-active-bg; + } + } + } + } + } + } + + > .tab-content > .tab-pane { + padding: @padding-standard @padding-standard 0 @padding-standard; + + &.pane-compact { + padding: 0; + } + } + + &.collapsed { + display: none; + } + } + + &.has-tabs { + > div.tab-content { + background: @body-bg; + } + } + + > div.tab-content { + > div.tab-pane { + padding: 0; + + &.padded-pane { + padding: @padding-standard @padding-standard 0 @padding-standard; + } + } + } + } + + // + // Forms and buttons + // + + .form-tabless-fields { + .clearfix(); + position: relative; + background: @color-fancy-form-tabless-fields-bg; + padding: 18px 23px 0 23px; + .transition(all 0.5s); + + label { + text-transform: uppercase; + color: @color-fancy-form-label; + margin-bottom: 0; + } + + input[type=text] { + background: transparent; + border: none; + color: @color-fancy-form-text; + font-size: 35px; + font-weight: 100; + height: auto; + padding: 0; + .placeholder(@color-fancy-form-placeholder); + .box-shadow(none); + + &:focus, &:hover { + background-color: rgba(255, 255, 255, 0.1); + } + } + + .form-group { + padding-bottom: 0; + + &.is-required { + > label:after { + display: none; + } + } + } + + .tab-collapse-icon { + .tab-collapse-icon(); + &.tabless { + top: 14px; + } + } + + &.collapsed { + padding: 5px 23px 0 10px; + + .tab-collapse-icon { + &.tabless { + .scaleAxes(1, -1); + } + } + + .form-group:not(.collapse-visible) { + display: none; + } + + .form-buttons { + margin-left: 10px; + padding-bottom: 0; + } + } + + .loading-indicator-container { + .loading-indicator { + background-color: @color-fancy-form-tabless-fields-bg; + padding: 0 0 0 30px; + color: @color-fancy-form-label; + margin-top: 1px; + height: 90%; + font-size: 12px; + line-height: 100%; + > span { + left: -10px; + top: 18px; + } + } + } + } + + .form-buttons { + .transition(all 0.5s); + padding-top: 14px; + padding-bottom: 5px; + + .btn { + padding: 0; + margin-right: 5px; + margin-top: -6px; + margin-right: 30px; + background: transparent; + color: @color-fancy-master-tabs-active-text; + font-weight: normal; + .box-shadow(none); + + .opacity(0.5); + .transition(all 0.3s ease); + + &:hover { + .opacity(1); + } + + &:last-child { + margin-right: 0; + } + + &[class^="oc-icon-"], + &[class*=" oc-icon-"] { + &:before { + opacity: 1; + } + } + } + } + + form.oc-data-changed { + .btn.save { + .opacity(1); + } + } + + // + // Code editor + // + + .field-codeeditor { + border: none !important; + .border-radius(0); + + .editor-code { + .border-radius(0); + } + } + + // + // Rich editor + // + + .field-richeditor { + border: none; + border-left: 1px solid @color-form-field-border !important; + + &, .fr-toolbar, .fr-wrapper { + .border-radius(0); + .border-top-radius(0); + } + } + + .secondary-content-tabs .field-richeditor { + .fr-toolbar { + background: white; + } + } +} + +body.side-panel-not-fixed { + .fancy-layout { + .field-richeditor { + border-left: none; + } + } +} + +html.cssanimations { + .fancy-layout { + .form-tabless-fields { + .loading-indicator-container { + .loading-indicator > span { + .animation(spin 1s linear infinite); + background-image: url('../../../system/assets/ui/images/loader-white.svg'); + background-size: 20px 20px; + } + } + } + } +} + +html.gecko { + .fancy-layout .control-tabs.secondary-tabs > div > ul.nav-tabs > li.active a { + padding-top: 13px; + } +} diff --git a/modules/backend/assets/less/layout/flexlayout.less b/modules/backend/assets/less/layout/flexlayout.less new file mode 100644 index 0000000..fe00e05 --- /dev/null +++ b/modules/backend/assets/less/layout/flexlayout.less @@ -0,0 +1,50 @@ +.flex-layout-column { + .flex-display(); + .flex-direction-column(); + + &.full-height-strict { + height: 100%; + } + + &.absolute { + position: absolute!important; + } + + &.fill-container { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + } +} + +.flex-layout-row { + .flex-display(); + .flex-direction-row(); +} + +.flex-layout-column, .flex-layout-row { + &.justify-center {.justify-content(center);} + &.align-center { + .align-items(center); + .align-content(center); + } + + &.full-height { + min-height: 100%; + // height: 100%; + } +} + +.flex-layout-item { + margin: 0; + &.fix { .flex-fix(); } + &.stretch { .flex-stretch(); } + &.stretch-constrain { .flex-stretch-constrain(); } + &.center { .align-self(center); } + + &.relative { position: relative; } + + &.layout-container { max-width: none; } +} diff --git a/modules/backend/assets/less/layout/flyout.less b/modules/backend/assets/less/layout/flyout.less new file mode 100644 index 0000000..a276396 --- /dev/null +++ b/modules/backend/assets/less/layout/flyout.less @@ -0,0 +1,48 @@ +.flyout-container { + > .flyout { + overflow: hidden; + width: 0; + left: 0!important; + .transition(width 0.1s); + } +} + +.flyout-overlay { + width: 100%; + height: 100%; + top: 0; + z-index: 5000; + position: absolute; + background-color: rgba(0,0,0,0); + .transition(background-color 0.3s); +} + +.flyout-toggle { + position: absolute; + top: 20px; + left: 0; + width: 23px; + height: 25px; + background: #2b3e50; + cursor: pointer; + .border-right-radius(4px); + color: #bdc3c7; + font-size: 10px; + + i { + margin: 7px 0 0 6px; + display: inline-block; + } + + &:hover i { + color: #ffffff; + } +} + +body.flyout-visible { + overflow: hidden; + + .flyout-overlay { + background-color: rgba(0,0,0,0.3); + } +} \ No newline at end of file diff --git a/modules/backend/assets/less/layout/footer.less b/modules/backend/assets/less/layout/footer.less new file mode 100644 index 0000000..f3ae25f --- /dev/null +++ b/modules/backend/assets/less/layout/footer.less @@ -0,0 +1,32 @@ +@footer-zindex: 100; +@footer-height: 60; + +#layout-footer { + width: 100%; + z-index: @footer-zindex; + height: @footer-height + 0px; + position: fixed; + bottom: 0; + color: @color-footer-text; + background-color: @color-footer; + border-top: 1px solid @color-footer-border; + + .brand, .tagline { + margin: 10px; + height: (@footer-height - 20) + 0px; + line-height: (@footer-height - 20) + 0px; + } + + .brand { + float: left; + font-size: 16px; + .logo { margin: 0 10px; } + .name { } + } + + .tagline { + float: right; + p { color: lighten(@color-footer-text, 20%); } + } +} + diff --git a/modules/backend/assets/less/layout/layout.less b/modules/backend/assets/less/layout/layout.less new file mode 100644 index 0000000..be3ff7f --- /dev/null +++ b/modules/backend/assets/less/layout/layout.less @@ -0,0 +1,222 @@ +// +// Common layout elements +// -------------------------------------------------- + +html:not(.mobile) body.drag * { + cursor: grab !important; + cursor: -webkit-grab !important; + cursor: -moz-grab !important; +} + +// Used by sortable plugin +body.dragging, body.dragging * { + cursor: move !important; +} + +body.loading, body.loading * { + cursor: wait !important; +} + +body.no-select { + .user-select(none); + cursor: default !important; +} + +// +// Layout canvas +// + +html, +body { + height: 100%; + /* The html and body elements cannot have any padding or margin. */ +} + +body { + font-family: @font-family-base; + background: @body-bg; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +#layout-canvas { + min-height: 100%; + height: 100%; +} + +// +// Font +// + +// Removed for performance reasons +// +// @import url(https://fonts.googleapis.com/css?family=Noto+Sans:400,400italic,700,700italic); +// +// body { +// font-family: 'Noto Sans', sans-serif; +// } + +// +// Tabs override for Layout +// Primary tabs should use inset by default, unless otherwise specified +// -------------------------------------------------- + +.control-tabs.primary-tabs { + > ul.nav-tabs, > div > ul.nav-tabs, > div > div > ul.nav-tabs { + margin-left: -(@padding-standard); + margin-right: -(@padding-standard); + } + + &.tabs-no-inset { + > ul.nav-tabs, > div > ul.nav-tabs, > div > div > ul.nav-tabs { + margin-left: 0; + margin-right: 0; + } + } +} + +// +// Flexible layout system +// -------------------------------------------------- + +.layout { + .layout-cell() { + display: table-cell; + vertical-align: top; + height: 100%; + + &.layout-container, .layout-container, &.padded-container, .padded-container { + padding: @padding-standard @padding-standard 0 @padding-standard; + + // Container to sit flush to the element above + .container-flush { + padding-top: 0; + } + } + + .layout-relative { + position: relative; + height: 100%; + } + + .layout-absolute { + position: absolute; + height: 100%; + width: 100%; + } + + &.min-size { + width: 0; + } + + &.min-height { + height: 0; + } + + &.center { + text-align: center; + } + + &.middle { + vertical-align: middle; + } + } + + display: table; + table-layout: fixed; + height: 100%; + width: 100%; + + > .layout-row { + display: table-row; + vertical-align: top; + height: 100%; + + > .layout-cell { + .layout-cell(); + } + + &.min-size { + height: 0.1px; + } + } + + > .layout-cell { + .layout-cell(); + } +} + +.whiteboard { + background: white; +} + +.layout-fill-container { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; +} + +// +// Calculated fixed width +// + +[data-calculate-width] { + > form, > div { + display: inline-block; + } +} + +// +// Layout styles +// + +body.compact-container { + .layout { + &.layout-container, .layout-container { padding: 0 !important; } + } +} + +body.slim-container { + .layout { + &.layout-container, .layout-container { padding-left: 0 !important; padding-right: 0 !important; } + } +} + +// +// Screen specific +// + +@media (max-width: @screen-sm) { + .layout { + .hide-on-small { + display: none; + } + + // + // Layout with a responsive sidebar + // + + &.responsive-sidebar { + > .layout-cell:first-child { + display: table-footer-group; + height: auto; + + .control-breadcrumb { + display: none; + } + } + + > .layout-cell:last-child { + display: table-header-group; + width: auto; + height: auto; + + .layout-absolute { + position: static; + } + } + } + } +} diff --git a/modules/backend/assets/less/layout/mainmenu.less b/modules/backend/assets/less/layout/mainmenu.less new file mode 100644 index 0000000..f4b8c37 --- /dev/null +++ b/modules/backend/assets/less/layout/mainmenu.less @@ -0,0 +1,680 @@ +// +// Top navigation bar +// -------------------------------------------------- + +@mainmenu-mode-tile-height: 78px; +@mainmenu-mode-inline-height: 60px; +@mainmenu-mode-collapse-height: 45px; + +@mainmenu-icon-dimension: 30px; +@mainmenu-tile-dimension: 65px; +@mainmenu-tile-label-height: 20px; +@mainmenu-tile-label-width: 100px; + +body.mainmenu-open { + overflow: hidden; + position: fixed; +} + +.mainmenu-item-link() { + display: inline-block; + font-size: @font-size-base; + color: inherit; + + &:hover { + background-color: transparent; + } + + &:active, &:focus { + text-decoration: none; + color: @color-mainmenu-inactive; + } + + i { + line-height: 1; + font-size: 30px; + vertical-align: middle; + } +} + +.mainmenu-item-link-active() { + // background: @color-mainmenu-active-bg; + // .border-radius(3px); + // .box-shadow(inset 0 -2px 0 rgba(0,0,0,.25)); +} + +.mainmenu-set-height(@height) { + height: @height; + + ul.mainmenu-toolbar { + li.mainmenu-quick-action { + a { + height: @height; + line-height: @height; + } + } + + li.mainmenu-account { + > a { + height: @height; + line-height: @height; + } + } + } + + ul li .mainmenu-accountmenu { + top: @height + 10; + } +} + +.mainmenu-tooltip { + .tooltip-inner { + font-size: @font-size-base - 1; + padding: 6px 16px; + } +} + +ul.mainmenu-nav { + font-size: @font-size-base; + + li { + /* Fix for SVG icons not rendering on initial page load until repaint (hover, move, etc) */ + .svg-icon { + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + } + + span.counter { + display: block; + position: absolute; + top: .143em; + right: 0; + padding: .143em .429em .214em .286em; + background-color: @color-sidebarnav-counter-bg; + color: @color-sidebarnav-counter-text; + font-size: .786em; + line-height: 100%; + .border-radius(3px); + .opacity(1); + .scale(1); + .transition(all 0.3s); + + &.empty { + .opacity(0); + .scale(0); + } + } + } +} + +nav#layout-mainmenu { + background-color: @color-mainmenu; + padding: 0 0 0 20px; + line-height: 0; + white-space: nowrap; + display: flex; + + a { + text-decoration: none; + &:focus { + background: transparent; + } + } + + ul { + margin: 0; + padding: 0; + list-style: none; + float: left; + white-space: nowrap; + overflow: hidden; + + li { + color: @color-mainmenu-inactive; + display: inline-block; + vertical-align: top; + position: relative; + margin-right: 30px; + + a { + .mainmenu-item-link(); + padding: 14px 0 10px; + + img.svg-icon { + height: 30px; + width: 30px; + margin-right: 10px; + position: relative; + top: 0; + } + } + } + + &.nav { + display: inline-block; + } + } + + .toolbar-item { + flex: 1 1 auto; + display: block; + padding-right: 0; + overflow: hidden; + + &-account { + flex: 0 0 auto; + } + + &:before, &:after { + margin-top: 0; + } + + &:before { + left: -12px; + } + + &:after { + right: -12px; + } + + &.scroll-active-before:before { + color: @color-mainmenu-active; + } + + &.scroll-active-after:after { + color: @color-mainmenu-active; + } + } + + // + // Toolbar + // + + ul.mainmenu-toolbar { + li.mainmenu-quick-action { + margin: 0; + + &:first-child { + margin-left: 21px; + } + + i { + font-size: 20px; + } + + a { + position: relative; + padding: 0 10px; + top: -1px; + } + } + + li.mainmenu-account { + margin-right: 0; + + > a { + padding: 0 15px 0 10px; + font-size: @font-size-base - 1; + position: relative; + } + + &.highlight > a { + z-index: @zindex-popover; + } + + img.account-avatar { + width: 45px; + height: 45px; + } + + .account-name { + //font-weight: bold; + margin-right: 15px; + } + + ul { + line-height: 23px; + } + } + } + + // + // Fading animation (disabled) + // + + &:hover { + ul.mainmenu-nav li { + //.transition(opacity .15s ease); + //.opacity(1); + } + } + + ul.mainmenu-nav li { + //.opacity(.65); + //.transition(opacity 5s ease); + //.transition-delay(5s); + + &.active { + //.opacity(1); + } + } +} + +// +// SVG support +// + +html.svg { + nav#layout-mainmenu, + .mainmenu-collapsed { + img.svg-icon { + display: inline-block; + } + } +} + +// +// User account menu +// + +nav#layout-mainmenu ul li .mainmenu-accountmenu { + position: fixed; + top: 0; // See mode for this value + right: @padding-standard; + background: @color-accountmenu-bg; + z-index: @zindex-popover; + display: none; + .box-shadow(@overlay-box-shadow); + border-radius: @border-radius-base; + + &.active { + display: block; + } + + &:after { + .triangle(up, 17px, 7px, @color-accountmenu-bg); + right: 9px; + top: -7px; + position: absolute; + } + + ul { + float: none; + display: block; + overflow: visible; + } + + li { + padding: 0; + margin: 0; + font-weight: normal; + text-align: left; + display: block; + + a { + display: block; + padding: (@padding-standard * 0.5) (@padding-standard * 1.5); + text-align: left; + font-size: @font-size-base; + color: @color-accountmenu-text; + + &:hover, &:focus { + background: @highlight-hover-bg; + color: @highlight-hover-text; + } + + &:active { + background: @highlight-active-bg; + color: @highlight-active-text; + } + } + + &:first-child a { + &:hover, &:focus, &:active { + &:after { + .triangle(up, 17px, 7px, @highlight-hover-bg); + position: absolute; + right: 9px; + top: -7px; + z-index: 102; + } + } + &:active { + &:after { + .triangle(up, 17px, 7px, @highlight-active-bg); + } + } + } + } + + li.divider { + height: 1px; + width: 100%; + background-color: @color-accountmenu-divider; + } +} + +// +// Navbar (Inline mode) +// + +nav#layout-mainmenu.navbar-mode-inline, +nav#layout-mainmenu.navbar-mode-inline_no_icons { + .mainmenu-set-height(@mainmenu-mode-inline-height); + + ul.mainmenu-nav { + li { + margin: 5px 0; + + a { + padding: 10px 15px; + + .nav-icon { + position: relative; + top: -1px; + margin-right: 5px; + width: @mainmenu-icon-dimension; + height: @mainmenu-icon-dimension; + i, img { margin: 0; } + } + .nav-label { + line-height: @mainmenu-icon-dimension; + } + } + + &:first-child { + margin-left: -13px; + } + + &:last-child { + margin-right: 0; + } + } + + li.active { + .mainmenu-item-link-active(); + + // &:first-child { + // margin-left: 0; + // } + } + + } +} + +// +// Navbar (Inline no icons mode) +// +nav#layout-mainmenu.navbar-mode-inline_no_icons .nav-icon { + display: none !important; +} + +// +// Navbar (Tiles mode) +// + +nav#layout-mainmenu.navbar-mode-tile { + .mainmenu-set-height(@mainmenu-mode-tile-height); + .mainmenu-navbar-tiles(); +} + +.mainmenu-navbar-tiles() { + ul.mainmenu-nav { + li a { + position: relative; + width: @mainmenu-tile-dimension; + height: @mainmenu-tile-dimension; + + // Offset from bottom + @tile-bottom-offset: 4; + + .nav-icon { + text-align: center; + display: block; + position: absolute; + top: 50%; + left: 50%; + margin-left: -(@mainmenu-icon-dimension / 2); + margin-top: -((@mainmenu-tile-dimension - @mainmenu-tile-label-height) / 2) - @tile-bottom-offset; + width: @mainmenu-icon-dimension; + height: @mainmenu-icon-dimension; + i, img { margin: 0; } + } + + .nav-label { + display: block; + width: @mainmenu-tile-label-width; + height: @mainmenu-tile-label-height; + line-height: @mainmenu-tile-label-height; + position: absolute; + bottom: @tile-bottom-offset + 0px; + left: 50%; + padding: 0 5px; + margin-left: -(@mainmenu-tile-label-width / 2); + overflow: hidden; + text-overflow: ellipsis; + text-align: center; + } + } + + li { + padding: 0 15px; + margin: 7px 0 0; + + &:first-child { + margin-left: -7px; + } + + &:hover { + .nav-label { + width: auto; + min-width: @mainmenu-tile-label-width; + text-overflow: all; + overflow: visible; + z-index: 2; + } + } + + } + + li.active { + .mainmenu-item-link-active(); + + a { + // font-weight: bold; + } + + &:first-child { + margin-left: 0; + } + } + } +} + +// +// Mobile (Collapsed mode) +// + +nav#layout-mainmenu { + .menu-toggle { + height: @mainmenu-mode-collapse-height; + line-height: @mainmenu-mode-collapse-height; + font-size: @font-size-base + 2; + display: none; + + .menu-toggle-icon { + background: #333; + display: inline-block; + height: @mainmenu-mode-collapse-height; + line-height: @mainmenu-mode-collapse-height; + width: @mainmenu-mode-collapse-height; + text-align: center; + opacity: .7; + + i { + line-height: @mainmenu-mode-collapse-height; + font-size: 20px; + vertical-align: bottom; + } + } + + .menu-toggle-title { + margin-left: 10px; + } + + &:hover { + .menu-toggle-icon { + opacity: 1; + } + } + } +} + +body.mainmenu-open { + nav#layout-mainmenu { + .menu-toggle-icon { + opacity: 1; + } + } +} + +nav#layout-mainmenu.navbar-mode-collapse { + .mainmenu-navbar-collapse(); +} + +@media (max-width: @menu-breakpoint-max) { + nav#layout-mainmenu.navbar { + .mainmenu-navbar-collapse(); + } +} + +.mainmenu-navbar-collapse() { + padding-left: 0; + + .mainmenu-set-height(@mainmenu-mode-collapse-height); + + ul.mainmenu-toolbar li.mainmenu-account > a { + padding-right: 0; + } + + ul li .mainmenu-accountmenu:after { + right: 13px; + } + + ul.nav { display: none; } + + .menu-toggle { + display: inline-block; + color: @color-mainmenu-active !important; + // font-weight: bold; + } +} + +.mainmenu-collapsed { + position: absolute; + height: 100%; + top: 0; + left: 0; + margin: 0; + background: @color-mainmenu-collapsed; + + > div { + display: block; + height: 100%; + + .mainmenu-navbar-tiles(); + + ul.mainmenu-nav li:first-child { + margin-left: 0; + } + + ul { + margin: 0; + padding: 5px 0 15px 15px; + overflow: hidden; + } + + ul li { + color: @color-mainmenu-inactive; + display: inline-block; + vertical-align: top; + position: relative; + margin-right: 30px; + } + + ul li a { + .mainmenu-item-link(); + + img.svg-icon { + height: 30px; + width: 30px; + position: relative; + top: 0; + } + } + } + + .vertical-scroll-marker(@color-mainmenu-inactive); +} + +body.mainmenu-open .mainmenu-collapsed ul { + position: absolute; + left: 0; + top: 10px; + bottom: 10px; +} + +html.mobile { + .mainmenu-collapsed ul { + overflow: auto; + -webkit-overflow-scrolling: touch; + } +} + +// +// Misc +// + +nav#layout-mainmenu.navbar ul li:hover, +.mainmenu-collapsed li:hover { + a { + &:active, &:focus { + color: @color-mainmenu-active !important; + } + } +} + +.touch .mainmenu-collapsed li a:hover { + color: @color-mainmenu-inactive; +} + +nav#layout-mainmenu.navbar ul li, +.mainmenu-collapsed li { + + // Used by account menu + &.highlight > a { + color: @color-mainmenu-active !important; + } + + &.active { + color: @color-mainmenu-active !important; + + a { + color: @color-mainmenu-active !important; + } + } + + &:hover { + color: @color-mainmenu-active; + background: transparent; + } +} + +body.drag { + nav#layout-mainmenu.navbar ul.nav li, + .mainmenu-collapsed ul li { + &:hover { + color: @color-mainmenu-inactive; + } + } +} diff --git a/modules/backend/assets/less/layout/outerlayout.less b/modules/backend/assets/less/layout/outerlayout.less new file mode 100644 index 0000000..1fd47da --- /dev/null +++ b/modules/backend/assets/less/layout/outerlayout.less @@ -0,0 +1,146 @@ + +// Layout for "Outside" pages, such as the Login screen +// + +body.outer { + background: @color-outer-bg; + + .layout { + > .layout-row { + &.layout-head { + text-align: center; + background: @color-outer-header; + + > .layout-cell { + height: 40%; + padding: 50px 0; + .box-sizing(border-box); + vertical-align: middle; + position: relative; + + &:after { + .triangle(down, 56px, 20px, @color-outer-header); + position: absolute; + bottom: -20px; + left: 50%; + margin-left: -28px; + } + + h1.oc-logo { + .hide-text(); + display: inline-block; + width: 100%; + max-width: 450px; + height: 170px; + min-height: 72px; + } + } + } + + > .layout-cell { + vertical-align: top; + + .outer-form-container { + margin: 0 auto; + width: 436px; + padding: (@padding-standard * 2) 0; + + h2 { + font-size: 18px; + margin: 20px 0; + color: @color-outer-heading; + } + + .horizontal-form { + font-size: 0; + .flex-display(); + + input { + vertical-align: top; + margin-right: 9px; + display: inline-block; + border: none; + .border-radius(2px); + } + + button { + background: @link-color; + text-align: center; + font-size: 13px; + font-weight: 600; + height: 40px; + vertical-align: top; + .box-sizing(border-box); + } + } + + .remember { + label { + color: @color-outer-muted-text; + } + input#remember { + display: none; + } + } + + .forgot-password { + margin-top: 30px; + font-size: 13px; + top: 8px; + + a { + color: @color-outer-muted-text; + } + + &:before { + color: @color-outer-muted-text; + font-size: 14px; + position: relative; + margin-right: 5px; + } + } + } + } + } + } +} + +html.csstransitions { + body.outer { + .outer-form-container { + .transition(all 0.5s ease-out); + .scaleAxes(1, 1); + } + + &.preload { + .outer-form-container { + .scaleAxes(0.2, 0.2); + } + } + } +} + +@media (max-width: @screen-sm) { + body.outer .layout > .layout-row { + &.layout-head { + > .layout-cell { + padding: 50px @padding-standard; + } + } + + > .layout-cell .outer-form-container { + width: auto; + padding: @padding-standard * 2; + + .horizontal-form { + display: block; + + input { + display: block; + width: 100% !important; + margin-bottom: @padding-standard; + } + } + } + } +} diff --git a/modules/backend/assets/less/layout/sidenav.less b/modules/backend/assets/less/layout/sidenav.less new file mode 100644 index 0000000..259bc4f --- /dev/null +++ b/modules/backend/assets/less/layout/sidenav.less @@ -0,0 +1,116 @@ +// +// Side navigation bar +// -------------------------------------------------- + +.layout-sidenav-container { + width: 120px; +} + +#layout-sidenav { + position: absolute; + height: 100%; + width: 100%; + .box-sizing(border-box); + font-size: @font-size-base; + + ul { + position: relative; + margin: 0; + padding: 0; + height: 100%; + overflow: hidden; + + li { + display: block; + text-align: center; + position: relative; + + a { + padding: 1.429em .714em; + display: block; + font-size: .929em; + color: @color-sidebarnav-inactive-text; + font-weight: normal; + position: relative; + + &:hover { + text-decoration: none; + background-color: transparent; + } + + &:focus { + background: transparent; + } + + i { + color: @color-sidebarnav-inactive-icon; + display: block; + margin-bottom: 5px; + font-size: 2em; + } + } + + &:first-child a { + padding-top: 2.143em; + } + + &.active a, a:hover { + color: @color-sidebarnav-active-text; + i { color: @color-sidebarnav-active-icon; } + } + + span.counter { + display: block; + position: absolute; + top: 1.071em; + right: 1.071em; + padding: .143em .429em .214em .286em; + background-color: @color-sidebarnav-counter-bg; + color: @color-sidebarnav-counter-text; + font-size: .786em; + line-height: 100%; + .border-radius(3px); + .opacity(1); + .scale(1); + .transition(all 0.3s); + + &.empty { + .opacity(0); + .scale(0); + } + } + } + } +} + +@media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { + #layout-sidenav { + font-size: 12px; + } + .layout-sidenav-container { + width: 100px; + } +} + +@media (max-width: @screen-xs-max) { + #layout-sidenav { + font-size: 10px; + } + .layout-sidenav-container { + width: 80px; + } +} + +html.mobile { + #layout-sidenav ul { + overflow: auto; + -webkit-overflow-scrolling: touch; + } +} + +#layout-sidenav.layout-sidenav ul.drag li:not(.active) a:hover, +.touch #layout-sidenav.layout-sidenav li:not(.active) a:hover { + color: @color-sidebarnav-inactive-text !important; + i { color: @color-sidebarnav-inactive-icon !important; } + &:after { display: none !important; } +} diff --git a/modules/backend/assets/less/layout/sidepanel.less b/modules/backend/assets/less/layout/sidepanel.less new file mode 100644 index 0000000..79d86ac --- /dev/null +++ b/modules/backend/assets/less/layout/sidepanel.less @@ -0,0 +1,97 @@ +// +// Side panel +// -------------------------------------------------- + +#layout-side-panel { + .fix-button { + position: absolute; + right: -25px; + top: 0; + display: none; + width: 25px; + height: 25px; + font-size: 13px; + background: #ecf0f1; + z-index: 120; + .opacity(0.5); + .border-radius(~'0 4px 4px 0'); + + i { + display: block; + text-align: center; + margin-top: 5px; + color: @color-scrollpanel-fix-button; + } + + &:hover { + text-decoration: none; + display: block; + .opacity(1)!important; + } + } + + &:hover { + .fix-button { + display: block; + } + } + + .fix-button-content-header .fix-button { + top: 46px; + } + + .sidepanel-content-header { + background: #d35400; + color: white; + font-size: 15px; + padding: 12px 20px 13px; + position: relative; + + &:after { + .triangle(down, 15px, 8px, #d35400); + position: absolute; + left: 14px; + bottom: -8px; + } + } +} + +body.side-panel-not-fixed { + #layout-side-panel { + display: none; + + .fix-button { + .opacity(0.5); + } + } +} + +body.display-side-panel { + #layout-side-panel { + display: block; + position: absolute; + // This needs to be higher than the dropdown overlay, otherwise the + // mouseout event fires and sidebar hides when opening a dropdown. + z-index: @zindex-dropdown; + width: 350px; + .box-shadow(3px 0px 3px 0 rgba(0, 0, 0, 0.1)); + } +} + +@media (min-width: @screen-md-min) { + body.side-panel-fix-shadow { + #layout-side-panel { + .box-shadow(none); + } + } +} + +.touch #layout-side-panel .fix-button { + display: none; +} + +@media (max-width: @screen-sm) { + #layout-side-panel .fix-button { + display: none; + } +} \ No newline at end of file diff --git a/modules/backend/assets/less/october.less b/modules/backend/assets/less/october.less new file mode 100644 index 0000000..0b2e297 --- /dev/null +++ b/modules/backend/assets/less/october.less @@ -0,0 +1,54 @@ +// Vendor +@import "../vendor/sweet-alert/sweet-alert.less"; +@import "../vendor/jcrop/css/jquery.Jcrop.min.css"; +@import "../../../system/assets/vendor/prettify/prettify.css"; +@import "../../../system/assets/vendor/prettify/theme-desert.css"; + +// +// October Controls +// + +@import "core/boot.less"; +@import "controls/alert.less"; +@import "controls/simplelist.less"; +@import "controls/scrollbar.less"; +@import "controls/filelist.less"; +@import "controls/common.less"; +@import "controls/reportwidgets.less"; +@import "controls/treelist.less"; +@import "controls/treeview.less"; +@import "controls/sidenav-tree.less"; +@import "controls/panels.less"; +@import "controls/selector-group.less"; +@import "controls/tree-path.less"; +@import "controls/namevaluelist.less"; +@import "controls/scrollpad.less"; +@import "controls/svg-icons.less"; + +// +// October Storm UI +// + +@import "../../../system/assets/ui/less/global.less"; + +// +// Combines layout and vendor styles +// + +// Core (shared elements) +@import "core/animations.less"; + +// Boot variables and mixins +@import "core/variables.less"; +@import "core/mixins.less"; + +// Layout +@import "layout/layout.less"; +@import "layout/flexlayout.less"; +@import "layout/mainmenu.less"; +@import "layout/sidenav.less"; +@import "layout/sidepanel.less"; +@import "layout/footer.less"; +@import "layout/outerlayout.less"; +@import "layout/fancylayout.less"; +@import "layout/flyout.less"; diff --git a/modules/backend/assets/vendor/css-browser-selector/css-browser-selector.js b/modules/backend/assets/vendor/css-browser-selector/css-browser-selector.js new file mode 100644 index 0000000..0668aa7 --- /dev/null +++ b/modules/backend/assets/vendor/css-browser-selector/css-browser-selector.js @@ -0,0 +1,8 @@ +/* +CSS Browser Selector v0.4.0 (Nov 02, 2010) +Rafael Lima (http://rafael.adm.br) +http://rafael.adm.br/css_browser_selector +License: http://creativecommons.org/licenses/by/2.5/ +Contributors: http://rafael.adm.br/css_browser_selector#contributors +*/ +function css_browser_selector(u){var ua=u.toLowerCase(),is=function(t){return ua.indexOf(t)>-1},g='gecko',w='webkit',s='safari',o='opera',m='mobile',h=document.documentElement,b=[(!(/opera|webtv/i.test(ua))&&/msie\s(\d)/.test(ua))?('ie ie'+RegExp.$1):is('firefox/2')?g+' ff2':is('firefox/3.5')?g+' ff3 ff3_5':is('firefox/3.6')?g+' ff3 ff3_6':is('firefox/3')?g+' ff3':is('gecko/')?g:is('opera')?o+(/version\/(\d+)/.test(ua)?' '+o+RegExp.$1:(/opera(\s|\/)(\d+)/.test(ua)?' '+o+RegExp.$2:'')):is('konqueror')?'konqueror':is('blackberry')?m+' blackberry':is('android')?m+' android':is('chrome')?w+' chrome':is('iron')?w+' iron':is('applewebkit/')?w+' '+s+(/version\/(\d+)/.test(ua)?' '+s+RegExp.$1:''):is('mozilla/')?g:'',is('j2me')?m+' j2me':is('iphone')?m+' iphone':is('ipod')?m+' ipod':is('ipad')?m+' ipad':is('mac')?'mac':is('darwin')?'mac':is('webtv')?'webtv':is('win')?'win'+(is('windows nt 6.0')?' vista':''):is('freebsd')?'freebsd':(is('x11')||is('linux'))?'linux':'','js']; c = b.join(' '); h.className += ' '+c; return c;}; css_browser_selector(navigator.userAgent); diff --git a/modules/backend/assets/vendor/dropzone/dropzone.js b/modules/backend/assets/vendor/dropzone/dropzone.js new file mode 100644 index 0000000..476c055 --- /dev/null +++ b/modules/backend/assets/vendor/dropzone/dropzone.js @@ -0,0 +1,3535 @@ +/** + * DropZone V5.5.1 (non-minified) for testing on October CMS + */ + +"use strict"; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/* + * + * More info at [www.dropzonejs.com](http://www.dropzonejs.com) + * + * Copyright (c) 2012, Matias Meno + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +// The Emitter class provides the ability to call `.on()` on Dropzone to listen +// to events. +// It is strongly based on component's emitter class, and I removed the +// functionality because of the dependency hell with different frameworks. +var Emitter = function () { + function Emitter() { + _classCallCheck(this, Emitter); + } + + _createClass(Emitter, [{ + key: "on", + + // Add an event listener for given event + value: function on(event, fn) { + this._callbacks = this._callbacks || {}; + // Create namespace for this event + if (!this._callbacks[event]) { + this._callbacks[event] = []; + } + this._callbacks[event].push(fn); + return this; + } + }, { + key: "emit", + value: function emit(event) { + this._callbacks = this._callbacks || {}; + var callbacks = this._callbacks[event]; + + if (callbacks) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + for (var _iterator = callbacks, _isArray = true, _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } + + var callback = _ref; + + callback.apply(this, args); + } + } + + return this; + } + + // Remove event listener for given event. If fn is not provided, all event + // listeners for that event will be removed. If neither is provided, all + // event listeners will be removed. + + }, { + key: "off", + value: function off(event, fn) { + if (!this._callbacks || arguments.length === 0) { + this._callbacks = {}; + return this; + } + + // specific event + var callbacks = this._callbacks[event]; + if (!callbacks) { + return this; + } + + // remove all handlers + if (arguments.length === 1) { + delete this._callbacks[event]; + return this; + } + + // remove specific handler + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; + if (callback === fn) { + callbacks.splice(i, 1); + break; + } + } + + return this; + } + }]); + + return Emitter; +}(); + +var Dropzone = function (_Emitter) { + _inherits(Dropzone, _Emitter); + + _createClass(Dropzone, null, [{ + key: "initClass", + value: function initClass() { + + // Exposing the emitter class, mainly for tests + this.prototype.Emitter = Emitter; + + /* + This is a list of all available events you can register on a dropzone object. + You can register an event handler like this: + dropzone.on("dragEnter", function() { }); + */ + this.prototype.events = ["drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave", "addedfile", "addedfiles", "removedfile", "thumbnail", "error", "errormultiple", "processing", "processingmultiple", "uploadprogress", "totaluploadprogress", "sending", "sendingmultiple", "success", "successmultiple", "canceled", "canceledmultiple", "complete", "completemultiple", "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete"]; + + this.prototype.defaultOptions = { + /** + * Has to be specified on elements other than form (or when the form + * doesn't have an `action` attribute). You can also + * provide a function that will be called with `files` and + * must return the url (since `v3.12.0`) + */ + url: null, + + /** + * Can be changed to `"put"` if necessary. You can also provide a function + * that will be called with `files` and must return the method (since `v3.12.0`). + */ + method: "post", + + /** + * Will be set on the XHRequest. + */ + withCredentials: false, + + /** + * The timeout for the XHR requests in milliseconds (since `v4.4.0`). + */ + timeout: 30000, + + /** + * How many file uploads to process in parallel (See the + * Enqueuing file uploads* documentation section for more info) + */ + parallelUploads: 2, + + /** + * Whether to send multiple files in one request. If + * this it set to true, then the fallback file input element will + * have the `multiple` attribute as well. This option will + * also trigger additional events (like `processingmultiple`). See the events + * documentation section for more information. + */ + uploadMultiple: false, + + /** + * Whether you want files to be uploaded in chunks to your server. This can't be + * used in combination with `uploadMultiple`. + * + * See [chunksUploaded](#config-chunksUploaded) for the callback to finalise an upload. + */ + chunking: false, + + /** + * If `chunking` is enabled, this defines whether **every** file should be chunked, + * even if the file size is below chunkSize. This means, that the additional chunk + * form data will be submitted and the `chunksUploaded` callback will be invoked. + */ + forceChunking: false, + + /** + * If `chunking` is `true`, then this defines the chunk size in bytes. + */ + chunkSize: 2000000, + + /** + * If `true`, the individual chunks of a file are being uploaded simultaneously. + */ + parallelChunkUploads: false, + + /** + * Whether a chunk should be retried if it fails. + */ + retryChunks: false, + + /** + * If `retryChunks` is true, how many times should it be retried. + */ + retryChunksLimit: 3, + + /** + * If not `null` defines how many files this Dropzone handles. If it exceeds, + * the event `maxfilesexceeded` will be called. The dropzone element gets the + * class `dz-max-files-reached` accordingly so you can provide visual feedback. + */ + maxFilesize: 256, + + /** + * The name of the file param that gets transferred. + * **NOTE**: If you have the option `uploadMultiple` set to `true`, then + * Dropzone will append `[]` to the name. + */ + paramName: "file", + + /** + * Whether thumbnails for images should be generated + */ + createImageThumbnails: true, + + /** + * In MB. When the filename exceeds this limit, the thumbnail will not be generated. + */ + maxThumbnailFilesize: 10, + + /** + * If `null`, the ratio of the image will be used to calculate it. + */ + thumbnailWidth: 120, + + /** + * The same as `thumbnailWidth`. If both are null, images will not be resized. + */ + thumbnailHeight: 120, + + /** + * How the images should be scaled down in case both, `thumbnailWidth` and `thumbnailHeight` are provided. + * Can be either `contain` or `crop`. + */ + thumbnailMethod: 'crop', + + /** + * If set, images will be resized to these dimensions before being **uploaded**. + * If only one, `resizeWidth` **or** `resizeHeight` is provided, the original aspect + * ratio of the file will be preserved. + * + * The `options.transformFile` function uses these options, so if the `transformFile` function + * is overridden, these options don't do anything. + */ + resizeWidth: null, + + /** + * See `resizeWidth`. + */ + resizeHeight: null, + + /** + * The mime type of the resized image (before it gets uploaded to the server). + * If `null` the original mime type will be used. To force jpeg, for example, use `image/jpeg`. + * See `resizeWidth` for more information. + */ + resizeMimeType: null, + + /** + * The quality of the resized images. See `resizeWidth`. + */ + resizeQuality: 0.8, + + /** + * How the images should be scaled down in case both, `resizeWidth` and `resizeHeight` are provided. + * Can be either `contain` or `crop`. + */ + resizeMethod: 'contain', + + /** + * The base that is used to calculate the filesize. You can change this to + * 1024 if you would rather display kibibytes, mebibytes, etc... + * 1024 is technically incorrect, because `1024 bytes` are `1 kibibyte` not `1 kilobyte`. + * You can change this to `1024` if you don't care about validity. + */ + filesizeBase: 1000, + + /** + * Can be used to limit the maximum number of files that will be handled by this Dropzone + */ + maxFiles: null, + + /** + * An optional object to send additional headers to the server. Eg: + * `{ "My-Awesome-Header": "header value" }` + */ + headers: null, + + /** + * If `true`, the dropzone element itself will be clickable, if `false` + * nothing will be clickable. + * + * You can also pass an HTML element, a CSS selector (for multiple elements) + * or an array of those. In that case, all of those elements will trigger an + * upload when clicked. + */ + clickable: true, + + /** + * Whether hidden files in directories should be ignored. + */ + ignoreHiddenFiles: true, + + /** + * The default implementation of `accept` checks the file's mime type or + * extension against this list. This is a comma separated list of mime + * types or file extensions. + * + * Eg.: `image/*,application/pdf,.psd` + * + * If the Dropzone is `clickable` this option will also be used as + * [`accept`](https://developer.mozilla.org/en-US/docs/HTML/Element/input#attr-accept) + * parameter on the hidden file input as well. + */ + acceptedFiles: null, + + /** + * **Deprecated!** + * Use acceptedFiles instead. + */ + acceptedMimeTypes: null, + + /** + * If false, files will be added to the queue but the queue will not be + * processed automatically. + * This can be useful if you need some additional user input before sending + * files (or if you want want all files sent at once). + * If you're ready to send the file simply call `myDropzone.processQueue()`. + * + * See the [enqueuing file uploads](#enqueuing-file-uploads) documentation + * section for more information. + */ + autoProcessQueue: true, + + /** + * If false, files added to the dropzone will not be queued by default. + * You'll have to call `enqueueFile(file)` manually. + */ + autoQueue: true, + + /** + * If `true`, this will add a link to every file preview to remove or cancel (if + * already uploading) the file. The `dictCancelUpload`, `dictCancelUploadConfirmation` + * and `dictRemoveFile` options are used for the wording. + */ + addRemoveLinks: false, + + /** + * Defines where to display the file previews – if `null` the + * Dropzone element itself is used. Can be a plain `HTMLElement` or a CSS + * selector. The element should have the `dropzone-previews` class so + * the previews are displayed properly. + */ + previewsContainer: null, + + /** + * This is the element the hidden input field (which is used when clicking on the + * dropzone to trigger file selection) will be appended to. This might + * be important in case you use frameworks to switch the content of your page. + * + * Can be a selector string, or an element directly. + */ + hiddenInputContainer: "body", + + /** + * If null, no capture type will be specified + * If camera, mobile devices will skip the file selection and choose camera + * If microphone, mobile devices will skip the file selection and choose the microphone + * If camcorder, mobile devices will skip the file selection and choose the camera in video mode + * On apple devices multiple must be set to false. AcceptedFiles may need to + * be set to an appropriate mime type (e.g. "image/*", "audio/*", or "video/*"). + */ + capture: null, + + /** + * **Deprecated**. Use `renameFile` instead. + */ + renameFilename: null, + + /** + * A function that is invoked before the file is uploaded to the server and renames the file. + * This function gets the `File` as argument and can use the `file.name`. The actual name of the + * file that gets used during the upload can be accessed through `file.upload.filename`. + */ + renameFile: null, + + /** + * If `true` the fallback will be forced. This is very useful to test your server + * implementations first and make sure that everything works as + * expected without dropzone if you experience problems, and to test + * how your fallbacks will look. + */ + forceFallback: false, + + /** + * The text used before any files are dropped. + */ + dictDefaultMessage: "Drop files here to upload", + + /** + * The text that replaces the default message text it the browser is not supported. + */ + dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.", + + /** + * The text that will be added before the fallback form. + * If you provide a fallback element yourself, or if this option is `null` this will + * be ignored. + */ + dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.", + + /** + * If the filesize is too big. + * `{{filesize}}` and `{{maxFilesize}}` will be replaced with the respective configuration values. + */ + dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.", + + /** + * If the file doesn't match the file type. + */ + dictInvalidFileType: "You can't upload files of this type.", + + /** + * If the server response was invalid. + * `{{statusCode}}` will be replaced with the servers status code. + */ + dictResponseError: "Server responded with {{statusCode}} code.", + + /** + * If `addRemoveLinks` is true, the text to be used for the cancel upload link. + */ + dictCancelUpload: "Cancel upload", + + /** + * The text that is displayed if an upload was manually canceled + */ + dictUploadCanceled: "Upload canceled.", + + /** + * If `addRemoveLinks` is true, the text to be used for confirmation when cancelling upload. + */ + dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?", + + /** + * If `addRemoveLinks` is true, the text to be used to remove a file. + */ + dictRemoveFile: "Remove file", + + /** + * If this is not null, then the user will be prompted before removing a file. + */ + dictRemoveFileConfirmation: null, + + /** + * Displayed if `maxFiles` is st and exceeded. + * The string `{{maxFiles}}` will be replaced by the configuration value. + */ + dictMaxFilesExceeded: "You can not upload any more files.", + + /** + * Allows you to translate the different units. Starting with `tb` for terabytes and going down to + * `b` for bytes. + */ + dictFileSizeUnits: { tb: "TB", gb: "GB", mb: "MB", kb: "KB", b: "b" }, + /** + * Called when dropzone initialized + * You can add event listeners here + */ + init: function init() {}, + + + /** + * Can be an **object** of additional parameters to transfer to the server, **or** a `Function` + * that gets invoked with the `files`, `xhr` and, if it's a chunked upload, `chunk` arguments. In case + * of a function, this needs to return a map. + * + * The default implementation does nothing for normal uploads, but adds relevant information for + * chunked uploads. + * + * This is the same as adding hidden input fields in the form element. + */ + params: function params(files, xhr, chunk) { + if (chunk) { + return { + dzuuid: chunk.file.upload.uuid, + dzchunkindex: chunk.index, + dztotalfilesize: chunk.file.size, + dzchunksize: this.options.chunkSize, + dztotalchunkcount: chunk.file.upload.totalChunkCount, + dzchunkbyteoffset: chunk.index * this.options.chunkSize + }; + } + }, + + + /** + * A function that gets a [file](https://developer.mozilla.org/en-US/docs/DOM/File) + * and a `done` function as parameters. + * + * If the done function is invoked without arguments, the file is "accepted" and will + * be processed. If you pass an error message, the file is rejected, and the error + * message will be displayed. + * This function will not be called if the file is too big or doesn't match the mime types. + */ + accept: function accept(file, done) { + return done(); + }, + + + /** + * The callback that will be invoked when all chunks have been uploaded for a file. + * It gets the file for which the chunks have been uploaded as the first parameter, + * and the `done` function as second. `done()` needs to be invoked when everything + * needed to finish the upload process is done. + */ + chunksUploaded: function chunksUploaded(file, done) { + done(); + }, + + /** + * Gets called when the browser is not supported. + * The default implementation shows the fallback input field and adds + * a text. + */ + fallback: function fallback() { + // This code should pass in IE7... :( + var messageElement = void 0; + this.element.className = this.element.className + " dz-browser-not-supported"; + + for (var _iterator2 = this.element.getElementsByTagName("div"), _isArray2 = true, _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref2; + + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref2 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref2 = _i2.value; + } + + var child = _ref2; + + if (/(^| )dz-message($| )/.test(child.className)) { + messageElement = child; + child.className = "dz-message"; // Removes the 'dz-default' class + break; + } + } + if (!messageElement) { + messageElement = Dropzone.createElement("
"); + this.element.appendChild(messageElement); + } + + var span = messageElement.getElementsByTagName("span")[0]; + if (span) { + if (span.textContent != null) { + span.textContent = this.options.dictFallbackMessage; + } else if (span.innerText != null) { + span.innerText = this.options.dictFallbackMessage; + } + } + + return this.element.appendChild(this.getFallbackForm()); + }, + + + /** + * Gets called to calculate the thumbnail dimensions. + * + * It gets `file`, `width` and `height` (both may be `null`) as parameters and must return an object containing: + * + * - `srcWidth` & `srcHeight` (required) + * - `trgWidth` & `trgHeight` (required) + * - `srcX` & `srcY` (optional, default `0`) + * - `trgX` & `trgY` (optional, default `0`) + * + * Those values are going to be used by `ctx.drawImage()`. + */ + resize: function resize(file, width, height, resizeMethod) { + var info = { + srcX: 0, + srcY: 0, + srcWidth: file.width, + srcHeight: file.height + }; + + var srcRatio = file.width / file.height; + + // Automatically calculate dimensions if not specified + if (width == null && height == null) { + width = info.srcWidth; + height = info.srcHeight; + } else if (width == null) { + width = height * srcRatio; + } else if (height == null) { + height = width / srcRatio; + } + + // Make sure images aren't upscaled + width = Math.min(width, info.srcWidth); + height = Math.min(height, info.srcHeight); + + var trgRatio = width / height; + + if (info.srcWidth > width || info.srcHeight > height) { + // Image is bigger and needs rescaling + if (resizeMethod === 'crop') { + if (srcRatio > trgRatio) { + info.srcHeight = file.height; + info.srcWidth = info.srcHeight * trgRatio; + } else { + info.srcWidth = file.width; + info.srcHeight = info.srcWidth / trgRatio; + } + } else if (resizeMethod === 'contain') { + // Method 'contain' + if (srcRatio > trgRatio) { + height = width / srcRatio; + } else { + width = height * srcRatio; + } + } else { + throw new Error("Unknown resizeMethod '" + resizeMethod + "'"); + } + } + + info.srcX = (file.width - info.srcWidth) / 2; + info.srcY = (file.height - info.srcHeight) / 2; + + info.trgWidth = width; + info.trgHeight = height; + + return info; + }, + + + /** + * Can be used to transform the file (for example, resize an image if necessary). + * + * The default implementation uses `resizeWidth` and `resizeHeight` (if provided) and resizes + * images according to those dimensions. + * + * Gets the `file` as the first parameter, and a `done()` function as the second, that needs + * to be invoked with the file when the transformation is done. + */ + transformFile: function transformFile(file, done) { + if ((this.options.resizeWidth || this.options.resizeHeight) && file.type.match(/image.*/)) { + return this.resizeImage(file, this.options.resizeWidth, this.options.resizeHeight, this.options.resizeMethod, done); + } else { + return done(file); + } + }, + + + /** + * A string that contains the template used for each dropped + * file. Change it to fulfill your needs but make sure to properly + * provide all elements. + * + * If you want to use an actual HTML element instead of providing a String + * as a config option, you could create a div with the id `tpl`, + * put the template inside it and provide the element like this: + * + * document + * .querySelector('#tpl') + * .innerHTML + * + */ + previewTemplate: "
\n
\n
\n
\n
\n
\n
\n
\n
\n \n Check\n \n \n \n \n \n
\n
\n \n Error\n \n \n \n \n \n \n \n
\n
", + + // END OPTIONS + // (Required by the dropzone documentation parser) + + + /* + Those functions register themselves to the events on init and handle all + the user interface specific stuff. Overwriting them won't break the upload + but can break the way it's displayed. + You can overwrite them if you don't like the default behavior. If you just + want to add an additional event handler, register it on the dropzone object + and don't overwrite those options. + */ + + // Those are self explanatory and simply concern the DragnDrop. + drop: function drop(e) { + return this.element.classList.remove("dz-drag-hover"); + }, + dragstart: function dragstart(e) {}, + dragend: function dragend(e) { + return this.element.classList.remove("dz-drag-hover"); + }, + dragenter: function dragenter(e) { + return this.element.classList.add("dz-drag-hover"); + }, + dragover: function dragover(e) { + return this.element.classList.add("dz-drag-hover"); + }, + dragleave: function dragleave(e) { + return this.element.classList.remove("dz-drag-hover"); + }, + paste: function paste(e) {}, + + + // Called whenever there are no files left in the dropzone anymore, and the + // dropzone should be displayed as if in the initial state. + reset: function reset() { + return this.element.classList.remove("dz-started"); + }, + + + // Called when a file is added to the queue + // Receives `file` + addedfile: function addedfile(file) { + var _this2 = this; + + if (this.element === this.previewsContainer) { + this.element.classList.add("dz-started"); + } + + if (this.previewsContainer) { + file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim()); + file.previewTemplate = file.previewElement; // Backwards compatibility + + this.previewsContainer.appendChild(file.previewElement); + for (var _iterator3 = file.previewElement.querySelectorAll("[data-dz-name]"), _isArray3 = true, _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref3; + + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref3 = _iterator3[_i3++]; + } else { + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref3 = _i3.value; + } + + var node = _ref3; + + node.textContent = file.name; + } + for (var _iterator4 = file.previewElement.querySelectorAll("[data-dz-size]"), _isArray4 = true, _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { + if (_isArray4) { + if (_i4 >= _iterator4.length) break; + node = _iterator4[_i4++]; + } else { + _i4 = _iterator4.next(); + if (_i4.done) break; + node = _i4.value; + } + + node.innerHTML = this.filesize(file.size); + } + + if (this.options.addRemoveLinks) { + file._removeLink = Dropzone.createElement("" + this.options.dictRemoveFile + ""); + file.previewElement.appendChild(file._removeLink); + } + + var removeFileEvent = function removeFileEvent(e) { + e.preventDefault(); + e.stopPropagation(); + if (file.status === Dropzone.UPLOADING) { + return Dropzone.confirm(_this2.options.dictCancelUploadConfirmation, function () { + return _this2.removeFile(file); + }); + } else { + if (_this2.options.dictRemoveFileConfirmation) { + return Dropzone.confirm(_this2.options.dictRemoveFileConfirmation, function () { + return _this2.removeFile(file); + }); + } else { + return _this2.removeFile(file); + } + } + }; + + for (var _iterator5 = file.previewElement.querySelectorAll("[data-dz-remove]"), _isArray5 = true, _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { + var _ref4; + + if (_isArray5) { + if (_i5 >= _iterator5.length) break; + _ref4 = _iterator5[_i5++]; + } else { + _i5 = _iterator5.next(); + if (_i5.done) break; + _ref4 = _i5.value; + } + + var removeLink = _ref4; + + removeLink.addEventListener("click", removeFileEvent); + } + } + }, + + + // Called whenever a file is removed. + removedfile: function removedfile(file) { + if (file.previewElement != null && file.previewElement.parentNode != null) { + file.previewElement.parentNode.removeChild(file.previewElement); + } + return this._updateMaxFilesReachedClass(); + }, + + + // Called when a thumbnail has been generated + // Receives `file` and `dataUrl` + thumbnail: function thumbnail(file, dataUrl) { + if (file.previewElement) { + file.previewElement.classList.remove("dz-file-preview"); + for (var _iterator6 = file.previewElement.querySelectorAll("[data-dz-thumbnail]"), _isArray6 = true, _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { + var _ref5; + + if (_isArray6) { + if (_i6 >= _iterator6.length) break; + _ref5 = _iterator6[_i6++]; + } else { + _i6 = _iterator6.next(); + if (_i6.done) break; + _ref5 = _i6.value; + } + + var thumbnailElement = _ref5; + + thumbnailElement.alt = file.name; + thumbnailElement.src = dataUrl; + } + + return setTimeout(function () { + return file.previewElement.classList.add("dz-image-preview"); + }, 1); + } + }, + + + // Called whenever an error occurs + // Receives `file` and `message` + error: function error(file, message) { + if (file.previewElement) { + file.previewElement.classList.add("dz-error"); + if (typeof message !== "String" && message.error) { + message = message.error; + } + for (var _iterator7 = file.previewElement.querySelectorAll("[data-dz-errormessage]"), _isArray7 = true, _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { + var _ref6; + + if (_isArray7) { + if (_i7 >= _iterator7.length) break; + _ref6 = _iterator7[_i7++]; + } else { + _i7 = _iterator7.next(); + if (_i7.done) break; + _ref6 = _i7.value; + } + + var node = _ref6; + + node.textContent = message; + } + } + }, + errormultiple: function errormultiple() {}, + + + // Called when a file gets processed. Since there is a cue, not all added + // files are processed immediately. + // Receives `file` + processing: function processing(file) { + if (file.previewElement) { + file.previewElement.classList.add("dz-processing"); + if (file._removeLink) { + return file._removeLink.innerHTML = this.options.dictCancelUpload; + } + } + }, + processingmultiple: function processingmultiple() {}, + + + // Called whenever the upload progress gets updated. + // Receives `file`, `progress` (percentage 0-100) and `bytesSent`. + // To get the total number of bytes of the file, use `file.size` + uploadprogress: function uploadprogress(file, progress, bytesSent) { + if (file.previewElement) { + for (var _iterator8 = file.previewElement.querySelectorAll("[data-dz-uploadprogress]"), _isArray8 = true, _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { + var _ref7; + + if (_isArray8) { + if (_i8 >= _iterator8.length) break; + _ref7 = _iterator8[_i8++]; + } else { + _i8 = _iterator8.next(); + if (_i8.done) break; + _ref7 = _i8.value; + } + + var node = _ref7; + + node.nodeName === 'PROGRESS' ? node.value = progress : node.style.width = progress + "%"; + } + } + }, + + + // Called whenever the total upload progress gets updated. + // Called with totalUploadProgress (0-100), totalBytes and totalBytesSent + totaluploadprogress: function totaluploadprogress() {}, + + + // Called just before the file is sent. Gets the `xhr` object as second + // parameter, so you can modify it (for example to add a CSRF token) and a + // `formData` object to add additional information. + sending: function sending() {}, + sendingmultiple: function sendingmultiple() {}, + + + // When the complete upload is finished and successful + // Receives `file` + success: function success(file) { + if (file.previewElement) { + return file.previewElement.classList.add("dz-success"); + } + }, + successmultiple: function successmultiple() {}, + + + // When the upload is canceled. + canceled: function canceled(file) { + return this.emit("error", file, this.options.dictUploadCanceled); + }, + canceledmultiple: function canceledmultiple() {}, + + + // When the upload is finished, either with success or an error. + // Receives `file` + complete: function complete(file) { + if (file._removeLink) { + file._removeLink.innerHTML = this.options.dictRemoveFile; + } + if (file.previewElement) { + return file.previewElement.classList.add("dz-complete"); + } + }, + completemultiple: function completemultiple() {}, + maxfilesexceeded: function maxfilesexceeded() {}, + maxfilesreached: function maxfilesreached() {}, + queuecomplete: function queuecomplete() {}, + addedfiles: function addedfiles() {} + }; + + this.prototype._thumbnailQueue = []; + this.prototype._processingThumbnail = false; + } + + // global utility + + }, { + key: "extend", + value: function extend(target) { + for (var _len2 = arguments.length, objects = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + objects[_key2 - 1] = arguments[_key2]; + } + + for (var _iterator9 = objects, _isArray9 = true, _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { + var _ref8; + + if (_isArray9) { + if (_i9 >= _iterator9.length) break; + _ref8 = _iterator9[_i9++]; + } else { + _i9 = _iterator9.next(); + if (_i9.done) break; + _ref8 = _i9.value; + } + + var object = _ref8; + + for (var key in object) { + var val = object[key]; + target[key] = val; + } + } + return target; + } + }]); + + function Dropzone(el, options) { + _classCallCheck(this, Dropzone); + + var _this = _possibleConstructorReturn(this, (Dropzone.__proto__ || Object.getPrototypeOf(Dropzone)).call(this)); + + var fallback = void 0, + left = void 0; + _this.element = el; + // For backwards compatibility since the version was in the prototype previously + _this.version = Dropzone.version; + + _this.defaultOptions.previewTemplate = _this.defaultOptions.previewTemplate.replace(/\n*/g, ""); + + _this.clickableElements = []; + _this.listeners = []; + _this.files = []; // All files + + if (typeof _this.element === "string") { + _this.element = document.querySelector(_this.element); + } + + // Not checking if instance of HTMLElement or Element since IE9 is extremely weird. + if (!_this.element || _this.element.nodeType == null) { + throw new Error("Invalid dropzone element."); + } + + if (_this.element.dropzone) { + throw new Error("Dropzone already attached."); + } + + // Now add this dropzone to the instances. + Dropzone.instances.push(_this); + + // Put the dropzone inside the element itself. + _this.element.dropzone = _this; + + var elementOptions = (left = Dropzone.optionsForElement(_this.element)) != null ? left : {}; + + _this.options = Dropzone.extend({}, _this.defaultOptions, elementOptions, options != null ? options : {}); + + // If the browser failed, just call the fallback and leave + if (_this.options.forceFallback || !Dropzone.isBrowserSupported()) { + var _ret; + + return _ret = _this.options.fallback.call(_this), _possibleConstructorReturn(_this, _ret); + } + + // @options.url = @element.getAttribute "action" unless @options.url? + if (_this.options.url == null) { + _this.options.url = _this.element.getAttribute("action"); + } + + if (!_this.options.url) { + throw new Error("No URL provided."); + } + + if (_this.options.acceptedFiles && _this.options.acceptedMimeTypes) { + throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated."); + } + + if (_this.options.uploadMultiple && _this.options.chunking) { + throw new Error('You cannot set both: uploadMultiple and chunking.'); + } + + // Backwards compatibility + if (_this.options.acceptedMimeTypes) { + _this.options.acceptedFiles = _this.options.acceptedMimeTypes; + delete _this.options.acceptedMimeTypes; + } + + // Backwards compatibility + if (_this.options.renameFilename != null) { + _this.options.renameFile = function (file) { + return _this.options.renameFilename.call(_this, file.name, file); + }; + } + + _this.options.method = _this.options.method.toUpperCase(); + + if ((fallback = _this.getExistingFallback()) && fallback.parentNode) { + // Remove the fallback + fallback.parentNode.removeChild(fallback); + } + + // Display previews in the previewsContainer element or the Dropzone element unless explicitly set to false + if (_this.options.previewsContainer !== false) { + if (_this.options.previewsContainer) { + _this.previewsContainer = Dropzone.getElement(_this.options.previewsContainer, "previewsContainer"); + } else { + _this.previewsContainer = _this.element; + } + } + + if (_this.options.clickable) { + if (_this.options.clickable === true) { + _this.clickableElements = [_this.element]; + } else { + _this.clickableElements = Dropzone.getElements(_this.options.clickable, "clickable"); + } + } + + _this.init(); + return _this; + } + + // Returns all files that have been accepted + + + _createClass(Dropzone, [{ + key: "getAcceptedFiles", + value: function getAcceptedFiles() { + return this.files.filter(function (file) { + return file.accepted; + }).map(function (file) { + return file; + }); + } + + // Returns all files that have been rejected + // Not sure when that's going to be useful, but added for completeness. + + }, { + key: "getRejectedFiles", + value: function getRejectedFiles() { + return this.files.filter(function (file) { + return !file.accepted; + }).map(function (file) { + return file; + }); + } + }, { + key: "getFilesWithStatus", + value: function getFilesWithStatus(status) { + return this.files.filter(function (file) { + return file.status === status; + }).map(function (file) { + return file; + }); + } + + // Returns all files that are in the queue + + }, { + key: "getQueuedFiles", + value: function getQueuedFiles() { + return this.getFilesWithStatus(Dropzone.QUEUED); + } + }, { + key: "getUploadingFiles", + value: function getUploadingFiles() { + return this.getFilesWithStatus(Dropzone.UPLOADING); + } + }, { + key: "getAddedFiles", + value: function getAddedFiles() { + return this.getFilesWithStatus(Dropzone.ADDED); + } + + // Files that are either queued or uploading + + }, { + key: "getActiveFiles", + value: function getActiveFiles() { + return this.files.filter(function (file) { + return file.status === Dropzone.UPLOADING || file.status === Dropzone.QUEUED; + }).map(function (file) { + return file; + }); + } + + // The function that gets called when Dropzone is initialized. You + // can (and should) setup event listeners inside this function. + + }, { + key: "init", + value: function init() { + var _this3 = this; + + // In case it isn't set already + if (this.element.tagName === "form") { + this.element.setAttribute("enctype", "multipart/form-data"); + } + + if (this.element.classList.contains("dropzone") && !this.element.querySelector(".dz-message")) { + this.element.appendChild(Dropzone.createElement("
" + this.options.dictDefaultMessage + "
")); + } + + if (this.clickableElements.length) { + var setupHiddenFileInput = function setupHiddenFileInput() { + if (_this3.hiddenFileInput) { + _this3.hiddenFileInput.parentNode.removeChild(_this3.hiddenFileInput); + } + _this3.hiddenFileInput = document.createElement("input"); + _this3.hiddenFileInput.setAttribute("type", "file"); + if (_this3.options.maxFiles === null || _this3.options.maxFiles > 1) { + _this3.hiddenFileInput.setAttribute("multiple", "multiple"); + } + _this3.hiddenFileInput.className = "dz-hidden-input"; + + if (_this3.options.acceptedFiles !== null) { + _this3.hiddenFileInput.setAttribute("accept", _this3.options.acceptedFiles); + } + if (_this3.options.capture !== null) { + _this3.hiddenFileInput.setAttribute("capture", _this3.options.capture); + } + + // Not setting `display="none"` because some browsers don't accept clicks + // on elements that aren't displayed. + _this3.hiddenFileInput.style.visibility = "hidden"; + _this3.hiddenFileInput.style.position = "absolute"; + _this3.hiddenFileInput.style.top = "0"; + _this3.hiddenFileInput.style.left = "0"; + _this3.hiddenFileInput.style.height = "0"; + _this3.hiddenFileInput.style.width = "0"; + Dropzone.getElement(_this3.options.hiddenInputContainer, 'hiddenInputContainer').appendChild(_this3.hiddenFileInput); + return _this3.hiddenFileInput.addEventListener("change", function () { + var files = _this3.hiddenFileInput.files; + + if (files.length) { + for (var _iterator10 = files, _isArray10 = true, _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { + var _ref9; + + if (_isArray10) { + if (_i10 >= _iterator10.length) break; + _ref9 = _iterator10[_i10++]; + } else { + _i10 = _iterator10.next(); + if (_i10.done) break; + _ref9 = _i10.value; + } + + var file = _ref9; + + _this3.addFile(file); + } + } + _this3.emit("addedfiles", files); + return setupHiddenFileInput(); + }); + }; + setupHiddenFileInput(); + } + + this.URL = window.URL !== null ? window.URL : window.webkitURL; + + // Setup all event listeners on the Dropzone object itself. + // They're not in @setupEventListeners() because they shouldn't be removed + // again when the dropzone gets disabled. + for (var _iterator11 = this.events, _isArray11 = true, _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { + var _ref10; + + if (_isArray11) { + if (_i11 >= _iterator11.length) break; + _ref10 = _iterator11[_i11++]; + } else { + _i11 = _iterator11.next(); + if (_i11.done) break; + _ref10 = _i11.value; + } + + var eventName = _ref10; + + this.on(eventName, this.options[eventName]); + } + + this.on("uploadprogress", function () { + return _this3.updateTotalUploadProgress(); + }); + + this.on("removedfile", function () { + return _this3.updateTotalUploadProgress(); + }); + + this.on("canceled", function (file) { + return _this3.emit("complete", file); + }); + + // Emit a `queuecomplete` event if all files finished uploading. + this.on("complete", function (file) { + if (_this3.getAddedFiles().length === 0 && _this3.getUploadingFiles().length === 0 && _this3.getQueuedFiles().length === 0) { + // This needs to be deferred so that `queuecomplete` really triggers after `complete` + return setTimeout(function () { + return _this3.emit("queuecomplete"); + }, 0); + } + }); + + var noPropagation = function noPropagation(e) { + e.stopPropagation(); + if (e.preventDefault) { + return e.preventDefault(); + } else { + return e.returnValue = false; + } + }; + + // Create the listeners + this.listeners = [{ + element: this.element, + events: { + "dragstart": function dragstart(e) { + return _this3.emit("dragstart", e); + }, + "dragenter": function dragenter(e) { + noPropagation(e); + return _this3.emit("dragenter", e); + }, + "dragover": function dragover(e) { + // Makes it possible to drag files from chrome's download bar + // http://stackoverflow.com/questions/19526430/drag-and-drop-file-uploads-from-chrome-downloads-bar + // Try is required to prevent bug in Internet Explorer 11 (SCRIPT65535 exception) + var efct = void 0; + try { + efct = e.dataTransfer.effectAllowed; + } catch (error) {} + e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy'; + + noPropagation(e); + return _this3.emit("dragover", e); + }, + "dragleave": function dragleave(e) { + return _this3.emit("dragleave", e); + }, + "drop": function drop(e) { + noPropagation(e); + return _this3.drop(e); + }, + "dragend": function dragend(e) { + return _this3.emit("dragend", e); + } + + // This is disabled right now, because the browsers don't implement it properly. + // "paste": (e) => + // noPropagation e + // @paste e + } }]; + + this.clickableElements.forEach(function (clickableElement) { + return _this3.listeners.push({ + element: clickableElement, + events: { + "click": function click(evt) { + // Only the actual dropzone or the message element should trigger file selection + if (clickableElement !== _this3.element || evt.target === _this3.element || Dropzone.elementInside(evt.target, _this3.element.querySelector(".dz-message"))) { + _this3.hiddenFileInput.click(); // Forward the click + } + return true; + } + } + }); + }); + + this.enable(); + + return this.options.init.call(this); + } + + // Not fully tested yet + + }, { + key: "destroy", + value: function destroy() { + this.disable(); + this.removeAllFiles(true); + if (this.hiddenFileInput != null ? this.hiddenFileInput.parentNode : undefined) { + this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput); + this.hiddenFileInput = null; + } + delete this.element.dropzone; + return Dropzone.instances.splice(Dropzone.instances.indexOf(this), 1); + } + }, { + key: "updateTotalUploadProgress", + value: function updateTotalUploadProgress() { + var totalUploadProgress = void 0; + var totalBytesSent = 0; + var totalBytes = 0; + + var activeFiles = this.getActiveFiles(); + + if (activeFiles.length) { + for (var _iterator12 = this.getActiveFiles(), _isArray12 = true, _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { + var _ref11; + + if (_isArray12) { + if (_i12 >= _iterator12.length) break; + _ref11 = _iterator12[_i12++]; + } else { + _i12 = _iterator12.next(); + if (_i12.done) break; + _ref11 = _i12.value; + } + + var file = _ref11; + + totalBytesSent += file.upload.bytesSent; + totalBytes += file.upload.total; + } + totalUploadProgress = 100 * totalBytesSent / totalBytes; + } else { + totalUploadProgress = 100; + } + + return this.emit("totaluploadprogress", totalUploadProgress, totalBytes, totalBytesSent); + } + + // @options.paramName can be a function taking one parameter rather than a string. + // A parameter name for a file is obtained simply by calling this with an index number. + + }, { + key: "_getParamName", + value: function _getParamName(n) { + if (typeof this.options.paramName === "function") { + return this.options.paramName(n); + } else { + return "" + this.options.paramName + (this.options.uploadMultiple ? "[" + n + "]" : ""); + } + } + + // If @options.renameFile is a function, + // the function will be used to rename the file.name before appending it to the formData + + }, { + key: "_renameFile", + value: function _renameFile(file) { + if (typeof this.options.renameFile !== "function") { + return file.name; + } + return this.options.renameFile(file); + } + + // Returns a form that can be used as fallback if the browser does not support DragnDrop + // + // If the dropzone is already a form, only the input field and button are returned. Otherwise a complete form element is provided. + // This code has to pass in IE7 :( + + }, { + key: "getFallbackForm", + value: function getFallbackForm() { + var existingFallback = void 0, + form = void 0; + if (existingFallback = this.getExistingFallback()) { + return existingFallback; + } + + var fieldsString = "
"; + if (this.options.dictFallbackText) { + fieldsString += "

" + this.options.dictFallbackText + "

"; + } + fieldsString += "
"; + + var fields = Dropzone.createElement(fieldsString); + if (this.element.tagName !== "FORM") { + form = Dropzone.createElement("
"); + form.appendChild(fields); + } else { + // Make sure that the enctype and method attributes are set properly + this.element.setAttribute("enctype", "multipart/form-data"); + this.element.setAttribute("method", this.options.method); + } + return form != null ? form : fields; + } + + // Returns the fallback elements if they exist already + // + // This code has to pass in IE7 :( + + }, { + key: "getExistingFallback", + value: function getExistingFallback() { + var getFallback = function getFallback(elements) { + for (var _iterator13 = elements, _isArray13 = true, _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) { + var _ref12; + + if (_isArray13) { + if (_i13 >= _iterator13.length) break; + _ref12 = _iterator13[_i13++]; + } else { + _i13 = _iterator13.next(); + if (_i13.done) break; + _ref12 = _i13.value; + } + + var el = _ref12; + + if (/(^| )fallback($| )/.test(el.className)) { + return el; + } + } + }; + + var _arr = ["div", "form"]; + for (var _i14 = 0; _i14 < _arr.length; _i14++) { + var tagName = _arr[_i14]; + var fallback; + if (fallback = getFallback(this.element.getElementsByTagName(tagName))) { + return fallback; + } + } + } + + // Activates all listeners stored in @listeners + + }, { + key: "setupEventListeners", + value: function setupEventListeners() { + return this.listeners.map(function (elementListeners) { + return function () { + var result = []; + for (var event in elementListeners.events) { + var listener = elementListeners.events[event]; + result.push(elementListeners.element.addEventListener(event, listener, false)); + } + return result; + }(); + }); + } + + // Deactivates all listeners stored in @listeners + + }, { + key: "removeEventListeners", + value: function removeEventListeners() { + return this.listeners.map(function (elementListeners) { + return function () { + var result = []; + for (var event in elementListeners.events) { + var listener = elementListeners.events[event]; + result.push(elementListeners.element.removeEventListener(event, listener, false)); + } + return result; + }(); + }); + } + + // Removes all event listeners and cancels all files in the queue or being processed. + + }, { + key: "disable", + value: function disable() { + var _this4 = this; + + this.clickableElements.forEach(function (element) { + return element.classList.remove("dz-clickable"); + }); + this.removeEventListeners(); + this.disabled = true; + + return this.files.map(function (file) { + return _this4.cancelUpload(file); + }); + } + }, { + key: "enable", + value: function enable() { + delete this.disabled; + this.clickableElements.forEach(function (element) { + return element.classList.add("dz-clickable"); + }); + return this.setupEventListeners(); + } + + // Returns a nicely formatted filesize + + }, { + key: "filesize", + value: function filesize(size) { + var selectedSize = 0; + var selectedUnit = "b"; + + if (size > 0) { + var units = ['tb', 'gb', 'mb', 'kb', 'b']; + + for (var i = 0; i < units.length; i++) { + var unit = units[i]; + var cutoff = Math.pow(this.options.filesizeBase, 4 - i) / 10; + + if (size >= cutoff) { + selectedSize = size / Math.pow(this.options.filesizeBase, 4 - i); + selectedUnit = unit; + break; + } + } + + selectedSize = Math.round(10 * selectedSize) / 10; // Cutting of digits + } + + return "" + selectedSize + " " + this.options.dictFileSizeUnits[selectedUnit]; + } + + // Adds or removes the `dz-max-files-reached` class from the form. + + }, { + key: "_updateMaxFilesReachedClass", + value: function _updateMaxFilesReachedClass() { + if (this.options.maxFiles != null && this.getAcceptedFiles().length >= this.options.maxFiles) { + if (this.getAcceptedFiles().length === this.options.maxFiles) { + this.emit('maxfilesreached', this.files); + } + return this.element.classList.add("dz-max-files-reached"); + } else { + return this.element.classList.remove("dz-max-files-reached"); + } + } + }, { + key: "drop", + value: function drop(e) { + if (!e.dataTransfer) { + return; + } + this.emit("drop", e); + + // Convert the FileList to an Array + // This is necessary for IE11 + var files = []; + for (var i = 0; i < e.dataTransfer.files.length; i++) { + files[i] = e.dataTransfer.files[i]; + } + + this.emit("addedfiles", files); + + // Even if it's a folder, files.length will contain the folders. + if (files.length) { + var items = e.dataTransfer.items; + + if (items && items.length && items[0].webkitGetAsEntry != null) { + // The browser supports dropping of folders, so handle items instead of files + this._addFilesFromItems(items); + } else { + this.handleFiles(files); + } + } + } + }, { + key: "paste", + value: function paste(e) { + if (__guard__(e != null ? e.clipboardData : undefined, function (x) { + return x.items; + }) == null) { + return; + } + + this.emit("paste", e); + var items = e.clipboardData.items; + + + if (items.length) { + return this._addFilesFromItems(items); + } + } + }, { + key: "handleFiles", + value: function handleFiles(files) { + for (var _iterator14 = files, _isArray14 = true, _i15 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) { + var _ref13; + + if (_isArray14) { + if (_i15 >= _iterator14.length) break; + _ref13 = _iterator14[_i15++]; + } else { + _i15 = _iterator14.next(); + if (_i15.done) break; + _ref13 = _i15.value; + } + + var file = _ref13; + + this.addFile(file); + } + } + + // When a folder is dropped (or files are pasted), items must be handled + // instead of files. + + }, { + key: "_addFilesFromItems", + value: function _addFilesFromItems(items) { + var _this5 = this; + + return function () { + var result = []; + for (var _iterator15 = items, _isArray15 = true, _i16 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) { + var _ref14; + + if (_isArray15) { + if (_i16 >= _iterator15.length) break; + _ref14 = _iterator15[_i16++]; + } else { + _i16 = _iterator15.next(); + if (_i16.done) break; + _ref14 = _i16.value; + } + + var item = _ref14; + + var entry; + if (item.webkitGetAsEntry != null && (entry = item.webkitGetAsEntry())) { + if (entry.isFile) { + result.push(_this5.addFile(item.getAsFile())); + } else if (entry.isDirectory) { + // Append all files from that directory to files + result.push(_this5._addFilesFromDirectory(entry, entry.name)); + } else { + result.push(undefined); + } + } else if (item.getAsFile != null) { + if (item.kind == null || item.kind === "file") { + result.push(_this5.addFile(item.getAsFile())); + } else { + result.push(undefined); + } + } else { + result.push(undefined); + } + } + return result; + }(); + } + + // Goes through the directory, and adds each file it finds recursively + + }, { + key: "_addFilesFromDirectory", + value: function _addFilesFromDirectory(directory, path) { + var _this6 = this; + + var dirReader = directory.createReader(); + + var errorHandler = function errorHandler(error) { + return __guardMethod__(console, 'log', function (o) { + return o.log(error); + }); + }; + + var readEntries = function readEntries() { + return dirReader.readEntries(function (entries) { + if (entries.length > 0) { + for (var _iterator16 = entries, _isArray16 = true, _i17 = 0, _iterator16 = _isArray16 ? _iterator16 : _iterator16[Symbol.iterator]();;) { + var _ref15; + + if (_isArray16) { + if (_i17 >= _iterator16.length) break; + _ref15 = _iterator16[_i17++]; + } else { + _i17 = _iterator16.next(); + if (_i17.done) break; + _ref15 = _i17.value; + } + + var entry = _ref15; + + if (entry.isFile) { + entry.file(function (file) { + if (_this6.options.ignoreHiddenFiles && file.name.substring(0, 1) === '.') { + return; + } + file.fullPath = path + "/" + file.name; + return _this6.addFile(file); + }); + } else if (entry.isDirectory) { + _this6._addFilesFromDirectory(entry, path + "/" + entry.name); + } + } + + // Recursively call readEntries() again, since browser only handle + // the first 100 entries. + // See: https://developer.mozilla.org/en-US/docs/Web/API/DirectoryReader#readEntries + readEntries(); + } + return null; + }, errorHandler); + }; + + return readEntries(); + } + + // If `done()` is called without argument the file is accepted + // If you call it with an error message, the file is rejected + // (This allows for asynchronous validation) + // + // This function checks the filesize, and if the file.type passes the + // `acceptedFiles` check. + + }, { + key: "accept", + value: function accept(file, done) { + if (this.options.maxFilesize && file.size > this.options.maxFilesize * 1024 * 1024) { + return done(this.options.dictFileTooBig.replace("{{filesize}}", Math.round(file.size / 1024 / 10.24) / 100).replace("{{maxFilesize}}", this.options.maxFilesize)); + } else if (!Dropzone.isValidFile(file, this.options.acceptedFiles)) { + return done(this.options.dictInvalidFileType); + } else if (this.options.maxFiles != null && this.getAcceptedFiles().length >= this.options.maxFiles) { + done(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}", this.options.maxFiles)); + return this.emit("maxfilesexceeded", file); + } else { + return this.options.accept.call(this, file, done); + } + } + + }, { + key: "addFile", + value: function addFile(file) { + var _this7 = this; + + file.upload = { + uuid: Dropzone.uuidv4(), + progress: 0, + // Setting the total upload size to file.size for the beginning + // It's actual different than the size to be transmitted. + total: file.size, + bytesSent: 0, + filename: this._renameFile(file), + chunked: this.options.chunking && (this.options.forceChunking || file.size > this.options.chunkSize), + totalChunkCount: Math.ceil(file.size / this.options.chunkSize) + }; + this.files.push(file); + + file.status = Dropzone.ADDED; + + this.emit("addedfile", file); + + this._enqueueThumbnail(file); + + return this.accept(file, function (error) { + if (error) { + file.accepted = false; + _this7._errorProcessing([file], error); // Will set the file.status + } else { + file.accepted = true; + if (_this7.options.autoQueue) { + _this7.enqueueFile(file); + } // Will set .accepted = true + } + return _this7._updateMaxFilesReachedClass(); + }); + } + + // Wrapper for enqueueFile + + }, { + key: "enqueueFiles", + value: function enqueueFiles(files) { + for (var _iterator17 = files, _isArray17 = true, _i18 = 0, _iterator17 = _isArray17 ? _iterator17 : _iterator17[Symbol.iterator]();;) { + var _ref16; + + if (_isArray17) { + if (_i18 >= _iterator17.length) break; + _ref16 = _iterator17[_i18++]; + } else { + _i18 = _iterator17.next(); + if (_i18.done) break; + _ref16 = _i18.value; + } + + var file = _ref16; + + this.enqueueFile(file); + } + return null; + } + }, { + key: "enqueueFile", + value: function enqueueFile(file) { + var _this8 = this; + + if (file.status === Dropzone.ADDED && file.accepted === true) { + file.status = Dropzone.QUEUED; + if (this.options.autoProcessQueue) { + return setTimeout(function () { + return _this8.processQueue(); + }, 0); // Deferring the call + } + } else { + throw new Error("This file can't be queued because it has already been processed or was rejected."); + } + } + }, { + key: "_enqueueThumbnail", + value: function _enqueueThumbnail(file) { + var _this9 = this; + + if (this.options.createImageThumbnails && file.type.match(/image.*/) && file.size <= this.options.maxThumbnailFilesize * 1024 * 1024) { + this._thumbnailQueue.push(file); + return setTimeout(function () { + return _this9._processThumbnailQueue(); + }, 0); // Deferring the call + } + } + }, { + key: "_processThumbnailQueue", + value: function _processThumbnailQueue() { + var _this10 = this; + + if (this._processingThumbnail || this._thumbnailQueue.length === 0) { + return; + } + + this._processingThumbnail = true; + var file = this._thumbnailQueue.shift(); + return this.createThumbnail(file, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.thumbnailMethod, true, function (dataUrl) { + _this10.emit("thumbnail", file, dataUrl); + _this10._processingThumbnail = false; + return _this10._processThumbnailQueue(); + }); + } + + // Can be called by the user to remove a file + + }, { + key: "removeFile", + value: function removeFile(file) { + if (file.status === Dropzone.UPLOADING) { + this.cancelUpload(file); + } + this.files = without(this.files, file); + + this.emit("removedfile", file); + if (this.files.length === 0) { + return this.emit("reset"); + } + } + + // Removes all files that aren't currently processed from the list + + }, { + key: "removeAllFiles", + value: function removeAllFiles(cancelIfNecessary) { + // Create a copy of files since removeFile() changes the @files array. + if (cancelIfNecessary == null) { + cancelIfNecessary = false; + } + for (var _iterator18 = this.files.slice(), _isArray18 = true, _i19 = 0, _iterator18 = _isArray18 ? _iterator18 : _iterator18[Symbol.iterator]();;) { + var _ref17; + + if (_isArray18) { + if (_i19 >= _iterator18.length) break; + _ref17 = _iterator18[_i19++]; + } else { + _i19 = _iterator18.next(); + if (_i19.done) break; + _ref17 = _i19.value; + } + + var file = _ref17; + + if (file.status !== Dropzone.UPLOADING || cancelIfNecessary) { + this.removeFile(file); + } + } + return null; + } + + // Resizes an image before it gets sent to the server. This function is the default behavior of + // `options.transformFile` if `resizeWidth` or `resizeHeight` are set. The callback is invoked with + // the resized blob. + + }, { + key: "resizeImage", + value: function resizeImage(file, width, height, resizeMethod, callback) { + var _this11 = this; + + return this.createThumbnail(file, width, height, resizeMethod, true, function (dataUrl, canvas) { + if (canvas == null) { + // The image has not been resized + return callback(file); + } else { + var resizeMimeType = _this11.options.resizeMimeType; + + if (resizeMimeType == null) { + resizeMimeType = file.type; + } + var resizedDataURL = canvas.toDataURL(resizeMimeType, _this11.options.resizeQuality); + if (resizeMimeType === 'image/jpeg' || resizeMimeType === 'image/jpg') { + // Now add the original EXIF information + resizedDataURL = ExifRestore.restore(file.dataURL, resizedDataURL); + } + return callback(Dropzone.dataURItoBlob(resizedDataURL)); + } + }); + } + }, { + key: "createThumbnail", + value: function createThumbnail(file, width, height, resizeMethod, fixOrientation, callback) { + var _this12 = this; + + var fileReader = new FileReader(); + + fileReader.onload = function () { + + file.dataURL = fileReader.result; + + // Don't bother creating a thumbnail for SVG images since they're vector + if (file.type === "image/svg+xml") { + if (callback != null) { + callback(fileReader.result); + } + return; + } + + return _this12.createThumbnailFromUrl(file, width, height, resizeMethod, fixOrientation, callback); + }; + + return fileReader.readAsDataURL(file); + } + }, { + key: "createThumbnailFromUrl", + value: function createThumbnailFromUrl(file, width, height, resizeMethod, fixOrientation, callback, crossOrigin) { + var _this13 = this; + + // Not using `new Image` here because of a bug in latest Chrome versions. + // See https://github.com/enyo/dropzone/pull/226 + var img = document.createElement("img"); + + if (crossOrigin) { + img.crossOrigin = crossOrigin; + } + + img.onload = function () { + var loadExif = function loadExif(callback) { + return callback(1); + }; + if (typeof EXIF !== 'undefined' && EXIF !== null && fixOrientation) { + loadExif = function loadExif(callback) { + return EXIF.getData(img, function () { + return callback(EXIF.getTag(this, 'Orientation')); + }); + }; + } + + return loadExif(function (orientation) { + file.width = img.width; + file.height = img.height; + + var resizeInfo = _this13.options.resize.call(_this13, file, width, height, resizeMethod); + + var canvas = document.createElement("canvas"); + var ctx = canvas.getContext("2d"); + + canvas.width = resizeInfo.trgWidth; + canvas.height = resizeInfo.trgHeight; + + if (orientation > 4) { + canvas.width = resizeInfo.trgHeight; + canvas.height = resizeInfo.trgWidth; + } + + switch (orientation) { + case 2: + // horizontal flip + ctx.translate(canvas.width, 0); + ctx.scale(-1, 1); + break; + case 3: + // 180° rotate left + ctx.translate(canvas.width, canvas.height); + ctx.rotate(Math.PI); + break; + case 4: + // vertical flip + ctx.translate(0, canvas.height); + ctx.scale(1, -1); + break; + case 5: + // vertical flip + 90 rotate right + ctx.rotate(0.5 * Math.PI); + ctx.scale(1, -1); + break; + case 6: + // 90° rotate right + ctx.rotate(0.5 * Math.PI); + ctx.translate(0, -canvas.width); + break; + case 7: + // horizontal flip + 90 rotate right + ctx.rotate(0.5 * Math.PI); + ctx.translate(canvas.height, -canvas.width); + ctx.scale(-1, 1); + break; + case 8: + // 90° rotate left + ctx.rotate(-0.5 * Math.PI); + ctx.translate(-canvas.height, 0); + break; + } + + // This is a bugfix for iOS' scaling bug. + drawImageIOSFix(ctx, img, resizeInfo.srcX != null ? resizeInfo.srcX : 0, resizeInfo.srcY != null ? resizeInfo.srcY : 0, resizeInfo.srcWidth, resizeInfo.srcHeight, resizeInfo.trgX != null ? resizeInfo.trgX : 0, resizeInfo.trgY != null ? resizeInfo.trgY : 0, resizeInfo.trgWidth, resizeInfo.trgHeight); + + var thumbnail = canvas.toDataURL("image/png"); + + if (callback != null) { + return callback(thumbnail, canvas); + } + }); + }; + + if (callback != null) { + img.onerror = callback; + } + + return img.src = file.dataURL; + } + + // Goes through the queue and processes files if there aren't too many already. + + }, { + key: "processQueue", + value: function processQueue() { + var parallelUploads = this.options.parallelUploads; + + var processingLength = this.getUploadingFiles().length; + var i = processingLength; + + // There are already at least as many files uploading than should be + if (processingLength >= parallelUploads) { + return; + } + + var queuedFiles = this.getQueuedFiles(); + + if (!(queuedFiles.length > 0)) { + return; + } + + if (this.options.uploadMultiple) { + // The files should be uploaded in one request + return this.processFiles(queuedFiles.slice(0, parallelUploads - processingLength)); + } else { + while (i < parallelUploads) { + if (!queuedFiles.length) { + return; + } // Nothing left to process + this.processFile(queuedFiles.shift()); + i++; + } + } + } + + // Wrapper for `processFiles` + + }, { + key: "processFile", + value: function processFile(file) { + return this.processFiles([file]); + } + + // Loads the file, then calls finishedLoading() + + }, { + key: "processFiles", + value: function processFiles(files) { + for (var _iterator19 = files, _isArray19 = true, _i20 = 0, _iterator19 = _isArray19 ? _iterator19 : _iterator19[Symbol.iterator]();;) { + var _ref18; + + if (_isArray19) { + if (_i20 >= _iterator19.length) break; + _ref18 = _iterator19[_i20++]; + } else { + _i20 = _iterator19.next(); + if (_i20.done) break; + _ref18 = _i20.value; + } + + var file = _ref18; + + file.processing = true; // Backwards compatibility + file.status = Dropzone.UPLOADING; + + this.emit("processing", file); + } + + if (this.options.uploadMultiple) { + this.emit("processingmultiple", files); + } + + return this.uploadFiles(files); + } + }, { + key: "_getFilesWithXhr", + value: function _getFilesWithXhr(xhr) { + var files = void 0; + return files = this.files.filter(function (file) { + return file.xhr === xhr; + }).map(function (file) { + return file; + }); + } + + // Cancels the file upload and sets the status to CANCELED + // **if** the file is actually being uploaded. + // If it's still in the queue, the file is being removed from it and the status + // set to CANCELED. + + }, { + key: "cancelUpload", + value: function cancelUpload(file) { + if (file.status === Dropzone.UPLOADING) { + var groupedFiles = this._getFilesWithXhr(file.xhr); + for (var _iterator20 = groupedFiles, _isArray20 = true, _i21 = 0, _iterator20 = _isArray20 ? _iterator20 : _iterator20[Symbol.iterator]();;) { + var _ref19; + + if (_isArray20) { + if (_i21 >= _iterator20.length) break; + _ref19 = _iterator20[_i21++]; + } else { + _i21 = _iterator20.next(); + if (_i21.done) break; + _ref19 = _i21.value; + } + + var groupedFile = _ref19; + + groupedFile.status = Dropzone.CANCELED; + } + if (typeof file.xhr !== 'undefined') { + file.xhr.abort(); + } + for (var _iterator21 = groupedFiles, _isArray21 = true, _i22 = 0, _iterator21 = _isArray21 ? _iterator21 : _iterator21[Symbol.iterator]();;) { + var _ref20; + + if (_isArray21) { + if (_i22 >= _iterator21.length) break; + _ref20 = _iterator21[_i22++]; + } else { + _i22 = _iterator21.next(); + if (_i22.done) break; + _ref20 = _i22.value; + } + + var _groupedFile = _ref20; + + this.emit("canceled", _groupedFile); + } + if (this.options.uploadMultiple) { + this.emit("canceledmultiple", groupedFiles); + } + } else if (file.status === Dropzone.ADDED || file.status === Dropzone.QUEUED) { + file.status = Dropzone.CANCELED; + this.emit("canceled", file); + if (this.options.uploadMultiple) { + this.emit("canceledmultiple", [file]); + } + } + + if (this.options.autoProcessQueue) { + return this.processQueue(); + } + } + }, { + key: "resolveOption", + value: function resolveOption(option) { + if (typeof option === 'function') { + for (var _len3 = arguments.length, args = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { + args[_key3 - 1] = arguments[_key3]; + } + + return option.apply(this, args); + } + return option; + } + }, { + key: "uploadFile", + value: function uploadFile(file) { + return this.uploadFiles([file]); + } + }, { + key: "uploadFiles", + value: function uploadFiles(files) { + var _this14 = this; + + this._transformFiles(files, function (transformedFiles) { + if (files[0].upload.chunked) { + // This file should be sent in chunks! + + // If the chunking option is set, we **know** that there can only be **one** file, since + // uploadMultiple is not allowed with this option. + var file = files[0]; + var transformedFile = transformedFiles[0]; + var startedChunkCount = 0; + + file.upload.chunks = []; + + var handleNextChunk = function handleNextChunk() { + var chunkIndex = 0; + + // Find the next item in file.upload.chunks that is not defined yet. + while (file.upload.chunks[chunkIndex] !== undefined) { + chunkIndex++; + } + + // This means, that all chunks have already been started. + if (chunkIndex >= file.upload.totalChunkCount) return; + + startedChunkCount++; + + var start = chunkIndex * _this14.options.chunkSize; + var end = Math.min(start + _this14.options.chunkSize, file.size); + + var dataBlock = { + name: _this14._getParamName(0), + data: transformedFile.webkitSlice ? transformedFile.webkitSlice(start, end) : transformedFile.slice(start, end), + filename: file.upload.filename, + chunkIndex: chunkIndex + }; + + file.upload.chunks[chunkIndex] = { + file: file, + index: chunkIndex, + dataBlock: dataBlock, // In case we want to retry. + status: Dropzone.UPLOADING, + progress: 0, + retries: 0 // The number of times this block has been retried. + }; + + _this14._uploadData(files, [dataBlock]); + }; + + file.upload.finishedChunkUpload = function (chunk) { + var allFinished = true; + chunk.status = Dropzone.SUCCESS; + + // Clear the data from the chunk + chunk.dataBlock = null; + // Leaving this reference to xhr intact here will cause memory leaks in some browsers + chunk.xhr = null; + + for (var i = 0; i < file.upload.totalChunkCount; i++) { + if (file.upload.chunks[i] === undefined) { + return handleNextChunk(); + } + if (file.upload.chunks[i].status !== Dropzone.SUCCESS) { + allFinished = false; + } + } + + if (allFinished) { + _this14.options.chunksUploaded(file, function () { + _this14._finished(files, '', null); + }); + } + }; + + if (_this14.options.parallelChunkUploads) { + for (var i = 0; i < file.upload.totalChunkCount; i++) { + handleNextChunk(); + } + } else { + handleNextChunk(); + } + } else { + var dataBlocks = []; + for (var _i23 = 0; _i23 < files.length; _i23++) { + dataBlocks[_i23] = { + name: _this14._getParamName(_i23), + data: transformedFiles[_i23], + filename: files[_i23].upload.filename + }; + } + _this14._uploadData(files, dataBlocks); + } + }); + } + + /// Returns the right chunk for given file and xhr + + }, { + key: "_getChunk", + value: function _getChunk(file, xhr) { + for (var i = 0; i < file.upload.totalChunkCount; i++) { + if (file.upload.chunks[i] !== undefined && file.upload.chunks[i].xhr === xhr) { + return file.upload.chunks[i]; + } + } + } + + // This function actually uploads the file(s) to the server. + // If dataBlocks contains the actual data to upload (meaning, that this could either be transformed + // files, or individual chunks for chunked upload). + + }, { + key: "_uploadData", + value: function _uploadData(files, dataBlocks) { + var _this15 = this; + + var xhr = new XMLHttpRequest(); + + // Put the xhr object in the file objects to be able to reference it later. + for (var _iterator22 = files, _isArray22 = true, _i24 = 0, _iterator22 = _isArray22 ? _iterator22 : _iterator22[Symbol.iterator]();;) { + var _ref21; + + if (_isArray22) { + if (_i24 >= _iterator22.length) break; + _ref21 = _iterator22[_i24++]; + } else { + _i24 = _iterator22.next(); + if (_i24.done) break; + _ref21 = _i24.value; + } + + var file = _ref21; + + file.xhr = xhr; + } + if (files[0].upload.chunked) { + // Put the xhr object in the right chunk object, so it can be associated later, and found with _getChunk + files[0].upload.chunks[dataBlocks[0].chunkIndex].xhr = xhr; + } + + var method = this.resolveOption(this.options.method, files); + var url = this.resolveOption(this.options.url, files); + xhr.open(method, url, true); + + // Setting the timeout after open because of IE11 issue: https://gitlab.com/meno/dropzone/issues/8 + xhr.timeout = this.resolveOption(this.options.timeout, files); + + // Has to be after `.open()`. See https://github.com/enyo/dropzone/issues/179 + xhr.withCredentials = !!this.options.withCredentials; + + xhr.onload = function (e) { + _this15._finishedUploading(files, xhr, e); + }; + + xhr.onerror = function () { + _this15._handleUploadError(files, xhr); + }; + + // Some browsers do not have the .upload property + var progressObj = xhr.upload != null ? xhr.upload : xhr; + progressObj.onprogress = function (e) { + return _this15._updateFilesUploadProgress(files, xhr, e); + }; + + var headers = { + "Accept": "application/json", + "Cache-Control": "no-cache", + "X-Requested-With": "XMLHttpRequest" + }; + + if (this.options.headers) { + Dropzone.extend(headers, this.options.headers); + } + + for (var headerName in headers) { + var headerValue = headers[headerName]; + if (headerValue) { + xhr.setRequestHeader(headerName, headerValue); + } + } + + var formData = new FormData(); + + // Adding all @options parameters + if (this.options.params) { + var additionalParams = this.options.params; + if (typeof additionalParams === 'function') { + additionalParams = additionalParams.call(this, files, xhr, files[0].upload.chunked ? this._getChunk(files[0], xhr) : null); + } + + for (var key in additionalParams) { + var value = additionalParams[key]; + formData.append(key, value); + } + } + + // Let the user add additional data if necessary + for (var _iterator23 = files, _isArray23 = true, _i25 = 0, _iterator23 = _isArray23 ? _iterator23 : _iterator23[Symbol.iterator]();;) { + var _ref22; + + if (_isArray23) { + if (_i25 >= _iterator23.length) break; + _ref22 = _iterator23[_i25++]; + } else { + _i25 = _iterator23.next(); + if (_i25.done) break; + _ref22 = _i25.value; + } + + var _file = _ref22; + + this.emit("sending", _file, xhr, formData); + } + if (this.options.uploadMultiple) { + this.emit("sendingmultiple", files, xhr, formData); + } + + this._addFormElementData(formData); + + // Finally add the files + // Has to be last because some servers (eg: S3) expect the file to be the last parameter + for (var i = 0; i < dataBlocks.length; i++) { + var dataBlock = dataBlocks[i]; + formData.append(dataBlock.name, dataBlock.data, dataBlock.filename); + } + + this.submitRequest(xhr, formData, files); + } + + // Transforms all files with this.options.transformFile and invokes done with the transformed files when done. + + }, { + key: "_transformFiles", + value: function _transformFiles(files, done) { + var _this16 = this; + + var transformedFiles = []; + // Clumsy way of handling asynchronous calls, until I get to add a proper Future library. + var doneCounter = 0; + + var _loop = function _loop(i) { + _this16.options.transformFile.call(_this16, files[i], function (transformedFile) { + transformedFiles[i] = transformedFile; + if (++doneCounter === files.length) { + done(transformedFiles); + } + }); + }; + + for (var i = 0; i < files.length; i++) { + _loop(i); + } + } + + // Takes care of adding other input elements of the form to the AJAX request + + }, { + key: "_addFormElementData", + value: function _addFormElementData(formData) { + // Take care of other input elements + if (this.element.tagName === "FORM") { + for (var _iterator24 = this.element.querySelectorAll("input, textarea, select, button"), _isArray24 = true, _i26 = 0, _iterator24 = _isArray24 ? _iterator24 : _iterator24[Symbol.iterator]();;) { + var _ref23; + + if (_isArray24) { + if (_i26 >= _iterator24.length) break; + _ref23 = _iterator24[_i26++]; + } else { + _i26 = _iterator24.next(); + if (_i26.done) break; + _ref23 = _i26.value; + } + + var input = _ref23; + + var inputName = input.getAttribute("name"); + var inputType = input.getAttribute("type"); + if (inputType) inputType = inputType.toLowerCase(); + + // If the input doesn't have a name, we can't use it. + if (typeof inputName === 'undefined' || inputName === null) continue; + + if (input.tagName === "SELECT" && input.hasAttribute("multiple")) { + // Possibly multiple values + for (var _iterator25 = input.options, _isArray25 = true, _i27 = 0, _iterator25 = _isArray25 ? _iterator25 : _iterator25[Symbol.iterator]();;) { + var _ref24; + + if (_isArray25) { + if (_i27 >= _iterator25.length) break; + _ref24 = _iterator25[_i27++]; + } else { + _i27 = _iterator25.next(); + if (_i27.done) break; + _ref24 = _i27.value; + } + + var option = _ref24; + + if (option.selected) { + formData.append(inputName, option.value); + } + } + } else if (!inputType || inputType !== "checkbox" && inputType !== "radio" || input.checked) { + formData.append(inputName, input.value); + } + } + } + } + + // Invoked when there is new progress information about given files. + // If e is not provided, it is assumed that the upload is finished. + + }, { + key: "_updateFilesUploadProgress", + value: function _updateFilesUploadProgress(files, xhr, e) { + var progress = void 0; + if (typeof e !== 'undefined') { + progress = 100 * e.loaded / e.total; + + if (files[0].upload.chunked) { + var file = files[0]; + // Since this is a chunked upload, we need to update the appropriate chunk progress. + var chunk = this._getChunk(file, xhr); + chunk.progress = progress; + chunk.total = e.total; + chunk.bytesSent = e.loaded; + var fileProgress = 0, + fileTotal = void 0, + fileBytesSent = void 0; + file.upload.progress = 0; + file.upload.total = 0; + file.upload.bytesSent = 0; + for (var i = 0; i < file.upload.totalChunkCount; i++) { + if (file.upload.chunks[i] !== undefined && file.upload.chunks[i].progress !== undefined) { + file.upload.progress += file.upload.chunks[i].progress; + file.upload.total += file.upload.chunks[i].total; + file.upload.bytesSent += file.upload.chunks[i].bytesSent; + } + } + file.upload.progress = file.upload.progress / file.upload.totalChunkCount; + } else { + for (var _iterator26 = files, _isArray26 = true, _i28 = 0, _iterator26 = _isArray26 ? _iterator26 : _iterator26[Symbol.iterator]();;) { + var _ref25; + + if (_isArray26) { + if (_i28 >= _iterator26.length) break; + _ref25 = _iterator26[_i28++]; + } else { + _i28 = _iterator26.next(); + if (_i28.done) break; + _ref25 = _i28.value; + } + + var _file2 = _ref25; + + _file2.upload.progress = progress; + _file2.upload.total = e.total; + _file2.upload.bytesSent = e.loaded; + } + } + for (var _iterator27 = files, _isArray27 = true, _i29 = 0, _iterator27 = _isArray27 ? _iterator27 : _iterator27[Symbol.iterator]();;) { + var _ref26; + + if (_isArray27) { + if (_i29 >= _iterator27.length) break; + _ref26 = _iterator27[_i29++]; + } else { + _i29 = _iterator27.next(); + if (_i29.done) break; + _ref26 = _i29.value; + } + + var _file3 = _ref26; + + this.emit("uploadprogress", _file3, _file3.upload.progress, _file3.upload.bytesSent); + } + } else { + // Called when the file finished uploading + + var allFilesFinished = true; + + progress = 100; + + for (var _iterator28 = files, _isArray28 = true, _i30 = 0, _iterator28 = _isArray28 ? _iterator28 : _iterator28[Symbol.iterator]();;) { + var _ref27; + + if (_isArray28) { + if (_i30 >= _iterator28.length) break; + _ref27 = _iterator28[_i30++]; + } else { + _i30 = _iterator28.next(); + if (_i30.done) break; + _ref27 = _i30.value; + } + + var _file4 = _ref27; + + if (_file4.upload.progress !== 100 || _file4.upload.bytesSent !== _file4.upload.total) { + allFilesFinished = false; + } + _file4.upload.progress = progress; + _file4.upload.bytesSent = _file4.upload.total; + } + + // Nothing to do, all files already at 100% + if (allFilesFinished) { + return; + } + + for (var _iterator29 = files, _isArray29 = true, _i31 = 0, _iterator29 = _isArray29 ? _iterator29 : _iterator29[Symbol.iterator]();;) { + var _ref28; + + if (_isArray29) { + if (_i31 >= _iterator29.length) break; + _ref28 = _iterator29[_i31++]; + } else { + _i31 = _iterator29.next(); + if (_i31.done) break; + _ref28 = _i31.value; + } + + var _file5 = _ref28; + + this.emit("uploadprogress", _file5, progress, _file5.upload.bytesSent); + } + } + } + }, { + key: "_finishedUploading", + value: function _finishedUploading(files, xhr, e) { + var response = void 0; + + if (files[0].status === Dropzone.CANCELED) { + return; + } + + if (xhr.readyState !== 4) { + return; + } + + if (xhr.responseType !== 'arraybuffer' && xhr.responseType !== 'blob') { + response = xhr.responseText; + + if (xhr.getResponseHeader("content-type") && ~xhr.getResponseHeader("content-type").indexOf("application/json")) { + try { + response = JSON.parse(response); + } catch (error) { + e = error; + response = "Invalid JSON response from server."; + } + } + } + + this._updateFilesUploadProgress(files); + + if (!(200 <= xhr.status && xhr.status < 300)) { + this._handleUploadError(files, xhr, response); + } else { + if (files[0].upload.chunked) { + files[0].upload.finishedChunkUpload(this._getChunk(files[0], xhr)); + } else { + this._finished(files, response, e); + } + } + } + }, { + key: "_handleUploadError", + value: function _handleUploadError(files, xhr, response) { + if (files[0].status === Dropzone.CANCELED) { + return; + } + + if (files[0].upload.chunked && this.options.retryChunks) { + var chunk = this._getChunk(files[0], xhr); + if (chunk.retries++ < this.options.retryChunksLimit) { + this._uploadData(files, [chunk.dataBlock]); + return; + } else { + console.warn('Retried this chunk too often. Giving up.'); + } + } + + for (var _iterator30 = files, _isArray30 = true, _i32 = 0, _iterator30 = _isArray30 ? _iterator30 : _iterator30[Symbol.iterator]();;) { + var _ref29; + + if (_isArray30) { + if (_i32 >= _iterator30.length) break; + _ref29 = _iterator30[_i32++]; + } else { + _i32 = _iterator30.next(); + if (_i32.done) break; + _ref29 = _i32.value; + } + + var file = _ref29; + + this._errorProcessing(files, response || this.options.dictResponseError.replace("{{statusCode}}", xhr.status), xhr); + } + } + }, { + key: "submitRequest", + value: function submitRequest(xhr, formData, files) { + xhr.send(formData); + } + + // Called internally when processing is finished. + // Individual callbacks have to be called in the appropriate sections. + + }, { + key: "_finished", + value: function _finished(files, responseText, e) { + for (var _iterator31 = files, _isArray31 = true, _i33 = 0, _iterator31 = _isArray31 ? _iterator31 : _iterator31[Symbol.iterator]();;) { + var _ref30; + + if (_isArray31) { + if (_i33 >= _iterator31.length) break; + _ref30 = _iterator31[_i33++]; + } else { + _i33 = _iterator31.next(); + if (_i33.done) break; + _ref30 = _i33.value; + } + + var file = _ref30; + + file.status = Dropzone.SUCCESS; + this.emit("success", file, responseText, e); + this.emit("complete", file); + } + if (this.options.uploadMultiple) { + this.emit("successmultiple", files, responseText, e); + this.emit("completemultiple", files); + } + + if (this.options.autoProcessQueue) { + return this.processQueue(); + } + } + + // Called internally when processing is finished. + // Individual callbacks have to be called in the appropriate sections. + + }, { + key: "_errorProcessing", + value: function _errorProcessing(files, message, xhr) { + for (var _iterator32 = files, _isArray32 = true, _i34 = 0, _iterator32 = _isArray32 ? _iterator32 : _iterator32[Symbol.iterator]();;) { + var _ref31; + + if (_isArray32) { + if (_i34 >= _iterator32.length) break; + _ref31 = _iterator32[_i34++]; + } else { + _i34 = _iterator32.next(); + if (_i34.done) break; + _ref31 = _i34.value; + } + + var file = _ref31; + + file.status = Dropzone.ERROR; + this.emit("error", file, message, xhr); + this.emit("complete", file); + } + if (this.options.uploadMultiple) { + this.emit("errormultiple", files, message, xhr); + this.emit("completemultiple", files); + } + + if (this.options.autoProcessQueue) { + return this.processQueue(); + } + } + }], [{ + key: "uuidv4", + value: function uuidv4() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = Math.random() * 16 | 0, + v = c === 'x' ? r : r & 0x3 | 0x8; + return v.toString(16); + }); + } + }]); + + return Dropzone; +}(Emitter); + +Dropzone.initClass(); + +Dropzone.version = "5.5.1"; + +// This is a map of options for your different dropzones. Add configurations +// to this object for your different dropzone elemens. +// +// Example: +// +// Dropzone.options.myDropzoneElementId = { maxFilesize: 1 }; +// +// To disable autoDiscover for a specific element, you can set `false` as an option: +// +// Dropzone.options.myDisabledElementId = false; +// +// And in html: +// +//
+Dropzone.options = {}; + +// Returns the options for an element or undefined if none available. +Dropzone.optionsForElement = function (element) { + // Get the `Dropzone.options.elementId` for this element if it exists + if (element.getAttribute("id")) { + return Dropzone.options[camelize(element.getAttribute("id"))]; + } else { + return undefined; + } +}; + +// Holds a list of all dropzone instances +Dropzone.instances = []; + +// Returns the dropzone for given element if any +Dropzone.forElement = function (element) { + if (typeof element === "string") { + element = document.querySelector(element); + } + if ((element != null ? element.dropzone : undefined) == null) { + throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone."); + } + return element.dropzone; +}; + +// Set to false if you don't want Dropzone to automatically find and attach to .dropzone elements. +Dropzone.autoDiscover = true; + +// Looks for all .dropzone elements and creates a dropzone for them +Dropzone.discover = function () { + var dropzones = void 0; + if (document.querySelectorAll) { + dropzones = document.querySelectorAll(".dropzone"); + } else { + dropzones = []; + // IE :( + var checkElements = function checkElements(elements) { + return function () { + var result = []; + for (var _iterator33 = elements, _isArray33 = true, _i35 = 0, _iterator33 = _isArray33 ? _iterator33 : _iterator33[Symbol.iterator]();;) { + var _ref32; + + if (_isArray33) { + if (_i35 >= _iterator33.length) break; + _ref32 = _iterator33[_i35++]; + } else { + _i35 = _iterator33.next(); + if (_i35.done) break; + _ref32 = _i35.value; + } + + var el = _ref32; + + if (/(^| )dropzone($| )/.test(el.className)) { + result.push(dropzones.push(el)); + } else { + result.push(undefined); + } + } + return result; + }(); + }; + checkElements(document.getElementsByTagName("div")); + checkElements(document.getElementsByTagName("form")); + } + + return function () { + var result = []; + for (var _iterator34 = dropzones, _isArray34 = true, _i36 = 0, _iterator34 = _isArray34 ? _iterator34 : _iterator34[Symbol.iterator]();;) { + var _ref33; + + if (_isArray34) { + if (_i36 >= _iterator34.length) break; + _ref33 = _iterator34[_i36++]; + } else { + _i36 = _iterator34.next(); + if (_i36.done) break; + _ref33 = _i36.value; + } + + var dropzone = _ref33; + + // Create a dropzone unless auto discover has been disabled for specific element + if (Dropzone.optionsForElement(dropzone) !== false) { + result.push(new Dropzone(dropzone)); + } else { + result.push(undefined); + } + } + return result; + }(); +}; + +// Since the whole Drag'n'Drop API is pretty new, some browsers implement it, +// but not correctly. +// So I created a blacklist of userAgents. Yes, yes. Browser sniffing, I know. +// But what to do when browsers *theoretically* support an API, but crash +// when using it. +// +// This is a list of regular expressions tested against navigator.userAgent +// +// ** It should only be used on browser that *do* support the API, but +// incorrectly ** +// +Dropzone.blacklistedBrowsers = [ +// The mac os and windows phone version of opera 12 seems to have a problem with the File drag'n'drop API. +/opera.*(Macintosh|Windows Phone).*version\/12/i]; + +// Checks if the browser is supported +Dropzone.isBrowserSupported = function () { + var capableBrowser = true; + + if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector) { + if (!("classList" in document.createElement("a"))) { + capableBrowser = false; + } else { + // The browser supports the API, but may be blacklisted. + for (var _iterator35 = Dropzone.blacklistedBrowsers, _isArray35 = true, _i37 = 0, _iterator35 = _isArray35 ? _iterator35 : _iterator35[Symbol.iterator]();;) { + var _ref34; + + if (_isArray35) { + if (_i37 >= _iterator35.length) break; + _ref34 = _iterator35[_i37++]; + } else { + _i37 = _iterator35.next(); + if (_i37.done) break; + _ref34 = _i37.value; + } + + var regex = _ref34; + + if (regex.test(navigator.userAgent)) { + capableBrowser = false; + continue; + } + } + } + } else { + capableBrowser = false; + } + + return capableBrowser; +}; + +Dropzone.dataURItoBlob = function (dataURI) { + // convert base64 to raw binary data held in a string + // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this + var byteString = atob(dataURI.split(',')[1]); + + // separate out the mime component + var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; + + // write the bytes of the string to an ArrayBuffer + var ab = new ArrayBuffer(byteString.length); + var ia = new Uint8Array(ab); + for (var i = 0, end = byteString.length, asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) { + ia[i] = byteString.charCodeAt(i); + } + + // write the ArrayBuffer to a blob + return new Blob([ab], { type: mimeString }); +}; + +// Returns an array without the rejected item +var without = function without(list, rejectedItem) { + return list.filter(function (item) { + return item !== rejectedItem; + }).map(function (item) { + return item; + }); +}; + +// abc-def_ghi -> abcDefGhi +var camelize = function camelize(str) { + return str.replace(/[\-_](\w)/g, function (match) { + return match.charAt(1).toUpperCase(); + }); +}; + +// Creates an element from string +Dropzone.createElement = function (string) { + var div = document.createElement("div"); + div.innerHTML = string; + return div.childNodes[0]; +}; + +// Tests if given element is inside (or simply is) the container +Dropzone.elementInside = function (element, container) { + if (element === container) { + return true; + } // Coffeescript doesn't support do/while loops + while (element = element.parentNode) { + if (element === container) { + return true; + } + } + return false; +}; + +Dropzone.getElement = function (el, name) { + var element = void 0; + if (typeof el === "string") { + element = document.querySelector(el); + } else if (el.nodeType != null) { + element = el; + } + if (element == null) { + throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector or a plain HTML element."); + } + return element; +}; + +Dropzone.getElements = function (els, name) { + var el = void 0, + elements = void 0; + if (els instanceof Array) { + elements = []; + try { + for (var _iterator36 = els, _isArray36 = true, _i38 = 0, _iterator36 = _isArray36 ? _iterator36 : _iterator36[Symbol.iterator]();;) { + if (_isArray36) { + if (_i38 >= _iterator36.length) break; + el = _iterator36[_i38++]; + } else { + _i38 = _iterator36.next(); + if (_i38.done) break; + el = _i38.value; + } + + elements.push(this.getElement(el, name)); + } + } catch (e) { + elements = null; + } + } else if (typeof els === "string") { + elements = []; + for (var _iterator37 = document.querySelectorAll(els), _isArray37 = true, _i39 = 0, _iterator37 = _isArray37 ? _iterator37 : _iterator37[Symbol.iterator]();;) { + if (_isArray37) { + if (_i39 >= _iterator37.length) break; + el = _iterator37[_i39++]; + } else { + _i39 = _iterator37.next(); + if (_i39.done) break; + el = _i39.value; + } + + elements.push(el); + } + } else if (els.nodeType != null) { + elements = [els]; + } + + if (elements == null || !elements.length) { + throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector, a plain HTML element or a list of those."); + } + + return elements; +}; + +// Asks the user the question and calls accepted or rejected accordingly +// +// The default implementation just uses `window.confirm` and then calls the +// appropriate callback. +Dropzone.confirm = function (question, accepted, rejected) { + if (window.confirm(question)) { + return accepted(); + } else if (rejected != null) { + return rejected(); + } +}; + +// Validates the mime type like this: +// +// https://developer.mozilla.org/en-US/docs/HTML/Element/input#attr-accept +Dropzone.isValidFile = function (file, acceptedFiles) { + if (!acceptedFiles) { + return true; + } // If there are no accepted mime types, it's OK + acceptedFiles = acceptedFiles.split(","); + + var mimeType = file.type; + var baseMimeType = mimeType.replace(/\/.*$/, ""); + + for (var _iterator38 = acceptedFiles, _isArray38 = true, _i40 = 0, _iterator38 = _isArray38 ? _iterator38 : _iterator38[Symbol.iterator]();;) { + var _ref35; + + if (_isArray38) { + if (_i40 >= _iterator38.length) break; + _ref35 = _iterator38[_i40++]; + } else { + _i40 = _iterator38.next(); + if (_i40.done) break; + _ref35 = _i40.value; + } + + var validType = _ref35; + + validType = validType.trim(); + if (validType.charAt(0) === ".") { + if (file.name.toLowerCase().indexOf(validType.toLowerCase(), file.name.length - validType.length) !== -1) { + return true; + } + } else if (/\/\*$/.test(validType)) { + // This is something like a image/* mime type + if (baseMimeType === validType.replace(/\/.*$/, "")) { + return true; + } + } else { + if (mimeType === validType) { + return true; + } + } + } + + return false; +}; + +// Augment jQuery +if (typeof jQuery !== 'undefined' && jQuery !== null) { + jQuery.fn.dropzone = function (options) { + return this.each(function () { + return new Dropzone(this, options); + }); + }; +} + +if (typeof module !== 'undefined' && module !== null) { + module.exports = Dropzone; +} else { + window.Dropzone = Dropzone; +} + +// Dropzone file status codes +Dropzone.ADDED = "added"; + +Dropzone.QUEUED = "queued"; +// For backwards compatibility. Now, if a file is accepted, it's either queued +// or uploading. +Dropzone.ACCEPTED = Dropzone.QUEUED; + +Dropzone.UPLOADING = "uploading"; +Dropzone.PROCESSING = Dropzone.UPLOADING; // alias + +Dropzone.CANCELED = "canceled"; +Dropzone.ERROR = "error"; +Dropzone.SUCCESS = "success"; + +/* + + Bugfix for iOS 6 and 7 + Source: http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios + based on the work of https://github.com/stomita/ios-imagefile-megapixel + + */ + +// Detecting vertical squash in loaded image. +// Fixes a bug which squash image vertically while drawing into canvas for some images. +// This is a bug in iOS6 devices. This function from https://github.com/stomita/ios-imagefile-megapixel +var detectVerticalSquash = function detectVerticalSquash(img) { + var iw = img.naturalWidth; + var ih = img.naturalHeight; + var canvas = document.createElement("canvas"); + canvas.width = 1; + canvas.height = ih; + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0); + + var _ctx$getImageData = ctx.getImageData(1, 0, 1, ih), + data = _ctx$getImageData.data; + + // search image edge pixel position in case it is squashed vertically. + + + var sy = 0; + var ey = ih; + var py = ih; + while (py > sy) { + var alpha = data[(py - 1) * 4 + 3]; + + if (alpha === 0) { + ey = py; + } else { + sy = py; + } + + py = ey + sy >> 1; + } + var ratio = py / ih; + + if (ratio === 0) { + return 1; + } else { + return ratio; + } +}; + +// A replacement for context.drawImage +// (args are for source and destination). +var drawImageIOSFix = function drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { + var vertSquashRatio = detectVerticalSquash(img); + return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio); +}; + +// Based on MinifyJpeg +// Source: http://www.perry.cz/files/ExifRestorer.js +// http://elicon.blog57.fc2.com/blog-entry-206.html + +var ExifRestore = function () { + function ExifRestore() { + _classCallCheck(this, ExifRestore); + } + + _createClass(ExifRestore, null, [{ + key: "initClass", + value: function initClass() { + this.KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + } + }, { + key: "encode64", + value: function encode64(input) { + var output = ''; + var chr1 = undefined; + var chr2 = undefined; + var chr3 = ''; + var enc1 = undefined; + var enc2 = undefined; + var enc3 = undefined; + var enc4 = ''; + var i = 0; + while (true) { + chr1 = input[i++]; + chr2 = input[i++]; + chr3 = input[i++]; + enc1 = chr1 >> 2; + enc2 = (chr1 & 3) << 4 | chr2 >> 4; + enc3 = (chr2 & 15) << 2 | chr3 >> 6; + enc4 = chr3 & 63; + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4); + chr1 = chr2 = chr3 = ''; + enc1 = enc2 = enc3 = enc4 = ''; + if (!(i < input.length)) { + break; + } + } + return output; + } + }, { + key: "restore", + value: function restore(origFileBase64, resizedFileBase64) { + if (!origFileBase64.match('data:image/jpeg;base64,')) { + return resizedFileBase64; + } + var rawImage = this.decode64(origFileBase64.replace('data:image/jpeg;base64,', '')); + var segments = this.slice2Segments(rawImage); + var image = this.exifManipulation(resizedFileBase64, segments); + return "data:image/jpeg;base64," + this.encode64(image); + } + }, { + key: "exifManipulation", + value: function exifManipulation(resizedFileBase64, segments) { + var exifArray = this.getExifArray(segments); + var newImageArray = this.insertExif(resizedFileBase64, exifArray); + var aBuffer = new Uint8Array(newImageArray); + return aBuffer; + } + }, { + key: "getExifArray", + value: function getExifArray(segments) { + var seg = undefined; + var x = 0; + while (x < segments.length) { + seg = segments[x]; + if (seg[0] === 255 & seg[1] === 225) { + return seg; + } + x++; + } + return []; + } + }, { + key: "insertExif", + value: function insertExif(resizedFileBase64, exifArray) { + var imageData = resizedFileBase64.replace('data:image/jpeg;base64,', ''); + var buf = this.decode64(imageData); + var separatePoint = buf.indexOf(255, 3); + var mae = buf.slice(0, separatePoint); + var ato = buf.slice(separatePoint); + var array = mae; + array = array.concat(exifArray); + array = array.concat(ato); + return array; + } + }, { + key: "slice2Segments", + value: function slice2Segments(rawImageArray) { + var head = 0; + var segments = []; + while (true) { + var length; + if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 218) { + break; + } + if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 216) { + head += 2; + } else { + length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3]; + var endPoint = head + length + 2; + var seg = rawImageArray.slice(head, endPoint); + segments.push(seg); + head = endPoint; + } + if (head > rawImageArray.length) { + break; + } + } + return segments; + } + }, { + key: "decode64", + value: function decode64(input) { + var output = ''; + var chr1 = undefined; + var chr2 = undefined; + var chr3 = ''; + var enc1 = undefined; + var enc2 = undefined; + var enc3 = undefined; + var enc4 = ''; + var i = 0; + var buf = []; + // remove all characters that are not A-Z, a-z, 0-9, +, /, or = + var base64test = /[^A-Za-z0-9\+\/\=]/g; + if (base64test.exec(input)) { + console.warn('There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, \'+\', \'/\',and \'=\'\nExpect errors in decoding.'); + } + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); + while (true) { + enc1 = this.KEY_STR.indexOf(input.charAt(i++)); + enc2 = this.KEY_STR.indexOf(input.charAt(i++)); + enc3 = this.KEY_STR.indexOf(input.charAt(i++)); + enc4 = this.KEY_STR.indexOf(input.charAt(i++)); + chr1 = enc1 << 2 | enc2 >> 4; + chr2 = (enc2 & 15) << 4 | enc3 >> 2; + chr3 = (enc3 & 3) << 6 | enc4; + buf.push(chr1); + if (enc3 !== 64) { + buf.push(chr2); + } + if (enc4 !== 64) { + buf.push(chr3); + } + chr1 = chr2 = chr3 = ''; + enc1 = enc2 = enc3 = enc4 = ''; + if (!(i < input.length)) { + break; + } + } + return buf; + } + }]); + + return ExifRestore; +}(); + +ExifRestore.initClass(); + +/* + * contentloaded.js + * + * Author: Diego Perini (diego.perini at gmail.com) + * Summary: cross-browser wrapper for DOMContentLoaded + * Updated: 20101020 + * License: MIT + * Version: 1.2 + * + * URL: + * http://javascript.nwbox.com/ContentLoaded/ + * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE + */ + +// @win window reference +// @fn function reference +var contentLoaded = function contentLoaded(win, fn) { + var done = false; + var top = true; + var doc = win.document; + var root = doc.documentElement; + var add = doc.addEventListener ? "addEventListener" : "attachEvent"; + var rem = doc.addEventListener ? "removeEventListener" : "detachEvent"; + var pre = doc.addEventListener ? "" : "on"; + var init = function init(e) { + if (e.type === "readystatechange" && doc.readyState !== "complete") { + return; + } + (e.type === "load" ? win : doc)[rem](pre + e.type, init, false); + if (!done && (done = true)) { + return fn.call(win, e.type || e); + } + }; + + var poll = function poll() { + try { + root.doScroll("left"); + } catch (e) { + setTimeout(poll, 50); + return; + } + return init("poll"); + }; + + if (doc.readyState !== "complete") { + if (doc.createEventObject && root.doScroll) { + try { + top = !win.frameElement; + } catch (error) {} + if (top) { + poll(); + } + } + doc[add](pre + "DOMContentLoaded", init, false); + doc[add](pre + "readystatechange", init, false); + return win[add](pre + "load", init, false); + } +}; + +// As a single function to be able to write tests. +Dropzone._autoDiscoverFunction = function () { + if (Dropzone.autoDiscover) { + return Dropzone.discover(); + } +}; +contentLoaded(window, Dropzone._autoDiscoverFunction); + +function __guard__(value, transform) { + return typeof value !== 'undefined' && value !== null ? transform(value) : undefined; +} +function __guardMethod__(obj, methodName, transform) { + if (typeof obj !== 'undefined' && obj !== null && typeof obj[methodName] === 'function') { + return transform(obj, methodName); + } else { + return undefined; + } +} \ No newline at end of file diff --git a/modules/backend/assets/vendor/jcrop/MIT-LICENSE.txt b/modules/backend/assets/vendor/jcrop/MIT-LICENSE.txt new file mode 100755 index 0000000..4f3a0fe --- /dev/null +++ b/modules/backend/assets/vendor/jcrop/MIT-LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2011 Tapmodo Interactive LLC, + http://github.com/tapmodo/Jcrop + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/modules/backend/assets/vendor/jcrop/OCTOBER-README.md b/modules/backend/assets/vendor/jcrop/OCTOBER-README.md new file mode 100644 index 0000000..e8b1d46 --- /dev/null +++ b/modules/backend/assets/vendor/jcrop/OCTOBER-README.md @@ -0,0 +1 @@ +There's a hack in line 1090 in jquery.Jcrop.js. The hack prevents DOM element leakage through the event that is not unbound in the destroy() method. --ab Apr 08 2015 \ No newline at end of file diff --git a/modules/backend/assets/vendor/jcrop/README.md b/modules/backend/assets/vendor/jcrop/README.md new file mode 100755 index 0000000..c1585fb --- /dev/null +++ b/modules/backend/assets/vendor/jcrop/README.md @@ -0,0 +1,66 @@ +Jcrop Image Cropping Plugin +=========================== + +Jcrop is the quick and easy way to add image cropping functionality to +your web application. It combines the ease-of-use of a typical jQuery +plugin with a powerful cross-platform DHTML cropping engine that is +faithful to familiar desktop graphics applications. + +Cross-platform Compatibility +---------------------------- + +* Firefox 2+ +* Safari 3+ +* Opera 9.5+ +* Google Chrome 0.2+ +* Internet Explorer 6+ + +Feature Overview +---------------- + +* Attaches unobtrusively to any image +* Supports aspect ratio locking +* Supports minSize/maxSize setting +* Callbacks for selection done, or while moving +* Keyboard support for nudging selection +* API features to create interactivity, including animation +* Support for CSS styling +* Experimental touch-screen support (iOS, Android, etc) + +Contributors +============ + +**Special thanks to the following contributors:** + +* [Bruno Agutoli](mailto:brunotla1@gmail.com) +* dhorrigan +* Phil-B +* jaymecd +* all others who have committed their time and effort to help improve Jcrop + +MIT License +=========== + +**Jcrop is free software under MIT License.** + +#### Copyright (c) 2008-2012 Tapmodo Interactive LLC,
http://github.com/tapmodo/Jcrop + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/modules/backend/assets/vendor/jcrop/css/Jcrop.gif b/modules/backend/assets/vendor/jcrop/css/Jcrop.gif new file mode 100755 index 0000000..72ea7cc Binary files /dev/null and b/modules/backend/assets/vendor/jcrop/css/Jcrop.gif differ diff --git a/modules/backend/assets/vendor/jcrop/css/jquery.Jcrop.min.css b/modules/backend/assets/vendor/jcrop/css/jquery.Jcrop.min.css new file mode 100755 index 0000000..edc76b2 --- /dev/null +++ b/modules/backend/assets/vendor/jcrop/css/jquery.Jcrop.min.css @@ -0,0 +1,29 @@ +/* jquery.Jcrop.min.css v0.9.12 (build:20130126) */ +.jcrop-holder{direction:ltr;text-align:left;} +.jcrop-vline,.jcrop-hline{background:#FFF url(Jcrop.gif);font-size:0;position:absolute;} +.jcrop-vline{height:100%;width:1px!important;} +.jcrop-vline.right{right:0;} +.jcrop-hline{height:1px!important;width:100%;} +.jcrop-hline.bottom{bottom:0;} +.jcrop-tracker{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-webkit-user-select:none;height:100%;width:100%;} +.jcrop-handle{background-color:#333;border:1px #EEE solid;font-size:1px;height:7px;width:7px;} +.jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0;} +.jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px;} +.jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%;} +.jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%;} +.jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0;} +.jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0;} +.jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0;} +.jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px;} +.jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%;} +.jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px;} +.jcrop-dragbar.ord-n{margin-top:-4px;} +.jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px;} +.jcrop-dragbar.ord-e{margin-right:-4px;right:0;} +.jcrop-dragbar.ord-w{margin-left:-4px;} +.jcrop-light .jcrop-vline,.jcrop-light .jcrop-hline{background:#FFF;filter:alpha(opacity=70)!important;opacity:.70!important;} +.jcrop-light .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#000;border-color:#FFF;border-radius:3px;} +.jcrop-dark .jcrop-vline,.jcrop-dark .jcrop-hline{background:#000;filter:alpha(opacity=70)!important;opacity:.7!important;} +.jcrop-dark .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#FFF;border-color:#000;border-radius:3px;} +.solid-line .jcrop-vline,.solid-line .jcrop-hline{background:#FFF;} +.jcrop-holder img,img.jcrop-preview{max-width:none;} diff --git a/modules/backend/assets/vendor/jcrop/js/jquery.Jcrop.js b/modules/backend/assets/vendor/jcrop/js/jquery.Jcrop.js new file mode 100755 index 0000000..feed10e --- /dev/null +++ b/modules/backend/assets/vendor/jcrop/js/jquery.Jcrop.js @@ -0,0 +1,1699 @@ +/** + * jquery.Jcrop.js v0.9.12 + * jQuery Image Cropping Plugin - released under MIT License + * Author: Kelly Hallman + * http://github.com/tapmodo/Jcrop + * Copyright (c) 2008-2013 Tapmodo Interactive LLC {{{ + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * }}} + */ + +(function ($) { + + $.Jcrop = function (obj, opt) { + var options = $.extend({}, $.Jcrop.defaults), + docOffset, + _ua = navigator.userAgent.toLowerCase(), + is_msie = /msie/.test(_ua), + ie6mode = /msie [1-6]\./.test(_ua); + + // Internal Methods {{{ + function px(n) { + return Math.round(n) + 'px'; + } + function cssClass(cl) { + return options.baseClass + '-' + cl; + } + function supportsColorFade() { + return $.fx.step.hasOwnProperty('backgroundColor'); + } + function getPos(obj) //{{{ + { + var pos = $(obj).offset(); + return [pos.left, pos.top]; + } + //}}} + function mouseAbs(e) //{{{ + { + return [(e.pageX - docOffset[0]), (e.pageY - docOffset[1])]; + } + //}}} + function setOptions(opt) //{{{ + { + if (typeof(opt) !== 'object') opt = {}; + options = $.extend(options, opt); + + $.each(['onChange','onSelect','onRelease','onDblClick'],function(i,e) { + if (typeof(options[e]) !== 'function') options[e] = function () {}; + }); + } + //}}} + function startDragMode(mode, pos, touch) //{{{ + { + docOffset = getPos($img); + Tracker.setCursor(mode === 'move' ? mode : mode + '-resize'); + + if (mode === 'move') { + return Tracker.activateHandlers(createMover(pos), doneSelect, touch); + } + + var fc = Coords.getFixed(); + var opp = oppLockCorner(mode); + var opc = Coords.getCorner(oppLockCorner(opp)); + + Coords.setPressed(Coords.getCorner(opp)); + Coords.setCurrent(opc); + + Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect, touch); + } + //}}} + function dragmodeHandler(mode, f) //{{{ + { + return function (pos) { + if (!options.aspectRatio) { + switch (mode) { + case 'e': + pos[1] = f.y2; + break; + case 'w': + pos[1] = f.y2; + break; + case 'n': + pos[0] = f.x2; + break; + case 's': + pos[0] = f.x2; + break; + } + } else { + switch (mode) { + case 'e': + pos[1] = f.y + 1; + break; + case 'w': + pos[1] = f.y + 1; + break; + case 'n': + pos[0] = f.x + 1; + break; + case 's': + pos[0] = f.x + 1; + break; + } + } + Coords.setCurrent(pos); + Selection.update(); + }; + } + //}}} + function createMover(pos) //{{{ + { + var lloc = pos; + KeyManager.watchKeys(); + + return function (pos) { + Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]); + lloc = pos; + + Selection.update(); + }; + } + //}}} + function oppLockCorner(ord) //{{{ + { + switch (ord) { + case 'n': + return 'sw'; + case 's': + return 'nw'; + case 'e': + return 'nw'; + case 'w': + return 'ne'; + case 'ne': + return 'sw'; + case 'nw': + return 'se'; + case 'se': + return 'nw'; + case 'sw': + return 'ne'; + } + } + //}}} + function createDragger(ord) //{{{ + { + return function (e) { + if (options.disabled) { + return false; + } + if ((ord === 'move') && !options.allowMove) { + return false; + } + + // Fix position of crop area when dragged the very first time. + // Necessary when crop image is in a hidden element when page is loaded. + docOffset = getPos($img); + + btndown = true; + startDragMode(ord, mouseAbs(e)); + e.stopPropagation(); + e.preventDefault(); + return false; + }; + } + //}}} + function presize($obj, w, h) //{{{ + { + var nw = $obj.width(), + nh = $obj.height(); + if ((nw > w) && w > 0) { + nw = w; + nh = (w / $obj.width()) * $obj.height(); + } + if ((nh > h) && h > 0) { + nh = h; + nw = (h / $obj.height()) * $obj.width(); + } + xscale = $obj.width() / nw; + yscale = $obj.height() / nh; + $obj.width(nw).height(nh); + } + //}}} + function unscale(c) //{{{ + { + return { + x: c.x * xscale, + y: c.y * yscale, + x2: c.x2 * xscale, + y2: c.y2 * yscale, + w: c.w * xscale, + h: c.h * yscale + }; + } + //}}} + function doneSelect(pos) //{{{ + { + var c = Coords.getFixed(); + if ((c.w > options.minSelect[0]) && (c.h > options.minSelect[1])) { + Selection.enableHandles(); + Selection.done(); + } else { + Selection.release(); + } + Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default'); + } + //}}} + function newSelection(e) //{{{ + { + if (options.disabled) { + return false; + } + if (!options.allowSelect) { + return false; + } + btndown = true; + docOffset = getPos($img); + Selection.disableHandles(); + Tracker.setCursor('crosshair'); + var pos = mouseAbs(e); + Coords.setPressed(pos); + Selection.update(); + Tracker.activateHandlers(selectDrag, doneSelect, e.type.substring(0,5)==='touch'); + KeyManager.watchKeys(); + + e.stopPropagation(); + e.preventDefault(); + return false; + } + //}}} + function selectDrag(pos) //{{{ + { + Coords.setCurrent(pos); + Selection.update(); + } + //}}} + function newTracker() //{{{ + { + var trk = $('
').addClass(cssClass('tracker')); + if (is_msie) { + trk.css({ + opacity: 0, + backgroundColor: 'white' + }); + } + return trk; + } + //}}} + + // }}} + // Initialization {{{ + // Sanitize some options {{{ + if (typeof(obj) !== 'object') { + obj = $(obj)[0]; + } + if (typeof(opt) !== 'object') { + opt = {}; + } + // }}} + setOptions(opt); + // Initialize some jQuery objects {{{ + // The values are SET on the image(s) for the interface + // If the original image has any of these set, they will be reset + // However, if you destroy() the Jcrop instance the original image's + // character in the DOM will be as you left it. + var img_css = { + border: 'none', + visibility: 'visible', + margin: 0, + padding: 0, + position: 'absolute', + top: 0, + left: 0 + }; + + var $origimg = $(obj), + img_mode = true; + + if (obj.tagName == 'IMG') { + // Fix size of crop image. + // Necessary when crop image is within a hidden element when page is loaded. + if ($origimg[0].width != 0 && $origimg[0].height != 0) { + // Obtain dimensions from contained img element. + $origimg.width($origimg[0].width); + $origimg.height($origimg[0].height); + } else { + // Obtain dimensions from temporary image in case the original is not loaded yet (e.g. IE 7.0). + var tempImage = new Image(); + tempImage.src = $origimg[0].src; + $origimg.width(tempImage.width); + $origimg.height(tempImage.height); + } + + var $img = $origimg.clone().removeAttr('id').css(img_css).show(); + + $img.width($origimg.width()); + $img.height($origimg.height()); + $origimg.after($img).hide(); + + } else { + $img = $origimg.css(img_css).show(); + img_mode = false; + if (options.shade === null) { options.shade = true; } + } + + presize($img, options.boxWidth, options.boxHeight); + + var boundx = $img.width(), + boundy = $img.height(), + + + $div = $('
').width(boundx).height(boundy).addClass(cssClass('holder')).css({ + position: 'relative', + backgroundColor: options.bgColor + }).insertAfter($origimg).append($img); + + if (options.addClass) { + $div.addClass(options.addClass); + } + + var $img2 = $('
'), + + $img_holder = $('
') + .width('100%').height('100%').css({ + zIndex: 310, + position: 'absolute', + overflow: 'hidden' + }), + + $hdl_holder = $('
') + .width('100%').height('100%').css('zIndex', 320), + + $sel = $('
') + .css({ + position: 'absolute', + zIndex: 600 + }).dblclick(function(){ + var c = Coords.getFixed(); + options.onDblClick.call(api,c); + }).insertBefore($img).append($img_holder, $hdl_holder); + + if (img_mode) { + + $img2 = $('') + .attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy), + + $img_holder.append($img2); + + } + + if (ie6mode) { + $sel.css({ + overflowY: 'hidden' + }); + } + + var bound = options.boundary; + var $trk = newTracker().width(boundx + (bound * 2)).height(boundy + (bound * 2)).css({ + position: 'absolute', + top: px(-bound), + left: px(-bound), + zIndex: 290 + }).mousedown(newSelection); + + /* }}} */ + // Set more variables {{{ + var bgcolor = options.bgColor, + bgopacity = options.bgOpacity, + xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true, + btndown, animating, shift_down; + + docOffset = getPos($img); + // }}} + // }}} + // Internal Modules {{{ + // Touch Module {{{ + var Touch = (function () { + // Touch support detection function adapted (under MIT License) + // from code by Jeffrey Sambells - http://github.com/iamamused/ + function hasTouchSupport() { + var support = {}, events = ['touchstart', 'touchmove', 'touchend'], + el = document.createElement('div'), i; + + try { + for(i=0; i x1 + ox) { + ox -= ox + x1; + } + if (0 > y1 + oy) { + oy -= oy + y1; + } + + if (boundy < y2 + oy) { + oy += boundy - (y2 + oy); + } + if (boundx < x2 + ox) { + ox += boundx - (x2 + ox); + } + + x1 += ox; + x2 += ox; + y1 += oy; + y2 += oy; + } + //}}} + function getCorner(ord) //{{{ + { + var c = getFixed(); + switch (ord) { + case 'ne': + return [c.x2, c.y]; + case 'nw': + return [c.x, c.y]; + case 'se': + return [c.x2, c.y2]; + case 'sw': + return [c.x, c.y2]; + } + } + //}}} + function getFixed() //{{{ + { + if (!options.aspectRatio) { + return getRect(); + } + // This function could use some optimization I think... + var aspect = options.aspectRatio, + min_x = options.minSize[0] / xscale, + + + //min_y = options.minSize[1]/yscale, + max_x = options.maxSize[0] / xscale, + max_y = options.maxSize[1] / yscale, + rw = x2 - x1, + rh = y2 - y1, + rwa = Math.abs(rw), + rha = Math.abs(rh), + real_ratio = rwa / rha, + xx, yy, w, h; + + if (max_x === 0) { + max_x = boundx * 10; + } + if (max_y === 0) { + max_y = boundy * 10; + } + if (real_ratio < aspect) { + yy = y2; + w = rha * aspect; + xx = rw < 0 ? x1 - w : w + x1; + + if (xx < 0) { + xx = 0; + h = Math.abs((xx - x1) / aspect); + yy = rh < 0 ? y1 - h : h + y1; + } else if (xx > boundx) { + xx = boundx; + h = Math.abs((xx - x1) / aspect); + yy = rh < 0 ? y1 - h : h + y1; + } + } else { + xx = x2; + h = rwa / aspect; + yy = rh < 0 ? y1 - h : y1 + h; + if (yy < 0) { + yy = 0; + w = Math.abs((yy - y1) * aspect); + xx = rw < 0 ? x1 - w : w + x1; + } else if (yy > boundy) { + yy = boundy; + w = Math.abs(yy - y1) * aspect; + xx = rw < 0 ? x1 - w : w + x1; + } + } + + // Magic %-) + if (xx > x1) { // right side + if (xx - x1 < min_x) { + xx = x1 + min_x; + } else if (xx - x1 > max_x) { + xx = x1 + max_x; + } + if (yy > y1) { + yy = y1 + (xx - x1) / aspect; + } else { + yy = y1 - (xx - x1) / aspect; + } + } else if (xx < x1) { // left side + if (x1 - xx < min_x) { + xx = x1 - min_x; + } else if (x1 - xx > max_x) { + xx = x1 - max_x; + } + if (yy > y1) { + yy = y1 + (x1 - xx) / aspect; + } else { + yy = y1 - (x1 - xx) / aspect; + } + } + + if (xx < 0) { + x1 -= xx; + xx = 0; + } else if (xx > boundx) { + x1 -= xx - boundx; + xx = boundx; + } + + if (yy < 0) { + y1 -= yy; + yy = 0; + } else if (yy > boundy) { + y1 -= yy - boundy; + yy = boundy; + } + + return makeObj(flipCoords(x1, y1, xx, yy)); + } + //}}} + function rebound(p) //{{{ + { + if (p[0] < 0) p[0] = 0; + if (p[1] < 0) p[1] = 0; + + if (p[0] > boundx) p[0] = boundx; + if (p[1] > boundy) p[1] = boundy; + + return [Math.round(p[0]), Math.round(p[1])]; + } + //}}} + function flipCoords(x1, y1, x2, y2) //{{{ + { + var xa = x1, + xb = x2, + ya = y1, + yb = y2; + if (x2 < x1) { + xa = x2; + xb = x1; + } + if (y2 < y1) { + ya = y2; + yb = y1; + } + return [xa, ya, xb, yb]; + } + //}}} + function getRect() //{{{ + { + var xsize = x2 - x1, + ysize = y2 - y1, + delta; + + if (xlimit && (Math.abs(xsize) > xlimit)) { + x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit); + } + if (ylimit && (Math.abs(ysize) > ylimit)) { + y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit); + } + + if (ymin / yscale && (Math.abs(ysize) < ymin / yscale)) { + y2 = (ysize > 0) ? (y1 + ymin / yscale) : (y1 - ymin / yscale); + } + if (xmin / xscale && (Math.abs(xsize) < xmin / xscale)) { + x2 = (xsize > 0) ? (x1 + xmin / xscale) : (x1 - xmin / xscale); + } + + if (x1 < 0) { + x2 -= x1; + x1 -= x1; + } + if (y1 < 0) { + y2 -= y1; + y1 -= y1; + } + if (x2 < 0) { + x1 -= x2; + x2 -= x2; + } + if (y2 < 0) { + y1 -= y2; + y2 -= y2; + } + if (x2 > boundx) { + delta = x2 - boundx; + x1 -= delta; + x2 -= delta; + } + if (y2 > boundy) { + delta = y2 - boundy; + y1 -= delta; + y2 -= delta; + } + if (x1 > boundx) { + delta = x1 - boundy; + y2 -= delta; + y1 -= delta; + } + if (y1 > boundy) { + delta = y1 - boundy; + y2 -= delta; + y1 -= delta; + } + + return makeObj(flipCoords(x1, y1, x2, y2)); + } + //}}} + function makeObj(a) //{{{ + { + return { + x: a[0], + y: a[1], + x2: a[2], + y2: a[3], + w: a[2] - a[0], + h: a[3] - a[1] + }; + } + //}}} + + return { + flipCoords: flipCoords, + setPressed: setPressed, + setCurrent: setCurrent, + getOffset: getOffset, + moveOffset: moveOffset, + getCorner: getCorner, + getFixed: getFixed + }; + }()); + + //}}} + // Shade Module {{{ + var Shade = (function() { + var enabled = false, + holder = $('
').css({ + position: 'absolute', + zIndex: 240, + opacity: 0 + }), + shades = { + top: createShade(), + left: createShade().height(boundy), + right: createShade().height(boundy), + bottom: createShade() + }; + + function resizeShades(w,h) { + shades.left.css({ height: px(h) }); + shades.right.css({ height: px(h) }); + } + function updateAuto() + { + return updateShade(Coords.getFixed()); + } + function updateShade(c) + { + shades.top.css({ + left: px(c.x), + width: px(c.w), + height: px(c.y) + }); + shades.bottom.css({ + top: px(c.y2), + left: px(c.x), + width: px(c.w), + height: px(boundy-c.y2) + }); + shades.right.css({ + left: px(c.x2), + width: px(boundx-c.x2) + }); + shades.left.css({ + width: px(c.x) + }); + } + function createShade() { + return $('
').css({ + position: 'absolute', + backgroundColor: options.shadeColor||options.bgColor + }).appendTo(holder); + } + function enableShade() { + if (!enabled) { + enabled = true; + holder.insertBefore($img); + updateAuto(); + Selection.setBgOpacity(1,0,1); + $img2.hide(); + + setBgColor(options.shadeColor||options.bgColor,1); + if (Selection.isAwake()) + { + setOpacity(options.bgOpacity,1); + } + else setOpacity(1,1); + } + } + function setBgColor(color,now) { + colorChangeMacro(getShades(),color,now); + } + function disableShade() { + if (enabled) { + holder.remove(); + $img2.show(); + enabled = false; + if (Selection.isAwake()) { + Selection.setBgOpacity(options.bgOpacity,1,1); + } else { + Selection.setBgOpacity(1,1,1); + Selection.disableHandles(); + } + colorChangeMacro($div,0,1); + } + } + function setOpacity(opacity,now) { + if (enabled) { + if (options.bgFade && !now) { + holder.animate({ + opacity: 1-opacity + },{ + queue: false, + duration: options.fadeTime + }); + } + else holder.css({opacity:1-opacity}); + } + } + function refreshAll() { + options.shade ? enableShade() : disableShade(); + if (Selection.isAwake()) setOpacity(options.bgOpacity); + } + function getShades() { + return holder.children(); + } + + return { + update: updateAuto, + updateRaw: updateShade, + getShades: getShades, + setBgColor: setBgColor, + enable: enableShade, + disable: disableShade, + resize: resizeShades, + refresh: refreshAll, + opacity: setOpacity + }; + }()); + // }}} + // Selection Module {{{ + var Selection = (function () { + var awake, + hdep = 370, + borders = {}, + handle = {}, + dragbar = {}, + seehandles = false; + + // Private Methods + function insertBorder(type) //{{{ + { + var jq = $('
').css({ + position: 'absolute', + opacity: options.borderOpacity + }).addClass(cssClass(type)); + $img_holder.append(jq); + return jq; + } + //}}} + function dragDiv(ord, zi) //{{{ + { + var jq = $('
').mousedown(createDragger(ord)).css({ + cursor: ord + '-resize', + position: 'absolute', + zIndex: zi + }).addClass('ord-'+ord); + + if (Touch.support) { + jq.bind('touchstart.jcrop', Touch.createDragger(ord)); + } + + $hdl_holder.append(jq); + return jq; + } + //}}} + function insertHandle(ord) //{{{ + { + var hs = options.handleSize, + + div = dragDiv(ord, hdep++).css({ + opacity: options.handleOpacity + }).addClass(cssClass('handle')); + + if (hs) { div.width(hs).height(hs); } + + return div; + } + //}}} + function insertDragbar(ord) //{{{ + { + return dragDiv(ord, hdep++).addClass('jcrop-dragbar'); + } + //}}} + function createDragbars(li) //{{{ + { + var i; + for (i = 0; i < li.length; i++) { + dragbar[li[i]] = insertDragbar(li[i]); + } + } + //}}} + function createBorders(li) //{{{ + { + var cl,i; + for (i = 0; i < li.length; i++) { + switch(li[i]){ + case'n': cl='hline'; break; + case's': cl='hline bottom'; break; + case'e': cl='vline right'; break; + case'w': cl='vline'; break; + } + borders[li[i]] = insertBorder(cl); + } + } + //}}} + function createHandles(li) //{{{ + { + var i; + for (i = 0; i < li.length; i++) { + handle[li[i]] = insertHandle(li[i]); + } + } + //}}} + function moveto(x, y) //{{{ + { + if (!options.shade) { + $img2.css({ + top: px(-y), + left: px(-x) + }); + } + $sel.css({ + top: px(y), + left: px(x) + }); + } + //}}} + function resize(w, h) //{{{ + { + $sel.width(Math.round(w)).height(Math.round(h)); + } + //}}} + function refresh() //{{{ + { + var c = Coords.getFixed(); + + Coords.setPressed([c.x, c.y]); + Coords.setCurrent([c.x2, c.y2]); + + updateVisible(); + } + //}}} + + // Internal Methods + function updateVisible(select) //{{{ + { + if (awake) { + return update(select); + } + } + //}}} + function update(select) //{{{ + { + var c = Coords.getFixed(); + + resize(c.w, c.h); + moveto(c.x, c.y); + if (options.shade) Shade.updateRaw(c); + + awake || show(); + + if (select) { + options.onSelect.call(api, unscale(c)); + } else { + options.onChange.call(api, unscale(c)); + } + } + //}}} + function setBgOpacity(opacity,force,now) //{{{ + { + if (!awake && !force) return; + if (options.bgFade && !now) { + $img.animate({ + opacity: opacity + },{ + queue: false, + duration: options.fadeTime + }); + } else { + $img.css('opacity', opacity); + } + } + //}}} + function show() //{{{ + { + $sel.show(); + + if (options.shade) Shade.opacity(bgopacity); + else setBgOpacity(bgopacity,true); + + awake = true; + } + //}}} + function release() //{{{ + { + disableHandles(); + $sel.hide(); + + if (options.shade) Shade.opacity(1); + else setBgOpacity(1); + + awake = false; + options.onRelease.call(api); + } + //}}} + function showHandles() //{{{ + { + if (seehandles) { + $hdl_holder.show(); + } + } + //}}} + function enableHandles() //{{{ + { + seehandles = true; + if (options.allowResize) { + $hdl_holder.show(); + return true; + } + } + //}}} + function disableHandles() //{{{ + { + seehandles = false; + $hdl_holder.hide(); + } + //}}} + function animMode(v) //{{{ + { + if (v) { + animating = true; + disableHandles(); + } else { + animating = false; + enableHandles(); + } + } + //}}} + function done() //{{{ + { + animMode(false); + refresh(); + } + //}}} + // Insert draggable elements {{{ + // Insert border divs for outline + + if (options.dragEdges && $.isArray(options.createDragbars)) + createDragbars(options.createDragbars); + + if ($.isArray(options.createHandles)) + createHandles(options.createHandles); + + if (options.drawBorders && $.isArray(options.createBorders)) + createBorders(options.createBorders); + + //}}} + + // This is a hack for iOS5 to support drag/move touch functionality + // Hack OctoberCMS - the event handler was moved to the Touch module. + // The closure used before was handling a reference to the target object, + // preventing it from removing from DOM after the control is destroyed. + $(document).bind('touchstart.jcrop-ios', Touch.fixTouchSupport); + + var $track = newTracker().mousedown(createDragger('move')).css({ + cursor: 'move', + position: 'absolute', + zIndex: 360 + }); + + if (Touch.support) { + $track.bind('touchstart.jcrop', Touch.createDragger('move')); + } + + $img_holder.append($track); + disableHandles(); + + return { + updateVisible: updateVisible, + update: update, + release: release, + refresh: refresh, + isAwake: function () { + return awake; + }, + setCursor: function (cursor) { + $track.css('cursor', cursor); + }, + enableHandles: enableHandles, + enableOnly: function () { + seehandles = true; + }, + showHandles: showHandles, + disableHandles: disableHandles, + animMode: animMode, + setBgOpacity: setBgOpacity, + done: done + }; + }()); + + //}}} + // Tracker Module {{{ + var Tracker = (function () { + var onMove = function () {}, + onDone = function () {}, + trackDoc = options.trackDocument; + + function toFront(touch) //{{{ + { + $trk.css({ + zIndex: 450 + }); + + if (touch) + $(document) + .bind('touchmove.jcrop', trackTouchMove) + .bind('touchend.jcrop', trackTouchEnd); + + else if (trackDoc) + $(document) + .bind('mousemove.jcrop',trackMove) + .bind('mouseup.jcrop',trackUp); + } + //}}} + function toBack() //{{{ + { + $trk.css({ + zIndex: 290 + }); + $(document).unbind('.jcrop'); + } + //}}} + function trackMove(e) //{{{ + { + onMove(mouseAbs(e)); + return false; + } + //}}} + function trackUp(e) //{{{ + { + e.preventDefault(); + e.stopPropagation(); + + if (btndown) { + btndown = false; + + onDone(mouseAbs(e)); + + if (Selection.isAwake()) { + options.onSelect.call(api, unscale(Coords.getFixed())); + } + + toBack(); + onMove = function () {}; + onDone = function () {}; + } + + return false; + } + //}}} + function activateHandlers(move, done, touch) //{{{ + { + btndown = true; + onMove = move; + onDone = done; + toFront(touch); + return false; + } + //}}} + function trackTouchMove(e) //{{{ + { + onMove(mouseAbs(Touch.cfilter(e))); + return false; + } + //}}} + function trackTouchEnd(e) //{{{ + { + return trackUp(Touch.cfilter(e)); + } + //}}} + function setCursor(t) //{{{ + { + $trk.css('cursor', t); + } + //}}} + + if (!trackDoc) { + $trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp); + } + + $img.before($trk); + return { + activateHandlers: activateHandlers, + setCursor: setCursor + }; + }()); + //}}} + // KeyManager Module {{{ + var KeyManager = (function () { + var $keymgr = $('').css({ + position: 'fixed', + left: '-120px', + width: '12px' + }).addClass('jcrop-keymgr'), + + $keywrap = $('
').css({ + position: 'absolute', + overflow: 'hidden' + }).append($keymgr); + + function watchKeys() //{{{ + { + if (options.keySupport) { + $keymgr.show(); + $keymgr.focus(); + } + } + //}}} + function onBlur(e) //{{{ + { + $keymgr.hide(); + } + //}}} + function doNudge(e, x, y) //{{{ + { + if (options.allowMove) { + Coords.moveOffset([x, y]); + Selection.updateVisible(true); + } + e.preventDefault(); + e.stopPropagation(); + } + //}}} + function parseKey(e) //{{{ + { + if (e.ctrlKey || e.metaKey) { + return true; + } + shift_down = e.shiftKey ? true : false; + var nudge = shift_down ? 10 : 1; + + switch (e.keyCode) { + case 37: + doNudge(e, -nudge, 0); + break; + case 39: + doNudge(e, nudge, 0); + break; + case 38: + doNudge(e, 0, -nudge); + break; + case 40: + doNudge(e, 0, nudge); + break; + case 27: + if (options.allowSelect) Selection.release(); + break; + case 9: + return true; + } + + return false; + } + //}}} + + if (options.keySupport) { + $keymgr.keydown(parseKey).blur(onBlur); + if (ie6mode || !options.fixedSupport) { + $keymgr.css({ + position: 'absolute', + left: '-20px' + }); + $keywrap.append($keymgr).insertBefore($img); + } else { + $keymgr.insertBefore($img); + } + } + + + return { + watchKeys: watchKeys + }; + }()); + //}}} + // }}} + // API methods {{{ + function setClass(cname) //{{{ + { + $div.removeClass().addClass(cssClass('holder')).addClass(cname); + } + //}}} + function animateTo(a, callback) //{{{ + { + var x1 = a[0] / xscale, + y1 = a[1] / yscale, + x2 = a[2] / xscale, + y2 = a[3] / yscale; + + if (animating) { + return; + } + + var animto = Coords.flipCoords(x1, y1, x2, y2), + c = Coords.getFixed(), + initcr = [c.x, c.y, c.x2, c.y2], + animat = initcr, + interv = options.animationDelay, + ix1 = animto[0] - initcr[0], + iy1 = animto[1] - initcr[1], + ix2 = animto[2] - initcr[2], + iy2 = animto[3] - initcr[3], + pcent = 0, + velocity = options.swingSpeed; + + x1 = animat[0]; + y1 = animat[1]; + x2 = animat[2]; + y2 = animat[3]; + + Selection.animMode(true); + var anim_timer; + + function queueAnimator() { + window.setTimeout(animator, interv); + } + var animator = (function () { + return function () { + pcent += (100 - pcent) / velocity; + + animat[0] = Math.round(x1 + ((pcent / 100) * ix1)); + animat[1] = Math.round(y1 + ((pcent / 100) * iy1)); + animat[2] = Math.round(x2 + ((pcent / 100) * ix2)); + animat[3] = Math.round(y2 + ((pcent / 100) * iy2)); + + if (pcent >= 99.8) { + pcent = 100; + } + if (pcent < 100) { + setSelectRaw(animat); + queueAnimator(); + } else { + Selection.done(); + Selection.animMode(false); + if (typeof(callback) === 'function') { + callback.call(api); + } + } + }; + }()); + queueAnimator(); + } + //}}} + function setSelect(rect) //{{{ + { + setSelectRaw([rect[0] / xscale, rect[1] / yscale, rect[2] / xscale, rect[3] / yscale]); + options.onSelect.call(api, unscale(Coords.getFixed())); + Selection.enableHandles(); + } + //}}} + function setSelectRaw(l) //{{{ + { + Coords.setPressed([l[0], l[1]]); + Coords.setCurrent([l[2], l[3]]); + Selection.update(); + } + //}}} + function tellSelect() //{{{ + { + return unscale(Coords.getFixed()); + } + //}}} + function tellScaled() //{{{ + { + return Coords.getFixed(); + } + //}}} + function setOptionsNew(opt) //{{{ + { + setOptions(opt); + interfaceUpdate(); + } + //}}} + function disableCrop() //{{{ + { + options.disabled = true; + Selection.disableHandles(); + Selection.setCursor('default'); + Tracker.setCursor('default'); + } + //}}} + function enableCrop() //{{{ + { + options.disabled = false; + interfaceUpdate(); + } + //}}} + function cancelCrop() //{{{ + { + Selection.done(); + Tracker.activateHandlers(null, null); + } + //}}} + function destroy() //{{{ + { + $(document).unbind('touchstart.jcrop-ios', Touch.fixTouchSupport); + $div.remove(); + $origimg.show(); + $origimg.css('visibility','visible'); + $(obj).removeData('Jcrop'); + } + //}}} + function setImage(src, callback) //{{{ + { + Selection.release(); + disableCrop(); + var img = new Image(); + img.onload = function () { + var iw = img.width; + var ih = img.height; + var bw = options.boxWidth; + var bh = options.boxHeight; + $img.width(iw).height(ih); + $img.attr('src', src); + $img2.attr('src', src); + presize($img, bw, bh); + boundx = $img.width(); + boundy = $img.height(); + $img2.width(boundx).height(boundy); + $trk.width(boundx + (bound * 2)).height(boundy + (bound * 2)); + $div.width(boundx).height(boundy); + Shade.resize(boundx,boundy); + enableCrop(); + + if (typeof(callback) === 'function') { + callback.call(api); + } + }; + img.src = src; + } + //}}} + function colorChangeMacro($obj,color,now) { + var mycolor = color || options.bgColor; + if (options.bgFade && supportsColorFade() && options.fadeTime && !now) { + $obj.animate({ + backgroundColor: mycolor + }, { + queue: false, + duration: options.fadeTime + }); + } else { + $obj.css('backgroundColor', mycolor); + } + } + function interfaceUpdate(alt) //{{{ + // This method tweaks the interface based on options object. + // Called when options are changed and at end of initialization. + { + if (options.allowResize) { + if (alt) { + Selection.enableOnly(); + } else { + Selection.enableHandles(); + } + } else { + Selection.disableHandles(); + } + + Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default'); + Selection.setCursor(options.allowMove ? 'move' : 'default'); + + if (options.hasOwnProperty('trueSize')) { + xscale = options.trueSize[0] / boundx; + yscale = options.trueSize[1] / boundy; + } + + if (options.hasOwnProperty('setSelect')) { + setSelect(options.setSelect); + Selection.done(); + delete(options.setSelect); + } + + Shade.refresh(); + + if (options.bgColor != bgcolor) { + colorChangeMacro( + options.shade? Shade.getShades(): $div, + options.shade? + (options.shadeColor || options.bgColor): + options.bgColor + ); + bgcolor = options.bgColor; + } + + if (bgopacity != options.bgOpacity) { + bgopacity = options.bgOpacity; + if (options.shade) Shade.refresh(); + else Selection.setBgOpacity(bgopacity); + } + + xlimit = options.maxSize[0] || 0; + ylimit = options.maxSize[1] || 0; + xmin = options.minSize[0] || 0; + ymin = options.minSize[1] || 0; + + if (options.hasOwnProperty('outerImage')) { + $img.attr('src', options.outerImage); + delete(options.outerImage); + } + + Selection.refresh(); + } + //}}} + //}}} + + if (Touch.support) $trk.bind('touchstart.jcrop', Touch.newSelection); + + $hdl_holder.hide(); + interfaceUpdate(true); + + var api = { + setImage: setImage, + animateTo: animateTo, + setSelect: setSelect, + setOptions: setOptionsNew, + tellSelect: tellSelect, + tellScaled: tellScaled, + setClass: setClass, + + disable: disableCrop, + enable: enableCrop, + cancel: cancelCrop, + release: Selection.release, + destroy: destroy, + + focus: KeyManager.watchKeys, + + getBounds: function () { + return [boundx * xscale, boundy * yscale]; + }, + getWidgetSize: function () { + return [boundx, boundy]; + }, + getScaleFactor: function () { + return [xscale, yscale]; + }, + getOptions: function() { + // careful: internal values are returned + return options; + }, + + ui: { + holder: $div, + selection: $sel + } + }; + + if (is_msie) $div.bind('selectstart', function () { return false; }); + + $origimg.data('Jcrop', api); + return api; + }; + $.fn.Jcrop = function (options, callback) //{{{ + { + var api; + // Iterate over each object, attach Jcrop + this.each(function () { + // If we've already attached to this object + if ($(this).data('Jcrop')) { + // The API can be requested this way (undocumented) + if (options === 'api') return $(this).data('Jcrop'); + // Otherwise, we just reset the options... + else $(this).data('Jcrop').setOptions(options); + } + // If we haven't been attached, preload and attach + else { + if (this.tagName == 'IMG') + $.Jcrop.Loader(this,function(){ + $(this).css({display:'block',visibility:'hidden'}); + api = $.Jcrop(this, options); + if ($.isFunction(callback)) callback.call(api); + }); + else { + $(this).css({display:'block',visibility:'hidden'}); + api = $.Jcrop(this, options); + if ($.isFunction(callback)) callback.call(api); + } + } + }); + + // Return "this" so the object is chainable (jQuery-style) + return this; + }; + //}}} + // $.Jcrop.Loader - basic image loader {{{ + + $.Jcrop.Loader = function(imgobj,success,error){ + var $img = $(imgobj), img = $img[0]; + + function completeCheck(){ + if (img.complete) { + $img.unbind('.jcloader'); + if ($.isFunction(success)) success.call(img); + } + else window.setTimeout(completeCheck,50); + } + + $img + .bind('load.jcloader',completeCheck) + .bind('error.jcloader',function(e){ + $img.unbind('.jcloader'); + if ($.isFunction(error)) error.call(img); + }); + + if (img.complete && $.isFunction(success)){ + $img.unbind('.jcloader'); + success.call(img); + } + }; + + //}}} + // Global Defaults {{{ + $.Jcrop.defaults = { + + // Basic Settings + allowSelect: true, + allowMove: true, + allowResize: true, + + trackDocument: true, + + // Styling Options + baseClass: 'jcrop', + addClass: null, + bgColor: 'black', + bgOpacity: 0.6, + bgFade: false, + borderOpacity: 0.4, + handleOpacity: 0.5, + handleSize: null, + + aspectRatio: 0, + keySupport: true, + createHandles: ['n','s','e','w','nw','ne','se','sw'], + createDragbars: ['n','s','e','w'], + createBorders: ['n','s','e','w'], + drawBorders: true, + dragEdges: true, + fixedSupport: true, + touchSupport: null, + + shade: null, + + boxWidth: 0, + boxHeight: 0, + boundary: 2, + fadeTime: 400, + animationDelay: 20, + swingSpeed: 3, + + minSelect: [0, 0], + maxSize: [0, 0], + minSize: [0, 0], + + // Callbacks / Event Handlers + onChange: function () {}, + onSelect: function () {}, + onDblClick: function () {}, + onRelease: function () {} + }; + + // }}} +}(jQuery)); diff --git a/modules/backend/assets/vendor/sweet-alert/sweet-alert-animations.less b/modules/backend/assets/vendor/sweet-alert/sweet-alert-animations.less new file mode 100644 index 0000000..031b20e --- /dev/null +++ b/modules/backend/assets/vendor/sweet-alert/sweet-alert-animations.less @@ -0,0 +1,255 @@ +@-webkit-keyframes showSweetAlert { + 0% { + transform: scale(0.7); + -webkit-transform: scale(0.7); } + 45% { + transform: scale(1.05); + -webkit-transform: scale(1.05); } + 80% { + transform: scale(0.95); + -webkit-tranform: scale(0.95); } + 100% { + transform: scale(1); + -webkit-transform: scale(1); } } +@keyframes showSweetAlert { + 0% { + transform: scale(0.7); + -webkit-transform: scale(0.7); } + 45% { + transform: scale(1.05); + -webkit-transform: scale(1.05); } + 80% { + transform: scale(0.95); + -webkit-tranform: scale(0.95); } + 100% { + transform: scale(1); + -webkit-transform: scale(1); } } +@-webkit-keyframes hideSweetAlert { + 0% { + transform: scale(1); + -webkit-transform: scale(1); } + 100% { + transform: scale(0.5); + -webkit-transform: scale(0.5); } } +@keyframes hideSweetAlert { + 0% { + transform: scale(1); + -webkit-transform: scale(1); } + 100% { + transform: scale(0.5); + -webkit-transform: scale(0.5); } } +.showSweetAlert { + -webkit-animation: showSweetAlert 0.3s; + animation: showSweetAlert 0.3s; } + +.hideSweetAlert { + -webkit-animation: hideSweetAlert 0.2s; + animation: hideSweetAlert 0.2s; } + +@-webkit-keyframes animateSuccessTip { + 0% { + width: 0; + left: 1px; + top: 19px; } + 54% { + width: 0; + left: 1px; + top: 19px; } + 70% { + width: 50px; + left: -8px; + top: 37px; } + 84% { + width: 17px; + left: 21px; + top: 48px; } + 100% { + width: 25px; + left: 14px; + top: 45px; } } +@keyframes animateSuccessTip { + 0% { + width: 0; + left: 1px; + top: 19px; } + 54% { + width: 0; + left: 1px; + top: 19px; } + 70% { + width: 50px; + left: -8px; + top: 37px; } + 84% { + width: 17px; + left: 21px; + top: 48px; } + 100% { + width: 25px; + left: 14px; + top: 45px; } } +@-webkit-keyframes animateSuccessLong { + 0% { + width: 0; + right: 46px; + top: 54px; } + 65% { + width: 0; + right: 46px; + top: 54px; } + 84% { + width: 55px; + right: 0px; + top: 35px; } + 100% { + width: 47px; + right: 8px; + top: 38px; } } +@keyframes animateSuccessLong { + 0% { + width: 0; + right: 46px; + top: 54px; } + 65% { + width: 0; + right: 46px; + top: 54px; } + 84% { + width: 55px; + right: 0px; + top: 35px; } + 100% { + width: 47px; + right: 8px; + top: 38px; } } +@-webkit-keyframes rotatePlaceholder { + 0% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); } + 5% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); } + 12% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); } + 100% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); } } +@keyframes rotatePlaceholder { + 0% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); } + 5% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); } + 12% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); } + 100% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); } } +.animateSuccessTip { + -webkit-animation: animateSuccessTip 0.75s; + animation: animateSuccessTip 0.75s; } + +.animateSuccessLong { + -webkit-animation: animateSuccessLong 0.75s; + animation: animateSuccessLong 0.75s; } + +.icon.success.animate::after { + -webkit-animation: rotatePlaceholder 4.25s ease-in; + animation: rotatePlaceholder 4.25s ease-in; } + +@-webkit-keyframes animateErrorIcon { + 0% { + transform: rotateX(100deg); + -webkit-transform: rotateX(100deg); + opacity: 0; } + 100% { + transform: rotateX(0deg); + -webkit-transform: rotateX(0deg); + opacity: 1; } } +@keyframes animateErrorIcon { + 0% { + transform: rotateX(100deg); + -webkit-transform: rotateX(100deg); + opacity: 0; } + 100% { + transform: rotateX(0deg); + -webkit-transform: rotateX(0deg); + opacity: 1; } } +.animateErrorIcon { + -webkit-animation: animateErrorIcon 0.5s; + animation: animateErrorIcon 0.5s; } + +@-webkit-keyframes animateXMark { + 0% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; } + 50% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; } + 80% { + transform: scale(1.15); + -webkit-transform: scale(1.15); + margin-top: -6px; } + 100% { + transform: scale(1); + -webkit-transform: scale(1); + margin-top: 0; + opacity: 1; } } +@keyframes animateXMark { + 0% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; } + 50% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; } + 80% { + transform: scale(1.15); + -webkit-transform: scale(1.15); + margin-top: -6px; } + 100% { + transform: scale(1); + -webkit-transform: scale(1); + margin-top: 0; + opacity: 1; } } +.animateXMark { + -webkit-animation: animateXMark 0.5s; + animation: animateXMark 0.5s; } + +@-webkit-keyframes pulseWarning { + 0% { + border-color: #F8D486; } + 100% { + border-color: #F8BB86; } } +@keyframes pulseWarning { + 0% { + border-color: #F8D486; } + 100% { + border-color: #F8BB86; } } +.pulseWarning { + -webkit-animation: pulseWarning 0.75s infinite alternate; + animation: pulseWarning 0.75s infinite alternate; } + +@-webkit-keyframes pulseWarningIns { + 0% { + background-color: #F8D486; } + 100% { + background-color: #F8BB86; } } +@keyframes pulseWarningIns { + 0% { + background-color: #F8D486; } + 100% { + background-color: #F8BB86; } } +.pulseWarningIns { + -webkit-animation: pulseWarningIns 0.75s infinite alternate; + animation: pulseWarningIns 0.75s infinite alternate; } diff --git a/modules/backend/assets/vendor/sweet-alert/sweet-alert-combine.less b/modules/backend/assets/vendor/sweet-alert/sweet-alert-combine.less new file mode 100644 index 0000000..2b9296c --- /dev/null +++ b/modules/backend/assets/vendor/sweet-alert/sweet-alert-combine.less @@ -0,0 +1,7 @@ +/* + SweetAlert for Bootstrap + https://github.com/lipis/bootstrap-sweetalert + */ +@import "../../../../system/assets/vendor/bootstrap/variables"; +@import "../../../../system/assets/vendor/bootstrap/mixins"; +@import "sweet-alert"; diff --git a/modules/backend/assets/vendor/sweet-alert/sweet-alert.css b/modules/backend/assets/vendor/sweet-alert/sweet-alert.css new file mode 100644 index 0000000..7075866 --- /dev/null +++ b/modules/backend/assets/vendor/sweet-alert/sweet-alert.css @@ -0,0 +1,564 @@ +@-webkit-keyframes showSweetAlert { + 0% { + transform: scale(0.7); + -webkit-transform: scale(0.7); + } + 45% { + transform: scale(1.05); + -webkit-transform: scale(1.05); + } + 80% { + transform: scale(0.95); + -webkit-tranform: scale(0.95); + } + 100% { + transform: scale(1); + -webkit-transform: scale(1); + } +} +@keyframes showSweetAlert { + 0% { + transform: scale(0.7); + -webkit-transform: scale(0.7); + } + 45% { + transform: scale(1.05); + -webkit-transform: scale(1.05); + } + 80% { + transform: scale(0.95); + -webkit-tranform: scale(0.95); + } + 100% { + transform: scale(1); + -webkit-transform: scale(1); + } +} +@-webkit-keyframes hideSweetAlert { + 0% { + transform: scale(1); + -webkit-transform: scale(1); + } + 100% { + transform: scale(0.5); + -webkit-transform: scale(0.5); + } +} +@keyframes hideSweetAlert { + 0% { + transform: scale(1); + -webkit-transform: scale(1); + } + 100% { + transform: scale(0.5); + -webkit-transform: scale(0.5); + } +} +.showSweetAlert { + -webkit-animation: showSweetAlert 0.3s; + animation: showSweetAlert 0.3s; +} +.hideSweetAlert { + -webkit-animation: hideSweetAlert 0.2s; + animation: hideSweetAlert 0.2s; +} +@-webkit-keyframes animateSuccessTip { + 0% { + width: 0; + left: 1px; + top: 19px; + } + 54% { + width: 0; + left: 1px; + top: 19px; + } + 70% { + width: 50px; + left: -8px; + top: 37px; + } + 84% { + width: 17px; + left: 21px; + top: 48px; + } + 100% { + width: 25px; + left: 14px; + top: 45px; + } +} +@keyframes animateSuccessTip { + 0% { + width: 0; + left: 1px; + top: 19px; + } + 54% { + width: 0; + left: 1px; + top: 19px; + } + 70% { + width: 50px; + left: -8px; + top: 37px; + } + 84% { + width: 17px; + left: 21px; + top: 48px; + } + 100% { + width: 25px; + left: 14px; + top: 45px; + } +} +@-webkit-keyframes animateSuccessLong { + 0% { + width: 0; + right: 46px; + top: 54px; + } + 65% { + width: 0; + right: 46px; + top: 54px; + } + 84% { + width: 55px; + right: 0px; + top: 35px; + } + 100% { + width: 47px; + right: 8px; + top: 38px; + } +} +@keyframes animateSuccessLong { + 0% { + width: 0; + right: 46px; + top: 54px; + } + 65% { + width: 0; + right: 46px; + top: 54px; + } + 84% { + width: 55px; + right: 0px; + top: 35px; + } + 100% { + width: 47px; + right: 8px; + top: 38px; + } +} +@-webkit-keyframes rotatePlaceholder { + 0% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); + } + 5% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); + } + 12% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); + } + 100% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); + } +} +@keyframes rotatePlaceholder { + 0% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); + } + 5% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); + } + 12% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); + } + 100% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); + } +} +.animateSuccessTip { + -webkit-animation: animateSuccessTip 0.75s; + animation: animateSuccessTip 0.75s; +} +.animateSuccessLong { + -webkit-animation: animateSuccessLong 0.75s; + animation: animateSuccessLong 0.75s; +} +.icon.success.animate::after { + -webkit-animation: rotatePlaceholder 4.25s ease-in; + animation: rotatePlaceholder 4.25s ease-in; +} +@-webkit-keyframes animateErrorIcon { + 0% { + transform: rotateX(100deg); + -webkit-transform: rotateX(100deg); + opacity: 0; + } + 100% { + transform: rotateX(0deg); + -webkit-transform: rotateX(0deg); + opacity: 1; + } +} +@keyframes animateErrorIcon { + 0% { + transform: rotateX(100deg); + -webkit-transform: rotateX(100deg); + opacity: 0; + } + 100% { + transform: rotateX(0deg); + -webkit-transform: rotateX(0deg); + opacity: 1; + } +} +.animateErrorIcon { + -webkit-animation: animateErrorIcon 0.5s; + animation: animateErrorIcon 0.5s; +} +@-webkit-keyframes animateXMark { + 0% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; + } + 50% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; + } + 80% { + transform: scale(1.15); + -webkit-transform: scale(1.15); + margin-top: -6px; + } + 100% { + transform: scale(1); + -webkit-transform: scale(1); + margin-top: 0; + opacity: 1; + } +} +@keyframes animateXMark { + 0% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; + } + 50% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; + } + 80% { + transform: scale(1.15); + -webkit-transform: scale(1.15); + margin-top: -6px; + } + 100% { + transform: scale(1); + -webkit-transform: scale(1); + margin-top: 0; + opacity: 1; + } +} +.animateXMark { + -webkit-animation: animateXMark 0.5s; + animation: animateXMark 0.5s; +} +@-webkit-keyframes pulseWarning { + 0% { + border-color: #F8D486; + } + 100% { + border-color: #F8BB86; + } +} +@keyframes pulseWarning { + 0% { + border-color: #F8D486; + } + 100% { + border-color: #F8BB86; + } +} +.pulseWarning { + -webkit-animation: pulseWarning 0.75s infinite alternate; + animation: pulseWarning 0.75s infinite alternate; +} +@-webkit-keyframes pulseWarningIns { + 0% { + background-color: #F8D486; + } + 100% { + background-color: #F8BB86; + } +} +@keyframes pulseWarningIns { + 0% { + background-color: #F8D486; + } + 100% { + background-color: #F8BB86; + } +} +.pulseWarningIns { + -webkit-animation: pulseWarningIns 0.75s infinite alternate; + animation: pulseWarningIns 0.75s infinite alternate; +} +.sweet-overlay { + background-color: rgba(0, 0, 0, 0.4); + position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; + display: none; + z-index: 1040; +} +.sweet-alert { + background-color: #ffffff; + width: 478px; + padding: 17px; + border-radius: 5px; + text-align: center; + position: fixed; + left: 50%; + top: 50%; + margin-left: -256px; + margin-top: -200px; + overflow: hidden; + display: none; + z-index: 2000; +} +@media all and (max-width: 767px) { + .sweet-alert { + width: auto; + margin-left: 0; + margin-right: 0; + left: 15px; + right: 15px; + } +} +.sweet-alert .icon { + width: 80px; + height: 80px; + border: 4px solid gray; + border-radius: 50%; + margin: 20px auto; + position: relative; + box-sizing: content-box; +} +.sweet-alert .icon.error { + border-color: #d43f3a; +} +.sweet-alert .icon.error .x-mark { + position: relative; + display: block; +} +.sweet-alert .icon.error .line { + position: absolute; + height: 5px; + width: 47px; + background-color: #d9534f; + display: block; + top: 37px; + border-radius: 2px; +} +.sweet-alert .icon.error .line.left { + -webkit-transform: rotate(45deg); + transform: rotate(45deg); + left: 17px; +} +.sweet-alert .icon.error .line.right { + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + right: 16px; +} +.sweet-alert .icon.warning { + border-color: #eea236; +} +.sweet-alert .icon.warning .body { + position: absolute; + width: 5px; + height: 47px; + left: 50%; + top: 10px; + border-radius: 2px; + margin-left: -2px; + background-color: #f0ad4e; +} +.sweet-alert .icon.warning .dot { + position: absolute; + width: 7px; + height: 7px; + border-radius: 50%; + margin-left: -3px; + left: 50%; + bottom: 10px; + background-color: #f0ad4e; +} +.sweet-alert .icon.info { + border-color: #46b8da; +} +.sweet-alert .icon.info::before { + content: ""; + position: absolute; + width: 5px; + height: 29px; + left: 50%; + bottom: 17px; + border-radius: 2px; + margin-left: -2px; + background-color: #5bc0de; +} +.sweet-alert .icon.info::after { + content: ""; + position: absolute; + width: 7px; + height: 7px; + border-radius: 50%; + margin-left: -3px; + top: 19px; + background-color: #5bc0de; +} +.sweet-alert .icon.success { + border-color: #4cae4c; +} +.sweet-alert .icon.success::before, +.sweet-alert .icon.success::after { + content: ''; + border-radius: 50%; + position: absolute; + width: 60px; + height: 120px; + background: white; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); +} +.sweet-alert .icon.success::before { + border-radius: 120px 0 0 120px; + top: -7px; + left: -33px; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + -webkit-transform-origin: 60px 60px; + transform-origin: 60px 60px; +} +.sweet-alert .icon.success::after { + border-radius: 0 120px 120px 0; + top: -11px; + left: 30px; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + -webkit-transform-origin: 0px 60px; + transform-origin: 0px 60px; +} +.sweet-alert .icon.success .placeholder { + width: 80px; + height: 80px; + border: 4px solid rgba(92, 184, 92, 0.2); + border-radius: 50%; + box-sizing: content-box; + position: absolute; + left: -4px; + top: -4px; + z-index: 2; +} +.sweet-alert .icon.success .fix { + width: 5px; + height: 90px; + background-color: #ffffff; + position: absolute; + left: 28px; + top: 8px; + z-index: 1; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); +} +.sweet-alert .icon.success .line { + height: 5px; + background-color: #5cb85c; + display: block; + border-radius: 2px; + position: absolute; + z-index: 2; +} +.sweet-alert .icon.success .line.tip { + width: 25px; + left: 14px; + top: 46px; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); +} +.sweet-alert .icon.success .line.long { + width: 47px; + right: 8px; + top: 38px; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); +} +.sweet-alert .icon.custom { + background-size: contain; + border-radius: 0; + border: none; + background-position: center center; + background-repeat: no-repeat; +} +.sweet-alert .btn-default:focus { + border-color: #cccccc; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(204, 204, 204, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(204, 204, 204, 0.6); +} +.sweet-alert .btn-success:focus { + border-color: #4cae4c; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(76, 174, 76, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(76, 174, 76, 0.6); +} +.sweet-alert .btn-info:focus { + border-color: #46b8da; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(70, 184, 218, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(70, 184, 218, 0.6); +} +.sweet-alert .btn-danger:focus { + border-color: #d43f3a; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(212, 63, 58, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(212, 63, 58, 0.6); +} +.sweet-alert .btn-warning:focus { + border-color: #eea236; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(238, 162, 54, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(238, 162, 54, 0.6); +} +.sweet-alert button::-moz-focus-inner { + border: 0; +} diff --git a/modules/backend/assets/vendor/sweet-alert/sweet-alert.html b/modules/backend/assets/vendor/sweet-alert/sweet-alert.html new file mode 100644 index 0000000..c1067fc --- /dev/null +++ b/modules/backend/assets/vendor/sweet-alert/sweet-alert.html @@ -0,0 +1,39 @@ + + +
+ + + +
+ +
+ + + + +
+ +
+ + +
+ +
+ +
+ + +
+
+
+ +
+ + +

Title

+

Text

+

+ + +

+
diff --git a/modules/backend/assets/vendor/sweet-alert/sweet-alert.js b/modules/backend/assets/vendor/sweet-alert/sweet-alert.js new file mode 100644 index 0000000..65c1d6f --- /dev/null +++ b/modules/backend/assets/vendor/sweet-alert/sweet-alert.js @@ -0,0 +1,751 @@ +// SweetAlert +// 2014 (c) - Tristan Edwards +// github.com/t4t5/sweetalert +(function(window, document) { + + var modalClass = '.sweet-alert', + overlayClass = '.sweet-overlay', + alertTypes = ['error', 'warning', 'info', 'success'], + defaultParams = { + title: '', + text: '', + type: null, + allowOutsideClick: false, + showCancelButton: false, + showConfirmButton: true, + closeOnConfirm: true, + closeOnCancel: true, + confirmButtonText: 'OK', + confirmButtonClass: 'btn-primary', + cancelButtonText: 'Cancel', + cancelButtonClass: 'btn-default', + containerClass: '', + titleClass: '', + textClass: '', + imageUrl: null, + imageSize: null, + timer: null + }; + + + /* + * Manipulate DOM + */ + + var getModal = function() { + return document.querySelector(modalClass); + }, + getOverlay = function() { + return document.querySelector(overlayClass); + }, + hasClass = function(elem, className) { + return new RegExp(' ' + className + ' ').test(' ' + elem.className + ' '); + }, + addClass = function(elem, className) { + if (className && !hasClass(elem, className)) { + elem.className += ' ' + className; + } + }, + removeClass = function(elem, className) { + var newClass = ' ' + elem.className.replace(/[\t\r\n]/g, ' ') + ' '; + if (hasClass(elem, className)) { + while (newClass.indexOf(' ' + className + ' ') >= 0) { + newClass = newClass.replace(' ' + className + ' ', ' '); + } + elem.className = newClass.replace(/^\s+|\s+$/g, ''); + } + }, + escapeHtml = function(str) { + var div = document.createElement('div'); + div.appendChild(document.createTextNode(str)); + return div.innerHTML; + }, + _show = function(elem) { + elem.style.opacity = ''; + elem.style.display = 'block'; + }, + show = function(elems) { + if (elems && !elems.length) { + return _show(elems); + } + for (var i = 0; i < elems.length; ++i) { + _show(elems[i]); + } + }, + _hide = function(elem) { + elem.style.opacity = ''; + elem.style.display = 'none'; + }, + hide = function(elems) { + if (elems && !elems.length) { + return _hide(elems); + } + for (var i = 0; i < elems.length; ++i) { + _hide(elems[i]); + } + }, + isDescendant = function(parent, child) { + var node = child.parentNode; + while (node !== null) { + if (node === parent) { + return true; + } + node = node.parentNode; + } + return false; + }, + getTopMargin = function(elem) { + elem.style.left = '-9999px'; + elem.style.display = 'block'; + + var height = elem.clientHeight; + var padding = parseInt(getComputedStyle(elem).getPropertyValue('padding'), 10); + + elem.style.left = ''; + elem.style.display = 'none'; + return ('-' + parseInt(height / 2 + padding) + 'px'); + }, + fadeIn = function(elem, interval) { + if(+elem.style.opacity < 1) { + interval = interval || 16; + elem.style.opacity = 0; + elem.style.display = 'block'; + var last = +new Date(); + var tick = function() { + elem.style.opacity = +elem.style.opacity + (new Date() - last) / 100; + last = +new Date(); + + if (+elem.style.opacity < 1) { + setTimeout(tick, interval); + } + }; + tick(); + } + }, + fadeOut = function(elem, interval) { + interval = interval || 16; + elem.style.opacity = 1; + var last = +new Date(); + var tick = function() { + elem.style.opacity = +elem.style.opacity - (new Date() - last) / 100; + last = +new Date(); + + if (+elem.style.opacity > 0) { + setTimeout(tick, interval); + } else { + elem.style.display = 'none'; + } + }; + tick(); + }, + fireClick = function(node) { + // Taken from http://www.nonobtrusive.com/2011/11/29/programatically-fire-crossbrowser-click-event-with-javascript/ + // Then fixed for today's Chrome browser. + if (MouseEvent) { + // Up-to-date approach + var mevt = new MouseEvent('click', { + view: window, + bubbles: false, + cancelable: true + }); + node.dispatchEvent(mevt); + } else if ( document.createEvent ) { + // Fallback + var evt = document.createEvent('MouseEvents'); + evt.initEvent('click', false, false); + node.dispatchEvent(evt); + } else if( document.createEventObject ) { + node.fireEvent('onclick') ; + } else if (typeof node.onclick === 'function' ) { + node.onclick(); + } + }, + stopEventPropagation = function(e) { + // In particular, make sure the space bar doesn't scroll the main window. + if (typeof e.stopPropagation === 'function') { + e.stopPropagation(); + e.preventDefault(); + } else if (window.event && window.event.hasOwnProperty('cancelBubble')) { + window.event.cancelBubble = true; + } + }; + + // Remember state in cases where opening and handling a modal will fiddle with it. + var previousActiveElement, + previousDocumentClick, + previousWindowKeyDown, + lastFocusedButton; + + /* + * Add modal + overlay to DOM + */ + + window.sweetAlertInitialize = function() { + var sweetHTML = '

Title

Text

', + sweetWrap = document.createElement('div'); + + sweetWrap.innerHTML = sweetHTML; + + // For readability: check sweet-alert.html + document.body.appendChild(sweetWrap); + + // For development use only! + /*jQuery.ajax({ + url: '../lib/sweet-alert.html', // Change path depending on file location + dataType: 'html' + }) + .done(function(html) { + jQuery('body').append(html); + });*/ + } + + /* + * Global sweetAlert function + */ + + window.sweetAlert = window.swal = function() { + if (arguments[0] === undefined) { + window.console.error('sweetAlert expects at least 1 attribute!'); + return false; + } + + var params = extend({}, defaultParams); + + switch (typeof arguments[0]) { + + case 'string': + params.title = arguments[0]; + params.text = arguments[1] || ''; + params.type = arguments[2] || ''; + + break; + + case 'object': + if (arguments[0].title === undefined) { + window.console.error('Missing "title" argument!'); + return false; + } + + params.title = arguments[0].title; + params.text = arguments[0].text || defaultParams.text; + params.type = arguments[0].type || defaultParams.type; + params.allowOutsideClick = arguments[0].allowOutsideClick || defaultParams.allowOutsideClick; + params.showCancelButton = arguments[0].showCancelButton !== undefined ? arguments[0].showCancelButton : defaultParams.showCancelButton; + params.showConfirmButton = arguments[0].showConfirmButton !== undefined ? arguments[0].showConfirmButton : defaultParams.showConfirmButton; + params.closeOnConfirm = arguments[0].closeOnConfirm !== undefined ? arguments[0].closeOnConfirm : defaultParams.closeOnConfirm; + params.closeOnCancel = arguments[0].closeOnCancel !== undefined ? arguments[0].closeOnCancel : defaultParams.closeOnCancel; + params.timer = arguments[0].timer || defaultParams.timer; + + // Show "Confirm" instead of "OK" if cancel button is visible + params.confirmButtonText = (defaultParams.showCancelButton) ? 'Confirm' : defaultParams.confirmButtonText; + params.confirmButtonText = arguments[0].confirmButtonText || defaultParams.confirmButtonText; + params.confirmButtonClass = arguments[0].confirmButtonClass || (arguments[0].type ? 'btn-' + arguments[0].type : null) || defaultParams.confirmButtonClass; + params.cancelButtonText = arguments[0].cancelButtonText || defaultParams.cancelButtonText; + params.cancelButtonClass = arguments[0].cancelButtonClass || defaultParams.cancelButtonClass; + params.containerClass = arguments[0].containerClass || defaultParams.containerClass; + params.titleClass = arguments[0].titleClass || defaultParams.titleClass; + params.textClass = arguments[0].textClass || defaultParams.textClass; + params.imageUrl = arguments[0].imageUrl || defaultParams.imageUrl; + params.imageSize = arguments[0].imageSize || defaultParams.imageSize; + params.doneFunction = arguments[1] || null; + + break; + + default: + window.console.error('Unexpected type of argument! Expected "string" or "object", got ' + typeof arguments[0]); + return false; + + } + + setParameters(params); + fixVerticalPosition(); + openModal(); + + + // Modal interactions + var modal = getModal(); + + // Mouse interactions + var onButtonEvent = function(e) { + + var target = e.target || e.srcElement, + targetedConfirm = (target.className.indexOf('confirm') > -1), + modalIsVisible = hasClass(modal, 'visible'), + doneFunctionExists = (params.doneFunction && modal.getAttribute('data-has-done-function') === 'true'); + + switch (e.type) { + case ("click"): + if (targetedConfirm && doneFunctionExists && modalIsVisible) { // Clicked "confirm" + + params.doneFunction(true); + + if (params.closeOnConfirm) { + closeModal(); + } + } else if (doneFunctionExists && modalIsVisible) { // Clicked "cancel" + + // Check if callback function expects a parameter (to track cancel actions) + var functionAsStr = String(params.doneFunction).replace(/\s/g, ''); + var functionHandlesCancel = functionAsStr.substring(0, 9) === "function(" && functionAsStr.substring(9, 10) !== ")"; + + if (functionHandlesCancel) { + params.doneFunction(false); + } + + if (params.closeOnCancel) { + closeModal(); + } + } else { + closeModal(); + } + + break; + } + }; + + var $buttons = modal.querySelectorAll('button'); + for (var i = 0; i < $buttons.length; i++) { + $buttons[i].onclick = onButtonEvent; + } + + // Remember the current document.onclick event. + previousDocumentClick = document.onclick; + document.onclick = function(e) { + var target = e.target || e.srcElement; + + var clickedOnModal = (modal === target), + clickedOnModalChild = isDescendant(modal, e.target), + modalIsVisible = hasClass(modal, 'visible'), + outsideClickIsAllowed = modal.getAttribute('data-allow-ouside-click') === 'true'; + + if (!clickedOnModal && !clickedOnModalChild && modalIsVisible && outsideClickIsAllowed) { + closeModal(); + } + }; + + + // Keyboard interactions + var $okButton = modal.querySelector('button.confirm'), + $cancelButton = modal.querySelector('button.cancel'), + $modalButtons = modal.querySelectorAll('button:not([type=hidden])'); + + + function handleKeyDown(e) { + var keyCode = e.keyCode || e.which; + + if ([9,13,32,27].indexOf(keyCode) === -1) { + // Don't do work on keys we don't care about. + return; + } + + var $targetElement = e.target || e.srcElement; + + var btnIndex = -1; // Find the button - note, this is a nodelist, not an array. + for (var i = 0; i < $modalButtons.length; i++) { + if ($targetElement === $modalButtons[i]) { + btnIndex = i; + break; + } + } + + if (keyCode === 9) { + // TAB + if (btnIndex === -1) { + // No button focused. Jump to the confirm button. + $targetElement = $okButton; + } else { + // Cycle to the next button + if (btnIndex === $modalButtons.length - 1) { + $targetElement = $modalButtons[0]; + } else { + $targetElement = $modalButtons[btnIndex + 1]; + } + } + + stopEventPropagation(e); + $targetElement.focus(); + + } else { + if (keyCode === 13 || keyCode === 32) { + if (btnIndex === -1) { + // ENTER/SPACE clicked outside of a button. + $targetElement = $okButton; + } else { + // Do nothing - let the browser handle it. + $targetElement = undefined; + } + } else if (keyCode === 27 && !($cancelButton.hidden || $cancelButton.style.display === 'none')) { + // ESC to cancel only if there's a cancel button displayed (like the alert() window). + $targetElement = $cancelButton; + } else { + // Fallback - let the browser handle it. + $targetElement = undefined; + } + + if ($targetElement !== undefined) { + fireClick($targetElement, e); + } + } + } + + previousWindowKeyDown = window.onkeydown; + window.onkeydown = handleKeyDown; + + function handleOnBlur(e) { + var $targetElement = e.target || e.srcElement, + $focusElement = e.relatedTarget, + modalIsVisible = hasClass(modal, 'visible'), + bootstrapModalIsVisible = document.querySelector('.control-popup.modal') || false; + + if (bootstrapModalIsVisible) { + // Bootstrap will enforce focus on the existing model, so don't + // do anything here to prevent infinite loop. + return; + } + + if (modalIsVisible) { + var btnIndex = -1; // Find the button - note, this is a nodelist, not an array. + + if ($focusElement !== null) { + // If we picked something in the DOM to focus to, let's see if it was a button. + for (var i = 0; i < $modalButtons.length; i++) { + if ($focusElement === $modalButtons[i]) { + btnIndex = i; + break; + } + } + + if (btnIndex === -1) { + // Something in the dom, but not a visible button. Focus back on the button. + $targetElement.focus(); + } + } else { + // Exiting the DOM (e.g. clicked in the URL bar); + lastFocusedButton = $targetElement; + } + } + } + + $okButton.onblur = handleOnBlur; + $cancelButton.onblur = handleOnBlur; + + window.onfocus = function() { + // When the user has focused away and focused back from the whole window. + window.setTimeout(function() { + // Put in a timeout to jump out of the event sequence. Calling focus() in the event + // sequence confuses things. + if (lastFocusedButton !== undefined) { + lastFocusedButton.focus(); + lastFocusedButton = undefined; + } + }, 0); + }; + }; + + /** + * Set default params for each popup + * @param {Object} userParams + */ + window.swal.setDefaults = function(userParams) { + if (!userParams) { + throw new Error('userParams is required'); + } + if (typeof userParams !== 'object') { + throw new Error('userParams has to be a object'); + } + + extend(defaultParams, userParams); + }; + + /** + * Closes the current modal + */ + window.swal.close = function() { + closeModal(); + } + + /* + * Set type, text and actions on modal + */ + + function setParameters(params) { + var modal = getModal(); + + var $title = modal.querySelector('h2'), + $text = modal.querySelector('p'), + $cancelBtn = modal.querySelector('button.cancel'), + $confirmBtn = modal.querySelector('button.confirm'); + + // Title + $title.innerHTML = escapeHtml(params.title).split("\n").join("
"); + + // Text + $text.innerHTML = escapeHtml(params.text || '').split("\n").join("
"); + if (params.text) { + show($text); + } + + // Icon + hide(modal.querySelectorAll('.icon')); + if (params.type) { + var validType = false; + for (var i = 0; i < alertTypes.length; i++) { + if (params.type === alertTypes[i]) { + validType = true; + break; + } + } + if (!validType) { + window.console.error('Unknown alert type: ' + params.type); + return false; + } + var $icon = modal.querySelector('.icon.' + params.type); + show($icon); + + // Animate icon + switch (params.type) { + case "success": + addClass($icon, 'animate'); + addClass($icon.querySelector('.tip'), 'animateSuccessTip'); + addClass($icon.querySelector('.long'), 'animateSuccessLong'); + break; + case "error": + addClass($icon, 'animateErrorIcon'); + addClass($icon.querySelector('.x-mark'), 'animateXMark'); + break; + case "warning": + addClass($icon, 'pulseWarning'); + addClass($icon.querySelector('.body'), 'pulseWarningIns'); + addClass($icon.querySelector('.dot'), 'pulseWarningIns'); + break; + } + + } + + // Custom image + if (params.imageUrl) { + var $customIcon = modal.querySelector('.icon.custom'); + + $customIcon.style.backgroundImage = 'url(' + params.imageUrl + ')'; + show($customIcon); + + var _imgWidth = 80, + _imgHeight = 80; + + if (params.imageSize) { + var imgWidth = params.imageSize.split('x')[0]; + var imgHeight = params.imageSize.split('x')[1]; + + if (!imgWidth || !imgHeight) { + window.console.error("Parameter imageSize expects value with format WIDTHxHEIGHT, got " + params.imageSize); + } else { + _imgWidth = imgWidth; + _imgHeight = imgHeight; + + $customIcon.css({ + 'width': imgWidth + 'px', + 'height': imgHeight + 'px' + }); + } + } + $customIcon.setAttribute('style', $customIcon.getAttribute('style') + 'width:' + _imgWidth + 'px; height:' + _imgHeight + 'px'); + } + + // Cancel button + modal.setAttribute('data-has-cancel-button', params.showCancelButton); + if (params.showCancelButton) { + $cancelBtn.style.display = 'inline-block'; + } else { + hide($cancelBtn); + } + + // Confirm button + modal.setAttribute('data-has-confirm-button', params.showConfirmButton); + if (params.showConfirmButton) { + $confirmBtn.style.display = 'inline-block'; + } else { + hide($confirmBtn); + } + + + // Edit text on cancel and confirm buttons + if (params.cancelButtonText) { + $cancelBtn.innerHTML = escapeHtml(params.cancelButtonText); + } + if (params.confirmButtonText) { + $confirmBtn.innerHTML = escapeHtml(params.confirmButtonText); + } + + // Reset confirm buttons to default class (Ugly fix) + $confirmBtn.className = 'confirm btn' + + // Attach selected class to the sweet alert modal + addClass(modal, params.containerClass); + + // Set confirm button to selected class + addClass($confirmBtn, params.confirmButtonClass); + + // Set cancel button to selected class + addClass($cancelBtn, params.cancelButtonClass); + + // Set title to selected class + addClass($title, params.titleClass); + + // Set text to selected class + addClass($text, params.textClass); + + // Allow outside click? + modal.setAttribute('data-allow-ouside-click', params.allowOutsideClick); + + // Done-function + var hasDoneFunction = (params.doneFunction) ? true : false; + modal.setAttribute('data-has-done-function', hasDoneFunction); + + // Close timer + modal.setAttribute('data-timer', params.timer); + } + + + /* + * Set hover, active and focus-states for buttons (source: http://www.sitepoint.com/javascript-generate-lighter-darker-color) + */ + + function colorLuminance(hex, lum) { + // Validate hex string + hex = String(hex).replace(/[^0-9a-f]/gi, ''); + if (hex.length < 6) { + hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2]; + } + lum = lum || 0; + + // Convert to decimal and change luminosity + var rgb = "#", c, i; + for (i = 0; i < 3; i++) { + c = parseInt(hex.substr(i*2,2), 16); + c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16); + rgb += ("00"+c).substr(c.length); + } + + return rgb; + } + + function extend(a, b){ + for (var key in b) { + if (b.hasOwnProperty(key)) { + a[key] = b[key]; + } + } + + return a; + } + + function hexToRgb(hex) { + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? parseInt(result[1], 16) + ', ' + parseInt(result[2], 16) + ', ' + parseInt(result[3], 16) : null; + } + + // Add box-shadow style to button (depending on its chosen bg-color) + function setFocusStyle($button, bgColor) { + var rgbColor = hexToRgb(bgColor); + $button.style.boxShadow = '0 0 2px rgba(' + rgbColor +', 0.8), inset 0 0 0 1px rgba(0, 0, 0, 0.05)'; + } + + + /* + * Animations + */ + + function openModal() { + var modal = getModal(); + fadeIn(getOverlay(), 10); + show(modal); + addClass(modal, 'showSweetAlert'); + removeClass(modal, 'hideSweetAlert'); + + previousActiveElement = document.activeElement; + var $okButton = modal.querySelector('button.confirm'); + $okButton.focus(); + + setTimeout(function() { + addClass(modal, 'visible'); + }, 500); + + var timer = modal.getAttribute('data-timer'); + if (timer !== "null" && timer !== "") { + setTimeout(function() { + closeModal(); + }, timer); + } + } + + function closeModal() { + var modal = getModal(); + fadeOut(getOverlay(), 5); + fadeOut(modal, 5); + removeClass(modal, 'showSweetAlert'); + addClass(modal, 'hideSweetAlert'); + removeClass(modal, 'visible'); + + + // Reset icon animations + + var $successIcon = modal.querySelector('.icon.success'); + removeClass($successIcon, 'animate'); + removeClass($successIcon.querySelector('.tip'), 'animateSuccessTip'); + removeClass($successIcon.querySelector('.long'), 'animateSuccessLong'); + + var $errorIcon = modal.querySelector('.icon.error'); + removeClass($errorIcon, 'animateErrorIcon'); + removeClass($errorIcon.querySelector('.x-mark'), 'animateXMark'); + + var $warningIcon = modal.querySelector('.icon.warning'); + removeClass($warningIcon, 'pulseWarning'); + removeClass($warningIcon.querySelector('.body'), 'pulseWarningIns'); + removeClass($warningIcon.querySelector('.dot'), 'pulseWarningIns'); + + + // Reset the page to its previous state + window.onkeydown = previousWindowKeyDown; + document.onclick = previousDocumentClick; + if (previousActiveElement) { + previousActiveElement.focus(); + } + lastFocusedButton = undefined; + } + + + /* + * Set "margin-top"-property on modal based on its computed height + */ + + function fixVerticalPosition() { + var modal = getModal(); + modal.style.marginTop = getTopMargin(getModal()); + } + + + /* + * If library is injected after page has loaded + */ + + (function () { + if (document.readyState === "complete" || document.readyState === "interactive" && document.body) { + sweetAlertInitialize(); + } else { + if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', function handler() { + document.removeEventListener('DOMContentLoaded', handler, false); + sweetAlertInitialize(); + }, false); + } else if (document.attachEvent) { + document.attachEvent('onreadystatechange', function handler() { + if (document.readyState === 'complete') { + document.detachEvent('onreadystatechange', handler); + sweetAlertInitialize(); + } + }); + } + } + })(); + +})(window, document); diff --git a/modules/backend/assets/vendor/sweet-alert/sweet-alert.less b/modules/backend/assets/vendor/sweet-alert/sweet-alert.less new file mode 100644 index 0000000..7dc68ee --- /dev/null +++ b/modules/backend/assets/vendor/sweet-alert/sweet-alert.less @@ -0,0 +1,254 @@ +// SweetAlert +// 2014 (c) - Tristan Edwards +// github.com/t4t5/sweetalert + +@import "sweet-alert-animations"; + +.sweet-overlay { + background-color: fade(#000, 40%); + + position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; + + display: none; + z-index: @zindex-modal + 7000; +} + +.sweet-alert { + @width: 478px; + @padding: 17px; + + background-color: @body-bg; + width: @width; + padding: @padding; + border-radius: 5px; + text-align: center; + + position: fixed; + left: 50%; + top: 50%; + margin-left: -(@width / 2 + @padding); + margin-top: -200px; + + overflow: hidden; + display: none; + z-index: @zindex-modal + 8000; + + @media all and (max-width: @screen-xs-max) { + width: auto; + margin-left: 0; + margin-right: 0; + + left: (@grid-gutter-width / 2); + right: (@grid-gutter-width / 2); + } + + .icon { + width: 80px; + height: 80px; + border: 4px solid gray; + border-radius: 50%; + margin: 20px auto; + position: relative; + box-sizing: content-box; + + &.error { + border-color: @btn-danger-border; + + .x-mark { + position: relative; + display: block; + } + + .line { + position: absolute; + height: 5px; + width: 47px; + background-color: @btn-danger-bg; + display: block; + top: 37px; + border-radius: 2px; + + &.left { + -webkit-transform: rotate(45deg); + transform: rotate(45deg); + left: 17px; + } + &.right { + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + right: 16px; + } + } + } + &.warning { + border-color: @btn-warning-border; + + .body { // Exclamation mark body + position: absolute; + width: 5px; + height: 47px; + left: 50%; + top: 10px; + border-radius: 2px; + margin-left: -2px; + background-color: @btn-warning-bg; + } + .dot { // Exclamation mark dot + position: absolute; + width: 7px; + height: 7px; + border-radius: 50%; + margin-left: -3px; + left: 50%; + bottom: 10px; + background-color: @btn-warning-bg; + } + } + &.info { + border-color: @btn-info-border; + + &::before { // i-letter body + content: ""; + position: absolute; + width: 5px; + height: 29px; + left: 50%; + bottom: 17px; + border-radius: 2px; + margin-left: -2px; + background-color: @btn-info-bg; + } + &::after { // i-letter dot + content: ""; + position: absolute; + width: 7px; + height: 7px; + border-radius: 50%; + margin-left: -3px; + top: 19px; + background-color: @btn-info-bg; + } + } + &.success { + border-color: @btn-success-border; + + &::before, &::after { // Emulate moving circular line + content: ''; + border-radius: 50%; + position: absolute; + width: 60px; + height: 120px; + background: white; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); + } + &::before { + border-radius: 120px 0 0 120px; + top: -7px; + left: -33px; + + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + -webkit-transform-origin: 60px 60px; + transform-origin: 60px 60px; + } + &::after { + border-radius: 0 120px 120px 0; + top: -11px; + left: 30px; + + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + -webkit-transform-origin: 0px 60px; + transform-origin: 0px 60px; + } + + .placeholder { // Ring + width: 80px; + height: 80px; + border: 4px solid fade(@brand-success, 20%); + border-radius: 50%; + box-sizing: content-box; + + position: absolute; + left: -4px; + top: -4px; + z-index: 2; + } + + .fix { // Hide corners left from animation + width: 5px; + height: 90px; + background-color: @body-bg; + + position: absolute; + left: 28px; + top: 8px; + z-index: 1; + + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + } + + .line { + height: 5px; + background-color: @btn-success-bg; + display: block; + border-radius: 2px; + + position: absolute; + z-index: 2; + + &.tip { + width: 25px; + + left: 14px; + top: 46px; + + -webkit-transform: rotate(45deg); + transform: rotate(45deg); + } + &.long { + width: 47px; + + right: 8px; + top: 38px; + + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + } + } + } + &.custom { + background-size: contain; + border-radius: 0; + border: none; + background-position: center center; + background-repeat: no-repeat; + } + } + + .btn-default { + .form-control-focus(@btn-default-border); + } + .btn-success { + .form-control-focus(@btn-success-border); + } + .btn-info { + .form-control-focus(@btn-info-border); + } + .btn-danger { + .form-control-focus(@btn-danger-border); + } + .btn-warning { + .form-control-focus(@btn-warning-border); + } + + button::-moz-focus-inner { + border: 0; + } +} diff --git a/modules/backend/behaviors/FormController.php b/modules/backend/behaviors/FormController.php new file mode 100644 index 0000000..01bef3b --- /dev/null +++ b/modules/backend/behaviors/FormController.php @@ -0,0 +1,885 @@ +config = $this->makeConfig($controller->formConfig, $this->requiredConfig); + $this->config->modelClass = Str::normalizeClassName($this->config->modelClass); + } + + /** + * Initialize the form configuration against a model and context value. + * This will process the configuration found in the `$formConfig` property + * and prepare the Form widget, which is the underlying tool used for + * actually rendering the form. The model used by this form is passed + * to this behavior via this method as the first argument. + * + * @see \Backend\Widgets\Form + * @param \October\Rain\Database\Model|\October\Rain\Halcyon\Model $model + * @param string $context Form context + * @return void + */ + public function initForm($model, $context = null) + { + if ($context !== null) { + $this->context = $context; + } + + $context = $this->formGetContext(); + + /* + * Each page can supply a unique form definition, if desired + */ + $formFields = $this->getConfig("{$context}[form]", $this->config->form); + + $config = $this->makeConfig($formFields); + $config->model = $model; + $config->arrayName = class_basename($model); + $config->context = $context; + + /* + * Form Widget with extensibility + */ + $this->formWidget = $this->makeWidget('Backend\Widgets\Form', $config); + + // Setup the default preview mode on form initialization if the context is preview + if ($config->context === 'preview') { + $this->formWidget->previewMode = true; + } + + $this->formWidget->bindEvent('form.extendFieldsBefore', function () { + $this->controller->formExtendFieldsBefore($this->formWidget); + }); + + $this->formWidget->bindEvent('form.extendFields', function ($fields) { + $this->controller->formExtendFields($this->formWidget, $fields); + }); + + $this->formWidget->bindEvent('form.beforeRefresh', function ($holder) { + $result = $this->controller->formExtendRefreshData($this->formWidget, $holder->data); + if (is_array($result)) { + $holder->data = $result; + } + }); + + $this->formWidget->bindEvent('form.refreshFields', function ($fields) { + return $this->controller->formExtendRefreshFields($this->formWidget, $fields); + }); + + $this->formWidget->bindEvent('form.refresh', function ($result) { + return $this->controller->formExtendRefreshResults($this->formWidget, $result); + }); + + $this->formWidget->bindToController(); + + /* + * Detected Relation controller behavior + */ + if ($this->controller->isClassExtendedWith('Backend.Behaviors.RelationController')) { + $this->controller->initRelation($model); + } + + $this->prepareVars($model); + $this->model = $model; + } + + /** + * Prepares commonly used view data. + * @param \October\Rain\Database\Model|\October\Rain\Halcyon\Model $model + */ + protected function prepareVars($model) + { + $this->controller->vars['formModel'] = $model; + $this->controller->vars['formContext'] = $this->formGetContext(); + $this->controller->vars['formRecordName'] = Lang::get($this->getConfig('name', 'backend::lang.model.name')); + } + + // + // Create + // + + /** + * Controller "create" action used for creating new model records. + * + * @param string $context Form context + * @return void + */ + public function create($context = null) + { + try { + $this->context = strlen($context) ? $context : $this->getConfig('create[context]', self::CONTEXT_CREATE); + $this->controller->pageTitle = $this->controller->pageTitle ?: $this->getLang( + "{$this->context}[title]", + 'backend::lang.form.create_title' + ); + + $model = $this->controller->formCreateModelObject(); + $model = $this->controller->formExtendModel($model) ?: $model; + + $this->initForm($model); + } + catch (Exception $ex) { + $this->controller->handleError($ex); + } + } + + /** + * AJAX handler "onSave" called from the create action and + * primarily used for creating new records. + * + * This handler will invoke the unique controller overrides + * `formBeforeCreate` and `formAfterCreate`. + * + * @param string $context Form context + * @return \Illuminate\Http\RedirectResponse|void + */ + public function create_onSave($context = null) + { + $this->context = strlen($context) ? $context : $this->getConfig('create[context]', self::CONTEXT_CREATE); + + $model = $this->controller->formCreateModelObject(); + $model = $this->controller->formExtendModel($model) ?: $model; + + $this->initForm($model); + + $this->controller->formBeforeSave($model); + $this->controller->formBeforeCreate($model); + + $modelsToSave = $this->prepareModelsToSave($model, $this->formWidget->getSaveData()); + Db::transaction(function () use ($modelsToSave) { + foreach ($modelsToSave as $modelToSave) { + $modelToSave->save(null, $this->formWidget->getSessionKey()); + } + }); + + $this->controller->formAfterSave($model); + $this->controller->formAfterCreate($model); + + Flash::success($this->getLang("{$this->context}[flashSave]", 'backend::lang.form.create_success')); + + if ($redirect = $this->makeRedirect($this->context, $model)) { + return $redirect; + } + } + + // + // Update + // + + /** + * Controller "update" action used for updating existing model records. + * This action takes a record identifier (primary key of the model) + * to locate the record used for sourcing the existing form values. + * + * @param int $recordId Record identifier + * @param string $context Form context + * @return void + */ + public function update($recordId = null, $context = null) + { + try { + $this->context = strlen($context) ? $context : $this->getConfig('update[context]', self::CONTEXT_UPDATE); + $this->controller->pageTitle = $this->controller->pageTitle ?: $this->getLang( + "{$this->context}[title]", + 'backend::lang.form.update_title' + ); + + $model = $this->controller->formFindModelObject($recordId); + $this->initForm($model); + } + catch (Exception $ex) { + $this->controller->handleError($ex); + } + } + + /** + * AJAX handler "onSave" called from the update action and + * primarily used for updating existing records. + * + * This handler will invoke the unique controller overrides + * `formBeforeUpdate` and `formAfterUpdate`. + * + * @param int $recordId Record identifier + * @param string $context Form context + * @return \Illuminate\Http\RedirectResponse|void + * @throws \October\Rain\Exception\ApplicationException if the provided recordId is not found + */ + public function update_onSave($recordId = null, $context = null) + { + $this->context = strlen($context) ? $context : $this->getConfig('update[context]', self::CONTEXT_UPDATE); + $model = $this->controller->formFindModelObject($recordId); + $this->initForm($model); + + $this->controller->formBeforeSave($model); + $this->controller->formBeforeUpdate($model); + + $modelsToSave = $this->prepareModelsToSave($model, $this->formWidget->getSaveData()); + Db::transaction(function () use ($modelsToSave) { + foreach ($modelsToSave as $modelToSave) { + $modelToSave->save(null, $this->formWidget->getSessionKey()); + } + }); + + $this->controller->formAfterSave($model); + $this->controller->formAfterUpdate($model); + + Flash::success($this->getLang("{$this->context}[flashSave]", 'backend::lang.form.update_success')); + + if ($redirect = $this->makeRedirect($this->context, $model)) { + return $redirect; + } + } + + /** + * AJAX handler "onDelete" called from the update action and + * used for deleting existing records. + * + * This handler will invoke the unique controller override + * `formAfterDelete`. + * + * @param int $recordId Record identifier + * @return \Illuminate\Http\RedirectResponse|void + * @throws \October\Rain\Exception\ApplicationException if the provided recordId is not found + * @throws Exception if there is no primary key on the model + */ + public function update_onDelete($recordId = null) + { + $this->context = $this->getConfig('update[context]', self::CONTEXT_UPDATE); + $model = $this->controller->formFindModelObject($recordId); + $this->initForm($model); + + $model->delete(); + + $this->controller->formAfterDelete($model); + + Flash::success($this->getLang("{$this->context}[flashDelete]", 'backend::lang.form.delete_success')); + + if ($redirect = $this->makeRedirect('delete', $model)) { + return $redirect; + } + } + + // + // Preview + // + + /** + * Controller "preview" action used for viewing existing model records. + * This action takes a record identifier (primary key of the model) + * to locate the record used for sourcing the existing preview data. + * + * @param int $recordId Record identifier + * @param string $context Form context + * @return void + */ + public function preview($recordId = null, $context = null) + { + try { + $this->context = strlen($context) ? $context : $this->getConfig('preview[context]', self::CONTEXT_PREVIEW); + $this->controller->pageTitle = $this->controller->pageTitle ?: $this->getLang( + "{$this->context}[title]", + 'backend::lang.form.preview_title' + ); + + $model = $this->controller->formFindModelObject($recordId); + $this->initForm($model); + } + catch (Exception $ex) { + $this->controller->handleError($ex); + } + } + + // + // Utils + // + + /** + * Method to render the prepared form markup. This method is usually + * called from a view file. + * + * formRender() ?> + * + * The first argument supports an array of render options. The supported + * options can be found via the `render` method of the Form widget class. + * + * formRender(['preview' => true, section' => 'primary']) ?> + * + * @see \Backend\Widgets\Form + * @param array $options Render options + * @return string Rendered HTML for the form. + * @throws \October\Rain\Exception\ApplicationException if the Form Widget isn't set + */ + public function formRender($options = []) + { + if (!$this->formWidget) { + throw new ApplicationException(Lang::get('backend::lang.form.behavior_not_ready')); + } + + return $this->formWidget->render($options); + } + + /** + * Returns the model initialized by this form behavior. + * The model will be provided by one of the page actions or AJAX + * handlers via the `initForm` method. + * + * @return \October\Rain\Database\Model|\October\Rain\Halcyon\Model + */ + public function formGetModel() + { + return $this->model; + } + + /** + * Returns the active form context, either obtained from the postback + * variable called `form_context` or detected from the configuration, + * or routing parameters. + * + * @return string + */ + public function formGetContext() + { + return post('form_context', $this->context); + } + + /** + * Internal method used to prepare the form model object. + * + * @return \October\Rain\Database\Model|\October\Rain\Halcyon\Model + */ + protected function createModel() + { + $class = $this->config->modelClass; + return new $class; + } + + /** + * Returns a Redirect object based on supplied context and parses + * the model primary key. + * + * @param string $context Redirect context, eg: create, update, delete + * @param \October\Rain\Database\Model|\October\Rain\Halcyon\Model $model The active model to parse in it's ID and attributes. + * @return \Illuminate\Http\RedirectResponse + */ + public function makeRedirect($context = null, $model = null) + { + $redirectUrl = null; + if (post('close') && !ends_with($context, '-close')) { + $context .= '-close'; + } + + if (post('refresh', false)) { + return Redirect::refresh(); + } + + if (post('redirect', true)) { + $redirectUrl = $this->controller->formGetRedirectUrl($context, $model); + } + + if ($model && $redirectUrl) { + $redirectUrl = RouterHelper::replaceParameters($model, $redirectUrl); + } + + if (starts_with($redirectUrl, 'http://') || starts_with($redirectUrl, 'https://')) { + // Process absolute redirects + $redirect = Redirect::to($redirectUrl); + } else { + // Process relative redirects + $redirect = $redirectUrl ? Backend::redirect($redirectUrl) : null; + } + + return $redirect; + } + + /** + * Returns a redirect URL from the config based on supplied context. + * Otherwise the default redirect is used. Relative URLs are treated as + * backend URLs. + * + * @param string $context Redirect context, eg: create, update, delete. + * @param Model $model The active model. + * @return string + */ + public function formGetRedirectUrl($context = null, $model = null) + { + $redirectContext = explode('-', $context, 2)[0]; + $redirectSource = ends_with($context, '-close') ? 'redirectClose' : 'redirect'; + + // Get the redirect for the provided context + $redirects = [$context => $this->getConfig("{$redirectContext}[{$redirectSource}]", '')]; + + // Assign the default redirect afterwards to prevent the + // source for the default redirect being default[redirect] + $redirects['default'] = $this->getConfig('defaultRedirect', ''); + + if (empty($redirects[$context])) { + return $redirects['default']; + } + + return $redirects[$context]; + } + + /** + * Parses in some default variables to a language string defined in config. + * + * @param string $name Configuration property containing the language string + * @param string $default A default language string to use if the config is not found + * @param array $extras Any extra params to include in the language string variables + * @return string The translated string. + */ + protected function getLang($name, $default = null, $extras = []) + { + $name = $this->getConfig($name, $default); + $vars = [ + 'name' => Lang::get($this->getConfig('name', 'backend::lang.model.name')) + ]; + $vars = array_merge($vars, $extras); + return Lang::get($name, $vars); + } + + // + // Pass-through Helpers + // + + /** + * View helper to render a single form field. + * + * formRenderField('field_name') ?> + * + * @param string $name Field name + * @param array $options (e.g. ['useContainer'=>false]) + * @return string HTML markup + */ + public function formRenderField($name, $options = []) + { + return $this->formWidget->renderField($name, $options); + } + + /** + * View helper to render the form in preview mode. + * + * formRenderPreview() ?> + * + * @return string The form HTML markup. + * @throws \October\Rain\Exception\ApplicationException if the Form Widget isn't set + */ + public function formRenderPreview() + { + return $this->formRender(['preview' => true]); + } + + /** + * View helper to check if a form tab has fields in the + * non-tabbed section (outside fields). + * + * formHasOutsideFields()): ?> + * + * + * + * @return bool + */ + public function formHasOutsideFields() + { + return $this->formWidget->getTab('outside')->hasFields(); + } + + /** + * View helper to render the form fields belonging to the + * non-tabbed section (outside form fields). + * + * formRenderOutsideFields() ?> + * + * @return string HTML markup + * @throws \October\Rain\Exception\ApplicationException if the Form Widget isn't set + */ + public function formRenderOutsideFields() + { + return $this->formRender(['section' => 'outside']); + } + + /** + * View helper to check if a form tab has fields in the + * primary tab section. + * + * formHasPrimaryTabs()): ?> + * + * + * + * @return bool + */ + public function formHasPrimaryTabs() + { + return $this->formWidget->getTab('primary')->hasFields(); + } + + /** + * View helper to render the form fields belonging to the + * primary tabs section. + * + * formRenderPrimaryTabs() ?> + * + * @return string HTML markup + * @throws \October\Rain\Exception\ApplicationException if the Form Widget isn't set + */ + public function formRenderPrimaryTabs() + { + return $this->formRender(['section' => 'primary']); + } + + /** + * View helper to check if a form tab has fields in the + * secondary tab section. + * + * formHasSecondaryTabs()): ?> + * + * + * + * @return bool + */ + public function formHasSecondaryTabs() + { + return $this->formWidget->getTab('secondary')->hasFields(); + } + + /** + * View helper to render the form fields belonging to the + * secondary tabs section. + * + * formRenderSecondaryTabs() ?> + * + * @return string HTML markup + * @throws \October\Rain\Exception\ApplicationException if the Form Widget isn't set + */ + public function formRenderSecondaryTabs() + { + return $this->formRender(['section' => 'secondary']); + } + + /** + * Returns the form widget used by this behavior. + * + * @return \Backend\Widgets\Form + */ + public function formGetWidget() + { + return $this->formWidget; + } + + /** + * Returns a unique ID for the form widget used by this behavior. + * This is useful for dealing with identifiers in the markup. + * + *
...
+ * + * A suffix may be used passed as the first argument to reuse + * the identifier in other areas. + * + * + * + * @param string $suffix + * @return string + */ + public function formGetId($suffix = null) + { + return $this->formWidget->getId($suffix); + } + + /** + * Helper to get the form session key. + * + * @return string + */ + public function formGetSessionKey() + { + return $this->formWidget->getSessionKey(); + } + + // + // Overrides + // + + /** + * Called before the creation or updating form is saved. + * @param \October\Rain\Database\Model|\October\Rain\Halcyon\Model + */ + public function formBeforeSave($model) + { + } + + /** + * Called after the creation or updating form is saved. + * @param \October\Rain\Database\Model|\October\Rain\Halcyon\Model + */ + public function formAfterSave($model) + { + } + + /** + * Called before the creation form is saved. + * @param \October\Rain\Database\Model|\October\Rain\Halcyon\Model + */ + public function formBeforeCreate($model) + { + } + + /** + * Called after the creation form is saved. + * @param \October\Rain\Database\Model|\October\Rain\Halcyon\Model + */ + public function formAfterCreate($model) + { + } + + /** + * Called before the updating form is saved. + * @param \October\Rain\Database\Model|\October\Rain\Halcyon\Model + */ + public function formBeforeUpdate($model) + { + } + + /** + * Called after the updating form is saved. + * @param \October\Rain\Database\Model|\October\Rain\Halcyon\Model + */ + public function formAfterUpdate($model) + { + } + + /** + * Called after the form model is deleted. + * @param \October\Rain\Database\Model|\October\Rain\Halcyon\Model + */ + public function formAfterDelete($model) + { + } + + /** + * Finds a Model record by its primary identifier, used by update actions. This logic + * can be changed by overriding it in the controller. + * @param string $recordId + * @return \October\Rain\Database\Model|\October\Rain\Halcyon\Model + * @throws \October\Rain\Exception\ApplicationException if the provided recordId is not found + */ + public function formFindModelObject($recordId) + { + if (!strlen($recordId)) { + throw new ApplicationException($this->getLang('not-found-message', 'backend::lang.form.missing_id')); + } + + $model = $this->controller->formCreateModelObject(); + + /* + * Prepare query and find model record + */ + $query = $model->newQuery(); + $this->controller->formExtendQuery($query); + $result = $query->find($recordId); + + if (!$result) { + throw new ApplicationException($this->getLang('not-found-message', 'backend::lang.form.not_found', [ + 'class' => get_class($model), 'id' => $recordId + ])); + } + + $result = $this->controller->formExtendModel($result) ?: $result; + + return $result; + } + + /** + * Creates a new instance of a form model. This logic can be changed + * by overriding it in the controller. + * @return \October\Rain\Database\Model|\October\Rain\Halcyon\Model + */ + public function formCreateModelObject() + { + return $this->createModel(); + } + + /** + * Called before the form fields are defined. + * @param \Backend\Widgets\Form $host The hosting form widget + * @return void + */ + public function formExtendFieldsBefore($host) + { + } + + /** + * Called after the form fields are defined. + * @param \Backend\Widgets\Form $host The hosting form widget + * @param array $fields Array of all defined form field objects (\Backend\Classes\FormField) + * @return void + */ + public function formExtendFields($host, $fields) + { + } + + /** + * Called before the form is refreshed, should return an array of additional save data. + * @param \Backend\Widgets\Form $host The hosting form widget + * @param array $saveData Current save data + * @return array|void + */ + public function formExtendRefreshData($host, $saveData) + { + } + + /** + * Called when the form is refreshed, giving the opportunity to modify the form fields. + * @param \Backend\Widgets\Form $host The hosting form widget + * @param array $fields Current form fields + * @return array|void + */ + public function formExtendRefreshFields($host, $fields) + { + } + + /** + * Called after the form is refreshed, should return an array of additional result parameters. + * @param \Backend\Widgets\Form $host The hosting form widget + * @param array $result Current result parameters. + * @return array|void + */ + public function formExtendRefreshResults($host, $result) + { + } + + /** + * Extend supplied model used by create and update actions, the model can + * be altered by overriding it in the controller. + * @param \October\Rain\Database\Model|\October\Rain\Halcyon\Model $model + * @return \October\Rain\Database\Model|\October\Rain\Halcyon\Model|void + */ + public function formExtendModel($model) + { + } + + /** + * Extend the query used for finding the form model. Extra conditions + * can be applied to the query, for example, $query->withTrashed(); + * @param \October\Rain\Database\Builder|\October\Rain\Halcyon\Builder $query + * @return void + */ + public function formExtendQuery($query) + { + } + + /** + * Static helper for extending form fields. + * @param callable $callback + * @return void + */ + public static function extendFormFields($callback) + { + $calledClass = self::getCalledExtensionClass(); + Event::listen('backend.form.extendFields', function ($widget) use ($calledClass, $callback) { + if (!is_a($widget->getController(), $calledClass)) { + return; + } + call_user_func_array($callback, [$widget, $widget->model, $widget->getContext()]); + }); + } +} diff --git a/modules/backend/behaviors/ImportExportController.php b/modules/backend/behaviors/ImportExportController.php new file mode 100644 index 0000000..4fb497f --- /dev/null +++ b/modules/backend/behaviors/ImportExportController.php @@ -0,0 +1,848 @@ +config = $this->makeConfig($controller->importExportConfig, $this->requiredConfig); + + /* + * Process config + */ + if ($exportFileName = $this->getConfig('export[fileName]')) { + $this->exportFileName = $exportFileName; + } + + /* + * Import form widgets + */ + if ($this->importUploadFormWidget = $this->makeImportUploadFormWidget()) { + $this->importUploadFormWidget->bindToController(); + } + + if ($this->importOptionsFormWidget = $this->makeImportOptionsFormWidget()) { + $this->importOptionsFormWidget->bindToController(); + } + + /* + * Export form widgets + */ + if ($this->exportFormatFormWidget = $this->makeExportFormatFormWidget()) { + $this->exportFormatFormWidget->bindToController(); + } + + if ($this->exportOptionsFormWidget = $this->makeExportOptionsFormWidget()) { + $this->exportOptionsFormWidget->bindToController(); + } + } + + // + // Controller actions + // + + public function import() + { + if ($response = $this->checkPermissionsForType('import')) { + return $response; + } + + $this->addJs('js/october.import.js', 'core'); + $this->addCss('css/import.css', 'core'); + + $this->controller->pageTitle = $this->controller->pageTitle + ?: Lang::get($this->getConfig('import[title]', 'Import records')); + + $this->prepareImportVars(); + } + + public function export() + { + if ($response = $this->checkPermissionsForType('export')) { + return $response; + } + + if ($response = $this->checkUseListExportMode()) { + return $response; + } + + $this->addJs('js/october.export.js', 'core'); + $this->addCss('css/export.css', 'core'); + + $this->controller->pageTitle = $this->controller->pageTitle + ?: Lang::get($this->getConfig('export[title]', 'Export records')); + + $this->prepareExportVars(); + } + + public function download($name, $outputName = null) + { + $this->controller->pageTitle = $this->controller->pageTitle + ?: Lang::get($this->getConfig('export[title]', 'Export records')); + + return $this->exportGetModel()->download($name, $outputName); + } + + // + // Importing AJAX + // + + public function onImport() + { + try { + $model = $this->importGetModel(); + $matches = post('column_match', []); + + if ($optionData = post('ImportOptions')) { + $model->fill($optionData); + } + + $importOptions = $this->getFormatOptionsFromPost(); + $importOptions['sessionKey'] = $this->importUploadFormWidget->getSessionKey(); + $importOptions['firstRowTitles'] = post('first_row_titles', false); + + $model->import($matches, $importOptions); + + $this->vars['importResults'] = $model->getResultStats(); + $this->vars['returnUrl'] = $this->getRedirectUrlForType('import'); + } + catch (MassAssignmentException $ex) { + $this->controller->handleError(new ApplicationException(Lang::get( + 'backend::lang.model.mass_assignment_failed', + ['attribute' => $ex->getMessage()] + ))); + } + catch (Exception $ex) { + $this->controller->handleError($ex); + } + + $this->vars['sourceIndexOffset'] = $this->getImportSourceIndexOffset($importOptions['firstRowTitles']); + + return $this->importExportMakePartial('import_result_form'); + } + + public function onImportLoadForm() + { + try { + $this->checkRequiredImportColumns(); + } + catch (Exception $ex) { + $this->controller->handleError($ex); + } + + return $this->importExportMakePartial('import_form'); + } + + public function onImportLoadColumnSampleForm() + { + if (($columnId = post('file_column_id', false)) === false) { + throw new ApplicationException(Lang::get('backend::lang.import_export.missing_column_id_error')); + } + + $columns = $this->getImportFileColumns(); + if (!array_key_exists($columnId, $columns)) { + throw new ApplicationException(Lang::get('backend::lang.import_export.unknown_column_error')); + } + + $path = $this->getImportFilePath(); + $reader = $this->createCsvReader($path); + + if (post('first_row_titles')) { + $reader->setHeaderOffset(1); + } + + $result = (new Statement()) + ->limit(50) + ->process($reader) + ->fetchColumn((int) $columnId); + $data = iterator_to_array($result, false); + + /* + * Clean up data + */ + foreach ($data as $index => $sample) { + $data[$index] = Str::limit($sample, 100); + if (!strlen($data[$index])) { + unset($data[$index]); + } + } + + $this->vars['columnName'] = array_get($columns, $columnId); + $this->vars['columnData'] = $data; + + return $this->importExportMakePartial('column_sample_form'); + } + + // + // Importing + // + + /** + * Prepares the view data. + * @return void + */ + public function prepareImportVars() + { + $this->vars['importUploadFormWidget'] = $this->importUploadFormWidget; + $this->vars['importOptionsFormWidget'] = $this->importOptionsFormWidget; + $this->vars['importDbColumns'] = $this->getImportDbColumns(); + $this->vars['importFileColumns'] = $this->getImportFileColumns(); + + // Make these variables available to widgets + $this->controller->vars += $this->vars; + } + + public function importRender() + { + return $this->importExportMakePartial('container_import'); + } + + public function importGetModel() + { + return $this->getModelForType('import'); + } + + protected function getImportDbColumns() + { + if ($this->importColumns !== null) { + return $this->importColumns; + } + + $columnConfig = $this->getConfig('import[list]'); + $columns = $this->makeListColumns($columnConfig); + + if (empty($columns)) { + throw new ApplicationException(Lang::get('backend::lang.import_export.empty_import_columns_error')); + } + + return $this->importColumns = $columns; + } + + protected function getImportFileColumns() + { + if (!$path = $this->getImportFilePath()) { + return null; + } + + $reader = $this->createCsvReader($path); + $firstRow = $reader->fetchOne(0); + + if (!post('first_row_titles')) { + array_walk($firstRow, function (&$value, $key) { + $value = 'Column #'.($key + 1); + }); + } + + /* + * Prevents unfriendly error to be thrown due to bad encoding at response time. + */ + if (json_encode($firstRow) === false) { + throw new ApplicationException(Lang::get('backend::lang.import_export.encoding_not_supported_error')); + } + + return $firstRow; + } + + /** + * Get the index offset to add to the reported row number in status messages + * + * @param bool $firstRowTitles Whether or not the first row contains column titles + * @return int $offset + */ + protected function getImportSourceIndexOffset($firstRowTitles) + { + return $firstRowTitles ? 2 : 1; + } + + protected function makeImportUploadFormWidget() + { + if (!$this->getConfig('import')) { + return null; + } + + $widgetConfig = $this->makeConfig('~/modules/backend/behaviors/importexportcontroller/partials/fields_import.yaml'); + $widgetConfig->model = $this->importGetModel(); + $widgetConfig->alias = 'importUploadForm'; + + $widget = $this->makeWidget('Backend\Widgets\Form', $widgetConfig); + + $widget->bindEvent('form.beforeRefresh', function ($holder) { + $holder->data = []; + }); + + return $widget; + } + + protected function makeImportOptionsFormWidget() + { + $widget = $this->makeOptionsFormWidgetForType('import'); + + if (!$widget && $this->importUploadFormWidget) { + $stepSection = $this->importUploadFormWidget->getField('step3_section'); + $stepSection->hidden = true; + } + + return $widget; + } + + protected function getImportFilePath() + { + return $this + ->importGetModel() + ->getImportFilePath($this->importUploadFormWidget->getSessionKey()); + } + + public function importIsColumnRequired($columnName) + { + $model = $this->importGetModel(); + + return $model->isAttributeRequired($columnName); + } + + protected function checkRequiredImportColumns() + { + if (!$matches = post('column_match', [])) { + throw new ApplicationException(Lang::get('backend::lang.import_export.match_some_column_error')); + } + + $dbColumns = $this->getImportDbColumns(); + foreach ($dbColumns as $column => $label) { + if (!$this->importIsColumnRequired($column)) { + continue; + } + + $found = false; + foreach ($matches as $matchedColumns) { + if (in_array($column, $matchedColumns)) { + $found = true; + break; + } + } + + if (!$found) { + throw new ApplicationException(Lang::get('backend::lang.import_export.required_match_column_error', [ + 'label' => Lang::get($label) + ])); + } + } + } + + // + // Exporting AJAX + // + + public function onExport() + { + try { + $model = $this->exportGetModel(); + $columns = $this->processExportColumnsFromPost(); + + if ($optionData = post('ExportOptions')) { + $model->fill($optionData); + } + + $exportOptions = $this->getFormatOptionsFromPost(); + $exportOptions['sessionKey'] = $this->exportFormatFormWidget->getSessionKey(); + + $reference = $model->export($columns, $exportOptions); + $fileUrl = $this->controller->actionUrl( + 'download', + $reference.'/'.$this->exportFileName + ); + + $this->vars['fileUrl'] = $fileUrl; + $this->vars['returnUrl'] = $this->getRedirectUrlForType('export'); + } + catch (MassAssignmentException $ex) { + $this->controller->handleError(new ApplicationException(Lang::get( + 'backend::lang.model.mass_assignment_failed', + ['attribute' => $ex->getMessage()] + ))); + } + catch (Exception $ex) { + $this->controller->handleError($ex); + } + + return $this->importExportMakePartial('export_result_form'); + } + + public function onExportLoadForm() + { + return $this->importExportMakePartial('export_form'); + } + + // + // Exporting + // + + /** + * Prepares the view data. + * @return void + */ + public function prepareExportVars() + { + $this->vars['exportFormatFormWidget'] = $this->exportFormatFormWidget; + $this->vars['exportOptionsFormWidget'] = $this->exportOptionsFormWidget; + $this->vars['exportColumns'] = $this->getExportColumns(); + + // Make these variables available to widgets + $this->controller->vars += $this->vars; + } + + public function exportRender() + { + return $this->importExportMakePartial('container_export'); + } + + public function exportGetModel() + { + return $this->getModelForType('export'); + } + + protected function getExportColumns() + { + if ($this->exportColumns !== null) { + return $this->exportColumns; + } + + $columnConfig = $this->getConfig('export[list]'); + $columns = $this->makeListColumns($columnConfig); + + if (empty($columns)) { + throw new ApplicationException(Lang::get('backend::lang.import_export.empty_export_columns_error')); + } + + return $this->exportColumns = $columns; + } + + protected function makeExportFormatFormWidget() + { + if (!$this->getConfig('export') || $this->getConfig('export[useList]')) { + return null; + } + + $widgetConfig = $this->makeConfig('~/modules/backend/behaviors/importexportcontroller/partials/fields_export.yaml'); + $widgetConfig->model = $this->exportGetModel(); + $widgetConfig->alias = 'exportUploadForm'; + + $widget = $this->makeWidget('Backend\Widgets\Form', $widgetConfig); + + $widget->bindEvent('form.beforeRefresh', function ($holder) { + $holder->data = []; + }); + + return $widget; + } + + protected function makeExportOptionsFormWidget() + { + $widget = $this->makeOptionsFormWidgetForType('export'); + + if (!$widget && $this->exportFormatFormWidget) { + $stepSection = $this->exportFormatFormWidget->getField('step3_section'); + $stepSection->hidden = true; + } + + return $widget; + } + + protected function processExportColumnsFromPost() + { + $visibleColumns = post('visible_columns', []); + $columns = post('export_columns', []); + + foreach ($columns as $key => $columnName) { + if (!isset($visibleColumns[$columnName])) { + unset($columns[$key]); + } + } + + $result = []; + $definitions = $this->getExportColumns(); + + foreach ($columns as $column) { + $result[$column] = array_get($definitions, $column, '???'); + } + + return $result; + } + + // + // ListController integration + // + + protected function checkUseListExportMode() + { + if (!$useList = $this->getConfig('export[useList]')) { + return false; + } + + if (!$this->controller->isClassExtendedWith('Backend.Behaviors.ListController')) { + throw new ApplicationException(Lang::get('backend::lang.import_export.behavior_missing_uselist_error')); + } + + if (is_array($useList)) { + $listDefinition = array_get($useList, 'definition'); + } + else { + $listDefinition = $useList; + } + + return $this->exportFromList($listDefinition); + } + + /** + * Outputs the list results as a CSV export. + * @param string $definition + * @param array $options + * @return void + */ + public function exportFromList($definition = null, $options = []) + { + $lists = $this->controller->makeLists(); + + $widget = $lists[$definition] ?? reset($lists); + + /* + * Parse options + */ + $defaultOptions = [ + 'fileName' => $this->exportFileName, + 'delimiter' => $this->getConfig('defaultFormatOptions[delimiter]', ','), + 'enclosure' => $this->getConfig('defaultFormatOptions[enclosure]', '"'), + 'escape' => $this->getConfig('defaultFormatOptions[escape]', '\\'), + ]; + + $options = array_merge($defaultOptions, $options); + + $filename = filter_var($options['fileName'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW); + + /* + * Prepare CSV + */ + $csv = CsvWriter::createFromFileObject(new SplTempFileObject); + $csv->setOutputBOM(CsvWriter::BOM_UTF8); + $csv->setDelimiter($options['delimiter']); + $csv->setEnclosure($options['enclosure']); + $csv->setEscape($options['escape']); + $csv->addFormatter(new CsvEscapeFormula()); + + /* + * Add headers + */ + $headers = []; + $columns = $widget->getVisibleColumns(); + foreach ($columns as $column) { + $headers[] = $widget->getHeaderValue($column); + } + $csv->insertOne($headers); + + /* + * Add records + */ + $getter = $this->getConfig('export[useList][raw]', false) + ? 'getColumnValueRaw' + : 'getColumnValue'; + + $query = $widget->prepareQuery(); + $results = $query->get(); + + if ($event = $widget->fireSystemEvent('backend.list.extendRecords', [&$results])) { + $results = $event; + } + + foreach ($results as $result) { + $record = []; + foreach ($columns as $column) { + $value = $widget->$getter($result, $column); + if (is_array($value)) { + $value = implode('|', $value); + } + $record[] = $value; + } + + $csv->insertOne($record); + } + + /* + * Response + */ + $response = Response::make(); + $response->header('Content-Type', 'text/csv'); + $response->header('Content-Transfer-Encoding', 'binary'); + $response->header('Content-Disposition', sprintf('%s; filename="%s"', 'attachment', $filename)); + $response->setContent((string) $csv); + return $response; + } + + // + // Helpers + // + + /** + * Controller accessor for making partials within this behavior. + * @param string $partial + * @param array $params + * @return string Partial contents + */ + public function importExportMakePartial($partial, $params = []) + { + $contents = $this->controller->makePartial('import_export_'.$partial, $params + $this->vars, false); + + if (!$contents) { + $contents = $this->makePartial($partial, $params); + } + + return $contents; + } + + /** + * Checks to see if the import/export is controlled by permissions + * and if the logged in user has permissions. + * @return \View + */ + protected function checkPermissionsForType($type) + { + if ( + ($permissions = $this->getConfig($type.'[permissions]')) && + (!BackendAuth::getUser()->hasAnyAccess((array) $permissions)) + ) { + return Response::make(View::make('backend::access_denied'), 403); + } + } + + protected function makeOptionsFormWidgetForType($type) + { + if (!$this->getConfig($type)) { + return null; + } + + if ($fieldConfig = $this->getConfig($type.'[form]')) { + $widgetConfig = $this->makeConfig($fieldConfig); + $widgetConfig->model = $this->getModelForType($type); + $widgetConfig->alias = $type.'OptionsForm'; + $widgetConfig->arrayName = ucfirst($type).'Options'; + + return $this->makeWidget('Backend\Widgets\Form', $widgetConfig); + } + + return null; + } + + protected function getModelForType($type) + { + $cacheProperty = $type.'Model'; + + if ($this->{$cacheProperty} !== null) { + return $this->{$cacheProperty}; + } + + $modelClass = $this->getConfig($type.'[modelClass]'); + if (!$modelClass) { + throw new ApplicationException(Lang::get('backend::lang.import_export.missing_model_class_error', [ + 'type' => $type + ])); + } + + return $this->{$cacheProperty} = new $modelClass; + } + + protected function makeListColumns($config) + { + $config = $this->makeConfig($config); + + if (!isset($config->columns) || !is_array($config->columns)) { + return null; + } + + $result = []; + foreach ($config->columns as $attribute => $column) { + if (is_array($column)) { + $result[$attribute] = array_get($column, 'label', $attribute); + } + else { + $result[$attribute] = $column ?: $attribute; + } + } + + return $result; + } + + protected function getRedirectUrlForType($type) + { + $redirect = $this->getConfig($type.'[redirect]'); + + if ($redirect !== null) { + return $redirect ? Backend::url($redirect) : 'javascript:;'; + } + + return $this->controller->actionUrl($type); + } + + /** + * Create a new CSV reader with options selected by the user + * @param string $path + * + * @return CsvReader + */ + protected function createCsvReader($path) + { + $reader = CsvReader::createFromPath($path); + $options = $this->getFormatOptionsFromPost(); + + if ($options['delimiter'] !== null) { + $reader->setDelimiter($options['delimiter']); + } + + if ($options['enclosure'] !== null) { + $reader->setEnclosure($options['enclosure']); + } + + if ($options['escape'] !== null) { + $reader->setEscape($options['escape']); + } + + if ( + $options['encoding'] !== null && + $reader->supportsStreamFilter() + ) { + $reader->addStreamFilter(sprintf( + '%s%s:%s', + TranscodeFilter::FILTER_NAME, + strtolower($options['encoding']), + 'utf-8' + )); + } + + return $reader; + } + + /** + * Returns the file format options from postback. This method + * can be used to define presets. + * @return array + */ + protected function getFormatOptionsFromPost() + { + $presetMode = post('format_preset'); + + $options = [ + 'delimiter' => $this->getConfig('defaultFormatOptions[delimiter]'), + 'enclosure' => $this->getConfig('defaultFormatOptions[enclosure]'), + 'escape' => $this->getConfig('defaultFormatOptions[escape]'), + 'encoding' => $this->getConfig('defaultFormatOptions[encoding]'), + ]; + + if ($presetMode == 'custom') { + $options['delimiter'] = post('format_delimiter'); + $options['enclosure'] = post('format_enclosure'); + $options['escape'] = post('format_escape'); + $options['encoding'] = post('format_encoding'); + } + + return $options; + } +} diff --git a/modules/backend/behaviors/ListController.php b/modules/backend/behaviors/ListController.php new file mode 100644 index 0000000..ea20e99 --- /dev/null +++ b/modules/backend/behaviors/ListController.php @@ -0,0 +1,605 @@ +listConfig)) { + $this->listDefinitions = $controller->listConfig; + $this->primaryDefinition = key($this->listDefinitions); + } + else { + $this->listDefinitions = ['list' => $controller->listConfig]; + $this->primaryDefinition = 'list'; + } + + /* + * Build configuration + */ + $this->setConfig($this->listDefinitions[$this->primaryDefinition], $this->requiredConfig); + } + + /** + * Creates all the list widgets based on the definitions. + * @return array + */ + public function makeLists() + { + foreach ($this->listDefinitions as $definition => $config) { + $this->listWidgets[$definition] = $this->makeList($definition); + } + + return $this->listWidgets; + } + + /** + * Prepare the widgets used by this action + * @return \Backend\Widgets\Lists + */ + public function makeList($definition = null) + { + if (!$definition || !isset($this->listDefinitions[$definition])) { + $definition = $this->primaryDefinition; + } + + $listConfig = $this->controller->listGetConfig($definition); + + /* + * Create the model + */ + $class = $listConfig->modelClass; + $model = new $class; + $model = $this->controller->listExtendModel($model, $definition); + + /* + * Prepare the list widget + */ + $columnConfig = $this->makeConfig($listConfig->list); + $columnConfig->model = $model; + $columnConfig->alias = $definition; + + /* + * Prepare the columns configuration + */ + $configFieldsToTransfer = [ + 'recordUrl', + 'recordOnClick', + 'recordsPerPage', + 'perPageOptions', + 'showPageNumbers', + 'noRecordsMessage', + 'defaultSort', + 'showSorting', + 'showSetup', + 'showCheckboxes', + 'showTree', + 'treeExpanded', + 'customViewPath', + ]; + + foreach ($configFieldsToTransfer as $field) { + if (isset($listConfig->{$field})) { + $columnConfig->{$field} = $listConfig->{$field}; + } + } + + /* + * List Widget with extensibility + */ + $widget = $this->makeWidget(\Backend\Widgets\Lists::class, $columnConfig); + + $widget->bindEvent('list.extendColumns', function () use ($widget) { + $this->controller->listExtendColumns($widget); + }); + + $widget->bindEvent('list.extendQueryBefore', function ($query) use ($definition) { + $this->controller->listExtendQueryBefore($query, $definition); + }); + + $widget->bindEvent('list.extendQuery', function ($query) use ($definition) { + $this->controller->listExtendQuery($query, $definition); + }); + + $widget->bindEvent('list.extendRecords', function ($records) use ($definition) { + return $this->controller->listExtendRecords($records, $definition); + }); + + $widget->bindEvent('list.injectRowClass', function ($record) use ($definition) { + return $this->controller->listInjectRowClass($record, $definition); + }); + + $widget->bindEvent('list.overrideColumnValue', function ($record, $column, $value) use ($definition) { + return $this->controller->listOverrideColumnValue($record, $column->columnName, $definition); + }); + + $widget->bindEvent('list.overrideHeaderValue', function ($column, $value) use ($definition) { + return $this->controller->listOverrideHeaderValue($column->columnName, $definition); + }); + + $widget->bindToController(); + + /* + * Prepare the toolbar widget (optional) + */ + if (isset($listConfig->toolbar)) { + $toolbarConfig = $this->makeConfig($listConfig->toolbar); + $toolbarConfig->alias = $widget->alias . 'Toolbar'; + $toolbarWidget = $this->makeWidget(\Backend\Widgets\Toolbar::class, $toolbarConfig); + $toolbarWidget->bindToController(); + $toolbarWidget->cssClasses[] = 'list-header'; + + /* + * Link the Search Widget to the List Widget + */ + if ($searchWidget = $toolbarWidget->getSearchWidget()) { + $searchWidget->bindEvent('search.submit', function () use ($widget, $searchWidget) { + $widget->setSearchTerm($searchWidget->getActiveTerm(), true); + return $widget->onRefresh(); + }); + + $widget->setSearchOptions([ + 'mode' => $searchWidget->mode, + 'scope' => $searchWidget->scope, + ]); + + // Find predefined search term + $widget->setSearchTerm($searchWidget->getActiveTerm()); + } + + $this->toolbarWidgets[$definition] = $toolbarWidget; + } + + /* + * Prepare the filter widget (optional) + */ + if (isset($listConfig->filter)) { + $filterConfig = $this->makeConfig($listConfig->filter); + + if (!empty($filterConfig->scopes)) { + $widget->cssClasses[] = 'list-flush'; + + $filterConfig->alias = $widget->alias . 'Filter'; + $filterWidget = $this->makeWidget(\Backend\Widgets\Filter::class, $filterConfig); + $filterWidget->bindToController(); + + /* + * Filter the list when the scopes are changed + */ + $filterWidget->bindEvent('filter.update', function () use ($widget, $filterWidget) { + return $widget->onFilter(); + }); + + /* + * Filter Widget with extensibility + */ + $filterWidget->bindEvent('filter.extendScopes', function () use ($filterWidget) { + $this->controller->listFilterExtendScopes($filterWidget); + }); + + /* + * Extend the query of the list of options + */ + $filterWidget->bindEvent('filter.extendQuery', function ($query, $scope) { + $this->controller->listFilterExtendQuery($query, $scope); + }); + + // Apply predefined filter values + $widget->addFilter([$filterWidget, 'applyAllScopesToQuery']); + + $this->filterWidgets[$definition] = $filterWidget; + } + } + + return $widget; + } + + /** + * Index Controller action. + * @return void + */ + public function index() + { + $this->controller->pageTitle = $this->controller->pageTitle ?: Lang::get($this->getConfig( + 'title', + 'backend::lang.list.default_title' + )); + $this->controller->bodyClass = 'slim-container'; + $this->makeLists(); + } + + /** + * Bulk delete records. + * @return void + * @throws \October\Rain\Exception\ApplicationException when the parent definition is missing. + */ + public function index_onDelete() + { + if (method_exists($this->controller, 'onDelete')) { + return call_user_func_array([$this->controller, 'onDelete'], func_get_args()); + } + + /* + * Establish the list definition + */ + $definition = post('definition', $this->primaryDefinition); + + if (!isset($this->listDefinitions[$definition])) { + throw new ApplicationException(Lang::get('backend::lang.list.missing_parent_definition', compact('definition'))); + } + + $listConfig = $this->controller->listGetConfig($definition); + + /* + * Validate checked identifiers + */ + $checkedIds = post('checked'); + + if (!$checkedIds || !is_array($checkedIds) || !count($checkedIds)) { + Flash::error(Lang::get( + (!empty($listConfig->noRecordsDeletedMessage)) + ? $listConfig->noRecordsDeletedMessage + : 'backend::lang.list.delete_selected_empty' + )); + return $this->controller->listRefresh(); + } + + /* + * Create the model + */ + $class = $listConfig->modelClass; + $model = new $class; + $model = $this->controller->listExtendModel($model, $definition); + + /* + * Create the query + */ + $query = $model->newQuery(); + $this->controller->listExtendQueryBefore($query, $definition); + + $query->whereIn($model->getKeyName(), $checkedIds); + $this->controller->listExtendQuery($query, $definition); + + /* + * Delete records + */ + $records = $query->get(); + + if ($records->count()) { + foreach ($records as $record) { + $record->delete(); + } + + Flash::success(Lang::get( + (!empty($listConfig->deleteMessage)) + ? $listConfig->deleteMessage + : 'backend::lang.list.delete_selected_success' + )); + } + else { + Flash::error(Lang::get( + (!empty($listConfig->noRecordsDeletedMessage)) + ? $listConfig->noRecordsDeletedMessage + : 'backend::lang.list.delete_selected_empty' + )); + } + + return $this->controller->listRefresh($definition); + } + + /** + * Renders the widget collection. + * @param string $definition Optional list definition. + * @return string Rendered HTML for the list. + * @throws \October\Rain\Exception\ApplicationException when there are no list widgets set. + */ + public function listRender($definition = null) + { + if (!count($this->listWidgets)) { + throw new ApplicationException(Lang::get('backend::lang.list.behavior_not_ready')); + } + + if (!$definition || !isset($this->listDefinitions[$definition])) { + $definition = $this->primaryDefinition; + } + + $listConfig = $this->controller->listGetConfig($definition); + + $vars = [ + 'toolbar' => null, + 'filter' => null, + 'list' => null, + ]; + + if (isset($this->toolbarWidgets[$definition])) { + $vars['toolbar'] = $this->toolbarWidgets[$definition]; + } + + if (isset($this->filterWidgets[$definition])) { + $vars['filter'] = $this->filterWidgets[$definition]; + } + + $vars['list'] = $this->listWidgets[$definition]; + + return $this->listMakePartial('container', $vars); + } + + /** + * Controller accessor for making partials within this behavior. + * @param string $partial + * @param array $params + * @return string Partial contents + */ + public function listMakePartial($partial, $params = []) + { + $contents = $this->controller->makePartial('list_'.$partial, $params + $this->vars, false); + if (!$contents) { + $contents = $this->makePartial($partial, $params); + } + + return $contents; + } + + /** + * Refreshes the list container only, useful for returning in custom AJAX requests. + * @param string $definition Optional list definition. + * @return array The list element selector as the key, and the list contents are the value. + */ + public function listRefresh($definition = null) + { + if (!count($this->listWidgets)) { + $this->makeLists(); + } + + if (!$definition || !isset($this->listDefinitions[$definition])) { + $definition = $this->primaryDefinition; + } + + return $this->listWidgets[$definition]->onRefresh(); + } + + /** + * Returns the widget used by this behavior. + * @return \Backend\Classes\WidgetBase + */ + public function listGetWidget($definition = null) + { + if (!$definition) { + $definition = $this->primaryDefinition; + } + + return array_get($this->listWidgets, $definition); + } + + /** + * Returns the configuration used by this behavior. + * @return \Backend\Classes\WidgetBase + */ + public function listGetConfig($definition = null) + { + if (!$definition) { + $definition = $this->primaryDefinition; + } + + if (!$config = array_get($this->listConfig, $definition)) { + $config = $this->listConfig[$definition] = $this->makeConfig($this->listDefinitions[$definition], $this->requiredConfig); + } + + return $config; + } + + // + // Overrides + // + + /** + * Called after the list columns are defined. + * @param \Backend\Widgets\Lists $host The hosting list widget + * @return void + */ + public function listExtendColumns($host) + { + } + + /** + * Called after the filter scopes are defined. + * @param \Backend\Widgets\Filter $host The hosting filter widget + * @return void + */ + public function listFilterExtendScopes($host) + { + } + + /** + * Controller override: Extend supplied model + * @param \October\Rain\Database\Model $model + * @param string|null $definition + * @return \October\Rain\Database\Model + */ + public function listExtendModel($model, $definition = null) + { + return $model; + } + + /** + * Controller override: Extend the query used for populating the list + * before the default query is processed. + * @param \October\Rain\Database\Builder $query + * @param string|null $definition + */ + public function listExtendQueryBefore($query, $definition = null) + { + } + + /** + * Controller override: Extend the query used for populating the list + * after the default query is processed. + * @param \October\Rain\Database\Builder $query + * @param string|null $definition + */ + public function listExtendQuery($query, $definition = null) + { + } + + /** + * Controller override: Extend the records used for populating the list + * after the query is processed. + * @param \Illuminate\Contracts\Pagination\LengthAwarePaginator|\Illuminate\Database\Eloquent\Collection $records + * @param string|null $definition + */ + public function listExtendRecords($records, $definition = null) + { + } + + /** + * Controller override: Extend the query used for populating the filter + * options before the default query is processed. + * @param \October\Rain\Database\Builder $query + * @param array $scope + */ + public function listFilterExtendQuery($query, $scope) + { + } + + /** + * Returns a CSS class name for a list row (). + * @param \October\Rain\Database\Model $record The populated model used for the column + * @param string|null $definition List definition (optional) + * @return string|void CSS class name + */ + public function listInjectRowClass($record, $definition = null) + { + } + + /** + * Replace a table column value (...) + * @param \October\Rain\Database\Model $record The populated model used for the column + * @param string $columnName The column name to override + * @param string|null $definition List definition (optional) + * @return string|void HTML view + */ + public function listOverrideColumnValue($record, $columnName, $definition = null) + { + } + + /** + * Replace the entire table header contents (...) with custom HTML + * @param string $columnName The column name to override + * @param string|null $definition List definition (optional) + * @return string|void HTML view + */ + public function listOverrideHeaderValue($columnName, $definition = null) + { + } + + /** + * Static helper for extending list columns. + * @param callable $callback + * @return void + */ + public static function extendListColumns($callback) + { + $calledClass = self::getCalledExtensionClass(); + Event::listen('backend.list.extendColumns', function (\Backend\Widgets\Lists $widget) use ($calledClass, $callback) { + if (!is_a($widget->getController(), $calledClass)) { + return; + } + call_user_func_array($callback, [$widget, $widget->model]); + }); + } + + /** + * Static helper for extending filter scopes. + * @param callable $callback + * @return void + */ + public static function extendListFilterScopes($callback) + { + $calledClass = self::getCalledExtensionClass(); + Event::listen('backend.filter.extendScopes', function (\Backend\Widgets\Filter $widget) use ($calledClass, $callback) { + if (!is_a($widget->getController(), $calledClass)) { + return; + } + call_user_func_array($callback, [$widget]); + }); + } +} diff --git a/modules/backend/behaviors/RelationController.php b/modules/backend/behaviors/RelationController.php new file mode 100644 index 0000000..26174ba --- /dev/null +++ b/modules/backend/behaviors/RelationController.php @@ -0,0 +1,1818 @@ +addJs('js/october.relation.js', 'core'); + $this->addCss('css/relation.css', 'core'); + + /* + * Build configuration + */ + $this->config = $this->originalConfig = $this->makeConfig($controller->relationConfig, $this->requiredConfig); + } + + /** + * Validates the supplied field and initializes the relation manager. + * @param string $field The relationship field. + * @return string The active field name. + */ + protected function validateField($field = null) + { + $field = $field ?: post(self::PARAM_FIELD); + + if ($field && $field != $this->field) { + $this->initRelation($this->model, $field); + } + + if (!$field && !$this->field) { + throw new ApplicationException(Lang::get('backend::lang.relation.missing_definition', compact('field'))); + } + + return $field ?: $this->field; + } + + /** + * Prepares the view data. + * @return void + */ + public function prepareVars() + { + $this->vars['relationManageId'] = $this->manageId; + $this->vars['relationLabel'] = $this->config->label ?: $this->field; + $this->vars['relationManageTitle'] = $this->manageTitle; + $this->vars['relationField'] = $this->field; + $this->vars['relationType'] = $this->relationType; + $this->vars['relationSearchWidget'] = $this->searchWidget; + $this->vars['relationManageFilterWidget'] = $this->manageFilterWidget; + $this->vars['relationViewFilterWidget'] = $this->viewFilterWidget; + $this->vars['relationToolbarWidget'] = $this->toolbarWidget; + $this->vars['relationManageMode'] = $this->manageMode; + $this->vars['relationManageWidget'] = $this->manageWidget; + $this->vars['relationToolbarButtons'] = $this->toolbarButtons; + $this->vars['relationViewMode'] = $this->viewMode; + $this->vars['relationViewWidget'] = $this->viewWidget; + $this->vars['relationViewModel'] = $this->viewModel; + $this->vars['relationPivotWidget'] = $this->pivotWidget; + $this->vars['relationSessionKey'] = $this->relationGetSessionKey(); + $this->vars['relationExtraConfig'] = $this->extraConfig; + } + + /** + * The controller action is responsible for supplying the parent model + * so it's action must be fired. Additionally, each AJAX request must + * supply the relation's field name (_relation_field). + */ + protected function beforeAjax() + { + if ($this->initialized) { + return; + } + + $this->controller->pageAction(); + if ($fatalError = $this->controller->getFatalError()) { + throw new ApplicationException($fatalError); + } + + $this->validateField(); + $this->prepareVars(); + $this->initialized = true; + } + + // + // Interface + // + + /** + * Prepare the widgets used by this behavior + * @param Model $model + * @param string $field + * @return void + */ + public function initRelation($model, $field = null) + { + if ($field == null) { + $field = post(self::PARAM_FIELD); + } + + $this->config = $this->originalConfig; + $this->model = $model; + $this->field = $field; + + if ($field == null) { + return; + } + + if (!$this->model) { + throw new ApplicationException(Lang::get('backend::lang.relation.missing_model', [ + 'class' => get_class($this->controller), + ])); + } + + if (!$this->model instanceof Model) { + throw new ApplicationException(Lang::get('backend::lang.model.invalid_class', [ + 'model' => get_class($this->model), + 'class' => get_class($this->controller), + ])); + } + + if (!$this->getConfig($field)) { + throw new ApplicationException(Lang::get('backend::lang.relation.missing_definition', compact('field'))); + } + + if ($extraConfig = post(self::PARAM_EXTRA_CONFIG)) { + $this->applyExtraConfig($extraConfig); + } + + $this->alias = camel_case('relation ' . $field); + $this->config = $this->makeConfig($this->getConfig($field), $this->requiredRelationProperties); + $this->controller->relationExtendConfig($this->config, $this->field, $this->model); + + /* + * Relationship details + */ + $this->relationName = $field; + $this->relationType = $this->model->getRelationType($field); + $this->relationObject = $this->model->{$field}(); + $this->relationModel = $this->relationObject->getRelated(); + + $this->manageId = post('manage_id'); + $this->foreignId = post('foreign_id'); + $this->readOnly = $this->getConfig('readOnly'); + $this->deferredBinding = $this->getConfig('deferredBinding') || !$this->model->exists; + $this->viewMode = $this->evalViewMode(); + $this->manageMode = $this->evalManageMode(); + $this->manageTitle = $this->evalManageTitle(); + $this->toolbarButtons = $this->evalToolbarButtons(); + + /* + * Toolbar widget + */ + if ($this->toolbarWidget = $this->makeToolbarWidget()) { + $this->toolbarWidget->bindToController(); + } + + /* + * Search widget + */ + if ($this->searchWidget = $this->makeSearchWidget()) { + $this->searchWidget->bindToController(); + } + + /* + * Filter widgets (optional) + */ + if ($this->manageFilterWidget = $this->makeFilterWidget('manage')) { + $this->controller->relationExtendManageFilterWidget($this->manageFilterWidget, $this->field, $this->model); + $this->manageFilterWidget->bindToController(); + } + + if ($this->viewFilterWidget = $this->makeFilterWidget('view')) { + $this->controller->relationExtendViewFilterWidget($this->viewFilterWidget, $this->field, $this->model); + $this->viewFilterWidget->bindToController(); + } + + /* + * View widget + */ + if ($this->viewWidget = $this->makeViewWidget()) { + $this->controller->relationExtendViewWidget($this->viewWidget, $this->field, $this->model); + $this->viewWidget->bindToController(); + } + + /* + * Manage widget + */ + if ($this->manageWidget = $this->makeManageWidget()) { + $this->controller->relationExtendManageWidget($this->manageWidget, $this->field, $this->model); + $this->manageWidget->bindToController(); + } + + /* + * Pivot widget + */ + if ($this->manageMode == 'pivot' && $this->pivotWidget = $this->makePivotWidget()) { + $this->controller->relationExtendPivotWidget($this->pivotWidget, $this->field, $this->model); + $this->pivotWidget->bindToController(); + } + } + + /** + * Renders the relationship manager. + * @param string $field The relationship field. + * @param array $options + * @return string Rendered HTML for the relationship manager. + */ + public function relationRender($field, $options = []) + { + /* + * Session key + */ + if (is_string($options)) { + $options = ['sessionKey' => $options]; + } + + if (isset($options['sessionKey'])) { + $this->sessionKey = $options['sessionKey']; + } + + /* + * Apply options and extra config + */ + $allowConfig = ['readOnly', 'recordUrl', 'recordOnClick']; + $extraConfig = array_only($options, $allowConfig); + $this->extraConfig = $extraConfig; + $this->applyExtraConfig($extraConfig, $field); + + /* + * Initialize + */ + $this->validateField($field); + $this->prepareVars(); + + /* + * Determine the partial to use based on the supplied section option + */ + $section = $options['section'] ?? null; + switch (strtolower($section)) { + case 'toolbar': + return $this->toolbarWidget ? $this->toolbarWidget->render() : null; + + case 'view': + return $this->relationMakePartial('view'); + + default: + return $this->relationMakePartial('container'); + } + } + + /** + * Refreshes the relation container only, useful for returning in custom AJAX requests. + * @param string $field Relation definition. + * @return array The relation element selector as the key, and the relation view contents are the value. + */ + public function relationRefresh($field = null) + { + $field = $this->validateField($field); + + $result = ['#'.$this->relationGetId('view') => $this->relationRenderView($field)]; + if ($toolbar = $this->relationRenderToolbar($field)) { + $result['#'.$this->relationGetId('toolbar')] = $toolbar; + } + + if ($eventResult = $this->controller->relationExtendRefreshResults($field)) { + $result = $eventResult + $result; + } + + return $result; + } + + /** + * Renders the toolbar only. + * @param string $field The relationship field. + * @return string Rendered HTML for the toolbar. + */ + public function relationRenderToolbar($field = null) + { + return $this->relationRender($field, ['section' => 'toolbar']); + } + + /** + * Renders the view only. + * @param string $field The relationship field. + * @return string Rendered HTML for the view. + */ + public function relationRenderView($field = null) + { + return $this->relationRender($field, ['section' => 'view']); + } + + /** + * Controller accessor for making partials within this behavior. + * @param string $partial + * @param array $params + * @return string Partial contents + */ + public function relationMakePartial($partial, $params = []) + { + $contents = $this->controller->makePartial('relation_'.$partial, $params + $this->vars, false); + if (!$contents) { + $contents = $this->makePartial($partial, $params); + } + + return $contents; + } + + /** + * Returns a unique ID for this relation and field combination. + * @param string $suffix A suffix to use with the identifier. + * @return string + */ + public function relationGetId($suffix = null) + { + $id = class_basename($this); + if ($this->field) { + $id .= '-' . $this->field; + } + + if ($suffix !== null) { + $id .= '-' . $suffix; + } + + return $this->controller->getId($id); + } + + /** + * Returns the active session key. + */ + public function relationGetSessionKey($force = false) + { + if ($this->sessionKey && !$force) { + return $this->sessionKey; + } + + if (post('_relation_session_key')) { + return $this->sessionKey = post('_relation_session_key'); + } + + if (post('_session_key')) { + return $this->sessionKey = post('_session_key'); + } + + return $this->sessionKey = FormHelper::getSessionKey(); + } + + // + // Widgets + // + + /** + * Initialize a filter widget + * + * @param $type string Either 'manage' or 'view' + * @return \Backend\Classes\WidgetBase|null + */ + protected function makeFilterWidget($type) + { + if (!$this->getConfig($type . '[filter]')) { + return null; + } + + $filterConfig = $this->makeConfig($this->getConfig($type . '[filter]')); + $filterConfig->alias = $this->alias . ucfirst($type) . 'Filter'; + $filterWidget = $this->makeWidget('Backend\Widgets\Filter', $filterConfig); + + return $filterWidget; + } + + + protected function makeToolbarWidget() + { + $defaultConfig = []; + + /* + * Add buttons to toolbar + */ + $defaultButtons = null; + + if (!$this->readOnly && $this->toolbarButtons) { + $defaultButtons = '~/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm'; + } + + $defaultConfig['buttons'] = $this->getConfig('view[toolbarPartial]', $defaultButtons); + + /* + * Make config + */ + $toolbarConfig = $this->makeConfig($this->getConfig('toolbar', $defaultConfig)); + $toolbarConfig->alias = $this->alias . 'Toolbar'; + + /* + * Add search to toolbar + */ + $useSearch = $this->viewMode == 'multi' && $this->getConfig('view[showSearch]'); + + if ($useSearch) { + $toolbarConfig->search = [ + 'prompt' => 'backend::lang.list.search_prompt' + ]; + } + + /* + * No buttons, no search should mean no toolbar + */ + if (empty($toolbarConfig->search) && empty($toolbarConfig->buttons)) { + return; + } + + $toolbarWidget = $this->makeWidget('Backend\Widgets\Toolbar', $toolbarConfig); + $toolbarWidget->cssClasses[] = 'list-header'; + + return $toolbarWidget; + } + + protected function makeSearchWidget() + { + if (!$this->getConfig('manage[showSearch]')) { + return null; + } + + $config = $this->makeConfig(); + $config->alias = $this->alias . 'ManageSearch'; + $config->growable = false; + $config->prompt = 'backend::lang.list.search_prompt'; + $widget = $this->makeWidget('Backend\Widgets\Search', $config); + $widget->cssClasses[] = 'recordfinder-search'; + + /* + * Persist the search term across AJAX requests only + */ + if (!Request::ajax()) { + $widget->setActiveTerm(null); + } + + return $widget; + } + + protected function makeViewWidget() + { + $widget = null; + + /* + * Multiple (has many, belongs to many) + */ + if ($this->viewMode == 'multi') { + $config = $this->makeConfigForMode('view', 'list'); + $config->model = $this->relationModel; + $config->alias = $this->alias . 'ViewList'; + $config->showSorting = $this->getConfig('view[showSorting]', true); + $config->defaultSort = $this->getConfig('view[defaultSort]'); + $config->recordsPerPage = $this->getConfig('view[recordsPerPage]'); + $config->showCheckboxes = $this->getConfig('view[showCheckboxes]', !$this->readOnly); + $config->recordUrl = $this->getConfig('view[recordUrl]'); + $config->customViewPath = $this->getConfig('view[customViewPath]'); + $config->noRecordsMessage = $this->getConfig('view[noRecordsMessage]'); + + $defaultOnClick = sprintf( + "$.oc.relationBehavior.clickViewListRecord(':%s', '%s', '%s')", + $this->relationModel->getKeyName(), + $this->relationGetId(), + $this->relationGetSessionKey() + ); + + if ($config->recordUrl) { + $defaultOnClick = null; + } + elseif ( + !$this->makeConfigForMode('manage', 'form', false) && + !$this->makeConfigForMode('pivot', 'form', false) + ) { + $defaultOnClick = null; + } + + $config->recordOnClick = $this->getConfig('view[recordOnClick]', $defaultOnClick); + + if ($emptyMessage = $this->getConfig('emptyMessage')) { + $config->noRecordsMessage = $emptyMessage; + } + + $widget = $this->makeWidget('Backend\Widgets\Lists', $config); + + /* + * Apply defined constraints + */ + if ($sqlConditions = $this->getConfig('view[conditions]')) { + $widget->bindEvent('list.extendQueryBefore', function ($query) use ($sqlConditions) { + $query->whereRaw($sqlConditions); + }); + } + elseif ($scopeMethod = $this->getConfig('view[scope]')) { + $widget->bindEvent('list.extendQueryBefore', function ($query) use ($scopeMethod) { + $query->$scopeMethod($this->model); + }); + } + else { + $widget->bindEvent('list.extendQueryBefore', function ($query) use ($widget) { + $this->relationObject->addDefinedConstraintsToQuery($query); + if ($widget->getSortColumn()) { + $query->getQuery()->orders = []; + } + }); + } + + /* + * Constrain the query by the relationship and deferred items + */ + $widget->bindEvent('list.extendQuery', function ($query) { + $this->relationObject->setQuery($query); + + $sessionKey = $this->deferredBinding ? $this->relationGetSessionKey() : null; + + if ($sessionKey) { + $this->relationObject->withDeferred($sessionKey); + } + elseif ($this->model->exists) { + $this->relationObject->addConstraints(); + } + + /* + * Allows pivot data to enter the fray + */ + if ($this->relationType == 'belongsToMany' + || $this->relationType == 'morphToMany' + || $this->relationType == 'morphedByMany' + ) { + $this->relationObject->setQuery($query->getQuery()); + return $this->relationObject; + } + }); + + /* + * Constrain the list by the search widget, if available + */ + if ($this->toolbarWidget && $this->getConfig('view[showSearch]') + && $searchWidget = $this->toolbarWidget->getSearchWidget() + ) { + $searchWidget->bindEvent('search.submit', function () use ($widget, $searchWidget) { + $widget->setSearchTerm($searchWidget->getActiveTerm()); + return $widget->onRefresh(); + }); + + /* + * Persist the search term across AJAX requests only + */ + if (Request::ajax()) { + $widget->setSearchTerm($searchWidget->getActiveTerm()); + } + else { + $searchWidget->setActiveTerm(null); + } + } + + /* + * Link the Filter Widget to the List Widget + */ + if ($this->viewFilterWidget) { + $this->viewFilterWidget->bindEvent('filter.update', function () use ($widget) { + return $widget->onFilter(); + }); + + // Apply predefined filter values + $widget->addFilter([$this->viewFilterWidget, 'applyAllScopesToQuery']); + } + } + /* + * Single (belongs to, has one) + */ + elseif ($this->viewMode == 'single') { + $this->viewModel = $this->relationObject->getResults() + ?: $this->relationModel; + + $config = $this->makeConfigForMode('view', 'form'); + $config->model = $this->viewModel; + $config->arrayName = class_basename($this->relationModel); + $config->context = 'relation'; + $config->alias = $this->alias . 'ViewForm'; + + $widget = $this->makeWidget('Backend\Widgets\Form', $config); + $widget->previewMode = true; + } + + return $widget; + } + + protected function makeManageWidget() + { + $widget = null; + + /* + * List / Pivot + */ + if ($this->manageMode == 'list' || $this->manageMode == 'pivot') { + $isPivot = $this->manageMode == 'pivot'; + + $config = $this->makeConfigForMode('manage', 'list'); + $config->model = $this->relationModel; + $config->alias = $this->alias . 'ManageList'; + $config->showSetup = false; + $config->showCheckboxes = $this->getConfig('manage[showCheckboxes]', !$isPivot); + $config->showSorting = $this->getConfig('manage[showSorting]', !$isPivot); + $config->defaultSort = $this->getConfig('manage[defaultSort]'); + $config->recordsPerPage = $this->getConfig('manage[recordsPerPage]'); + $config->noRecordsMessage = $this->getConfig('manage[noRecordsMessage]'); + + if ($this->viewMode == 'single') { + $config->showCheckboxes = false; + $config->recordOnClick = sprintf( + "$.oc.relationBehavior.clickManageListRecord(':%s', '%s', '%s')", + $this->relationModel->getKeyName(), + $this->relationGetId(), + $this->relationGetSessionKey() + ); + } + elseif ($config->showCheckboxes) { + $config->recordOnClick = "$.oc.relationBehavior.toggleListCheckbox(this)"; + } + elseif ($isPivot) { + $config->recordOnClick = sprintf( + "$.oc.relationBehavior.clickManagePivotListRecord(':%s', '%s', '%s')", + $this->relationModel->getKeyName(), + $this->relationGetId(), + $this->relationGetSessionKey() + ); + } + + $widget = $this->makeWidget('Backend\Widgets\Lists', $config); + + /* + * Apply defined constraints + */ + if ($sqlConditions = $this->getConfig('manage[conditions]')) { + $widget->bindEvent('list.extendQueryBefore', function ($query) use ($sqlConditions) { + $query->whereRaw($sqlConditions); + }); + } + elseif ($scopeMethod = $this->getConfig('manage[scope]')) { + $widget->bindEvent('list.extendQueryBefore', function ($query) use ($scopeMethod) { + $query->$scopeMethod($this->model); + }); + } + else { + $widget->bindEvent('list.extendQueryBefore', function ($query) use ($widget) { + $this->relationObject->addDefinedConstraintsToQuery($query); + if ($widget->getSortColumn()) { + $query->getQuery()->orders = []; + } + }); + } + + /* + * Link the Search Widget to the List Widget + */ + if ($this->searchWidget) { + $this->searchWidget->bindEvent('search.submit', function () use ($widget) { + $widget->setSearchTerm($this->searchWidget->getActiveTerm()); + return $widget->onRefresh(); + }); + + /* + * Persist the search term across AJAX requests only + */ + if (Request::ajax()) { + $widget->setSearchTerm($this->searchWidget->getActiveTerm()); + } + } + + /* + * Link the Filter Widget to the List Widget + */ + if ($this->manageFilterWidget) { + $this->manageFilterWidget->bindEvent('filter.update', function () use ($widget) { + return $widget->onFilter(); + }); + + // Apply predefined filter values + $widget->addFilter([$this->manageFilterWidget, 'applyAllScopesToQuery']); + } + } + /* + * Form + */ + elseif ($this->manageMode == 'form') { + if (!$config = $this->makeConfigForMode('manage', 'form', false)) { + return null; + } + + $config->model = $this->relationModel; + $config->arrayName = class_basename($this->relationModel); + $config->context = $this->evalFormContext('manage', !!$this->manageId); + $config->alias = $this->alias . 'ManageForm'; + + /* + * Existing record + */ + if ($this->manageId) { + $model = $config->model->find($this->manageId); + if ($model) { + $config->model = $model; + } else { + throw new ApplicationException(Lang::get('backend::lang.model.not_found', [ + 'class' => get_class($config->model), + 'id' => $this->manageId, + ])); + } + } + + $widget = $this->makeWidget('Backend\Widgets\Form', $config); + } + + if (!$widget) { + return null; + } + + /* + * Exclude existing relationships + */ + if ($this->manageMode == 'pivot' || $this->manageMode == 'list') { + $widget->bindEvent('list.extendQuery', function ($query) { + /* + * Where not in the current list of related records + */ + $existingIds = $this->findExistingRelationIds(); + if (count($existingIds)) { + $query->whereNotIn($this->relationModel->getQualifiedKeyName(), $existingIds); + } + }); + } + + return $widget; + } + + protected function makePivotWidget() + { + $config = $this->makeConfigForMode('pivot', 'form'); + $config->model = $this->relationModel; + $config->arrayName = class_basename($this->relationModel); + $config->context = $this->evalFormContext('pivot', !!$this->manageId); + $config->alias = $this->alias . 'ManagePivotForm'; + + $foreignKeyName = $this->relationModel->getQualifiedKeyName(); + + /* + * Existing record + */ + if ($this->manageId) { + $hydratedModel = $this->relationObject->where($foreignKeyName, $this->manageId)->first(); + + if ($hydratedModel) { + $config->model = $hydratedModel; + } else { + throw new ApplicationException(Lang::get('backend::lang.model.not_found', [ + 'class' => get_class($config->model), + 'id' => $this->manageId, + ])); + } + } + /* + * New record + */ + else { + if ($this->foreignId) { + $foreignModel = $this->relationModel + ->whereIn($foreignKeyName, (array) $this->foreignId) + ->first(); + + if ($foreignModel) { + $foreignModel->exists = false; + $config->model = $foreignModel; + } + } + + $pivotModel = $this->relationObject->newPivot(); + $config->model->setRelation('pivot', $pivotModel); + } + + return $this->makeWidget('Backend\Widgets\Form', $config); + } + + // + // AJAX (Buttons) + // + + public function onRelationButtonAdd() + { + $this->eventTarget = 'button-add'; + + return $this->onRelationManageForm(); + } + + public function onRelationButtonCreate() + { + $this->eventTarget = 'button-create'; + + return $this->onRelationManageForm(); + } + + public function onRelationButtonDelete() + { + return $this->onRelationManageDelete(); + } + + public function onRelationButtonLink() + { + $this->eventTarget = 'button-link'; + + return $this->onRelationManageForm(); + } + + public function onRelationButtonUnlink() + { + return $this->onRelationManageRemove(); + } + + public function onRelationButtonRemove() + { + return $this->onRelationManageRemove(); + } + + public function onRelationButtonUpdate() + { + $this->eventTarget = 'button-update'; + + return $this->onRelationManageForm(); + } + + // + // AJAX (List events) + // + + public function onRelationClickManageList() + { + return $this->onRelationManageAdd(); + } + + public function onRelationClickManageListPivot() + { + return $this->onRelationManagePivotForm(); + } + + public function onRelationClickViewList() + { + $this->eventTarget = 'list'; + return $this->onRelationManageForm(); + } + + // + // AJAX + // + + public function onRelationManageForm() + { + $this->beforeAjax(); + + if ($this->manageMode == 'pivot' && $this->manageId) { + return $this->onRelationManagePivotForm(); + } + + // The form should not share its session key with the parent + $this->vars['newSessionKey'] = str_random(40); + + $view = 'manage_' . $this->manageMode; + + return $this->relationMakePartial($view); + } + + /** + * Create a new related model + */ + public function onRelationManageCreate() + { + $this->forceManageMode = 'form'; + $this->beforeAjax(); + $saveData = $this->manageWidget->getSaveData(); + $sessionKey = $this->deferredBinding ? $this->relationGetSessionKey(true) : null; + + if ($this->viewMode == 'multi') { + $newModel = $this->relationModel; + + /* + * In special cases, has one/many will require a foreign key set + * to pass any constraints imposed by the database. This emulates + * the "create" method on the relation object. + */ + if (in_array($this->relationType, ['hasOne', 'hasMany'])) { + $newModel->setAttribute( + $this->relationObject->getForeignKeyName(), + $this->relationObject->getParentKey() + ); + } + + $modelsToSave = $this->prepareModelsToSave($newModel, $saveData); + foreach ($modelsToSave as $modelToSave) { + $modelToSave->save(null, $this->manageWidget->getSessionKey()); + } + + $this->relationObject->add($newModel, $sessionKey); + } + elseif ($this->viewMode == 'single') { + $newModel = $this->viewModel = $this->viewWidget->model = $this->manageWidget->model; + $this->viewWidget->setFormValues($saveData); + + /* + * Has one relations will save as part of the add() call. + */ + if ($this->deferredBinding || $this->relationType != 'hasOne') { + $newModel->save(null, $this->manageWidget->getSessionKey()); + } + + if ($this->relationType === 'hasOne') { + // Unassign previous relation if one is already assigned + $relation = $this->relationObject->getParent()->{$this->relationName} ?? null; + + if ($relation) { + $this->relationObject->remove($relation, $sessionKey); + } + } + + $this->relationObject->add($newModel, $sessionKey); + + /* + * Belongs to relations won't save when using add() so + * it should occur if the conditions are right. + */ + if (!$this->deferredBinding && $this->relationType == 'belongsTo') { + $parentModel = $this->relationObject->getParent(); + if ($parentModel->exists) { + $parentModel->save(); + } + } + } + + return $this->relationRefresh(); + } + + /** + * Updated an existing related model's fields + */ + public function onRelationManageUpdate() + { + $this->forceManageMode = 'form'; + $this->beforeAjax(); + $saveData = $this->manageWidget->getSaveData(); + + if ($this->viewMode == 'multi') { + $model = $this->manageWidget->model; + $modelsToSave = $this->prepareModelsToSave($model, $saveData); + foreach ($modelsToSave as $modelToSave) { + $modelToSave->save(null, $this->manageWidget->getSessionKey()); + } + } + elseif ($this->viewMode == 'single') { + $this->manageWidget->setFormValues($saveData); + $this->manageWidget->model->save(null, $this->manageWidget->getSessionKey()); + $this->viewWidget->setFormValues($saveData); + } + + return $this->relationRefresh(); + } + + /** + * Delete an existing related model completely + */ + public function onRelationManageDelete() + { + $this->beforeAjax(); + + /* + * Multiple (has many, belongs to many) + */ + if ($this->viewMode == 'multi') { + if (($checkedIds = post('checked')) && is_array($checkedIds)) { + foreach ($checkedIds as $relationId) { + if (!$obj = $this->relationModel->find($relationId)) { + continue; + } + + $obj->delete(); + } + } + } + /* + * Single (belongs to, has one) + */ + elseif ($this->viewMode == 'single') { + $relatedModel = $this->viewModel; + if ($relatedModel->exists) { + $relatedModel->delete(); + } + + // Reinitialise the form with a blank model + $this->initRelation($this->model); + + $this->viewWidget->setFormValues([]); + $this->viewModel = $this->relationModel; + } + + return $this->relationRefresh(); + } + + /** + * Add an existing related model to the primary model + */ + public function onRelationManageAdd() + { + $this->beforeAjax(); + + $recordId = post('record_id'); + $sessionKey = $this->deferredBinding ? $this->relationGetSessionKey() : null; + + /* + * Add + */ + if ($this->viewMode == 'multi') { + $checkedIds = $recordId ? [$recordId] : post('checked'); + + if (is_array($checkedIds)) { + /* + * Remove existing relations from the array + */ + $existingIds = $this->findExistingRelationIds($checkedIds); + $checkedIds = array_diff($checkedIds, $existingIds); + $foreignKeyName = $this->relationModel->getKeyName(); + + $models = $this->relationModel->whereIn($foreignKeyName, $checkedIds)->get(); + foreach ($models as $model) { + $this->relationObject->add($model, $sessionKey); + } + } + } + /* + * Link + */ + elseif ($this->viewMode == 'single') { + if ($recordId && ($model = $this->relationModel->find($recordId))) { + if ($this->relationType === 'hasOne') { + // Unassign previous relation if one is already assigned + $relation = $this->relationObject->getParent()->{$this->relationName} ?? null; + + if ($relation) { + $this->relationObject->remove($relation, $sessionKey); + } + } + + $this->relationObject->add($model, $sessionKey); + $this->viewWidget->setFormValues($model->attributes); + + /* + * Belongs to relations won't save when using add() so + * it should occur if the conditions are right. + */ + if (!$this->deferredBinding && $this->relationType == 'belongsTo') { + $parentModel = $this->relationObject->getParent(); + if ($parentModel->exists) { + $parentModel->save(); + } + } + } + } + + return $this->relationRefresh(); + } + + /** + * Remove an existing related model from the primary model + */ + public function onRelationManageRemove() + { + $this->beforeAjax(); + + $recordId = post('record_id'); + $sessionKey = $this->deferredBinding ? $this->relationGetSessionKey() : null; + $relatedModel = $this->relationModel; + + /* + * Remove + */ + if ($this->viewMode == 'multi') { + $checkedIds = $recordId ? [$recordId] : post('checked'); + + if (is_array($checkedIds)) { + $foreignKeyName = $relatedModel->getKeyName(); + + $models = $relatedModel->whereIn($foreignKeyName, $checkedIds)->get(); + foreach ($models as $model) { + $this->relationObject->remove($model, $sessionKey); + } + } + } + /* + * Unlink + */ + elseif ($this->viewMode == 'single') { + if ($this->relationType == 'belongsTo') { + $this->relationObject->dissociate(); + $this->relationObject->getParent()->save(); + + // If the relation manager isn't using deferred binding, reinitialise the form with a blank model + if (is_null($sessionKey)) { + $this->model->refresh(); + $this->initRelation($this->model); + } + } + elseif ($this->relationType == 'hasOne' || $this->relationType == 'morphOne') { + if ($obj = $relatedModel->find($recordId)) { + $this->relationObject->remove($obj, $sessionKey); + } + elseif ($this->viewModel->exists) { + $this->relationObject->remove($this->viewModel, $sessionKey); + } + } + + // Reinitialise the form with a blank model + $this->initRelation($this->model); + + $this->viewWidget->setFormValues([]); + $this->viewModel = $this->relationModel; + } + + return $this->relationRefresh(); + } + + /** + * Add multiple items using a single pivot form. + */ + public function onRelationManageAddPivot() + { + return $this->onRelationManagePivotForm(); + } + + public function onRelationManagePivotForm() + { + $this->beforeAjax(); + + $this->vars['foreignId'] = $this->foreignId ?: post('checked'); + + return $this->relationMakePartial('pivot_form'); + } + + public function onRelationManagePivotCreate() + { + $this->beforeAjax(); + + /* + * If the pivot model fails for some reason, abort the sync + */ + Db::transaction(function () { + /* + * Add the checked IDs to the pivot table + */ + $foreignIds = (array) $this->foreignId; + $this->relationObject->sync($foreignIds, false); + + /* + * Save data to models + */ + $foreignKeyName = $this->relationModel->getQualifiedKeyName(); + $hydratedModels = $this->relationObject->whereIn($foreignKeyName, $foreignIds)->get(); + $saveData = $this->pivotWidget->getSaveData(); + + foreach ($hydratedModels as $hydratedModel) { + $modelsToSave = $this->prepareModelsToSave($hydratedModel, $saveData); + foreach ($modelsToSave as $modelToSave) { + $modelToSave->save(null, $this->pivotWidget->getSessionKey()); + } + } + }); + + return ['#'.$this->relationGetId('view') => $this->relationRenderView()]; + } + + public function onRelationManagePivotUpdate() + { + $this->beforeAjax(); + + $foreignKeyName = $this->relationModel->getQualifiedKeyName(); + $hydratedModel = $this->pivotWidget->model; + $saveData = $this->pivotWidget->getSaveData(); + + $modelsToSave = $this->prepareModelsToSave($hydratedModel, $saveData); + foreach ($modelsToSave as $modelToSave) { + $modelToSave->save(null, $this->pivotWidget->getSessionKey()); + } + + return ['#'.$this->relationGetId('view') => $this->relationRenderView()]; + } + + // + // Overrides + // + + /** + * Provides an opportunity to manipulate the field configuration. + * @param object $config + * @param string $field + * @param \October\Rain\Database\Model $model + */ + public function relationExtendConfig($config, $field, $model) + { + } + + /** + * Provides an opportunity to manipulate the view widget. + * @param Backend\Classes\WidgetBase $widget + * @param string $field + * @param \October\Rain\Database\Model $model + */ + public function relationExtendViewWidget($widget, $field, $model) + { + } + + /** + * Provides an opportunity to manipulate the manage widget. + * @param Backend\Classes\WidgetBase $widget + * @param string $field + * @param \October\Rain\Database\Model $model + */ + public function relationExtendManageWidget($widget, $field, $model) + { + } + + /** + * Provides an opportunity to manipulate the pivot widget. + * @param Backend\Classes\WidgetBase $widget + * @param string $field + * @param \October\Rain\Database\Model $model + */ + public function relationExtendPivotWidget($widget, $field, $model) + { + } + + /** + * Provides an opportunity to manipulate the manage filter widget. + * @param \Backend\Widgets\Filter $widget + * @param string $field + * @param \October\Rain\Database\Model $model + */ + public function relationExtendManageFilterWidget($widget, $field, $model) + { + } + + /** + * Provides an opportunity to manipulate the view filter widget. + * @param \Backend\Widgets\Filter $widget + * @param string $field + * @param \October\Rain\Database\Model $model + */ + public function relationExtendViewFilterWidget($widget, $field, $model) + { + } + + /** + * The view widget is often refreshed when the manage widget makes a change, + * you can use this method to inject additional containers when this process + * occurs. Return an array with the extra values to send to the browser, eg: + * + * return ['#myCounter' => 'Total records: 6']; + * + * @param string $field + * @return array + */ + public function relationExtendRefreshResults($field) + { + } + + // + // Helpers + // + + /** + * Returns the existing record IDs for the relation. + */ + protected function findExistingRelationIds($checkIds = null) + { + $foreignKeyName = $this->relationModel->getQualifiedKeyName(); + + $results = $this->relationObject + ->getBaseQuery() + ->select($foreignKeyName); + + if ($checkIds !== null && is_array($checkIds) && count($checkIds)) { + $results = $results->whereIn($foreignKeyName, $checkIds); + } + + return $results->lists($foreignKeyName); + } + + /** + * Determine the default buttons based on the model relationship type. + * @return array|null + */ + protected function evalToolbarButtons() + { + $buttons = $this->getConfig('view[toolbarButtons]'); + + if (!is_array($buttons)) { + if ($buttons === false) { + return null; + } elseif (is_string($buttons)) { + $buttons = array_map('trim', explode('|', $buttons)); + } elseif ($this->manageMode === 'pivot') { + $buttons = ['add', 'remove']; + } else { + switch ($this->relationType) { + case 'hasMany': + case 'morphMany': + case 'morphToMany': + case 'morphedByMany': + case 'belongsToMany': + $buttons = ['create', 'add', 'delete', 'remove']; + break; + + case 'hasOne': + case 'morphOne': + case 'belongsTo': + $buttons = ['create', 'update', 'link', 'delete', 'unlink']; + break; + } + } + } + + $buttonText = []; + + foreach ($buttons as $type => $text) { + if (is_numeric($type) || !$text) { + if (is_numeric($type) && $text) { + $type = $text; + } + + switch ($type) { + case 'create': + $text = 'backend::lang.relation.create_name'; + break; + + case 'update': + $text = 'backend::lang.relation.update_name'; + break; + + case 'delete': + $text = 'backend::lang.relation.delete'; + break; + + case 'add': + $text = 'backend::lang.relation.add_name'; + break; + + case 'remove': + $text = 'backend::lang.relation.remove'; + break; + + case 'link': + $text = 'backend::lang.relation.link_name'; + break; + + case 'unlink': + $text = 'backend::lang.relation.unlink'; + break; + } + } + + $buttonText[$type] = $text; + } + + return $buttonText; + } + + /** + * Determine the view mode based on the model relationship type. + * @return string + */ + protected function evalViewMode() + { + if ($this->forceViewMode) { + return $this->forceViewMode; + } + + switch ($this->relationType) { + case 'hasMany': + case 'morphMany': + case 'morphToMany': + case 'morphedByMany': + case 'belongsToMany': + return 'multi'; + + case 'hasOne': + case 'morphOne': + case 'belongsTo': + return 'single'; + } + } + + /** + * Determine the management mode popup title. + * @return string + */ + protected function evalManageTitle() + { + $customTitle = $this->getConfig('manage[title]'); + + if (is_string($customTitle)) { + return $customTitle; + } + + $customTitles = is_array($customTitle) ? $customTitle : []; + + switch ($this->manageMode) { + case 'pivot': + if (array_key_exists('pivot', $customTitles)) { + return $customTitles['pivot']; + } elseif ($this->eventTarget === 'button-link') { + return 'backend::lang.relation.link_a_new'; + } + + return 'backend::lang.relation.add_a_new'; + case 'list': + if (array_key_exists('list', $customTitles)) { + return $customTitles['list']; + } elseif ($this->eventTarget === 'button-link') { + return 'backend::lang.relation.link_a_new'; + } + + return 'backend::lang.relation.add_a_new'; + case 'form': + if (array_key_exists('form', $customTitles)) { + return $customTitles['form']; + } elseif ($this->readOnly) { + return 'backend::lang.relation.preview_name'; + } elseif ($this->manageId) { + return 'backend::lang.relation.update_name'; + } + + return 'backend::lang.relation.create_name'; + } + } + + /** + * Determine the management mode based on the relation type and settings. + * @return string + */ + protected function evalManageMode() + { + if ($mode = post(self::PARAM_MODE)) { + return $mode; + } + + if ($this->forceManageMode) { + return $this->forceManageMode; + } + + switch ($this->eventTarget) { + case 'button-create': + case 'button-update': + return 'form'; + + case 'button-link': + return 'list'; + } + + switch ($this->relationType) { + case 'belongsTo': + return 'list'; + + case 'morphToMany': + case 'morphedByMany': + case 'belongsToMany': + if (isset($this->config->pivot)) { + return 'pivot'; + } + elseif ($this->eventTarget == 'list') { + return 'form'; + } + else { + return 'list'; + } + + case 'hasOne': + case 'morphOne': + case 'hasMany': + case 'morphMany': + if ($this->eventTarget == 'button-add') { + return 'list'; + } + + return 'form'; + } + } + + /** + * Determine supplied form context. + */ + protected function evalFormContext($mode = 'manage', $exists = false) + { + $config = $this->config->{$mode} ?? []; + + if (($context = array_get($config, 'context')) && is_array($context)) { + $context = $exists + ? array_get($context, 'update') + : array_get($context, 'create'); + } + + if (!$context) { + $context = $exists ? 'update' : 'create'; + } + + return $context; + } + + /** + * Apply extra configuration + */ + protected function applyExtraConfig($config, $field = null) + { + if (!$field) { + $field = $this->field; + } + + if (!$config || !isset($this->originalConfig->{$field})) { + return; + } + + if ( + !is_array($config) && + (!$config = @json_decode(@base64_decode($config), true)) + ) { + return; + } + + $parsedConfig = array_only($config, ['readOnly']); + $parsedConfig['view'] = array_only($config, ['recordUrl', 'recordOnClick']); + + $this->originalConfig->{$field} = array_replace_recursive( + $this->originalConfig->{$field}, + $parsedConfig + ); + } + + /** + * Returns the configuration for a mode (view, manage, pivot) for an + * expected type (list, form). Uses fallback configuration. + */ + protected function makeConfigForMode($mode = 'view', $type = 'list', $throwException = true) + { + $config = null; + + /* + * Look for $this->config->view['list'] + */ + if ( + isset($this->config->{$mode}) && + array_key_exists($type, $this->config->{$mode}) + ) { + $config = $this->config->{$mode}[$type]; + } + /* + * Look for $this->config->list + */ + elseif (isset($this->config->{$type})) { + $config = $this->config->{$type}; + } + + /* + * Apply substitutes: + * + * - view.list => manage.list + */ + if (!$config) { + if ($mode == 'manage' && $type == 'list') { + return $this->makeConfigForMode('view', $type); + } + + if ($throwException) { + throw new ApplicationException('Missing configuration for '.$mode.'.'.$type.' in RelationController definition '.$this->field); + } + + return false; + } + + return $this->makeConfig($config); + } + + /** + * Returns the manage widget used by this behavior. + * + * @return \Backend\Classes\WidgetBase + */ + public function relationGetManageWidget() + { + return $this->manageWidget; + } + + /** + * Returns the view widget used by this behavior. + * + * @return \Backend\Classes\WidgetBase + */ + public function relationGetViewWidget() + { + return $this->viewWidget; + } +} diff --git a/modules/backend/behaviors/ReorderController.php b/modules/backend/behaviors/ReorderController.php new file mode 100644 index 0000000..4b96819 --- /dev/null +++ b/modules/backend/behaviors/ReorderController.php @@ -0,0 +1,310 @@ +config = $this->makeConfig($controller->reorderConfig, $this->requiredConfig); + + /* + * Widgets + */ + if ($this->toolbarWidget = $this->makeToolbarWidget()) { + $this->toolbarWidget->bindToController(); + } + + /* + * Populate from config + */ + $this->nameFrom = $this->getConfig('nameFrom', $this->nameFrom); + } + + // + // Controller actions + // + + public function reorder() + { + $this->addJs('js/october.reorder.js', 'core'); + + $this->controller->pageTitle = $this->controller->pageTitle + ?: Lang::get($this->getConfig('title', 'backend::lang.reorder.default_title')); + + $this->validateModel(); + $this->prepareVars(); + } + + // + // AJAX + // + + public function onReorder() + { + $model = $this->validateModel(); + + /* + * Simple + */ + if ($this->sortMode == 'simple') { + if ( + (!$ids = post('record_ids')) || + (!$orders = post('sort_orders')) + ) { + return; + } + + $model->setSortableOrder($ids, $orders); + } + /* + * Nested set + */ + elseif ($this->sortMode == 'nested') { + $sourceNode = $model->find(post('sourceNode')); + $targetNode = post('targetNode') ? $model->find(post('targetNode')) : null; + + if ($sourceNode == $targetNode) { + return; + } + + switch (post('position')) { + case 'before': + $sourceNode->moveBefore($targetNode); + break; + + case 'after': + $sourceNode->moveAfter($targetNode); + break; + + case 'child': + $sourceNode->makeChildOf($targetNode); + break; + + default: + $sourceNode->makeRoot(); + break; + } + } + } + + // + // Reordering + // + + /** + * Prepares common form data + */ + protected function prepareVars() + { + $this->vars['reorderRecords'] = $this->getRecords(); + $this->vars['reorderModel'] = $this->model; + $this->vars['reorderSortMode'] = $this->sortMode; + $this->vars['reorderShowTree'] = $this->showTree; + $this->vars['reorderToolbarWidget'] = $this->toolbarWidget; + } + + public function reorderRender() + { + return $this->reorderMakePartial('container'); + } + + public function reorderGetModel() + { + if ($this->model !== null) { + return $this->model; + } + + $modelClass = $this->getConfig('modelClass'); + + if (!$modelClass) { + throw new ApplicationException('Please specify the modelClass property for reordering'); + } + + return $this->model = new $modelClass; + } + + /** + * Returns the display name for a record. + * @return string + */ + public function reorderGetRecordName($record) + { + return $record->{$this->nameFrom}; + } + + /** + * Validate the supplied form model. + * @return void + */ + protected function validateModel() + { + $model = $this->controller->reorderGetModel(); + $modelTraits = class_uses($model); + + if ( + isset($modelTraits[\October\Rain\Database\Traits\Sortable::class]) || + $model->isClassExtendedWith(\October\Rain\Database\Behaviors\Sortable::class) + ) { + $this->sortMode = 'simple'; + } + elseif (isset($modelTraits[\October\Rain\Database\Traits\NestedTree::class])) { + $this->sortMode = 'nested'; + $this->showTree = true; + } + else { + throw new ApplicationException('The model must implement the Sortable trait/behavior or the NestedTree trait.'); + } + + return $model; + } + + /** + * Returns all the records from the supplied model. + * @return Collection + */ + protected function getRecords() + { + $records = null; + $model = $this->controller->reorderGetModel(); + $query = $model->newQuery(); + + $this->controller->reorderExtendQuery($query); + + if ($this->sortMode == 'simple') { + $records = $query + ->orderBy($model->getSortOrderColumn()) + ->get() + ; + } + elseif ($this->sortMode == 'nested') { + $records = $query->getNested(); + } + + return $records; + } + + /** + * Extend the query used for finding reorder records. Extra conditions + * can be applied to the query, for example, $query->withTrashed(); + * @param October\Rain\Database\Builder $query + * @return void + */ + public function reorderExtendQuery($query) + { + } + + // + // Widgets + // + + protected function makeToolbarWidget() + { + if ($toolbarConfig = $this->getConfig('toolbar')) { + $toolbarConfig = $this->makeConfig($toolbarConfig); + $toolbarWidget = $this->makeWidget('Backend\Widgets\Toolbar', $toolbarConfig); + } + else { + $toolbarWidget = null; + } + + return $toolbarWidget; + } + + // + // Helpers + // + + /** + * Controller accessor for making partials within this behavior. + * @param string $partial + * @param array $params + * @return string Partial contents + */ + public function reorderMakePartial($partial, $params = []) + { + $contents = $this->controller->makePartial( + 'reorder_' . $partial, + $params + $this->vars, + false + ); + + if (!$contents) { + $contents = $this->makePartial($partial, $params); + } + + return $contents; + } +} diff --git a/modules/backend/behaviors/UserPreferencesModel.php b/modules/backend/behaviors/UserPreferencesModel.php new file mode 100644 index 0000000..0c17d53 --- /dev/null +++ b/modules/backend/behaviors/UserPreferencesModel.php @@ -0,0 +1,117 @@ +model->setTable('backend_user_preferences'); + } + + /** + * Create an instance of the settings model, intended as a static method + */ + public function instance() + { + if (isset(self::$instances[$this->recordCode])) { + return self::$instances[$this->recordCode]; + } + + if (!$item = $this->getSettingsRecord()) { + $this->model->initSettingsData(); + $item = $this->model; + } + + return self::$instances[$this->recordCode] = $item; + } + + /** + * Checks if the model has been set up previously, intended as a static method + */ + public function isConfigured() + { + return $this->getSettingsRecord() !== null; + } + + /** + * Returns the raw Model record that stores the settings. + * @return Model + */ + public function getSettingsRecord() + { + $item = UserPreference::forUser(); + $record = $item + ->scopeApplyKeyAndUser($this->model, $this->recordCode, $item->userContext) + ->remember(1440, $this->getCacheKey()) + ->first(); + + return $record ?: null; + } + + /** + * Before the model is saved, ensure the record code is set + * and the jsonable field values + */ + public function beforeModelSave() + { + $preferences = UserPreference::forUser(); + list($namespace, $group, $item) = $preferences->parseKey($this->recordCode); + $this->model->item = $item; + $this->model->group = $group; + $this->model->namespace = $namespace; + $this->model->user_id = $preferences->userContext->id; + + if ($this->fieldValues) { + $this->model->value = $this->fieldValues; + } + } + + /** + * Checks if a key is legitimate or should be added to + * the field value collection + */ + protected function isKeyAllowed($key) + { + /* + * Let the core columns through + */ + if ($key == 'namespace' || $key == 'group') { + return true; + } + + return parent::isKeyAllowed($key); + } + + /** + * Returns a cache key for this record. + */ + protected function getCacheKey() + { + $item = UserPreference::forUser(); + $userId = $item->userContext ? $item->userContext->id : 0; + return $this->recordCode.'-userpreference-'.$userId; + } +} diff --git a/modules/backend/behaviors/importexportcontroller/TranscodeFilter.php b/modules/backend/behaviors/importexportcontroller/TranscodeFilter.php new file mode 100644 index 0000000..93f99c1 --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/TranscodeFilter.php @@ -0,0 +1,77 @@ +encodingFrom, mb_list_encodings())) { + $resource->data = @mb_convert_encoding( + $resource->data, + $this->encodingTo, + $this->encodingFrom + ); + } else { + $resource->data = @iconv( + $this->encodingFrom, + $this->encodingTo, + $resource->data + ); + } + + $consumed += $resource->datalen; + + stream_bucket_append($out, $resource); + } + + return PSFS_PASS_ON; + } + + public function onCreate() + { + if (strpos($this->filtername, self::FILTER_NAME) !== 0) { + return false; + } + + $params = substr($this->filtername, strlen(self::FILTER_NAME)); + if (!preg_match('/^([-\w]+)(:([-\w]+))?$/', $params, $matches)) { + return false; + } + + if (isset($matches[1])) { + $this->encodingFrom = $matches[1]; + } + + $this->encodingTo = mb_internal_encoding(); + if (isset($matches[3])) { + $this->encodingTo = $matches[3]; + } + + $this->params['locale'] = setlocale(LC_CTYPE, '0'); + if (stripos($this->params['locale'], 'UTF-8') === false) { + setlocale(LC_CTYPE, 'en_US.UTF-8'); + } + + return true; + } + + public function onClose() + { + setlocale(LC_CTYPE, $this->params['locale']); + } +} diff --git a/modules/backend/behaviors/importexportcontroller/assets/css/export.css b/modules/backend/behaviors/importexportcontroller/assets/css/export.css new file mode 100644 index 0000000..b90013c --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/assets/css/export.css @@ -0,0 +1,7 @@ +.export-behavior .export-columns { + max-height: 400px; + background: #f0f0f0; + padding: 20px; + padding-bottom: 0; + overflow: auto; +} diff --git a/modules/backend/behaviors/importexportcontroller/assets/css/import.css b/modules/backend/behaviors/importexportcontroller/assets/css/import.css new file mode 100644 index 0000000..31660c0 --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/assets/css/import.css @@ -0,0 +1,164 @@ +.import-behavior ul { + margin: 0; + padding: 0; + list-style: none; +} +.import-behavior ul li { + font-size: 13px; +} +.import-behavior ul li.placeholder { + display: block; + position: relative; +} +.import-behavior ul li.dragged { + position: absolute; + z-index: 2000; + -webkit-box-shadow: 0 3px 6px rgba(0, 0, 0, 0.075); + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.075); +} +.import-behavior .import-file-columns, +.import-behavior .import-db-columns { + height: 400px; + background: #f0f0f0; + padding: 5px; + overflow: auto; +} +.import-behavior .import-file-columns .upload-prompt { + display: block; + text-align: center; + position: absolute; + top: 50%; + left: 0; + right: 0; + margin-top: -10px; +} +.import-behavior .import-column-bindings > ul > li, +.import-behavior .import-db-columns > ul > li { + cursor: pointer; +} +.import-behavior ul li.dragged, +.import-behavior .import-file-columns > ul > li, +.import-behavior .import-db-columns > ul > li { + background: #ffffff; + border: 1px solid #cccccc; + border-radius: 3px; + margin-bottom: 5px; +} +.import-behavior ul li.dragged div.import-column-name > span, +.import-behavior .import-file-columns > ul > li div.import-column-name > span, +.import-behavior .import-db-columns > ul > li div.import-column-name > span, +.import-behavior ul li.dragged > span, +.import-behavior .import-file-columns > ul > li > span, +.import-behavior .import-db-columns > ul > li > span { + display: block; + padding: 8px; + padding-left: 12px; +} +.import-behavior .import-db-columns > ul > li .column-icon { + color: #ccc; + position: relative; + left: -3px; +} +.import-behavior .import-db-columns > ul > li:hover .column-icon { + color: #4da7e8; +} +.import-behavior .import-db-columns > ul > li.is-required .column-icon { + color: #ab2a1c; +} +.import-behavior .import-file-columns > ul > li:before, +.import-behavior .import-file-columns > ul > li:after { + content: " "; + display: table; +} +.import-behavior .import-file-columns > ul > li:after { + clear: both; +} +.import-behavior .import-file-columns > ul > li.is-ignored { + display: none; +} +.import-behavior .import-file-columns > ul > li .column-success-icon { + display: none; + position: relative; + left: -2px; + width: 15px; +} +.import-behavior .import-file-columns > ul > li.is-matched .column-success-icon { + display: inline-block; +} +.import-behavior .import-file-columns > ul > li.is-matched .column-ignore-button { + display: none !important; +} +.import-behavior .import-file-columns > ul div.import-column-name { + float: left; + width: 45%; +} +.import-behavior .import-file-columns > ul div.import-column-name > span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.import-behavior .import-file-columns > ul div.import-column-name a.column-label { + color: #333; +} +.import-behavior .import-file-columns > ul div.import-column-name a.column-ignore-button { + color: #fff; + background: #ccc; + font-size: 10px; + border-radius: 15px; + display: inline-block; + text-decoration: none; + width: 15px; + height: 15px; + text-align: center; + position: relative; + top: -1px; + left: -3px; +} +.import-behavior .import-file-columns > ul div.import-column-name a.column-ignore-button:hover { + background: #ab2a1c; +} +.import-behavior .import-file-columns > ul .import-column-bindings > ul { + float: right; + width: 55%; +} +.import-behavior .import-column-bindings > ul { + background: #dadedf; + position: relative; + min-height: 34px; +} +.import-behavior .import-column-bindings > ul:after { + content: ''; + display: block; + width: 0; + height: 0; + border-top: 17px solid transparent; + border-bottom: 17px solid transparent; + border-left: 18px solid #ffffff; + position: absolute; + top: 0; + left: 0; +} +.import-behavior .import-column-bindings > ul:before { + position: absolute; + padding: 8px; + padding-left: 28px; + content: attr(data-empty-text); + color: rgba(0, 0, 0, 0.5); +} +.import-behavior .import-column-bindings > ul > li .column-icon { + color: #595959; + float: right; + margin: 3px; +} +.import-behavior .import-column-bindings > ul > li:hover .column-icon { + color: #333333; +} +.import-behavior .import-column-bindings > ul > li:not(.dragged) { + background: #e8eaeb; + position: relative; +} +.import-behavior .import-column-bindings > ul > li:not(.dragged) > span { + display: block; + padding: 8px; + padding-left: 28px; +} diff --git a/modules/backend/behaviors/importexportcontroller/assets/js/october.export.js b/modules/backend/behaviors/importexportcontroller/assets/js/october.export.js new file mode 100644 index 0000000..b6f8dd5 --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/assets/js/october.export.js @@ -0,0 +1,22 @@ +/* + * Scripts for the Export controller behavior. + */ ++function ($) { "use strict"; + + var ExportBehavior = function() { + + this.processExport = function () { + var $form = $('#exportColumns').closest('form') + + $form.request('onExport', { + success: function(data) { + $('#exportContainer').html(data.result) + $(document).trigger('render') + } + }) + } + + } + + $.oc.exportBehavior = new ExportBehavior; +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/behaviors/importexportcontroller/assets/js/october.import.js b/modules/backend/behaviors/importexportcontroller/assets/js/october.import.js new file mode 100644 index 0000000..6c2eb9e --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/assets/js/october.import.js @@ -0,0 +1,149 @@ +/* + * Scripts for the Import controller behavior. + */ ++function ($) { "use strict"; + + var ImportBehavior = function() { + + this.processImport = function () { + var $form = $('#importFileColumns').closest('form') + + $form.request('onImport', { + success: function(data) { + $('#importContainer').html(data.result) + $(document).trigger('render') + } + }) + } + + this.loadFileColumnSample = function(el) { + var $el = $(el), + $column = $el.closest('[data-column-id]'), + columnId = $column.data('column-id') + + $el.popup({ + handler: 'onImportLoadColumnSampleForm', + extraData: { + file_column_id: columnId + } + }) + } + + this.bindColumnSorting = function() { + /* + * Unbind existing + */ + $('#importDbColumns > ul, .import-column-bindings > ul').each(function(){ + var $this = $(this) + if ($this.data('oc.sortable')) { + $this.sortable('destroyGroup') + $this.sortable('destroy') + } + }) + + var sortableOptions = { + group: 'import-fields', + usePlaceholderClone: true, + nested: false, + onDrop: $.proxy(this.onDropColumn, this) + } + + $('#importDbColumns > ul, .import-column-bindings > ul').sortable(sortableOptions) + } + + this.onDropColumn = function ($dbItem, container, _super, event) { + var + $fileColumns = $('#importFileColumns'), + $fileItem, + isMatch = $.contains($fileColumns.get(0), $dbItem.get(0)), + matchColumnId + + /* + * Has a previous match? + */ + matchColumnId = $dbItem.data('column-matched-id') + if (matchColumnId !== null) { + $fileItem = $('[data-column-id='+matchColumnId+']', $fileColumns) + this.toggleMatchState($fileItem) + } + + /* + * Is a new match? + */ + if (isMatch) { + $fileItem = $dbItem.closest('[data-column-id]'), + this.matchColumn($dbItem, $fileItem) + } + else { + this.unmatchColumn($dbItem) + } + + if (_super) { + _super($dbItem, container) + } + } + + this.toggleMatchState = function ($container) { + var hasItems = !!$('.import-column-bindings li', $container).length + $container.toggleClass('is-matched', hasItems) + } + + this.ignoreFileColumn = function(el) { + var $el = $(el), + $column = $el.closest('[data-column-id]') + + $column.addClass('is-ignored') + $('#showIgnoredColumnsButton').removeClass('disabled') + } + + this.showIgnoredColumns = function() { + $('#importFileColumns li.is-ignored').removeClass('is-ignored') + $('#showIgnoredColumnsButton').addClass('disabled') + } + + this.autoMatchColumns = function() { + var self = this, + fileColumns = {}, + $this, + name + + $('#importFileColumns li').each(function() { + $this = $(this) + name = $.trim($('.column-label', $this).text()) + fileColumns[name] = $this + }) + + $('#importDbColumns li').each(function() { + $this = $(this) + name = $.trim($('> span', $this).text()) + if (fileColumns[name]) { + + $this.appendTo($('.import-column-bindings > ul', fileColumns[name])) + self.matchColumn($this, fileColumns[name]) + } + }) + } + + this.matchColumn = function($dbItem, $fileItem) { + var matchColumnId = $fileItem.data('column-id'), + dbColumnName = $dbItem.data('column-name'), + $dbItemMatchInput = $('[data-column-match-input]', $dbItem) + + this.toggleMatchState($fileItem) + + $dbItem.data('column-matched-id', matchColumnId) + $dbItemMatchInput.attr('name', 'column_match['+matchColumnId+'][]') + $dbItemMatchInput.attr('value', dbColumnName) + } + + this.unmatchColumn = function($dbItem) { + var $dbItemMatchInput = $('[data-column-match-input]', $dbItem) + + $dbItem.removeData('column-matched-id') + $dbItemMatchInput.attr('name', ''); + $dbItemMatchInput.attr('value', ''); + } + } + + $.oc.importBehavior = new ImportBehavior; +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/behaviors/importexportcontroller/assets/less/export.less b/modules/backend/behaviors/importexportcontroller/assets/less/export.less new file mode 100644 index 0000000..5f2e9f1 --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/assets/less/export.less @@ -0,0 +1,13 @@ +@import "../../../../assets/less/core/boot.less"; + +.export-behavior { + + .export-columns { + max-height: 400px; + background: #f0f0f0; + padding: @padding-standard; + padding-bottom: 0; + overflow: auto; + } + +} \ No newline at end of file diff --git a/modules/backend/behaviors/importexportcontroller/assets/less/import.less b/modules/backend/behaviors/importexportcontroller/assets/less/import.less new file mode 100644 index 0000000..56d8cba --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/assets/less/import.less @@ -0,0 +1,201 @@ +@import "../../../../assets/less/core/boot.less"; + +@color-import-column-bg: #fff; +@color-import-column-border: #ccc; +@color-import-bound-bg: #e8eaeb; +@import-column-padding: 8px; +@import-column-font-size: 13px; + +.import-behavior { + + ul { + margin: 0; + padding: 0; + list-style: none; + + li { + font-size: @import-column-font-size; + } + + li.placeholder { + display: block; + position: relative; + } + + li.dragged { + position: absolute; + z-index: 2000; + .box-shadow(0 3px 6px rgba(0,0,0,.075)); + } + } + + .import-file-columns, + .import-db-columns { + height: 400px; + background: #f0f0f0; + padding: 5px; + overflow: auto; + } + .import-file-columns { + .upload-prompt { + display: block; + text-align: center; + position: absolute; + top: 50%; + left: 0; + right: 0; + margin-top: -10px; + } + } + + .import-column-bindings > ul > li, + .import-db-columns > ul > li { + cursor: pointer; + } + + ul li.dragged, + .import-file-columns > ul > li, + .import-db-columns > ul > li { + background: @color-import-column-bg; + border: 1px solid @color-import-column-border; + border-radius: 3px; + margin-bottom: 5px; + + div.import-column-name > span, + > span { + display: block; + padding: @import-column-padding; + padding-left: (@import-column-padding * 1.5); + } + } + + .import-db-columns > ul { + > li { + .column-icon { + color: #ccc; + position: relative; + left: -3px; + } + &:hover .column-icon { + color: #4da7e8; + } + + &.is-required { + .column-icon { + color: #ab2a1c; + } + } + } + } + + .import-file-columns > ul { + > li { + .clearfix; + + &.is-ignored { + display: none; + } + + .column-success-icon { + display: none; + position: relative; + left: -2px; + width: 15px; + } + + &.is-matched { + .column-success-icon { + display: inline-block; + } + .column-ignore-button { + display: none !important; + } + } + } + + div.import-column-name { + float: left; + width: 45%; + + > span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + a.column-label { + color: #333; + } + + a.column-ignore-button { + color: #fff; + background: #ccc; + font-size: 10px; + border-radius: 15px; + display: inline-block; + text-decoration: none; + width: 15px; + height: 15px; + text-align: center; + position: relative; + top: -1px; + left: -3px; + &:hover { + background: #ab2a1c; + } + } + } + + .import-column-bindings > ul { + float: right; + width: 55%; + } + } + + .import-column-bindings > ul { + background: darken(@color-import-bound-bg, 5%); + position: relative; + min-height: (@import-column-padding * 2) + 18px; + + &:after { + .triangle(right, 18px, (@import-column-padding * 2) + 18px, @color-import-column-bg); + position: absolute; + top: 0; + left: 0; + } + + &:before { + position: absolute; + padding: @import-column-padding; + padding-left: 28px; + content: attr(data-empty-text); + color: rgba(0,0,0,.5); + } + + > li { + .column-icon { + color: #595959; + float: right; + margin: 3px; + } + + &:hover { + .column-icon { + color: #333333; + } + } + } + + > li:not(.dragged) { + background: @color-import-bound-bg; + position: relative; + + > span { + display: block; + padding: @import-column-padding; + padding-left: 28px; + } + } + } + +} \ No newline at end of file diff --git a/modules/backend/behaviors/importexportcontroller/partials/_button_export.htm b/modules/backend/behaviors/importexportcontroller/partials/_button_export.htm new file mode 100644 index 0000000..e69de29 diff --git a/modules/backend/behaviors/importexportcontroller/partials/_button_import.htm b/modules/backend/behaviors/importexportcontroller/partials/_button_import.htm new file mode 100644 index 0000000..e69de29 diff --git a/modules/backend/behaviors/importexportcontroller/partials/_column_sample_form.htm b/modules/backend/behaviors/importexportcontroller/partials/_column_sample_form.htm new file mode 100644 index 0000000..9dfbf66 --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/partials/_column_sample_form.htm @@ -0,0 +1,29 @@ + + + diff --git a/modules/backend/behaviors/importexportcontroller/partials/_container_export.htm b/modules/backend/behaviors/importexportcontroller/partials/_container_export.htm new file mode 100644 index 0000000..f7042e0 --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/partials/_container_export.htm @@ -0,0 +1,9 @@ +
+ + render() ?> + + + render() ?> + + +
diff --git a/modules/backend/behaviors/importexportcontroller/partials/_container_import.htm b/modules/backend/behaviors/importexportcontroller/partials/_container_import.htm new file mode 100644 index 0000000..508cb41 --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/partials/_container_import.htm @@ -0,0 +1,9 @@ +
+ + render() ?> + + + render() ?> + + +
diff --git a/modules/backend/behaviors/importexportcontroller/partials/_export_columns.htm b/modules/backend/behaviors/importexportcontroller/partials/_export_columns.htm new file mode 100644 index 0000000..5896796 --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/partials/_export_columns.htm @@ -0,0 +1,27 @@ +
+
+
    + $column): ?> +
  • +
    + + + +
    +
  • + +
+
+
\ No newline at end of file diff --git a/modules/backend/behaviors/importexportcontroller/partials/_export_form.htm b/modules/backend/behaviors/importexportcontroller/partials/_export_form.htm new file mode 100644 index 0000000..f98f261 --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/partials/_export_form.htm @@ -0,0 +1,50 @@ +
+ fatalError): ?> + + 'exportForm']) ?> + + +
+ +
+ + + + + + + + + + + +
diff --git a/modules/backend/behaviors/importexportcontroller/partials/_export_result_form.htm b/modules/backend/behaviors/importexportcontroller/partials/_export_result_form.htm new file mode 100644 index 0000000..81038ea --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/partials/_export_result_form.htm @@ -0,0 +1,34 @@ +fatalError): ?> + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/backend/behaviors/importexportcontroller/partials/_import_db_columns.htm b/modules/backend/behaviors/importexportcontroller/partials/_import_db_columns.htm new file mode 100644 index 0000000..00eeef4 --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/partials/_import_db_columns.htm @@ -0,0 +1,23 @@ +
+
    + $label): ?> + importIsColumnRequired($column); + $iconName = $isRequired ? 'icon-asterisk' : 'icon-link'; + ?> +
  • + + + + + +
  • + +
+
+ + \ No newline at end of file diff --git a/modules/backend/behaviors/importexportcontroller/partials/_import_file_columns.htm b/modules/backend/behaviors/importexportcontroller/partials/_import_file_columns.htm new file mode 100644 index 0000000..b221e54 --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/partials/_import_file_columns.htm @@ -0,0 +1,44 @@ +
+ +
    + $column): ?> +
  • +
    + + + + + + + + + +
    +
    +
      +
      +
    • + +
    + +

    + +

    + +
    + + diff --git a/modules/backend/behaviors/importexportcontroller/partials/_import_form.htm b/modules/backend/behaviors/importexportcontroller/partials/_import_form.htm new file mode 100644 index 0000000..220879d --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/partials/_import_form.htm @@ -0,0 +1,50 @@ +
    + fatalError): ?> + + 'importForm']) ?> + + +
    + +
    + + + + + + + + + + + +
    diff --git a/modules/backend/behaviors/importexportcontroller/partials/_import_result_form.htm b/modules/backend/behaviors/importexportcontroller/partials/_import_result_form.htm new file mode 100644 index 0000000..c6d97e8 --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/partials/_import_result_form.htm @@ -0,0 +1,101 @@ +fatalError): ?> + + + + + + + + + + diff --git a/modules/backend/behaviors/importexportcontroller/partials/_import_toolbar.htm b/modules/backend/behaviors/importexportcontroller/partials/_import_toolbar.htm new file mode 100644 index 0000000..f7b3e0b --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/partials/_import_toolbar.htm @@ -0,0 +1,16 @@ + diff --git a/modules/backend/behaviors/importexportcontroller/partials/fields_export.yaml b/modules/backend/behaviors/importexportcontroller/partials/fields_export.yaml new file mode 100644 index 0000000..3d0f1bd --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/partials/fields_export.yaml @@ -0,0 +1,58 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + step1_section: + label: backend::lang.import_export.export_output_format + type: section + + format_preset: + label: backend::lang.import_export.file_format + type: dropdown + default: standard + options: + standard: backend::lang.import_export.standard_format + custom: backend::lang.import_export.custom_format + span: left + + format_delimiter: + label: backend::lang.import_export.delimiter_char + default: ',' + span: left + trigger: + action: show + condition: value[custom] + field: format_preset + + format_enclosure: + label: backend::lang.import_export.enclosure_char + span: auto + default: '"' + trigger: + action: show + condition: value[custom] + field: format_preset + + format_escape: + label: backend::lang.import_export.escape_char + span: auto + default: '\' + trigger: + action: show + condition: value[custom] + field: format_preset + + step2_section: + label: backend::lang.import_export.select_columns + type: section + + export_columns: + label: backend::lang.import_export.columns + type: partial + path: ~/modules/backend/behaviors/importexportcontroller/partials/_export_columns.htm + span: left + + step3_section: + label: backend::lang.import_export.set_export_options + type: section diff --git a/modules/backend/behaviors/importexportcontroller/partials/fields_import.yaml b/modules/backend/behaviors/importexportcontroller/partials/fields_import.yaml new file mode 100644 index 0000000..7c23973 --- /dev/null +++ b/modules/backend/behaviors/importexportcontroller/partials/fields_import.yaml @@ -0,0 +1,95 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + step1_section: + label: backend::lang.import_export.upload_csv_file + type: section + + import_file: + label: backend::lang.import_export.import_file + type: fileupload + mode: file + span: left + fileTypes: csv + useCaption: false + + format_preset: + label: backend::lang.import_export.file_format + type: dropdown + default: standard + options: + standard: backend::lang.import_export.standard_format + custom: backend::lang.import_export.custom_format + span: right + + format_delimiter: + label: backend::lang.import_export.delimiter_char + default: ',' + span: left + trigger: + action: show + condition: value[custom] + field: format_preset + + format_enclosure: + label: backend::lang.import_export.enclosure_char + span: auto + default: '"' + trigger: + action: show + condition: value[custom] + field: format_preset + + format_escape: + label: backend::lang.import_export.escape_char + span: auto + default: '\' + trigger: + action: show + condition: value[custom] + field: format_preset + + format_encoding: + label: backend::lang.import_export.encoding_format + span: auto + default: UTF-8 + type: dropdown + trigger: + action: show + condition: value[custom] + field: format_preset + + first_row_titles: + label: backend::lang.import_export.first_row_contains_titles + comment: backend::lang.import_export.first_row_contains_titles_desc + type: checkbox + default: true + span: left + + step2_section: + label: backend::lang.import_export.match_columns + type: section + + column_control_panel: + type: partial + path: ~/modules/backend/behaviors/importexportcontroller/partials/_import_toolbar.htm + + import_file_columns: + label: backend::lang.import_export.file_columns + type: partial + path: ~/modules/backend/behaviors/importexportcontroller/partials/_import_file_columns.htm + dependsOn: [import_file, first_row_titles, format_delimiter, format_enclosure, format_escape, format_encoding] + span: left + + import_db_columns: + label: backend::lang.import_export.database_fields + type: partial + path: ~/modules/backend/behaviors/importexportcontroller/partials/_import_db_columns.htm + dependsOn: [import_file, first_row_titles, format_delimiter, format_enclosure, format_escape, format_encoding] + span: right + + step3_section: + label: backend::lang.import_export.set_import_options + type: section \ No newline at end of file diff --git a/modules/backend/behaviors/listcontroller/partials/_container.htm b/modules/backend/behaviors/listcontroller/partials/_container.htm new file mode 100644 index 0000000..037ba06 --- /dev/null +++ b/modules/backend/behaviors/listcontroller/partials/_container.htm @@ -0,0 +1,9 @@ + + render() ?> + + + + render() ?> + + +render() ?> diff --git a/modules/backend/behaviors/relationcontroller/assets/css/relation.css b/modules/backend/behaviors/relationcontroller/assets/css/relation.css new file mode 100644 index 0000000..ad68855 --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/assets/css/relation.css @@ -0,0 +1,39 @@ +.relation-behavior { + margin-bottom: 20px; +} +.relation-behavior .control-list { + border: 1px solid #eeeeee; +} +.relation-behavior .control-list thead > tr > th { + border-top: none !important; + border-color: #eeeeee; +} +.relation-behavior .control-toolbar { + padding: 0 20px 20px 20px; +} +.relation-behavior .control-toolbar .toolbar-item .form-control.search { + padding-top: 5px; + padding-bottom: 5px; +} +.relation-behavior .control-toolbar .loading-indicator-container.size-input-text { + min-height: 0; +} +.relation-behavior .control-toolbar .loading-indicator-container.size-input-text .loading-indicator > span { + top: 4px; +} +.relation-behavior .list-header { + padding: 0; +} +.relation-behavior .control-list:last-child > table { + margin-bottom: 0; +} +.relation-flush .control-list { + border-top: none; +} +.relation-inset { + margin-left: -20px; + margin-right: -20px; +} +.form-group > .relation-behavior .control-toolbar { + padding: 0 0 10px 0; +} diff --git a/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js b/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js new file mode 100644 index 0000000..126e392 --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js @@ -0,0 +1,100 @@ +/* + * Scripts for the Relation controller behavior. + */ ++function ($) { "use strict"; + + var RelationBehavior = function() { + + this.toggleListCheckbox = function(el) { + $(el).closest('.control-list').listWidget('toggleChecked', [el]) + } + + this.clickViewListRecord = function(recordId, relationId, sessionKey) { + var newPopup = $(''), + $container = $('#'+relationId), + requestData = paramToObj('data-request-data', $container.data('request-data')) + + newPopup.popup({ + handler: 'onRelationClickViewList', + size: 'huge', + extraData: $.extend({}, requestData, { + 'manage_id': recordId, + '_session_key': sessionKey + }) + }) + } + + this.clickManageListRecord = function(recordId, relationId, sessionKey) { + var oldPopup = $('#relationManagePopup'), + $container = $('#'+relationId), + requestData = paramToObj('data-request-data', $container.data('request-data')) + + $.request('onRelationClickManageList', { + data: $.extend({}, requestData, { + 'record_id': recordId, + '_session_key': sessionKey + }) + }) + + oldPopup.popup('hide') + } + + this.clickManagePivotListRecord = function(foreignId, relationId, sessionKey) { + var oldPopup = $('#relationManagePivotPopup'), + newPopup = $(''), + $container = $('#'+relationId), + requestData = paramToObj('data-request-data', $container.data('request-data')) + + if (oldPopup.length) { + oldPopup.popup('hide') + } + + newPopup.popup({ + handler: 'onRelationClickManageListPivot', + size: 'huge', + extraData: $.extend({}, requestData, { + 'foreign_id': foreignId, + '_session_key': sessionKey + }) + }) + } + + /* + * This function is called every time a record is created, added, removed + * or deleted using the relation widget. It triggers the change.oc.formwidget + * event to notify other elements on the page about the changed form state. + */ + this.changed = function(relationId, event) { + $('[data-field-name="' + relationId + '"]').trigger('change.oc.formwidget', {event: event}); + } + + /* + * This function transfers the supplied variables as hidden form inputs, + * to any popup that is spawned within the supplied container. The spawned + * popup must contain a form element. + */ + this.bindToPopups = function(container, vars) { + $(container).on('show.oc.popup', function(event, $trigger, $modal){ + var $form = $('form', $modal) + $.each(vars, function(name, value){ + $form.prepend($('').attr({ type: 'hidden', name: name, value: value })) + }) + }) + } + + function paramToObj(name, value) { + if (value === undefined) value = '' + if (typeof value == 'object') return value + + try { + return ocJSON("{" + value + "}") + } + catch (e) { + throw new Error('Error parsing the '+name+' attribute value. '+e) + } + } + + } + + $.oc.relationBehavior = new RelationBehavior; +}(window.jQuery); diff --git a/modules/backend/behaviors/relationcontroller/assets/less/relation.less b/modules/backend/behaviors/relationcontroller/assets/less/relation.less new file mode 100644 index 0000000..a6731fa --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/assets/less/relation.less @@ -0,0 +1,60 @@ +@import "../../../../assets/less/core/boot.less"; + +@color-relation-border: #eeeeee; + +.relation-behavior { + margin-bottom: 20px; + + .control-list { + border: 1px solid @color-relation-border; + + thead > tr > th { + border-top: none !important; + border-color: @color-relation-border; + } + } + + .control-toolbar { + padding: 0 20px 20px 20px; + + .toolbar-item .form-control.search { + padding-top: 5px; + padding-bottom: 5px; + } + + .loading-indicator-container.size-input-text { + min-height: 0; + .loading-indicator > span { + top: 4px; + } + } + } + + .list-header { + padding: 0; + } + + .control-list:last-child > table { + margin-bottom: 0; + } +} + +// Relation manager to sit flush to the element above +.relation-flush { + .control-list { + border-top: none; + } +} + +// Relation manager to sit inset the standard padding (20px) +.relation-inset { + margin-left: -20px; + margin-right: -20px; +} + +// Displayed in a form field +.form-group > .relation-behavior { + .control-toolbar { + padding: 0 0 10px 0; + } +} \ No newline at end of file diff --git a/modules/backend/behaviors/relationcontroller/partials/_button_add.htm b/modules/backend/behaviors/relationcontroller/partials/_button_add.htm new file mode 100644 index 0000000..6939b3b --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_button_add.htm @@ -0,0 +1,8 @@ + + trans($relationLabel)])) ?> + diff --git a/modules/backend/behaviors/relationcontroller/partials/_button_create.htm b/modules/backend/behaviors/relationcontroller/partials/_button_create.htm new file mode 100644 index 0000000..d7d3569 --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_button_create.htm @@ -0,0 +1,8 @@ + + trans($relationLabel)])) ?> + diff --git a/modules/backend/behaviors/relationcontroller/partials/_button_delete.htm b/modules/backend/behaviors/relationcontroller/partials/_button_delete.htm new file mode 100644 index 0000000..d8fd4ff --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_button_delete.htm @@ -0,0 +1,26 @@ + + + + + diff --git a/modules/backend/behaviors/relationcontroller/partials/_button_link.htm b/modules/backend/behaviors/relationcontroller/partials/_button_link.htm new file mode 100644 index 0000000..b4ad470 --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_button_link.htm @@ -0,0 +1,8 @@ + + trans($relationLabel)])) ?> + diff --git a/modules/backend/behaviors/relationcontroller/partials/_button_remove.htm b/modules/backend/behaviors/relationcontroller/partials/_button_remove.htm new file mode 100644 index 0000000..c288bde --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_button_remove.htm @@ -0,0 +1,24 @@ + + + + + diff --git a/modules/backend/behaviors/relationcontroller/partials/_button_unlink.htm b/modules/backend/behaviors/relationcontroller/partials/_button_unlink.htm new file mode 100644 index 0000000..30851ee --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_button_unlink.htm @@ -0,0 +1,9 @@ + + + diff --git a/modules/backend/behaviors/relationcontroller/partials/_button_update.htm b/modules/backend/behaviors/relationcontroller/partials/_button_update.htm new file mode 100644 index 0000000..3f267e4 --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_button_update.htm @@ -0,0 +1,9 @@ + + trans($relationLabel)])) ?> + diff --git a/modules/backend/behaviors/relationcontroller/partials/_container.htm b/modules/backend/behaviors/relationcontroller/partials/_container.htm new file mode 100644 index 0000000..eb66e96 --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_container.htm @@ -0,0 +1,18 @@ +
    + + relationRenderToolbar()): ?> + +
    + +
    + + + +
    + relationRenderView() ?> +
    + +
    diff --git a/modules/backend/behaviors/relationcontroller/partials/_manage_form.htm b/modules/backend/behaviors/relationcontroller/partials/_manage_form.htm new file mode 100644 index 0000000..adfe149 --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_manage_form.htm @@ -0,0 +1,100 @@ +
    + + + true, + 'sessionKey' => $newSessionKey, + 'data-request-success' => "$.oc.relationBehavior.changed('" . e($this->vars['relationField']) . "', 'updated')", + ]) ?> + + + + + + + + + + + + + + + + + + true, + 'data-request-success' => "$.oc.relationBehavior.changed('" . e($this->vars['relationField']) . "', 'created')", + 'sessionKey' => $newSessionKey + ]) ?> + + + + + + + + + + + + + +
    + + diff --git a/modules/backend/behaviors/relationcontroller/partials/_manage_list.htm b/modules/backend/behaviors/relationcontroller/partials/_manage_list.htm new file mode 100644 index 0000000..4d24002 --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_manage_list.htm @@ -0,0 +1,40 @@ +
    + + + +
    + + render() ?> + + + render() ?> + + render() ?> +
    + + + +
    \ No newline at end of file diff --git a/modules/backend/behaviors/relationcontroller/partials/_manage_pivot.htm b/modules/backend/behaviors/relationcontroller/partials/_manage_pivot.htm new file mode 100644 index 0000000..52885f1 --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_manage_pivot.htm @@ -0,0 +1,49 @@ +
    + + + + + +
    + + render() ?> + + + render() ?> + + render() ?> +
    + + + +
    + diff --git a/modules/backend/behaviors/relationcontroller/partials/_pivot_form.htm b/modules/backend/behaviors/relationcontroller/partials/_pivot_form.htm new file mode 100644 index 0000000..b2a9ff1 --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_pivot_form.htm @@ -0,0 +1,76 @@ + + + ['_relation_field' => $relationField, 'manage_id' => $relationManageId], + 'data-request-success' => "$.oc.relationBehavior.changed('" . e($this->vars['relationField']) . "', 'updated')", + 'data-popup-load-indicator' => true + ]) ?> + + + + + + + + + + ['_relation_field' => $relationField, 'foreign_id' => $foreignId], + 'data-request-success' => "$.oc.relationBehavior.changed('" . e($this->vars['relationField']) . "', 'created')", + 'data-popup-load-indicator' => true + ]) ?> + + + + + + + + + + + + diff --git a/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm b/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm new file mode 100644 index 0000000..d7f85f5 --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm @@ -0,0 +1,18 @@ +
    + + $text): ?> + + + relationMakePartial('button_update', [ + 'relationManageId' => $relationViewModel->getKey(), + 'text' => $text + ]) ?> + + relationMakePartial('button_' . $type, [ + 'text' => $text + ]) ?> + + + + +
    diff --git a/modules/backend/behaviors/relationcontroller/partials/_view.htm b/modules/backend/behaviors/relationcontroller/partials/_view.htm new file mode 100644 index 0000000..7f154eb --- /dev/null +++ b/modules/backend/behaviors/relationcontroller/partials/_view.htm @@ -0,0 +1,5 @@ + + render() ?> + + +render() ?> \ No newline at end of file diff --git a/modules/backend/behaviors/reordercontroller/assets/js/october.reorder.js b/modules/backend/behaviors/reordercontroller/assets/js/october.reorder.js new file mode 100644 index 0000000..5ce4957 --- /dev/null +++ b/modules/backend/behaviors/reordercontroller/assets/js/october.reorder.js @@ -0,0 +1,82 @@ +/* + * Scripts for the Reorder controller behavior. + * + * The following functions are observed: + * - Simple sorting: Post back the original sort orders and the new ordered identifiers. + * - Nested sorting: Post back source and target nodes IDs and the move positioning. + */ ++function ($) { "use strict"; + + var ReorderBehavior = function() { + + this.sortMode = null + + this.simpleSortOrders = [] + + this.initSorting = function (mode) { + this.sortMode = mode + + if (mode == 'simple') { + this.initSortingSimple() + } + + $('#reorderTreeList').on('move.oc.treelist', $.proxy(this.processReorder, this)) + } + + + this.processReorder = function(ev, sortData){ + var postData + + if (this.sortMode == 'simple') { + postData = { sort_orders: this.simpleSortOrders } + } + else if (this.sortMode == 'nested') { + postData = this.getNestedMoveData(sortData) + } + + $('#reorderTreeList').request('onReorder', { + data: postData + }) + } + + this.getNestedMoveData = function (sortData) { + var + $el, + $item = sortData.item, + moveData = { + targetNode: 0, + sourceNode: $item.data('recordId'), + position: 'root' + } + + if (($el = $item.next()) && $el.length) { + moveData.position = 'before' + } + else if (($el = $item.prev()) && $el.length) { + moveData.position = 'after' + } + else if (($el = $item.parents('li:first')) && $el.length) { + moveData.position = 'child' + } + + if ($el.length) { + moveData.targetNode = $el.data('recordId') + } + + return moveData + } + + this.initSortingSimple = function () { + var sortOrders = [] + + $('#reorderTreeList li').each(function(){ + sortOrders.push($(this).data('recordSortOrder')) + }) + + this.simpleSortOrders = sortOrders + } + + } + + $.oc.reorderBehavior = new ReorderBehavior; +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/behaviors/reordercontroller/partials/_container.htm b/modules/backend/behaviors/reordercontroller/partials/_container.htm new file mode 100644 index 0000000..6d329f3 --- /dev/null +++ b/modules/backend/behaviors/reordercontroller/partials/_container.htm @@ -0,0 +1,29 @@ + + +
    + render() ?> +
    + + + + +
    + data-handle=" li > .record > a.move' ?>" + data-stripe-load-indicator> + +
      + reorderMakePartial('records', ['records' => $reorderRecords]) ?> +
    + +

    + +
    + + + diff --git a/modules/backend/behaviors/reordercontroller/partials/_records.htm b/modules/backend/behaviors/reordercontroller/partials/_records.htm new file mode 100644 index 0000000..774461e --- /dev/null +++ b/modules/backend/behaviors/reordercontroller/partials/_records.htm @@ -0,0 +1,23 @@ + + +
  • + data-record-sort-order="{$record->getSortOrderColumn()} ?>" + + > +
    + + reorderGetRecordName($record)) ?> + +
    + + +
      + children): ?> + reorderMakePartial('records', ['records' => $record->children]) ?> + +
    + +
  • + + diff --git a/modules/backend/classes/AuthManager.php b/modules/backend/classes/AuthManager.php new file mode 100644 index 0000000..85a59ae --- /dev/null +++ b/modules/backend/classes/AuthManager.php @@ -0,0 +1,260 @@ + null, + 'label' => null, + 'comment' => null, + 'roles' => null, + 'order' => 500 + ]; + + /** + * @var array Cache of registration callbacks. + */ + protected $callbacks = []; + + /** + * @var array List of registered permissions. + */ + protected $permissions = []; + + /** + * @var array List of registered permission roles. + */ + protected $permissionRoles = false; + + /** + * @var array Cache of registered permissions. + */ + protected $permissionCache = false; + + protected function init() + { + $this->useThrottle = Config::get('auth.throttle.enabled', true); + parent::init(); + } + + /** + * Registers a callback function that defines authentication permissions. + * The callback function should register permissions by calling the manager's + * registerPermissions() function. The manager instance is passed to the + * callback function as an argument. Usage: + * + * BackendAuth::registerCallback(function ($manager) { + * $manager->registerPermissions([...]); + * }); + * + * @param callable $callback A callable function. + */ + public function registerCallback(callable $callback) + { + $this->callbacks[] = $callback; + } + + /** + * Registers the back-end permission items. + * The argument is an array of the permissions. The array keys represent the + * permission codes, specific for the plugin/module. Each element in the + * array should be an associative array with the following keys: + * - label - specifies the menu label localization string key, required. + * - order - a position of the item in the menu, optional. + * - comment - a brief comment that describes the permission, optional. + * - tab - assign this permission to a tabbed group, optional. + * @param string $owner Specifies the permissions' owner plugin or module in the format Author.Plugin + * @param array $definitions An array of the menu item definitions. + */ + public function registerPermissions($owner, array $definitions) + { + foreach ($definitions as $code => $definition) { + $permission = (object)array_merge(self::$permissionDefaults, array_merge($definition, [ + 'code' => $code, + 'owner' => $owner + ])); + + $this->permissions[] = $permission; + } + } + + /** + * Removes a single back-end permission + * @param string $owner Specifies the permissions' owner plugin or module in the format Author.Plugin + * @param string $code The code of the permission to remove + * @return void + */ + public function removePermission($owner, $code) + { + if (!$this->permissions) { + throw new SystemException('Unable to remove permissions before they are loaded.'); + } + + $ownerPermissions = array_filter($this->permissions, function ($permission) use ($owner) { + return $permission->owner === $owner; + }); + + foreach ($ownerPermissions as $key => $permission) { + if ($permission->code === $code) { + unset($this->permissions[$key]); + } + } + } + + /** + * Returns a list of the registered permissions items. + * @return array + */ + public function listPermissions() + { + if ($this->permissionCache !== false) { + return $this->permissionCache; + } + + /* + * Load module items + */ + foreach ($this->callbacks as $callback) { + $callback($this); + } + + /* + * Load plugin items + */ + $plugins = PluginManager::instance()->getPlugins(); + + foreach ($plugins as $id => $plugin) { + $items = $plugin->registerPermissions(); + if (!is_array($items)) { + continue; + } + + $this->registerPermissions($id, $items); + } + + /* + * Sort permission items + */ + usort($this->permissions, function ($a, $b) { + if ($a->order == $b->order) { + return 0; + } + + return $a->order > $b->order ? 1 : -1; + }); + + return $this->permissionCache = $this->permissions; + } + + /** + * Returns an array of registered permissions, grouped by tabs. + * @return array + */ + public function listTabbedPermissions() + { + $tabs = []; + + foreach ($this->listPermissions() as $permission) { + $tab = $permission->tab ?? 'backend::lang.form.undefined_tab'; + + if (!array_key_exists($tab, $tabs)) { + $tabs[$tab] = []; + } + + $tabs[$tab][] = $permission; + } + + return $tabs; + } + + /** + * {@inheritdoc} + */ + protected function createUserModelQuery() + { + return parent::createUserModelQuery()->withTrashed(); + } + + + /** + * {@inheritdoc} + */ + protected function validateUserModel($user) + { + if ( ! $user instanceof $this->userModel) { + return false; + } + + // Perform the deleted_at check manually since the relevant migrations + // might not have been run yet during the update to build 444. + // @see https://github.com/octobercms/october/issues/3999 + if (array_key_exists('deleted_at', $user->getAttributes()) && $user->deleted_at !== null) { + return false; + } + + return $user; + } + + /** + * Returns an array of registered permissions belonging to a given role code + * @param string $role + * @param bool $includeOrphans + * @return array + */ + public function listPermissionsForRole($role, $includeOrphans = true) + { + if ($this->permissionRoles === false) { + $this->permissionRoles = []; + + foreach ($this->listPermissions() as $permission) { + if ($permission->roles) { + foreach ((array) $permission->roles as $_role) { + $this->permissionRoles[$_role][$permission->code] = 1; + } + } + else { + $this->permissionRoles['*'][$permission->code] = 1; + } + } + } + + $result = $this->permissionRoles[$role] ?? []; + + if ($includeOrphans) { + $result += $this->permissionRoles['*'] ?? []; + } + + return $result; + } + + public function hasPermissionsForRole($role) + { + return !!$this->listPermissionsForRole($role, false); + } +} diff --git a/modules/backend/classes/BackendController.php b/modules/backend/classes/BackendController.php new file mode 100644 index 0000000..9e708db --- /dev/null +++ b/modules/backend/classes/BackendController.php @@ -0,0 +1,312 @@ +middleware(function ($request, $next) { + // Process the request before retrieving controller middleware, to allow for the session and auth data + // to be made available to the controller's constructor. + $response = $next($request); + + // Find requested controller to determine if any middleware has been attached + $pathParts = explode('/', str_replace(Request::root() . '/', '', Request::url())); + if (count($pathParts)) { + // Drop off preceding backend URL part if needed + if (!empty(Config::get('cms.backendUri', 'backend'))) { + array_shift($pathParts); + } + $path = implode('/', $pathParts); + + $requestedController = $this->getRequestedController($path); + if ( + !is_null($requestedController) + && is_array($requestedController) + && count($requestedController['controller']->getMiddleware()) + ) { + $action = $requestedController['action']; + + // Collect applicable middleware and insert middleware into pipeline + $controllerMiddleware = collect($requestedController['controller']->getMiddleware()) + ->reject(function ($data) use ($action) { + return static::methodExcludedByOptions($action, $data['options']); + }) + ->pluck('middleware'); + + foreach ($controllerMiddleware as $middleware) { + $middleware->call($requestedController['controller'], $request, $response); + } + } + } + + return $response; + }); + + $this->extendableConstruct(); + } + + /** + * Extend this object properties upon construction. + */ + public static function extend(Closure $callback) + { + self::extendableExtendCallback($callback); + } + + /** + * @inheritDoc + */ + public function callAction($method, $parameters) + { + return parent::callAction($method, array_values($parameters)); + } + + /** + * Pass unhandled URLs to the CMS Controller, if it exists + * + * @param string $url + * @return Response + */ + protected function passToCmsController($url) + { + if ( + in_array('Cms', Config::get('cms.loadModules', [])) && + class_exists('\Cms\Classes\Controller') + ) { + $this->cmsHandling = true; + return App::make('Cms\Classes\Controller')->run($url); + } else { + return Response::make(View::make('backend::404'), 404); + } + } + + /** + * Finds and serves the requested backend controller. + * If the controller cannot be found, returns the Cms page with the URL /404. + * If the /404 page doesn't exist, returns the system 404 page. + * @param string $url Specifies the requested page URL. + * If the parameter is omitted, the current URL used. + * @return string Returns the processed page content. + */ + public function run($url = null) + { + $params = RouterHelper::segmentizeUrl($url); + + // Handle NotFoundHttpExceptions in the backend (usually triggered by abort(404)) + Event::listen('exception.beforeRender', function ($exception, $httpCode, $request) { + if (!$this->cmsHandling && $exception instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException) { + return View::make('backend::404'); + } + }, 1); + + /* + * Database check + */ + if (!App::hasDatabase()) { + return Config::get('app.debug', false) + ? Response::make(View::make('backend::no_database'), 200) + : $this->passToCmsController($url); + } + + $controllerRequest = $this->getRequestedController($url); + if (!is_null($controllerRequest)) { + return $controllerRequest['controller']->run( + $controllerRequest['action'], + $controllerRequest['params'] + ); + } + + /* + * Fall back on Cms controller + */ + return $this->passToCmsController($url); + } + + /** + * Determines the controller and action to load in the backend via a provided URL. + * + * If a suitable controller is found, this will return an array with the controller class name as a string, the + * action to call as a string and an array of parameters. If a suitable controller and action cannot be found, + * this method will return null. + * + * @param string $url A URL to determine the requested controller and action for + * @return array|null A suitable controller, action and parameters in an array if found, otherwise null. + */ + protected function getRequestedController($url) + { + $params = RouterHelper::segmentizeUrl($url); + + /* + * Look for a Module controller + */ + $module = $params[0] ?? 'backend'; + $controller = $params[1] ?? 'index'; + self::$action = $action = isset($params[2]) ? $this->parseAction($params[2]) : 'index'; + self::$params = $controllerParams = array_slice($params, 3); + $controllerClass = '\\'.$module.'\Controllers\\'.$controller; + if ($controllerObj = $this->findController( + $controllerClass, + $action, + base_path().'/modules' + )) { + return [ + 'controller' => $controllerObj, + 'action' => $action, + 'params' => $controllerParams + ]; + } + + /* + * Look for a Plugin controller + */ + if (count($params) >= 2) { + [$author, $plugin] = $params; + + $pluginCode = ucfirst($author) . '.' . ucfirst($plugin); + if (PluginManager::instance()->isDisabled($pluginCode)) { + return Response::make(View::make('backend::404'), 404); + } + + $controller = $params[2] ?? 'index'; + self::$action = $action = isset($params[3]) ? $this->parseAction($params[3]) : 'index'; + self::$params = $controllerParams = array_slice($params, 4); + $controllerClass = '\\'.$author.'\\'.$plugin.'\Controllers\\'.$controller; + if ($controllerObj = $this->findController( + $controllerClass, + $action, + plugins_path() + )) { + return [ + 'controller' => $controllerObj, + 'action' => $action, + 'params' => $controllerParams + ]; + } + } + + return null; + } + + /** + * This method is used internally. + * Finds a backend controller with a callable action method. + * @param string $controller Specifies a method name to execute. + * @param string $action Specifies a method name to execute. + * @param string $inPath Base path for class file location. + * @return ControllerBase Returns the backend controller object + */ + protected function findController($controller, $action, $inPath) + { + if (isset($this->requestedController)) { + return $this->requestedController; + } + + /* + * Workaround: Composer does not support case insensitivity. + */ + if (!class_exists($controller)) { + $controller = Str::normalizeClassName($controller); + $controllerFile = $inPath.strtolower(str_replace('\\', '/', $controller)) . '.php'; + if ($controllerFile = File::existsInsensitive($controllerFile)) { + include_once $controllerFile; + } + } + + if (!class_exists($controller)) { + return $this->requestedController = null; + } + + $controllerObj = App::make($controller); + + if ($controllerObj->actionExists($action)) { + return $this->requestedController = $controllerObj; + } + + return $this->requestedController = null; + } + + /** + * Process the action name, since dashes are not supported in PHP methods. + * @param string $actionName + * @return string + */ + protected function parseAction($actionName) + { + if (strpos($actionName, '-') !== false) { + return camel_case($actionName); + } + + return $actionName; + } + + /** + * Determine if the given options exclude a particular method. + * + * @param string $method + * @param array $options + * @return bool + */ + protected static function methodExcludedByOptions($method, array $options) + { + return (isset($options['only']) && !in_array($method, (array) $options['only'])) || + (!empty($options['except']) && in_array($method, (array) $options['except'])); + } +} diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php new file mode 100644 index 0000000..a0790ed --- /dev/null +++ b/modules/backend/classes/Controller.php @@ -0,0 +1,753 @@ +action = BackendController::$action; + $this->params = BackendController::$params; + + /* + * Apply $guarded methods to hidden actions + */ + $this->hiddenActions = array_merge($this->hiddenActions, $this->guarded); + + /* + * Define layout and view paths + */ + $this->layout = $this->layout ?: 'default'; + $this->layoutPath = Skin::getActive()->getLayoutPaths(); + $this->viewPath = $this->configPath = $this->guessViewPath(); + + /* + * Add layout paths from the plugin / module context + */ + $relativePath = dirname(dirname(strtolower(str_replace('\\', '/', get_called_class())))); + $this->layoutPath[] = '~/modules/' . $relativePath . '/layouts'; + $this->layoutPath[] = '~/plugins/' . $relativePath . '/layouts'; + + /* + * Create a new instance of the admin user + */ + $this->user = BackendAuth::getUser(); + + /* + * Media Manager widget is available on all back-end pages + */ + if ($this->user && $this->user->hasAccess('media.*')) { + $manager = new MediaManager($this, 'ocmediamanager'); + $manager->bindToController(); + } + + $this->extendableConstruct(); + } + + /** + * Extend this object properties upon construction. + */ + public static function extend(Closure $callback) + { + self::extendableExtendCallback($callback); + } + + public function __get($name) + { + return $this->extendableGet($name); + } + + public function __set($name, $value) + { + $this->extendableSet($name, $value); + } + + public function __call($name, $params) + { + return $this->extendableCall($name, $params); + } + + public static function __callStatic($name, $params) + { + return self::extendableCallStatic($name, $params); + } + + /** + * Execute the controller action. + * @param string $action The action name. + * @param array $params Routing parameters to pass to the action. + * @return mixed The action result. + */ + public function run($action = null, $params = []) + { + $this->action = $action; + $this->params = $params; + + /* + * Check security token. + * @see \System\Traits\SecurityController + */ + if (!$this->verifyCsrfToken()) { + return Response::make(Lang::get('system::lang.page.invalid_token.label'), 403); + } + + /* + * Check forced HTTPS protocol. + * @see \System\Traits\SecurityController + */ + if (!$this->verifyForceSecure()) { + return Redirect::secure(Request::path()); + } + + /* + * Determine if this request is a public action. + */ + $isPublicAction = in_array($action, $this->publicActions); + + /* + * Check that user is logged in and has permission to view this page + */ + if (!$isPublicAction) { + /* + * Not logged in, redirect to login screen or show ajax error. + */ + if (!BackendAuth::check()) { + return Request::ajax() + ? Response::make(Lang::get('backend::lang.page.access_denied.label'), 403) + : Backend::redirectGuest('backend/auth'); + } + + /* + * Check access groups against the page definition + */ + if ($this->requiredPermissions && !$this->user->hasAnyAccess($this->requiredPermissions)) { + return Response::make(View::make('backend::access_denied'), 403); + } + } + + /** + * @event backend.page.beforeDisplay + * Provides an opportunity to override backend page content + * + * Example usage: + * + * Event::listen('backend.page.beforeDisplay', function ((\Backend\Classes\Controller) $backendController, (string) $action, (array) $params) { + * trace_log('redirect all backend pages to google'); + * return \Redirect::to('https://google.com'); + * }); + * + * Or + * + * $backendController->bindEvent('page.beforeDisplay', function ((string) $action, (array) $params) { + * trace_log('redirect all backend pages to google'); + * return \Redirect::to('https://google.com'); + * }); + * + */ + if ($event = $this->fireSystemEvent('backend.page.beforeDisplay', [$action, $params])) { + return $event; + } + + /* + * Set the admin preference locale + */ + BackendPreference::setAppLocale(); + BackendPreference::setAppFallbackLocale(); + + /* + * Execute AJAX event + */ + if ($ajaxResponse = $this->execAjaxHandlers()) { + $result = $ajaxResponse; + } + + /* + * Execute postback handler + */ + elseif ( + ($handler = post('_handler')) && + ($handlerResponse = $this->runAjaxHandler($handler)) && + $handlerResponse !== true + ) { + $result = $handlerResponse; + } + + /* + * Execute page action + */ + else { + $result = $this->execPageAction($action, $params); + } + + /* + * Prepare and return response + * @see \System\Traits\ResponseMaker + */ + return $this->makeResponse($result); + } + + /** + * This method is used internally. + * Determines whether an action with the specified name exists. + * Action must be a class public method. Action name can not be prefixed with the underscore character. + * @param string $name Specifies the action name. + * @param bool $internal Allow protected actions. + * @return boolean + */ + public function actionExists($name, $internal = false) + { + if (!strlen($name) || substr($name, 0, 1) == '_' || !$this->methodExists($name)) { + return false; + } + + foreach ($this->hiddenActions as $method) { + if (strtolower($name) == strtolower($method)) { + return false; + } + } + + $ownMethod = method_exists($this, $name); + + if ($ownMethod) { + $methodInfo = new \ReflectionMethod($this, $name); + $public = $methodInfo->isPublic(); + if ($public) { + return true; + } + } + + if ($internal && (($ownMethod && $methodInfo->isProtected()) || !$ownMethod)) { + return true; + } + + if (!$ownMethod) { + return true; + } + + return false; + } + + /** + * Returns a URL for this controller and supplied action. + */ + public function actionUrl($action = null, $path = null) + { + if ($action === null) { + $action = $this->action; + } + + $class = get_called_class(); + $uriPath = dirname(dirname(strtolower(str_replace('\\', '/', $class)))); + $controllerName = strtolower(class_basename($class)); + + $url = $uriPath.'/'.$controllerName.'/'.$action; + if ($path) { + $url .= '/'.$path; + } + + return Backend::url($url); + } + + /** + * Invokes the current controller action without rendering a view, + * used by AJAX handler that may rely on the logic inside the action. + */ + public function pageAction() + { + if (!$this->action) { + return; + } + + $this->suppressView = true; + $this->execPageAction($this->action, $this->params); + } + + /** + * This method is used internally. + * Invokes the controller action and loads the corresponding view. + * @param string $actionName Specifies a action name to execute. + * @param array $parameters A list of the action parameters. + */ + protected function execPageAction($actionName, $parameters) + { + $result = null; + + if (!$this->actionExists($actionName)) { + if (Config::get('app.debug', false)) { + throw new SystemException(sprintf( + "Action %s is not found in the controller %s", + $actionName, + get_class($this) + )); + } else { + Response::make(View::make('backend::404'), 404); + } + } + + // Execute the action + $result = call_user_func_array([$this, $actionName], $parameters); + + // Expecting \Response and \RedirectResponse + if ($result instanceof \Symfony\Component\HttpFoundation\Response) { + return $result; + } + + // No page title + if (!$this->pageTitle) { + $this->pageTitle = 'backend::lang.page.untitled'; + } + + // Load the view + if (!$this->suppressView && $result === null) { + return $this->makeView($actionName); + } + + return $this->makeViewContent($result); + } + + /** + * Returns the AJAX handler for the current request, if available. + * @return string + */ + public function getAjaxHandler() + { + if (!Request::ajax() || Request::method() != 'POST') { + return null; + } + + if ($handler = Request::header('X_OCTOBER_REQUEST_HANDLER')) { + return trim($handler); + } + + return null; + } + + /** + * This method is used internally. + * Invokes a controller event handler and loads the supplied partials. + */ + protected function execAjaxHandlers() + { + if ($handler = $this->getAjaxHandler()) { + try { + /* + * Validate the handler name + */ + if (!preg_match('/^(?:\w+\:{2})?on[A-Z]{1}[\w+]*$/', $handler)) { + throw new SystemException(Lang::get('backend::lang.ajax_handler.invalid_name', ['name'=>$handler])); + } + + /* + * Validate the handler partial list + */ + if ($partialList = trim(Request::header('X_OCTOBER_REQUEST_PARTIALS'))) { + $partialList = explode('&', $partialList); + + foreach ($partialList as $partial) { + if (!preg_match('/^(?!.*\/\/)[a-z0-9\_][a-z0-9\_\-\/]*$/i', $partial)) { + throw new SystemException(Lang::get('backend::lang.partial.invalid_name', ['name'=>$partial])); + } + } + } + else { + $partialList = []; + } + + $responseContents = []; + + /* + * Execute the handler + */ + if (!$result = $this->runAjaxHandler($handler)) { + throw new ApplicationException(Lang::get('backend::lang.ajax_handler.not_found', ['name'=>$handler])); + } + + /* + * Render partials and return the response as array that will be converted to JSON automatically. + */ + foreach ($partialList as $partial) { + $responseContents[$partial] = $this->makePartial($partial); + } + + /* + * If the handler returned a redirect, process the URL and dispose of it so + * framework.js knows to redirect the browser and not the request! + */ + if ($result instanceof RedirectResponse) { + $responseContents['X_OCTOBER_REDIRECT'] = $result->getTargetUrl(); + $result = null; + } + /* + * No redirect is used, look for any flash messages + */ + elseif (Flash::check()) { + $responseContents['#layout-flash-messages'] = $this->makeLayoutPartial('flash_messages'); + } + + /* + * Detect assets + */ + if ($this->hasAssetsDefined()) { + $responseContents['X_OCTOBER_ASSETS'] = $this->getAssetPaths(); + } + + /* + * If the handler returned an array, we should add it to output for rendering. + * If it is a string, add it to the array with the key "result". + * If an object, pass it to Laravel as a response object. + */ + if (is_array($result)) { + $responseContents = array_merge($responseContents, $result); + } + elseif (is_string($result)) { + $responseContents['result'] = $result; + } + elseif (is_object($result)) { + return $result; + } + + return Response::make()->setContent($responseContents); + } + catch (ValidationException $ex) { + /* + * Handle validation error gracefully + */ + Flash::error($ex->getMessage()); + $responseContents = []; + $responseContents['#layout-flash-messages'] = $this->makeLayoutPartial('flash_messages'); + $responseContents['X_OCTOBER_ERROR_FIELDS'] = $ex->getFields(); + throw new AjaxException($responseContents); + } + catch (MassAssignmentException $ex) { + throw new ApplicationException(Lang::get('backend::lang.model.mass_assignment_failed', ['attribute' => $ex->getMessage()])); + } + catch (Exception $ex) { + throw $ex; + } + } + + return null; + } + + /** + * Tries to find and run an AJAX handler in the page action. + * The method stops as soon as the handler is found. + * @return boolean Returns true if the handler was found. Returns false otherwise. + */ + protected function runAjaxHandler($handler) + { + /** + * @event backend.ajax.beforeRunHandler + * Provides an opportunity to modify an AJAX request + * + * The parameter provided is `$handler` (the requested AJAX handler to be run) + * + * Example usage (forwards AJAX handlers to a backend widget): + * + * Event::listen('backend.ajax.beforeRunHandler', function ((\Backend\Classes\Controller) $controller, (string) $handler) { + * if (strpos($handler, '::')) { + * list($componentAlias, $handlerName) = explode('::', $handler); + * if ($componentAlias === $this->getBackendWidgetAlias()) { + * return $this->backendControllerProxy->runAjaxHandler($handler); + * } + * } + * }); + * + * Or + * + * $this->controller->bindEvent('ajax.beforeRunHandler', function ((string) $handler) { + * if (strpos($handler, '::')) { + * list($componentAlias, $handlerName) = explode('::', $handler); + * if ($componentAlias === $this->getBackendWidgetAlias()) { + * return $this->backendControllerProxy->runAjaxHandler($handler); + * } + * } + * }); + * + */ + if ($event = $this->fireSystemEvent('backend.ajax.beforeRunHandler', [$handler])) { + return $event; + } + + /* + * Process Widget handler + */ + if (strpos($handler, '::')) { + list($widgetName, $handlerName) = explode('::', $handler); + + /* + * Execute the page action so widgets are initialized + */ + $this->pageAction(); + + if ($this->fatalError) { + throw new SystemException($this->fatalError); + } + + if (!isset($this->widget->{$widgetName})) { + throw new SystemException(Lang::get('backend::lang.widget.not_bound', ['name'=>$widgetName])); + } + + if (($widget = $this->widget->{$widgetName}) && $widget->methodExists($handlerName)) { + $result = $this->runAjaxHandlerForWidget($widget, $handlerName); + return $result ?: true; + } + } + else { + /* + * Process page specific handler (index_onSomething) + */ + $pageHandler = $this->action . '_' . $handler; + + if ($this->methodExists($pageHandler)) { + $result = call_user_func_array([$this, $pageHandler], array_values($this->params)); + return $result ?: true; + } + + /* + * Process page global handler (onSomething) + */ + if ($this->methodExists($handler)) { + $result = call_user_func_array([$this, $handler], array_values($this->params)); + return $result ?: true; + } + + /* + * Cycle each widget to locate a usable handler (widget::onSomething) + */ + $this->suppressView = true; + $this->execPageAction($this->action, $this->params); + + foreach ((array) $this->widget as $widget) { + if ($widget->methodExists($handler)) { + $result = $this->runAjaxHandlerForWidget($widget, $handler); + return $result ?: true; + } + } + } + + /* + * Generic handler that does nothing + */ + if ($handler == 'onAjax') { + return true; + } + + return false; + } + + /** + * Specific code for executing an AJAX handler for a widget. + * This will append the widget view paths to the controller and merge the vars. + * @return mixed + */ + protected function runAjaxHandlerForWidget($widget, $handler) + { + $this->addViewPath($widget->getViewPaths()); + + $result = call_user_func_array([$widget, $handler], array_values($this->params)); + + $this->vars = $widget->vars + $this->vars; + + return $result; + } + + /** + * Returns the controllers public actions. + */ + public function getPublicActions() + { + return $this->publicActions; + } + + /** + * Returns a unique ID for the controller and route. Useful in creating HTML markup. + */ + public function getId($suffix = null) + { + $id = class_basename(get_called_class()) . '-' . $this->action; + if ($suffix !== null) { + $id .= '-' . $suffix; + } + + return $id; + } + + // + // Hints + // + + /** + * Renders a hint partial, used for displaying informative information that + * can be hidden by the user. If you don't want to render a partial, you can + * supply content via the 'content' key of $params. + * @param string $name Unique key name + * @param string $partial Reference to content (partial name) + * @param array $params Extra parameters + * @return string + */ + public function makeHintPartial($name, $partial = null, $params = []) + { + if (is_array($partial)) { + $params = $partial; + $partial = null; + } + + if (!$partial) { + $partial = array_get($params, 'partial', $name); + } + + return $this->makeLayoutPartial('hint', [ + 'hintName' => $name, + 'hintPartial' => $partial, + 'hintContent' => array_get($params, 'content'), + 'hintParams' => $params + ] + $params); + } + + /** + * Ajax handler to hide a backend hint, once hidden the partial + * will no longer display for the user. + * @return void + */ + public function onHideBackendHint() + { + if (!$name = post('name')) { + throw new ApplicationException('Missing a hint name.'); + } + + $preferences = UserPreference::forUser(); + $hiddenHints = $preferences->get('backend::hints.hidden', []); + $hiddenHints[$name] = 1; + + $preferences->set('backend::hints.hidden', $hiddenHints); + } + + /** + * Checks if a hint has been hidden by the user. + * @param string $name Unique key name + * @return boolean + */ + public function isBackendHintHidden($name) + { + $hiddenHints = UserPreference::forUser()->get('backend::hints.hidden', []); + return array_key_exists($name, $hiddenHints); + } +} diff --git a/modules/backend/classes/ControllerBehavior.php b/modules/backend/classes/ControllerBehavior.php new file mode 100644 index 0000000..1df06bd --- /dev/null +++ b/modules/backend/classes/ControllerBehavior.php @@ -0,0 +1,165 @@ +controller = $controller; + $this->viewPath = $this->configPath = $this->guessViewPath('/partials'); + $this->assetPath = $this->guessViewPath('/assets', true); + + /* + * Validate controller properties + */ + foreach ($this->requiredProperties as $property) { + if (!isset($controller->{$property})) { + throw new ApplicationException(Lang::get('system::lang.behavior.missing_property', [ + 'class' => get_class($controller), + 'property' => $property, + 'behavior' => get_called_class() + ])); + } + } + + // Hide all methods that aren't explicitly listed as actions + if (is_array($this->actions)) { + $this->hideAction(array_diff(get_class_methods(get_class($this)), $this->actions)); + } + } + + /** + * Sets the configuration values + * @param mixed $config Config object or array + * @param array $required Required config items + */ + public function setConfig($config, $required = []) + { + $this->config = $this->makeConfig($config, $required); + } + + /** + * Safe accessor for configuration values. + * @param string $name Config name, supports array names like "field[key]" + * @param mixed $default Default value if nothing is found + * @return string + */ + public function getConfig($name = null, $default = null) + { + /* + * Return all config + */ + if ($name === null) { + return $this->config; + } + + /* + * Array field name, eg: field[key][key2][key3] + */ + $keyParts = HtmlHelper::nameToArray($name); + + /* + * First part will be the field name, pop it off + */ + $fieldName = array_shift($keyParts); + if (!isset($this->config->{$fieldName})) { + return $default; + } + + $result = $this->config->{$fieldName}; + + /* + * Loop the remaining key parts and build a result + */ + foreach ($keyParts as $key) { + if (!is_array($result) || !array_key_exists($key, $result)) { + return $default; + } + + $result = $result[$key]; + } + + return $result; + } + + /** + * Protects a public method from being available as an controller action. + * These methods could be defined in a controller to override a behavior default action. + * Such methods should be defined as public, to allow the behavior object to access it. + * By default public methods of a controller are considered as actions. + * To prevent this occurrence, methods should be hidden by using this method. + * @param mixed $methodName Specifies a method name. + */ + protected function hideAction($methodName) + { + if (!is_array($methodName)) { + $methodName = [$methodName]; + } + + $this->controller->hiddenActions = array_merge($this->controller->hiddenActions, $methodName); + } + + /** + * Makes all views in context of the controller, not the behavior. + * @param string $filePath Absolute path to the view file. + * @param array $extraParams Parameters that should be available to the view. + * @return string + */ + public function makeFileContents($filePath, $extraParams = []) + { + $this->controller->vars = array_merge($this->controller->vars, $this->vars); + return $this->controller->makeFileContents($filePath, $extraParams); + } + + /** + * Returns true in case if a specified method exists in the extended controller. + * @param string $methodName Specifies the method name + * @return bool + */ + protected function controllerMethodExists($methodName) + { + return method_exists($this->controller, $methodName); + } +} diff --git a/modules/backend/classes/FilterScope.php b/modules/backend/classes/FilterScope.php new file mode 100644 index 0000000..bf5d062 --- /dev/null +++ b/modules/backend/classes/FilterScope.php @@ -0,0 +1,168 @@ +scopeName = $scopeName; + $this->label = $label; + } + + /** + * Specifies a scope control rendering mode. Supported modes are: + * - group - filter by a group of IDs. Default. + * - checkbox - filter by a simple toggle switch. + * @param string $type Specifies a render mode as described above + * @param array $config A list of render mode specific config. + */ + public function displayAs($type, $config = []) + { + $this->type = strtolower($type) ?: $this->type; + $this->config = $this->evalConfig($config); + return $this; + } + + /** + * Process options and apply them to this object. + * @param array $config + * @return array + */ + protected function evalConfig($config) + { + if ($config === null) { + $config = []; + } + + /* + * Standard config:property values + */ + $applyConfigValues = [ + 'options', + 'dependsOn', + 'context', + 'default', + 'conditions', + 'scope', + 'cssClass', + 'nameFrom', + 'descriptionFrom', + 'disabled', + ]; + + foreach ($applyConfigValues as $value) { + if (array_key_exists($value, $config)) { + $this->{$value} = $config[$value]; + } + } + + return $config; + } + + /** + * Returns a value suitable for the scope id property. + */ + public function getId($suffix = null) + { + $id = 'scope'; + $id .= '-'.$this->scopeName; + + if ($suffix) { + $id .= '-'.$suffix; + } + + if ($this->idPrefix) { + $id = $this->idPrefix . '-' . $id; + } + + return HtmlHelper::nameToId($id); + } +} diff --git a/modules/backend/classes/FormField.php b/modules/backend/classes/FormField.php new file mode 100644 index 0000000..d9782a2 --- /dev/null +++ b/modules/backend/classes/FormField.php @@ -0,0 +1,724 @@ + + */ + public $arrayName; + + /** + * @var string A prefix to the field identifier so it can be totally unique. + */ + public $idPrefix; + + /** + * @var string Form field label. + */ + public $label; + + /** + * @var string Form field value. + */ + public $value; + + /** + * @var string Model attribute to use for the display value. + */ + public $valueFrom; + + /** + * @var string Specifies a default value for supported fields. + */ + public $defaults; + + /** + * @var string Model attribute to use for the default value. + */ + public $defaultFrom; + + /** + * @var string Specifies if this field belongs to a tab. + */ + public $tab; + + /** + * @var string Display mode. Text, textarea + */ + public $type = 'text'; + + /** + * @var string Field options. + */ + public $options; + + /** + * @var string Specifies a side. Possible values: auto, left, right, full. + */ + public $span = 'full'; + + /** + * @var string Specifies a size. Possible values: tiny, small, large, huge, giant. + */ + public $size = 'large'; + + /** + * @var string Specifies contextual visibility of this form field. + */ + public $context; + + /** + * @var bool Specifies if this field is mandatory. + */ + public $required; + + /** + * @var bool Specify if the field is read-only or not. + */ + public $readOnly = false; + + /** + * @var bool Specify if the field is disabled or not. + */ + public $disabled = false; + + /** + * @var bool Specify if the field is hidden. Hiddens fields are not included in postbacks. + */ + public $hidden = false; + + /** + * @var bool Specifies if this field stretch to fit the page height. + */ + public $stretch = false; + + /** + * @var string Specifies a comment to accompany the field + */ + public $comment = ''; + + /** + * @var string Specifies the comment position. + */ + public $commentPosition = 'below'; + + /** + * @var string Specifies if the comment is in HTML format. + */ + public $commentHtml = false; + + /** + * @var string Specifies a message to display when there is no value supplied (placeholder). + */ + public $placeholder = ''; + + /** + * @var array Contains a list of attributes specified in the field configuration. + */ + public $attributes; + + /** + * @var string Specifies a CSS class to attach to the field container. + */ + public $cssClass; + + /** + * @var string Specifies a path for partial-type fields. + */ + public $path; + + /** + * @var array Raw field configuration. + */ + public $config; + + /** + * @var array Other field names this field depends on, when the other fields are modified, this field will update. + */ + public $dependsOn; + + /** + * @var array Other field names this field can be triggered by, see the Trigger API documentation. + */ + public $trigger; + + /** + * @var array Other field names text is converted in to a URL, slug or file name value in this field. + */ + public $preset; + + /** + * Constructor. + * @param string $fieldName The name of the field + * @param string $label The label of the field + */ + public function __construct($fieldName, $label) + { + $this->fieldName = $fieldName; + $this->label = $label; + } + + /** + * If this field belongs to a tab. + */ + public function tab($value) + { + $this->tab = $value; + return $this; + } + + /** + * Sets a side of the field on a form. + * @param string $value Specifies a side. Possible values: left, right, full + */ + public function span($value = 'full') + { + $this->span = $value; + return $this; + } + + /** + * Sets a side of the field on a form. + * @param string $value Specifies a size. Possible values: tiny, small, large, huge, giant + */ + public function size($value = 'large') + { + $this->size = $value; + return $this; + } + + /** + * Sets field options, for dropdowns, radio lists and checkbox lists. + * @param array $value + * @return self + */ + public function options($value = null) + { + if ($value === null) { + if (is_array($this->options)) { + return $this->options; + } + elseif (is_callable($this->options)) { + $callable = $this->options; + return $callable(); + } + + return []; + } + + $this->options = $value; + + return $this; + } + + /** + * Specifies a field control rendering mode. Supported modes are: + * - text - creates a text field. Default for varchar column types. + * - textarea - creates a textarea control. Default for text column types. + * - dropdown - creates a drop-down list. Default for reference-based columns. + * - radio - creates a set of radio buttons. + * - checkbox - creates a single checkbox. + * - checkboxlist - creates a checkbox list. + * - switch - creates a switch field. + * @param string $type Specifies a render mode as described above + * @param array $config A list of render mode specific config. + */ + public function displayAs($type, $config = []) + { + $this->type = strtolower($type) ?: $this->type; + $this->config = $this->evalConfig($config); + + return $this; + } + + /** + * Process options and apply them to this object. + * @param array $config + * @return array + */ + protected function evalConfig($config) + { + if ($config === null) { + $config = []; + } + + /* + * Standard config:property values + */ + $applyConfigValues = [ + 'commentHtml', + 'placeholder', + 'dependsOn', + 'required', + 'readOnly', + 'disabled', + 'cssClass', + 'stretch', + 'context', + 'hidden', + 'trigger', + 'preset', + 'path', + ]; + + foreach ($applyConfigValues as $value) { + if (array_key_exists($value, $config)) { + $this->{$value} = $config[$value]; + } + } + + /* + * Custom applicators + */ + if (isset($config['options'])) { + $this->options($config['options']); + } + if (isset($config['span'])) { + $this->span($config['span']); + } + if (isset($config['size'])) { + $this->size($config['size']); + } + if (isset($config['tab'])) { + $this->tab($config['tab']); + } + if (isset($config['commentAbove'])) { + $this->comment($config['commentAbove'], 'above'); + } + if (isset($config['comment'])) { + $this->comment($config['comment']); + } + if (isset($config['default'])) { + $this->defaults = $config['default']; + } + if (isset($config['defaultFrom'])) { + $this->defaultFrom = $config['defaultFrom']; + } + if (isset($config['attributes'])) { + $this->attributes($config['attributes']); + } + if (isset($config['containerAttributes'])) { + $this->attributes($config['containerAttributes'], 'container'); + } + + if (isset($config['valueFrom'])) { + $this->valueFrom = $config['valueFrom']; + } + else { + $this->valueFrom = $this->fieldName; + } + + return $config; + } + + /** + * Adds a text comment above or below the field. + * @param string $text Specifies a comment text. + * @param string $position Specifies a comment position. + * @param bool $isHtml Set to true if you use HTML formatting in the comment + * Supported values are 'below' and 'above' + */ + public function comment($text, $position = 'below', $isHtml = null) + { + $this->comment = $text; + $this->commentPosition = $position; + + if ($isHtml !== null) { + $this->commentHtml = $isHtml; + } + + return $this; + } + + /** + * Determine if the provided value matches this field's value. + * @param string $value + * @return bool + */ + public function isSelected($value = true) + { + if ($this->value === null) { + return false; + } + + return (string) $value === (string) $this->value; + } + + /** + * Sets the attributes for this field in a given position. + * - field: Attributes are added to the form field element (input, select, textarea, etc) + * - container: Attributes are added to the form field container (div.form-group) + * @param array $items + * @param string $position + * @return void + */ + public function attributes($items, $position = 'field') + { + if (!is_array($items)) { + return; + } + + $multiArray = array_filter($items, 'is_array'); + if (!$multiArray) { + $this->attributes[$position] = $items; + return; + } + + foreach ($items as $_position => $_items) { + $this->attributes($_items, $_position); + } + + return $this; + } + + /** + * Checks if the field has the supplied [unfiltered] attribute. + * @param string $name + * @param string $position + * @return bool + */ + public function hasAttribute($name, $position = 'field') + { + if (!isset($this->attributes[$position])) { + return false; + } + + return array_key_exists($name, $this->attributes[$position]); + } + + /** + * Returns the attributes for this field at a given position. + * @param string $position + * @return array + */ + public function getAttributes($position = 'field', $htmlBuild = true) + { + $result = array_get($this->attributes, $position, []); + $result = $this->filterAttributes($result, $position); + + // Field is required, so add the "required" attribute + if ($position === 'field' && $this->required && (!isset($result['required']) || $result['required'])) { + $result['required'] = ''; + } + // The "required" attribute is set and falsy, so unset it + elseif ($position === 'field' && isset($result['required']) && !$result['required']) { + unset($result['required']); + } + + return $htmlBuild ? Html::attributes($result) : $result; + } + + /** + * Adds any circumstantial attributes to the field based on other + * settings, such as the 'disabled' option. + * @param array $attributes + * @param string $position + * @return array + */ + protected function filterAttributes($attributes, $position = 'field') + { + $position = strtolower($position); + + $attributes = $this->filterTriggerAttributes($attributes, $position); + $attributes = $this->filterPresetAttributes($attributes, $position); + + if ($position == 'field' && $this->disabled) { + $attributes = $attributes + ['disabled' => 'disabled']; + } + + if ($position == 'field' && $this->readOnly) { + $attributes = $attributes + ['readonly' => 'readonly']; + + if ($this->type == 'checkbox' || $this->type == 'switch') { + $attributes = $attributes + ['onclick' => 'return false;']; + } + } + + return $attributes; + } + + /** + * Adds attributes used specifically by the Trigger API + * @param array $attributes + * @param string $position + * @return array + */ + protected function filterTriggerAttributes($attributes, $position = 'field') + { + if (!$this->trigger || !is_array($this->trigger)) { + return $attributes; + } + + $triggerAction = array_get($this->trigger, 'action'); + $triggerField = array_get($this->trigger, 'field'); + $triggerCondition = array_get($this->trigger, 'condition'); + $triggerForm = $this->arrayName; + $triggerMulti = ''; + + // Apply these to container + if (in_array($triggerAction, ['hide', 'show']) && $position != 'container') { + return $attributes; + } + + // Apply these to field/input + if (in_array($triggerAction, ['enable', 'disable', 'empty']) && $position != 'field') { + return $attributes; + } + + // Reduce the field reference for the trigger condition field + $triggerFieldParentLevel = Str::getPrecedingSymbols($triggerField, self::HIERARCHY_UP); + if ($triggerFieldParentLevel > 0) { + // Remove the preceding symbols from the trigger field name + $triggerField = substr($triggerField, $triggerFieldParentLevel); + $triggerForm = HtmlHelper::reduceNameHierarchy($triggerForm, $triggerFieldParentLevel); + } + + // Preserve multi field types + if (Str::endsWith($triggerField, '[]')) { + $triggerField = substr($triggerField, 0, -2); + $triggerMulti = '[]'; + } + + // Final compilation + if ($this->arrayName) { + $fullTriggerField = $triggerForm.'['.implode('][', HtmlHelper::nameToArray($triggerField)).']'.$triggerMulti; + } + else { + $fullTriggerField = $triggerField.$triggerMulti; + } + + $newAttributes = [ + 'data-trigger' => '[name="'.$fullTriggerField.'"]', + 'data-trigger-action' => $triggerAction, + 'data-trigger-condition' => $triggerCondition, + 'data-trigger-closest-parent' => 'form, div[data-control="formwidget"]' + ]; + + return $attributes + $newAttributes; + } + + /** + * Adds attributes used specifically by the Input Preset API + * @param array $attributes + * @param string $position + * @return array + */ + protected function filterPresetAttributes($attributes, $position = 'field') + { + if (!$this->preset || $position != 'field') { + return $attributes; + } + + if (!is_array($this->preset)) { + $this->preset = ['field' => $this->preset, 'type' => 'slug']; + } + + $presetField = array_get($this->preset, 'field'); + $presetType = array_get($this->preset, 'type'); + + if ($this->arrayName) { + $fullPresetField = $this->arrayName.'['.implode('][', HtmlHelper::nameToArray($presetField)).']'; + } + else { + $fullPresetField = $presetField; + } + + $newAttributes = [ + 'data-input-preset' => '[name="'.$fullPresetField.'"]', + 'data-input-preset-type' => $presetType, + 'data-input-preset-closest-parent' => 'form' + ]; + + if ($prefixInput = array_get($this->preset, 'prefixInput')) { + $newAttributes['data-input-preset-prefix-input'] = $prefixInput; + } + + return $attributes + $newAttributes; + } + + /** + * Returns a value suitable for the field name property. + * @param string $arrayName Specify a custom array name + * @return string + */ + public function getName($arrayName = null) + { + if ($arrayName === null) { + $arrayName = $this->arrayName; + } + + if ($arrayName) { + return $arrayName.'['.implode('][', HtmlHelper::nameToArray($this->fieldName)).']'; + } + + return $this->fieldName; + } + + /** + * Returns a value suitable for the field id property. + * @param string $suffix Specify a suffix string + * @return string + */ + public function getId($suffix = null) + { + $id = 'field'; + if ($this->arrayName) { + $id .= '-'.$this->arrayName; + } + + $id .= '-'.$this->fieldName; + + if ($suffix) { + $id .= '-'.$suffix; + } + + if ($this->idPrefix) { + $id = $this->idPrefix . '-' . $id; + } + + return HtmlHelper::nameToId($id); + } + + /** + * Returns a raw config item value. + * @param string $value + * @param string $default + * @return mixed + */ + public function getConfig($value, $default = null) + { + return array_get($this->config, $value, $default); + } + + /** + * Returns this fields value from a supplied data set, which can be + * an array or a model or another generic collection. + * @param mixed $data + * @param mixed $default + * @return mixed + */ + public function getValueFromData($data, $default = null) + { + $fieldName = $this->valueFrom ?: $this->fieldName; + return $this->getFieldNameFromData($fieldName, $data, $default); + } + + /** + * Returns the default value for this field, the supplied data is used + * to source data when defaultFrom is specified. + * @param mixed $data + * @return mixed + */ + public function getDefaultFromData($data) + { + if ($this->defaultFrom) { + return $this->getFieldNameFromData($this->defaultFrom, $data); + } + + if ($this->defaults !== '') { + return $this->defaults; + } + + return null; + } + + /** + * Returns the final model and attribute name of a nested attribute. Eg: + * + * list($model, $attribute) = $this->resolveAttribute('person[phone]'); + * + * @param string $attribute. + * @return array + */ + public function resolveModelAttribute($model, $attribute = null) + { + if ($attribute === null) { + $attribute = $this->valueFrom ?: $this->fieldName; + } + + $parts = is_array($attribute) ? $attribute : HtmlHelper::nameToArray($attribute); + $last = array_pop($parts); + + foreach ($parts as $part) { + $model = $model->{$part}; + } + + return [$model, $last]; + } + + /** + * Internal method to extract the value of a field name from a data set. + * @param string $fieldName + * @param mixed $data + * @param mixed $default + * @return mixed + */ + protected function getFieldNameFromData($fieldName, $data, $default = null) + { + /* + * Array field name, eg: field[key][key2][key3] + */ + $keyParts = HtmlHelper::nameToArray($fieldName); + $lastField = end($keyParts); + $result = $data; + + /* + * Loop the field key parts and build a value. + * To support relations only the last field should return the + * relation value, all others will look up the relation object as normal. + */ + foreach ($keyParts as $key) { + if ($result instanceof Model && $result->hasRelation($key)) { + if ($key == $lastField) { + $result = $result->getRelationValue($key) ?: $default; + } + else { + $result = $result->{$key}; + } + } + elseif (is_array($result)) { + if (!array_key_exists($key, $result)) { + return $default; + } + $result = $result[$key]; + } + else { + if (!isset($result->{$key})) { + return $default; + } + $result = $result->{$key}; + } + } + + return $result; + } +} diff --git a/modules/backend/classes/FormTabs.php b/modules/backend/classes/FormTabs.php new file mode 100644 index 0000000..8da0526 --- /dev/null +++ b/modules/backend/classes/FormTabs.php @@ -0,0 +1,281 @@ +section = strtolower($section) ?: $this->section; + $this->config = $this->evalConfig($config); + + if ($this->section == self::SECTION_OUTSIDE) { + $this->suppressTabs = true; + } + } + + /** + * Process options and apply them to this object. + * @param array $config + * @return array + */ + protected function evalConfig($config) + { + if (array_key_exists('defaultTab', $config)) { + $this->defaultTab = $config['defaultTab']; + } + + if (array_key_exists('icons', $config)) { + $this->icons = $config['icons']; + } + + if (array_key_exists('stretch', $config)) { + $this->stretch = $config['stretch']; + } + + if (array_key_exists('suppressTabs', $config)) { + $this->suppressTabs = $config['suppressTabs']; + } + + if (array_key_exists('cssClass', $config)) { + $this->cssClass = $config['cssClass']; + } + + if (array_key_exists('paneCssClass', $config)) { + $this->paneCssClass = $config['paneCssClass']; + } + + if (array_key_exists('linkable', $config)) { + $this->linkable = (bool) $config['linkable']; + } + + if (array_key_exists('lazy', $config)) { + $this->lazy = $config['lazy']; + } + } + + /** + * Add a field to the collection of tabs. + * @param string $name + * @param FormField $field + * @param string $tab + */ + public function addField($name, FormField $field, $tab = null) + { + if (!$tab) { + $tab = $this->defaultTab; + } + + $this->fields[$tab][$name] = $field; + } + + /** + * Remove a field from all tabs by name. + * @param string $name + * @return boolean + */ + public function removeField($name) + { + foreach ($this->fields as $tab => $fields) { + foreach ($fields as $fieldName => $field) { + if ($fieldName == $name) { + unset($this->fields[$tab][$fieldName]); + + /* + * Remove empty tabs from collection + */ + if (!count($this->fields[$tab])) { + unset($this->fields[$tab]); + } + + return true; + } + } + } + + return false; + } + + /** + * Returns true if any fields have been registered for these tabs + * @return boolean + */ + public function hasFields() + { + return count($this->fields) > 0; + } + + /** + * Returns an array of the registered fields, including tabs. + * @return array + */ + public function getFields() + { + return $this->fields; + } + + /** + * Returns an array of the registered fields, without tabs. + * @return array + */ + public function getAllFields() + { + $tablessFields = []; + + foreach ($this->getFields() as $tab) { + $tablessFields += $tab; + } + + return $tablessFields; + } + + /** + * Returns an icon for the tab based on the tab's name. + * @param string $name + * @return string + */ + public function getIcon($name) + { + if (!empty($this->icons[$name])) { + return $this->icons[$name]; + } + } + + /** + * Returns a tab pane CSS class. + * @param string $index + * @param string $label + * @return string + */ + public function getPaneCssClass($index = null, $label = null) + { + if (is_string($this->paneCssClass)) { + return $this->paneCssClass; + } + + if ($index !== null && isset($this->paneCssClass[$index])) { + return $this->paneCssClass[$index]; + } + + if ($label !== null && isset($this->paneCssClass[$label])) { + return $this->paneCssClass[$label]; + } + } + + /** + * Get an iterator for the items. + * @return ArrayIterator + */ + public function getIterator() + { + return new ArrayIterator( + $this->suppressTabs + ? $this->getAllFields() + : $this->getFields() + ); + } + + /** + * ArrayAccess implementation + */ + public function offsetSet($offset, $value) + { + $this->fields[$offset] = $value; + } + + /** + * ArrayAccess implementation + */ + public function offsetExists($offset) + { + return isset($this->fields[$offset]); + } + + /** + * ArrayAccess implementation + */ + public function offsetUnset($offset) + { + unset($this->fields[$offset]); + } + + /** + * ArrayAccess implementation + */ + public function offsetGet($offset) + { + return $this->fields[$offset] ?? null; + } +} diff --git a/modules/backend/classes/FormWidgetBase.php b/modules/backend/classes/FormWidgetBase.php new file mode 100644 index 0000000..d505e77 --- /dev/null +++ b/modules/backend/classes/FormWidgetBase.php @@ -0,0 +1,152 @@ +formField = $formField; + $this->fieldName = $formField->fieldName; + $this->valueFrom = $formField->valueFrom; + + $this->config = $this->makeConfig($configuration); + + $this->fillFromConfig([ + 'model', + 'data', + 'sessionKey', + 'previewMode', + 'showLabels', + 'parentForm', + ]); + + parent::__construct($controller, $configuration); + } + + /** + * Retrieve the parent form for this formwidget + * + * @return Backend\Widgets\Form|null + */ + public function getParentForm() + { + return $this->parentForm; + } + + /** + * Returns the HTML element field name for this widget, used for capturing + * user input, passed back to the getSaveValue method when saving. + * @return string HTML element name + */ + public function getFieldName() + { + return $this->formField->getName(); + } + + /** + * Returns a unique ID for this widget. Useful in creating HTML markup. + */ + public function getId($suffix = null) + { + $id = parent::getId($suffix); + $id .= '-' . $this->fieldName; + return HtmlHelper::nameToId($id); + } + + /** + * Process the postback value for this widget. If the value is omitted from + * postback data, it will be NULL, otherwise it will be an empty string. + * @param mixed $value The existing value for this widget. + * @return string The new value for this widget. + */ + public function getSaveValue($value) + { + return $value; + } + + /** + * Returns the value for this form field, + * supports nesting via HTML array. + * @return string + */ + public function getLoadValue() + { + if ($this->formField->value !== null) { + return $this->formField->value; + } + + $defaultValue = !$this->model->exists + ? $this->formField->getDefaultFromData($this->data ?: $this->model) + : null; + + return $this->formField->getValueFromData($this->data ?: $this->model, $defaultValue); + } +} diff --git a/modules/backend/classes/ListColumn.php b/modules/backend/classes/ListColumn.php new file mode 100644 index 0000000..96384ad --- /dev/null +++ b/modules/backend/classes/ListColumn.php @@ -0,0 +1,283 @@ +columnName = $columnName; + $this->label = $label; + } + + /** + * Specifies a list column rendering mode. Supported modes are: + * - text - text column, aligned left + * - number - numeric column, aligned right + * @param string $type Specifies a render mode as described above + */ + public function displayAs($type, $config) + { + $this->type = strtolower($type) ?: $this->type; + $this->config = $this->evalConfig($config); + return $this; + } + + /** + * Process options and apply them to this object. + * @param array $config + * @return array + */ + protected function evalConfig($config) + { + if (isset($config['width'])) { + $this->width = $config['width']; + } + if (isset($config['cssClass'])) { + $this->cssClass = $config['cssClass']; + } + if (isset($config['headCssClass'])) { + $this->headCssClass = $config['headCssClass']; + } + if (isset($config['searchable'])) { + $this->searchable = $config['searchable']; + } + if (isset($config['sortable'])) { + $this->sortable = $config['sortable']; + } + if (isset($config['clickable'])) { + $this->clickable = $config['clickable']; + } + if (isset($config['invisible'])) { + $this->invisible = $config['invisible']; + } + if (isset($config['valueFrom'])) { + $this->valueFrom = $config['valueFrom']; + } + if (isset($config['default'])) { + $this->defaults = $config['default']; + } + if (isset($config['select'])) { + $this->sqlSelect = $config['select']; + } + if (isset($config['relation'])) { + $this->relation = $config['relation']; + } + if (isset($config['format'])) { + $this->format = $config['format']; + } + if (isset($config['path'])) { + $this->path = $config['path']; + } + if (isset($config['align']) && \in_array($config['align'], ['left', 'right', 'center'])) { + $this->align = $config['align']; + } + + return $config; + } + + /** + * Returns a HTML valid name for the column name. + * @return string + */ + public function getName() + { + return HtmlHelper::nameToId($this->columnName); + } + + /** + * Returns a value suitable for the column id property. + * @param string $suffix Specify a suffix string + * @return string + */ + public function getId($suffix = null) + { + $id = 'column'; + + $id .= '-'.$this->columnName; + + if ($suffix) { + $id .= '-'.$suffix; + } + + return HtmlHelper::nameToId($id); + } + + /** + * Returns the column specific aligment css class. + * @return string + */ + public function getAlignClass() + { + return $this->align ? 'list-cell-align-' . $this->align : ''; + } + + /** + * Returns a raw config item value. + * @param string $value + * @param string $default + * @return mixed + */ + public function getConfig($value, $default = null) + { + return array_get($this->config, $value, $default); + } + + /** + * Returns this columns value from a supplied data set, which can be + * an array or a model or another generic collection. + * @param mixed $data + * @param mixed $default + * @return mixed + */ + public function getValueFromData($data, $default = null) + { + $columnName = $this->valueFrom ?: $this->columnName; + return $this->getColumnNameFromData($columnName, $data, $default); + } + + /** + * Internal method to extract the value of a column name from a data set. + * @param string $columnName + * @param mixed $data + * @param mixed $default + * @return mixed + */ + protected function getColumnNameFromData($columnName, $data, $default = null) + { + /* + * Array column name, eg: column[key][key2][key3] + */ + $keyParts = HtmlHelper::nameToArray($columnName); + $result = $data; + + /* + * Loop the column key parts and build a value. + * To support relations only the last column should return the + * relation value, all others will look up the relation object as normal. + */ + foreach ($keyParts as $key) { + if ($result instanceof Model && $result->hasRelation($key)) { + $result = $result->{$key}; + } + else { + if (is_array($result) && array_key_exists($key, $result)) { + $result = $result[$key]; + } elseif (!isset($result->{$key})) { + return $default; + } else { + $result = $result->{$key}; + } + } + } + + return $result; + } +} diff --git a/modules/backend/classes/MainMenuItem.php b/modules/backend/classes/MainMenuItem.php new file mode 100644 index 0000000..7c1d1a7 --- /dev/null +++ b/modules/backend/classes/MainMenuItem.php @@ -0,0 +1,131 @@ +permissions[$permission] = $definition; + } + + /** + * @param SideMenuItem $sideMenu + */ + public function addSideMenuItem(SideMenuItem $sideMenu) + { + $this->sideMenu[$sideMenu->code] = $sideMenu; + } + + /** + * @param string $code + * @return SideMenuItem + * @throws SystemException + */ + public function getSideMenuItem(string $code) + { + if (!array_key_exists($code, $this->sideMenu)) { + throw new SystemException('No sidenavigation item available with code ' . $code); + } + + return $this->sideMenu[$code]; + } + + /** + * @param string $code + */ + public function removeSideMenuItem(string $code) + { + unset($this->sideMenu[$code]); + } + + /** + * @param array $data + * @return static + */ + public static function createFromArray(array $data) + { + $instance = new static(); + $instance->code = $data['code']; + $instance->owner = $data['owner']; + $instance->label = $data['label']; + $instance->url = $data['url']; + $instance->icon = $data['icon'] ?? null; + $instance->iconSvg = $data['iconSvg'] ?? null; + $instance->counter = $data['counter'] ?? null; + $instance->counterLabel = $data['counterLabel'] ?? null; + $instance->badge = $data['badge'] ?? null; + $instance->permissions = $data['permissions'] ?? $instance->permissions; + $instance->order = $data['order'] ?? $instance->order; + return $instance; + } +} diff --git a/modules/backend/classes/NavigationManager.php b/modules/backend/classes/NavigationManager.php new file mode 100644 index 0000000..f88baf6 --- /dev/null +++ b/modules/backend/classes/NavigationManager.php @@ -0,0 +1,757 @@ +pluginManager = PluginManager::instance(); + } + + /** + * Loads the menu items from modules and plugins + * @return void + * @throws SystemException + */ + protected function loadItems() + { + $this->items = []; + $this->quickActions = []; + + /* + * Load module items + */ + foreach ($this->callbacks as $callback) { + $callback($this); + } + + /* + * Load plugin items + */ + $plugins = $this->pluginManager->getPlugins(); + + foreach ($plugins as $id => $plugin) { + $items = $plugin->registerNavigation(); + $quickActions = $plugin->registerQuickActions(); + + if (!is_array($items) && !is_array($quickActions)) { + continue; + } + + if (is_array($items)) { + $this->registerMenuItems($id, $items); + } + if (is_array($quickActions)) { + $this->registerQuickActions($id, $quickActions); + } + } + + /** + * @event backend.menu.extendItems + * Provides an opportunity to manipulate the backend navigation + * + * Example usage: + * + * Event::listen('backend.menu.extendItems', function ((\Backend\Classes\NavigationManager) $navigationManager) { + * $navigationManager->addMainMenuItems(...) + * $navigationManager->addSideMenuItems(...) + * $navigationManager->removeMainMenuItem(...) + * }); + * + */ + Event::fire('backend.menu.extendItems', [$this]); + + /* + * Sort menu items and quick actions + */ + uasort($this->items, static function ($a, $b) { + return $a->order - $b->order; + }); + uasort($this->quickActions, static function ($a, $b) { + return $a->order - $b->order; + }); + + /* + * Filter items and quick actions that the user lacks permission for + */ + $user = BackendAuth::getUser(); + $this->items = $this->filterItemPermissions($user, $this->items); + $this->quickActions = $this->filterItemPermissions($user, $this->quickActions); + + foreach ($this->items as $item) { + if (!$item->sideMenu || !count($item->sideMenu)) { + continue; + } + + /* + * Apply incremental default orders + */ + $orderCount = 0; + foreach ($item->sideMenu as $sideMenuItem) { + if ($sideMenuItem->order !== -1) { + continue; + } + $sideMenuItem->order = ($orderCount += 100); + } + + /* + * Sort side menu items + */ + uasort($item->sideMenu, static function ($a, $b) { + return $a->order - $b->order; + }); + + /* + * Filter items user lacks permission for + */ + $item->sideMenu = $this->filterItemPermissions($user, $item->sideMenu); + } + } + + /** + * Registers a callback function that defines menu items. + * The callback function should register menu items by calling the manager's + * `registerMenuItems` method. The manager instance is passed to the callback + * function as an argument. Usage: + * + * BackendMenu::registerCallback(function ($manager) { + * $manager->registerMenuItems([...]); + * }); + * + * @param callable $callback A callable function. + */ + public function registerCallback(callable $callback) + { + $this->callbacks[] = $callback; + } + + /** + * Registers the back-end menu items. + * The argument is an array of the main menu items. The array keys represent the + * menu item codes, specific for the plugin/module. Each element in the + * array should be an associative array with the following keys: + * - label - specifies the menu label localization string key, required. + * - icon - an icon name from the Font Awesome icon collection, required. + * - url - the back-end relative URL the menu item should point to, required. + * - permissions - an array of permissions the back-end user should have, optional. + * The item will be displayed if the user has any of the specified permissions. + * - order - a position of the item in the menu, optional. + * - counter - an optional numeric value to output near the menu icon. The value should be + * a number or a callable returning a number. + * - counterLabel - an optional string value to describe the numeric reference in counter. + * - sideMenu - an array of side menu items, optional. If provided, the array items + * should represent the side menu item code, and each value should be an associative + * array with the following keys: + * - label - specifies the menu label localization string key, required. + * - icon - an icon name from the Font Awesome icon collection, required. + * - url - the back-end relative URL the menu item should point to, required. + * - attributes - an array of attributes and values to apply to the menu item, optional. + * - permissions - an array of permissions the back-end user should have, optional. + * - counter - an optional numeric value to output near the menu icon. The value should be + * a number or a callable returning a number. + * - counterLabel - an optional string value to describe the numeric reference in counter. + * - badge - an optional string value to output near the menu icon. The value should be + * a string. This value will override the counter if set. + * @param string $owner Specifies the menu items owner plugin or module in the format Author.Plugin. + * @param array $definitions An array of the menu item definitions. + * @throws SystemException + */ + public function registerMenuItems($owner, array $definitions) + { + $validator = Validator::make($definitions, [ + '*.label' => 'required', + '*.icon' => 'required_without:*.iconSvg', + '*.url' => 'required', + '*.sideMenu.*.label' => 'nullable|required', + '*.sideMenu.*.icon' => 'nullable|required_without:*.sideMenu.*.iconSvg', + '*.sideMenu.*.url' => 'nullable|required', + ]); + + if ($validator->fails()) { + $errorMessage = 'Invalid menu item detected in ' . $owner . '. Contact the plugin author to fix (' . $validator->errors()->first() . ')'; + if (Config::get('app.debug', false)) { + throw new SystemException($errorMessage); + } + + Log::error($errorMessage); + } + + $this->addMainMenuItems($owner, $definitions); + } + + /** + * Dynamically add an array of main menu items + * @param string $owner + * @param array $definitions + */ + public function addMainMenuItems($owner, array $definitions) + { + foreach ($definitions as $code => $definition) { + $this->addMainMenuItem($owner, $code, $definition); + } + } + + /** + * Dynamically add a single main menu item + * @param string $owner + * @param string $code + * @param array $definition + */ + public function addMainMenuItem($owner, $code, array $definition) + { + $itemKey = $this->makeItemKey($owner, $code); + + if (isset($this->items[$itemKey])) { + $definition = array_merge((array) $this->items[$itemKey], $definition); + } + + $item = array_merge($definition, [ + 'code' => $code, + 'owner' => $owner + ]); + + $this->items[$itemKey] = MainMenuItem::createFromArray($item); + + if (array_key_exists('sideMenu', $item)) { + $this->addSideMenuItems($owner, $code, $item['sideMenu']); + } + } + + /** + * @param string $owner + * @param string $code + * @return MainMenuItem + * @throws SystemException + */ + public function getMainMenuItem(string $owner, string $code) + { + $itemKey = $this->makeItemKey($owner, $code); + + if (!array_key_exists($itemKey, $this->items)) { + throw new SystemException('No main menu item found with key ' . $itemKey); + } + + return $this->items[$itemKey]; + } + + /** + * Removes a single main menu item + * @param $owner + * @param $code + */ + public function removeMainMenuItem($owner, $code) + { + $itemKey = $this->makeItemKey($owner, $code); + unset($this->items[$itemKey]); + } + + /** + * Dynamically add an array of side menu items + * @param string $owner + * @param string $code + * @param array $definitions + */ + public function addSideMenuItems($owner, $code, array $definitions) + { + foreach ($definitions as $sideCode => $definition) { + $this->addSideMenuItem($owner, $code, $sideCode, (array) $definition); + } + } + + /** + * Dynamically add a single side menu item + * @param string $owner + * @param string $code + * @param string $sideCode + * @param array $definition + * @return bool + */ + public function addSideMenuItem($owner, $code, $sideCode, array $definition) + { + $itemKey = $this->makeItemKey($owner, $code); + + if (!isset($this->items[$itemKey])) { + return false; + } + + $mainItem = $this->items[$itemKey]; + + $definition = array_merge($definition, [ + 'code' => $sideCode, + 'owner' => $owner + ]); + + if (isset($mainItem->sideMenu[$sideCode])) { + $definition = array_merge((array) $mainItem->sideMenu[$sideCode], $definition); + } + + $item = SideMenuItem::createFromArray($definition); + + $this->items[$itemKey]->addSideMenuItem($item); + return true; + } + + /** + * Remove multiple side menu items + * + * @param string $owner + * @param string $code + * @param array $sideCodes + * @return void + */ + public function removeSideMenuItems($owner, $code, $sideCodes) + { + foreach ($sideCodes as $sideCode) { + $this->removeSideMenuItem($owner, $code, $sideCode); + } + } + + /** + * Removes a single main menu item + * @param string $owner + * @param string $code + * @param string $sideCode + * @return bool + */ + public function removeSideMenuItem($owner, $code, $sideCode) + { + $itemKey = $this->makeItemKey($owner, $code); + if (!isset($this->items[$itemKey])) { + return false; + } + + $mainItem = $this->items[$itemKey]; + $mainItem->removeSideMenuItem($sideCode); + return true; + } + + /** + * Returns a list of the main menu items. + * @return array + * @throws SystemException + */ + public function listMainMenuItems() + { + if ($this->items === null && $this->quickActions === null) { + $this->loadItems(); + } + + if ($this->items === null) { + return []; + } + + foreach ($this->items as $item) { + if ($item->badge) { + $item->counter = (string) $item->badge; + continue; + } + if ($item->counter === false) { + continue; + } + + if ($item->counter !== null && is_callable($item->counter)) { + $item->counter = call_user_func($item->counter, $item); + } elseif (!empty((int) $item->counter)) { + $item->counter = (int) $item->counter; + } elseif (!empty($sideItems = $this->listSideMenuItems($item->owner, $item->code))) { + $item->counter = 0; + foreach ($sideItems as $sideItem) { + if ($sideItem->badge) { + continue; + } + $item->counter += $sideItem->counter; + } + } + + if (empty($item->counter) || !is_numeric($item->counter)) { + $item->counter = null; + } + } + + return $this->items; + } + + /** + * Returns a list of side menu items for the currently active main menu item. + * The currently active main menu item is set with the setContext methods. + * @param null $owner + * @param null $code + * @return SideMenuItem[] + * @throws SystemException + */ + public function listSideMenuItems($owner = null, $code = null) + { + $activeItem = null; + + if ($owner !== null && $code !== null) { + $activeItem = @$this->items[$this->makeItemKey($owner, $code)]; + } else { + foreach ($this->listMainMenuItems() as $item) { + if ($this->isMainMenuItemActive($item)) { + $activeItem = $item; + break; + } + } + } + + if (!$activeItem) { + return []; + } + + $items = $activeItem->sideMenu; + + foreach ($items as $item) { + if ($item->badge) { + $item->counter = (string) $item->badge; + continue; + } + if ($item->counter !== null && is_callable($item->counter)) { + $item->counter = call_user_func($item->counter, $item); + if (empty($item->counter)) { + $item->counter = null; + } + } + if (!is_null($item->counter) && !is_numeric($item->counter)) { + throw new SystemException("The menu item {$activeItem->code}.{$item->code}'s counter property is invalid. Check to make sure it's numeric or callable. Value: " . var_export($item->counter, true)); + } + } + + return $items; + } + + /** + * Registers quick actions in the main navigation. + * + * Quick actions are single purpose links displayed to the left of the user menu in the + * backend main navigation. + * + * The argument is an array of the quick action items. The array keys represent the + * quick action item codes, specific for the plugin/module. Each element in the + * array should be an associative array with the following keys: + * - label - specifies the action label localization string key, used as a tooltip, required. + * - icon - an icon name from the Font Awesome icon collection, required if iconSvg is unspecified. + * - iconSvg - a custom SVG icon to use for the icon, required if icon is unspecified. + * - url - the back-end relative URL the quick action item should point to, required. + * - permissions - an array of permissions the back-end user should have, optional. + * The item will be displayed if the user has any of the specified permissions. + * - order - a position of the item in the menu, optional. + * + * @param string $owner Specifies the quick action items owner plugin or module in the format Author.Plugin. + * @param array $definitions An array of the quick action item definitions. + * @return void + * @throws SystemException If the validation of the quick action configuration fails + */ + public function registerQuickActions($owner, array $definitions) + { + $validator = Validator::make($definitions, [ + '*.label' => 'required', + '*.icon' => 'required_without:*.iconSvg', + '*.url' => 'required' + ]); + + if ($validator->fails()) { + $errorMessage = 'Invalid quick action item detected in ' . $owner . '. Contact the plugin author to fix (' . $validator->errors()->first() . ')'; + if (Config::get('app.debug', false)) { + throw new SystemException($errorMessage); + } + + Log::error($errorMessage); + } + + $this->addQuickActionItems($owner, $definitions); + } + + /** + * Dynamically add an array of quick action items + * + * @param string $owner + * @param array $definitions + * @return void + */ + public function addQuickActionItems($owner, array $definitions) + { + foreach ($definitions as $code => $definition) { + $this->addQuickActionItem($owner, $code, $definition); + } + } + + /** + * Dynamically add a single quick action item + * + * @param string $owner + * @param string $code + * @param array $definition + * @return void + */ + public function addQuickActionItem($owner, $code, array $definition) + { + $itemKey = $this->makeItemKey($owner, $code); + + if (isset($this->quickActions[$itemKey])) { + $definition = array_merge((array) $this->quickActions[$itemKey], $definition); + } + + $item = array_merge($definition, [ + 'code' => $code, + 'owner' => $owner + ]); + + $this->quickActions[$itemKey] = QuickActionItem::createFromArray($item); + } + + /** + * Gets the instance of a specified quick action item. + * + * @param string $owner + * @param string $code + * @return QuickActionItem + * @throws SystemException + */ + public function getQuickActionItem(string $owner, string $code) + { + $itemKey = $this->makeItemKey($owner, $code); + + if (!array_key_exists($itemKey, $this->quickActions)) { + throw new SystemException('No quick action item found with key ' . $itemKey); + } + + return $this->quickActions[$itemKey]; + } + + /** + * Removes a single quick action item + * + * @param $owner + * @param $code + * @return void + */ + public function removeQuickActionItem($owner, $code) + { + $itemKey = $this->makeItemKey($owner, $code); + unset($this->quickActions[$itemKey]); + } + + /** + * Returns a list of quick action items. + * + * @return array + * @throws SystemException + */ + public function listQuickActionItems() + { + if ($this->items === null && $this->quickActions === null) { + $this->loadItems(); + } + + if ($this->quickActions === null) { + return []; + } + + return $this->quickActions; + } + + /** + * Sets the navigation context. + * The function sets the navigation owner, main menu item code and the side menu item code. + * @param string $owner Specifies the navigation owner in the format Vendor/Module + * @param string $mainMenuItemCode Specifies the main menu item code + * @param string $sideMenuItemCode Specifies the side menu item code + */ + public function setContext($owner, $mainMenuItemCode, $sideMenuItemCode = null) + { + $this->setContextOwner($owner); + $this->setContextMainMenu($mainMenuItemCode); + $this->setContextSideMenu($sideMenuItemCode); + } + + /** + * Sets the navigation context. + * The function sets the navigation owner. + * @param string $owner Specifies the navigation owner in the format Vendor/Module + */ + public function setContextOwner($owner) + { + $this->contextOwner = $owner; + } + + /** + * Specifies a code of the main menu item in the current navigation context. + * @param string $mainMenuItemCode Specifies the main menu item code + */ + public function setContextMainMenu($mainMenuItemCode) + { + $this->contextMainMenuItemCode = $mainMenuItemCode; + } + + /** + * Returns information about the current navigation context. + * @return mixed Returns an object with the following fields: + * - mainMenuCode + * - sideMenuCode + * - owner + */ + public function getContext() + { + return (object)[ + 'mainMenuCode' => $this->contextMainMenuItemCode, + 'sideMenuCode' => $this->contextSideMenuItemCode, + 'owner' => $this->contextOwner + ]; + } + + /** + * Specifies a code of the side menu item in the current navigation context. + * If the code is set to TRUE, the first item will be flagged as active. + * @param string $sideMenuItemCode Specifies the side menu item code + */ + public function setContextSideMenu($sideMenuItemCode) + { + $this->contextSideMenuItemCode = $sideMenuItemCode; + } + + /** + * Determines if a main menu item is active. + * @param MainMenuItem $item Specifies the item object. + * @return boolean Returns true if the menu item is active. + */ + public function isMainMenuItemActive($item) + { + return $this->contextOwner === $item->owner && $this->contextMainMenuItemCode === $item->code; + } + + /** + * Returns the currently active main menu item + * @return null|MainMenuItem $item Returns the item object or null. + * @throws SystemException + */ + public function getActiveMainMenuItem() + { + foreach ($this->listMainMenuItems() as $item) { + if ($this->isMainMenuItemActive($item)) { + return $item; + } + } + + return null; + } + + /** + * Determines if a side menu item is active. + * @param SideMenuItem $item Specifies the item object. + * @return boolean Returns true if the side item is active. + */ + public function isSideMenuItemActive($item) + { + if ($this->contextSideMenuItemCode === true) { + $this->contextSideMenuItemCode = null; + return true; + } + + return $this->contextOwner === $item->owner && $this->contextSideMenuItemCode === $item->code; + } + + /** + * Registers a special side navigation partial for a specific main menu. + * The sidenav partial replaces the standard side navigation. + * @param string $owner Specifies the navigation owner in the format Vendor/Module. + * @param string $mainMenuItemCode Specifies the main menu item code. + * @param string $partial Specifies the partial name. + */ + public function registerContextSidenavPartial($owner, $mainMenuItemCode, $partial) + { + $this->contextSidenavPartials[$owner.$mainMenuItemCode] = $partial; + } + + /** + * Returns the side navigation partial for a specific main menu previously registered + * with the registerContextSidenavPartial() method. + * + * @param string $owner Specifies the navigation owner in the format Vendor/Module. + * @param string $mainMenuItemCode Specifies the main menu item code. + * @return mixed Returns the partial name or null. + */ + public function getContextSidenavPartial($owner, $mainMenuItemCode) + { + $key = $owner.$mainMenuItemCode; + + return $this->contextSidenavPartials[$key] ?? null; + } + + /** + * Removes menu items from an array if the supplied user lacks permission. + * @param \Backend\Models\User $user A user object + * @param MainMenuItem[]|SideMenuItem[] $items A collection of menu items + * @return array The filtered menu items + */ + protected function filterItemPermissions($user, array $items) + { + if (!$user) { + return $items; + } + + $items = array_filter($items, static function ($item) use ($user) { + if (!$item->permissions || !count($item->permissions)) { + return true; + } + + return $user->hasAnyAccess($item->permissions); + }); + + return $items; + } + + /** + * Internal method to make a unique key for an item. + * @param string $owner + * @param string $code + * @return string + */ + protected function makeItemKey($owner, $code) + { + return strtoupper($owner).'.'.strtoupper($code); + } +} diff --git a/modules/backend/classes/QuickActionItem.php b/modules/backend/classes/QuickActionItem.php new file mode 100644 index 0000000..bf30cad --- /dev/null +++ b/modules/backend/classes/QuickActionItem.php @@ -0,0 +1,105 @@ +attributes[$attribute] = $value; + } + + public function removeAttribute($attribute) + { + unset($this->attributes[$attribute]); + } + + /** + * @param string $permission + * @param array $definition + */ + public function addPermission(string $permission, array $definition) + { + $this->permissions[$permission] = $definition; + } + + /** + * @param string $permission + * @return void + */ + public function removePermission(string $permission) + { + unset($this->permissions[$permission]); + } + + /** + * @param array $data + * @return static + */ + public static function createFromArray(array $data) + { + $instance = new static(); + $instance->code = $data['code']; + $instance->owner = $data['owner']; + $instance->label = $data['label']; + $instance->url = $data['url']; + $instance->icon = $data['icon'] ?? null; + $instance->iconSvg = $data['iconSvg'] ?? null; + $instance->attributes = $data['attributes'] ?? $instance->attributes; + $instance->permissions = $data['permissions'] ?? $instance->permissions; + $instance->order = $data['order'] ?? $instance->order; + return $instance; + } +} diff --git a/modules/backend/classes/ReportWidgetBase.php b/modules/backend/classes/ReportWidgetBase.php new file mode 100644 index 0000000..d37e180 --- /dev/null +++ b/modules/backend/classes/ReportWidgetBase.php @@ -0,0 +1,28 @@ +properties = $this->validateProperties($properties); + + /* + * Ensure the provided alias (if present) takes effect as the widget configuration is + * not passed to the WidgetBase constructor which would normally take care of that + */ + if (!isset($this->alias)) { + $this->alias = $properties['alias'] ?? $this->defaultAlias; + } + + parent::__construct($controller); + } +} diff --git a/modules/backend/classes/SideMenuItem.php b/modules/backend/classes/SideMenuItem.php new file mode 100644 index 0000000..27ec84e --- /dev/null +++ b/modules/backend/classes/SideMenuItem.php @@ -0,0 +1,123 @@ +attributes[$attribute] = $value; + } + + public function removeAttribute($attribute) + { + unset($this->attributes[$attribute]); + } + + /** + * @param string $permission + * @param array $definition + */ + public function addPermission(string $permission, array $definition) + { + $this->permissions[$permission] = $definition; + } + + /** + * @param string $permission + * @return void + */ + public function removePermission(string $permission) + { + unset($this->permissions[$permission]); + } + + /** + * @param array $data + * @return static + */ + public static function createFromArray(array $data) + { + $instance = new static(); + $instance->code = $data['code']; + $instance->owner = $data['owner']; + $instance->label = $data['label']; + $instance->url = $data['url']; + $instance->icon = $data['icon'] ?? null; + $instance->iconSvg = $data['iconSvg'] ?? null; + $instance->counter = $data['counter'] ?? null; + $instance->counterLabel = $data['counterLabel'] ?? null; + $instance->attributes = $data['attributes'] ?? $instance->attributes; + $instance->badge = $data['badge'] ?? null; + $instance->permissions = $data['permissions'] ?? $instance->permissions; + $instance->order = $data['order'] ?? $instance->order; + return $instance; + } +} diff --git a/modules/backend/classes/Skin.php b/modules/backend/classes/Skin.php new file mode 100644 index 0000000..e46865c --- /dev/null +++ b/modules/backend/classes/Skin.php @@ -0,0 +1,111 @@ +defaultSkinPath = base_path() . '/modules/backend'; + + /* + * Guess the skin path + */ + $class = get_called_class(); + $classFolder = strtolower(class_basename($class)); + $classFile = realpath(dirname(File::fromClass($class))); + $this->skinPath = $classFile + ? $classFile . '/' . $classFolder + : $this->defaultSkinPath; + + $this->publicSkinPath = File::localToPublic($this->skinPath); + $this->defaultPublicSkinPath = File::localToPublic($this->defaultSkinPath); + } + + /** + * Looks up a path to a skin-based file, if it doesn't exist, the default path is used. + * @param string $path + * @param boolean $isPublic + * @return string + */ + public function getPath($path = null, $isPublic = false) + { + $path = RouterHelper::normalizeUrl($path); + $assetFile = $this->skinPath . $path; + + if (File::isFile($assetFile)) { + return $isPublic + ? $this->publicSkinPath . $path + : $this->skinPath . $path; + } + + return $isPublic + ? $this->defaultPublicSkinPath . $path + : $this->defaultSkinPath . $path; + } + + /** + * Returns an array of paths where skin layouts can be found. + * @return array + */ + public function getLayoutPaths() + { + return [$this->skinPath.'/layouts', $this->defaultSkinPath.'/layouts']; + } + + /** + * Returns the active skin. + */ + public static function getActive() + { + if (self::$skinCache !== null) { + return self::$skinCache; + } + + $skinClass = Config::get('cms.backendSkin'); + $skinObject = new $skinClass(); + return self::$skinCache = $skinObject; + } +} diff --git a/modules/backend/classes/WidgetBase.php b/modules/backend/classes/WidgetBase.php new file mode 100644 index 0000000..3444b91 --- /dev/null +++ b/modules/backend/classes/WidgetBase.php @@ -0,0 +1,216 @@ +controller = $controller; + $this->viewPath = $this->configPath = $this->guessViewPath('/partials'); + $this->assetPath = $this->guessViewPath('/assets', true); + + /* + * Apply configuration values to a new config object, if a parent + * constructor hasn't done it already. + */ + if ($this->config === null) { + $this->config = $this->makeConfig($configuration); + } + + /* + * If no alias is set by the configuration. + */ + if (!isset($this->alias)) { + $this->alias = $this->config->alias ?? $this->defaultAlias; + } + + /* + * Prepare assets used by this widget. + */ + $this->loadAssets(); + + parent::__construct(); + + /* + * Initialize the widget. + */ + if (!$this->getConfig('noInit', false)) { + $this->init(); + } + } + + /** + * Initialize the widget, called by the constructor and free from its parameters. + * @return void + */ + public function init() + { + } + + /** + * Renders the widget's primary contents. + * @return string HTML markup supplied by this widget. + */ + public function render() + { + } + + /** + * Adds widget specific asset files. Use $this->addJs() and $this->addCss() + * to register new assets to include on the page. + * @return void + */ + protected function loadAssets() + { + } + + /** + * Binds a widget to the controller for safe use. + * @return void + */ + public function bindToController() + { + if ($this->controller->widget === null) { + $this->controller->widget = new stdClass; + } + + $this->controller->widget->{$this->alias} = $this; + } + + /** + * Transfers config values stored inside the $config property directly + * on to the root object properties. If no properties are defined + * all config will be transferred if it finds a matching property. + * @param array $properties + * @return void + */ + protected function fillFromConfig($properties = null) + { + if ($properties === null) { + $properties = array_keys((array) $this->config); + } + + foreach ($properties as $property) { + if (property_exists($this, $property)) { + $this->{$property} = $this->getConfig($property, $this->{$property}); + } + } + } + + /** + * Returns a unique ID for this widget. Useful in creating HTML markup. + * @param string $suffix An extra string to append to the ID. + * @return string A unique identifier. + */ + public function getId($suffix = null) + { + $id = class_basename(get_called_class()); + + if ($this->alias != $this->defaultAlias) { + $id .= '-' . $this->alias; + } + + if ($suffix !== null) { + $id .= '-' . $suffix; + } + + return HtmlHelper::nameToId($id); + } + + /** + * Returns a fully qualified event handler name for this widget. + * @param string $name The ajax event handler name. + * @return string + */ + public function getEventHandler($name) + { + return $this->alias . '::' . $name; + } + + /** + * Safe accessor for configuration values. + * @param string $name Config name, supports array names like "field[key]" + * @param string $default Default value if nothing is found + * @return string + */ + public function getConfig($name, $default = null) + { + /* + * Array field name, eg: field[key][key2][key3] + */ + $keyParts = HtmlHelper::nameToArray($name); + + /* + * First part will be the field name, pop it off + */ + $fieldName = array_shift($keyParts); + if (!isset($this->config->{$fieldName})) { + return $default; + } + + $result = $this->config->{$fieldName}; + + /* + * Loop the remaining key parts and build a result + */ + foreach ($keyParts as $key) { + if (!array_key_exists($key, $result)) { + return $default; + } + + $result = $result[$key]; + } + + return $result; + } + + /** + * Returns the controller using this widget. + */ + public function getController() + { + return $this->controller; + } +} diff --git a/modules/backend/classes/WidgetManager.php b/modules/backend/classes/WidgetManager.php new file mode 100644 index 0000000..7ec610c --- /dev/null +++ b/modules/backend/classes/WidgetManager.php @@ -0,0 +1,268 @@ + $formWidgetInfo]. + */ + protected $formWidgets; + + /** + * @var array Cache of form widget registration callbacks. + */ + protected $formWidgetCallbacks = []; + + /** + * @var array An array of form widgets keyed by their code. Stored in the form of ['formwidgetcode' => 'FormWidgetClass']. + */ + protected $formWidgetHints; + + /** + * @var array An array of report widgets. + */ + protected $reportWidgets; + + /** + * @var array Cache of report widget registration callbacks. + */ + protected $reportWidgetCallbacks = []; + + /** + * @var System\Classes\PluginManager + */ + protected $pluginManager; + + /** + * Initialize this singleton. + */ + protected function init() + { + $this->pluginManager = PluginManager::instance(); + } + + // + // Form Widgets + // + + /** + * Returns a list of registered form widgets. + * @return array Array keys are class names. + */ + public function listFormWidgets() + { + if ($this->formWidgets === null) { + $this->formWidgets = []; + + /* + * Load module widgets + */ + foreach ($this->formWidgetCallbacks as $callback) { + $callback($this); + } + + /* + * Load plugin widgets + */ + $plugins = $this->pluginManager->getPlugins(); + + foreach ($plugins as $plugin) { + if (!is_array($widgets = $plugin->registerFormWidgets())) { + continue; + } + + foreach ($widgets as $className => $widgetInfo) { + $this->registerFormWidget($className, $widgetInfo); + } + } + } + + return $this->formWidgets; + } + + /** + * Registers a single form widget. + * @param string $className Widget class name. + * @param array $widgetInfo Registration information, can contain a `code` key. + * @return void + */ + public function registerFormWidget($className, $widgetInfo = null) + { + if (!is_array($widgetInfo)) { + $widgetInfo = ['code' => $widgetInfo]; + } + + $widgetCode = $widgetInfo['code'] ?? null; + + if (!$widgetCode) { + $widgetCode = Str::getClassId($className); + } + + $this->formWidgets[$className] = $widgetInfo; + $this->formWidgetHints[$widgetCode] = $className; + } + + /** + * Manually registers form widget for consideration. Usage: + * + * WidgetManager::registerFormWidgets(function ($manager) { + * $manager->registerFormWidget('Backend\FormWidgets\CodeEditor', 'codeeditor'); + * }); + * + */ + public function registerFormWidgets(callable $definitions) + { + $this->formWidgetCallbacks[] = $definitions; + } + + /** + * Returns a class name from a form widget code + * Normalizes a class name or converts an code to its class name. + * @param string $name Class name or form widget code. + * @return string The class name resolved, or the original name. + */ + public function resolveFormWidget($name) + { + if ($this->formWidgets === null) { + $this->listFormWidgets(); + } + + $hints = $this->formWidgetHints; + + if (isset($hints[$name])) { + return $hints[$name]; + } + + $_name = Str::normalizeClassName($name); + if (isset($this->formWidgets[$_name])) { + return $_name; + } + + return $name; + } + + // + // Report Widgets + // + + /** + * Returns a list of registered report widgets. + * @return array Array keys are class names. + */ + public function listReportWidgets() + { + if ($this->reportWidgets === null) { + $this->reportWidgets = []; + + /* + * Load module widgets + */ + foreach ($this->reportWidgetCallbacks as $callback) { + $callback($this); + } + + /* + * Load plugin widgets + */ + $plugins = $this->pluginManager->getPlugins(); + + foreach ($plugins as $plugin) { + if (!is_array($widgets = $plugin->registerReportWidgets())) { + continue; + } + + foreach ($widgets as $className => $widgetInfo) { + $this->registerReportWidget($className, $widgetInfo); + } + } + } + + /** + * @event system.reportwidgets.extendItems + * Enables adding or removing report widgets. + * + * You will have access to the WidgetManager instance and be able to call the appropiate methods + * $manager->registerReportWidget(); + * $manager->removeReportWidget(); + * + * Example usage: + * + * Event::listen('system.reportwidgets.extendItems', function ($manager) { + * $manager->removeReportWidget('Acme\ReportWidgets\YourWidget'); + * }); + * + */ + Event::fire('system.reportwidgets.extendItems', [$this]); + + $user = BackendAuth::getUser(); + foreach ($this->reportWidgets as $widget => $config) { + if (!empty($config['permissions'])) { + if (!$user->hasAccess($config['permissions'], false)) { + unset($this->reportWidgets[$widget]); + } + } + } + + return $this->reportWidgets; + } + + /** + * Returns the raw array of registered report widgets. + * @return array Array keys are class names. + */ + public function getReportWidgets() + { + return $this->reportWidgets; + } + + /* + * Registers a single report widget. + */ + public function registerReportWidget($className, $widgetInfo) + { + $this->reportWidgets[$className] = $widgetInfo; + } + + /** + * Manually registers report widget for consideration. Usage: + * + * WidgetManager::registerReportWidgets(function ($manager) { + * $manager->registerReportWidget('RainLab\GoogleAnalytics\ReportWidgets\TrafficOverview', [ + * 'name' => 'Google Analytics traffic overview', + * 'context' => 'dashboard' + * ]); + * }); + * + */ + public function registerReportWidgets(callable $definitions) + { + $this->reportWidgetCallbacks[] = $definitions; + } + + /** + * Remove a registered ReportWidget. + * @param string $className Widget class name. + * @return void + */ + public function removeReportWidget($className) + { + if (!$this->reportWidgets) { + throw new SystemException('Unable to remove a widget before widgets are loaded.'); + } + + unset($this->reportWidgets[$className]); + } +} diff --git a/modules/backend/composer.json b/modules/backend/composer.json new file mode 100644 index 0000000..8da9bd5 --- /dev/null +++ b/modules/backend/composer.json @@ -0,0 +1,35 @@ +{ + "name": "october/backend", + "type": "october-module", + "description": "Backend module for October CMS", + "homepage": "https://octobercms.com", + "keywords": ["october cms", "october", "backend"], + "license": "MIT", + "authors": [ + { + "name": "Alexey Bobkov", + "email": "aleksey.bobkov@gmail.com", + "role": "Co-founder" + }, + { + "name": "Samuel Georges", + "email": "daftspunky@gmail.com", + "role": "Co-founder" + } + ], + "require": { + "php": ">=7.2", + "composer/installers": "~1.0" + }, + "autoload": { + "psr-4": { + "Backend\\": "" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "minimum-stability": "dev" +} diff --git a/modules/backend/controllers/AccessLogs.php b/modules/backend/controllers/AccessLogs.php new file mode 100644 index 0000000..512048f --- /dev/null +++ b/modules/backend/controllers/AccessLogs.php @@ -0,0 +1,48 @@ +listRefresh(); + } +} diff --git a/modules/backend/controllers/Auth.php b/modules/backend/controllers/Auth.php new file mode 100644 index 0000000..c6a7848 --- /dev/null +++ b/modules/backend/controllers/Auth.php @@ -0,0 +1,260 @@ +layout = 'auth'; + } + + /** + * Default route, redirects to signin. + */ + public function index() + { + return Backend::redirect('backend/auth/signin'); + } + + /** + * Displays the log in page. + */ + public function signin() + { + $this->bodyClass = 'signin'; + + // Clear Cache and any previous data to fix invalid security token issue + $this->setResponseHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); + + try { + if (post('postback')) { + return $this->signin_onSubmit(); + } + + $this->bodyClass .= ' preload'; + } catch (Exception $ex) { + Flash::error($ex->getMessage()); + } + } + + public function signin_onSubmit() + { + $rules = [ + 'login' => 'required|between:2,255', + 'password' => 'required|between:4,255' + ]; + + $validation = Validator::make(post(), $rules); + if ($validation->fails()) { + throw new ValidationException($validation); + } + + if (is_null($remember = Config::get('cms.backendForceRemember', true))) { + $remember = (bool) post('remember'); + } + + // Authenticate user + $user = BackendAuth::authenticate([ + 'login' => post('login'), + 'password' => post('password') + ], $remember); + + if (is_null($runMigrationsOnLogin = Config::get('cms.runMigrationsOnLogin', null))) { + $runMigrationsOnLogin = Config::get('app.debug', false); + } + + if ($runMigrationsOnLogin) { + try { + // Load version updates + UpdateManager::instance()->update(); + } catch (Exception $ex) { + Flash::error($ex->getMessage()); + } + } + + // Log the sign in event + AccessLog::add($user); + + // Redirect to the intended page after successful sign in + return Backend::redirectIntended('backend'); + } + + /** + * Logs out a backend user. + */ + public function signout() + { + if (BackendAuth::isImpersonator()) { + BackendAuth::stopImpersonate(); + } else { + BackendAuth::logout(); + } + + // Add HTTP Header 'Clear Site Data' to purge all sensitive data upon signout + if (Request::secure()) { + $this->setResponseHeader('Clear-Site-Data', 'cache, cookies, storage, executionContexts'); + } + + return Backend::redirect('backend'); + } + + /** + * Request a password reset verification code. + */ + public function restore() + { + try { + if (post('postback')) { + return $this->restore_onSubmit(); + } + } catch (Exception $ex) { + Flash::error($ex->getMessage()); + } + } + + /** + * Submits the restore form. + */ + public function restore_onSubmit() + { + // Force Trusted Host verification on password reset link generation + // regardless of config to protect against host header poisoning + $trustedHosts = Config::get('app.trustedHosts', false); + if ($trustedHosts === false) { + $hosts = CheckForTrustedHost::processTrustedHosts(true); + + if (count($hosts)) { + Request::setTrustedHosts($hosts); + + // Trigger the host validation logic + Request::getHost(); + } + } + + $rules = [ + 'login' => 'required|between:2,255' + ]; + + $validation = Validator::make(post(), $rules); + if ($validation->fails()) { + throw new ValidationException($validation); + } + + $user = BackendAuth::findUserByLogin(post('login')); + if (!$user) { + if (Config::get('app.debug', false)) { + throw new ValidationException([ + 'login' => trans('backend::lang.account.restore_error', ['login' => post('login')]) + ]); + } + else { + Flash::success(trans('backend::lang.account.restore_success')); + return Backend::redirect('backend/auth/signin'); + } + } + + Flash::success(trans('backend::lang.account.restore_success')); + + $code = $user->getResetPasswordCode(); + $link = Backend::url('backend/auth/reset/' . $user->id . '/' . $code); + + $data = [ + 'name' => $user->full_name, + 'link' => $link, + ]; + + Mail::send('backend::mail.restore', $data, function ($message) use ($user) { + $message->to($user->email, $user->full_name)->subject(trans('backend::lang.account.password_reset')); + }); + + return Backend::redirect('backend/auth/signin'); + } + + /** + * Reset backend user password using verification code. + */ + public function reset($userId = null, $code = null) + { + try { + if (post('postback')) { + return $this->reset_onSubmit(); + } + + if (!$userId || !$code) { + throw new ApplicationException(trans('backend::lang.account.reset_error')); + } + } catch (Exception $ex) { + Flash::error($ex->getMessage()); + } + + $this->vars['code'] = $code; + $this->vars['id'] = $userId; + } + + /** + * Submits the reset form. + */ + public function reset_onSubmit() + { + if (!post('id') || !post('code')) { + throw new ApplicationException(trans('backend::lang.account.reset_error')); + } + + $rules = [ + 'password' => 'required|between:4,255' + ]; + + $validation = Validator::make(post(), $rules); + if ($validation->fails()) { + throw new ValidationException($validation); + } + + $code = post('code'); + $user = BackendAuth::findUserById(post('id')); + + if (!$user->checkResetPasswordCode($code)) { + throw new ApplicationException(trans('backend::lang.account.reset_error')); + } + + if (!$user->attemptResetPassword($code, post('password'))) { + throw new ApplicationException(trans('backend::lang.account.reset_fail')); + } + + $user->clearResetPassword(); + + Flash::success(trans('backend::lang.account.reset_success')); + + return Backend::redirect('backend/auth/signin'); + } +} diff --git a/modules/backend/controllers/Files.php b/modules/backend/controllers/Files.php new file mode 100644 index 0000000..adc5bcf --- /dev/null +++ b/modules/backend/controllers/Files.php @@ -0,0 +1,195 @@ +findFileObject($code)->output('inline', true); + } + catch (Exception $ex) { + } + + return Response::make(View::make('backend::404'), 404); + } + + /** + * Output thumbnail, or fall back on the 404 page + */ + public function thumb($code = null, $width = 100, $height = 100, $mode = 'auto', $extension = 'auto') + { + try { + return $this->findFileObject($code)->outputThumb( + $width, + $height, + compact('mode', 'extension'), + true + ); + } + catch (Exception $ex) { + } + + return Response::make(View::make('backend::404'), 404); + } + + /** + * Attempt to return a redirect to a temporary URL to the asset instead of streaming the asset - if supported + * + * @param System|Models\File $file + * @param string|null $path Optional, defaults to the getDiskPath() of the file + * @return string|null + */ + protected static function getTemporaryUrl($file, $path = null) + { + // Get the disk and adapter used + $url = null; + $disk = $file->getDisk(); + $adapter = $disk->getAdapter(); + if (class_exists('\League\Flysystem\Cached\CachedAdapter') && $adapter instanceof \League\Flysystem\Cached\CachedAdapter) { + $adapter = $adapter->getAdapter(); + } + + if ((class_exists('\League\Flysystem\AwsS3v3\AwsS3Adapter') && $adapter instanceof \League\Flysystem\AwsS3v3\AwsS3Adapter) || + (class_exists('\League\Flysystem\Rackspace\RackspaceAdapter') && $adapter instanceof \League\Flysystem\Rackspace\RackspaceAdapter) || + method_exists($adapter, 'getTemporaryUrl') + ) { + if (empty($path)) { + $path = $file->getDiskPath(); + } + + // Check to see if the URL has already been generated + $pathKey = 'backend.file:' . $path; + $url = Cache::get($pathKey); + + // The AWS S3 storage drivers will return a valid temporary URL even if the file does not exist + if (is_null($url) && $disk->exists($path)) { + $expires = now()->addSeconds(Config::get('cms.storage.uploads.temporaryUrlTTL', 3600)); + $url = Cache::remember($pathKey, $expires, function () use ($disk, $path, $expires) { + return $disk->temporaryUrl($path, $expires); + }); + } + } + + return $url; + } + + /** + * Returns the URL for downloading a system file. + * @param $file System\Models\File + * @return string + */ + public static function getDownloadUrl($file) + { + $url = static::getTemporaryUrl($file); + + if (!empty($url)) { + return $url; + } else { + return Backend::url('backend/files/get/' . self::getUniqueCode($file)); + } + } + + /** + * Returns the URL for downloading a system file. + * @param $file System\Models\File + * @param $width int + * @param $height int + * @param $options array + * @return string + */ + public static function getThumbUrl($file, $width, $height, $options) + { + $url = static::getTemporaryUrl($file, $file->getDiskPath($file->getThumbFilename($width, $height, $options))); + + if (!empty($url)) { + return $url; + } else { + return Backend::url('backend/files/thumb/' . self::getUniqueCode($file)) . '/' . $width . '/' . $height . '/' . $options['mode'] . '/' . $options['extension']; + } + } + + /** + * Returns a unique code used for masking the file identifier. + * @param $file System\Models\File + * @return string + */ + public static function getUniqueCode($file) + { + if (!$file) { + return null; + } + + $hash = md5($file->file_name . '!' . $file->disk_name); + return base64_encode($file->id . '!' . $hash); + } + + /** + * Locates a file model based on the unique code. + * @param $code string + * @return System\Models\File + */ + protected function findFileObject($code) + { + if (!$code) { + throw new ApplicationException('Missing code'); + } + + $parts = explode('!', base64_decode($code)); + if (count($parts) < 2) { + throw new ApplicationException('Invalid code'); + } + + list($id, $hash) = $parts; + + if (!$file = FileModel::find((int) $id)) { + throw new ApplicationException('Unable to find file'); + } + + /** + * Ensure that the file model utilized for this request is + * the one specified in the relationship configuration + */ + if ($file->attachment) { + $fileModel = $file->attachment->{$file->field}()->getRelated(); + + /** + * Only attempt to get file model through its assigned class + * when the assigned class differs from the default one that + * the file has already been loaded from + */ + if (get_class($file) !== get_class($fileModel)) { + $file = $fileModel->find($file->id); + } + } + + $verifyCode = self::getUniqueCode($file); + if ($code != $verifyCode) { + throw new ApplicationException('Invalid hash'); + } + + return $file; + } +} diff --git a/modules/backend/controllers/Index.php b/modules/backend/controllers/Index.php new file mode 100644 index 0000000..75a18eb --- /dev/null +++ b/modules/backend/controllers/Index.php @@ -0,0 +1,82 @@ +addCss('/modules/backend/assets/css/dashboard/dashboard.css', 'core'); + } + + public function index() + { + if ($redirect = $this->checkPermissionRedirect()) { + return $redirect; + } + + $this->initReportContainer(); + + $this->pageTitle = 'backend::lang.dashboard.menu_label'; + + BackendMenu::setContextMainMenu('dashboard'); + } + + public function index_onInitReportContainer() + { + $this->initReportContainer(); + + return ['#dashReportContainer' => $this->widget->reportContainer->render()]; + } + + /** + * Prepare the report widget used by the dashboard + * @param Model $model + * @return void + */ + protected function initReportContainer() + { + new ReportContainer($this, 'config_dashboard.yaml'); + } + + /** + * Custom permissions check that will redirect to the next + * available menu item, if permission to this page is denied. + */ + protected function checkPermissionRedirect() + { + if (!$this->user->hasAccess('backend.access_dashboard')) { + $true = function () { + return true; + }; + if ($first = array_first(BackendMenu::listMainMenuItems(), $true)) { + return Redirect::intended($first->url); + } + } + } +} diff --git a/modules/backend/controllers/Media.php b/modules/backend/controllers/Media.php new file mode 100644 index 0000000..e8c8941 --- /dev/null +++ b/modules/backend/controllers/Media.php @@ -0,0 +1,38 @@ +pageTitle = 'backend::lang.media.menu_label'; + + $manager = new MediaManager($this, 'manager'); + $manager->bindToController(); + } + + public function index() + { + $this->bodyClass = 'compact-container'; + } +} diff --git a/modules/backend/controllers/Preferences.php b/modules/backend/controllers/Preferences.php new file mode 100644 index 0000000..1a9e258 --- /dev/null +++ b/modules/backend/controllers/Preferences.php @@ -0,0 +1,84 @@ +addCss('/modules/backend/formwidgets/codeeditor/assets/css/codeeditor.css', 'core'); + $this->addJs('/modules/backend/formwidgets/codeeditor/assets/js/build-min.js', 'core'); + $this->addJs('/modules/backend/assets/js/preferences/preferences.js', 'core'); + + BackendMenu::setContext('October.System', 'system', 'mysettings'); + SettingsManager::setContext('October.Backend', 'preferences'); + } + + public function index() + { + $this->pageTitle = 'backend::lang.backend_preferences.menu_label'; + $this->asExtension('FormController')->update(); + } + + /** + * Remove the code editor tab if there is no permission. + */ + public function formExtendFields($form) + { + if (!$this->user->hasAccess('backend.manage_own_editor')) { + $form->removeTab('backend::lang.backend_preferences.code_editor'); + } + } + + public function index_onSave() + { + return $this->asExtension('FormController')->update_onSave(); + } + + public function index_onResetDefault() + { + $model = $this->formFindModelObject(); + $model->resetDefault(); + + Flash::success(Lang::get('backend::lang.form.reset_success')); + + return Backend::redirect('backend/preferences'); + } + + public function formFindModelObject() + { + return PreferenceModel::instance(); + } +} diff --git a/modules/backend/controllers/UserGroups.php b/modules/backend/controllers/UserGroups.php new file mode 100644 index 0000000..ed5e4d3 --- /dev/null +++ b/modules/backend/controllers/UserGroups.php @@ -0,0 +1,49 @@ +bindEvent('page.beforeDisplay', function () { + if (!$this->user->isSuperUser()) { + return Response::make(View::make('backend::access_denied'), 403); + } + }); + } + + /** + * Add available permission fields to the Role form. + */ + public function formExtendFields($form) + { + /* + * Add permissions tab + */ + $form->addTabFields($this->generatePermissionsField()); + } + + /** + * Adds the permissions editor widget to the form. + * @return array + */ + protected function generatePermissionsField() + { + return [ + 'permissions' => [ + 'tab' => 'backend::lang.user.permissions', + 'type' => 'Backend\FormWidgets\PermissionEditor', + 'mode' => 'checkbox' + ] + ]; + } +} diff --git a/modules/backend/controllers/Users.php b/modules/backend/controllers/Users.php new file mode 100644 index 0000000..3aa4f7e --- /dev/null +++ b/modules/backend/controllers/Users.php @@ -0,0 +1,246 @@ +action == 'myaccount') { + $this->requiredPermissions = null; + } + + BackendMenu::setContext('October.System', 'system', 'users'); + SettingsManager::setContext('October.System', 'administrators'); + } + + /** + * Extends the list query to hide superusers if the current user is not a superuser themselves + */ + public function listExtendQuery($query) + { + if (!$this->user->isSuperUser()) { + $query->where('is_superuser', false); + } + } + + /** + * Prevents non-superusers from even seeing the is_superuser filter + */ + public function listFilterExtendScopes($filterWidget) + { + if (!$this->user->isSuperUser()) { + $filterWidget->removeScope('is_superuser'); + } + } + + /** + * Strike out deleted records + */ + public function listInjectRowClass($record, $definition = null) + { + if ($record->trashed()) { + return 'strike'; + } + } + + /** + * Extends the form query to prevent non-superusers from accessing superusers at all + */ + public function formExtendQuery($query) + { + if (!$this->user->isSuperUser()) { + $query->where('is_superuser', false); + } + + // Ensure soft-deleted records can still be managed + $query->withTrashed(); + } + + /** + * Update controller + */ + public function update($recordId, $context = null) + { + // Users cannot edit themselves, only use My Settings + if ($context != 'myaccount' && $recordId == $this->user->id) { + return Backend::redirect('backend/users/myaccount'); + } + + return $this->asExtension('FormController')->update($recordId, $context); + } + + /** + * Handle restoring users + */ + public function update_onRestore($recordId) + { + $this->formFindModelObject($recordId)->restore(); + + Flash::success(Lang::get('backend::lang.form.restore_success', ['name' => Lang::get('backend::lang.user.name')])); + + return Redirect::refresh(); + } + + /** + * Impersonate this user + */ + public function update_onImpersonateUser($recordId) + { + if (!$this->user->hasAccess('backend.impersonate_users')) { + return Response::make(Lang::get('backend::lang.page.access_denied.label'), 403); + } + + $model = $this->formFindModelObject($recordId); + + BackendAuth::impersonate($model); + + Flash::success(Lang::get('backend::lang.account.impersonate_success')); + + return Backend::redirect('backend/users/myaccount'); + } + + /** + * Unsuspend this user + */ + public function update_onUnsuspendUser($recordId) + { + $model = $this->formFindModelObject($recordId); + + $model->unsuspend(); + + Flash::success(Lang::get('backend::lang.account.unsuspend_success')); + + return Redirect::refresh(); + } + + /** + * My Settings controller + */ + public function myaccount() + { + SettingsManager::setContext('October.Backend', 'myaccount'); + + $this->pageTitle = 'backend::lang.myaccount.menu_label'; + return $this->update($this->user->id, 'myaccount'); + } + + /** + * Proxy update onSave event + */ + public function myaccount_onSave() + { + $result = $this->asExtension('FormController')->update_onSave($this->user->id, 'myaccount'); + + /* + * If the password or login name has been updated, reauthenticate the user + */ + $loginChanged = $this->user->login != post('User[login]'); + $passwordChanged = strlen(post('User[password]')); + if ($loginChanged || $passwordChanged) { + BackendAuth::login($this->user->reload(), true); + } + + return $result; + } + + /** + * Add available permission fields to the User form. + * Mark default groups as checked for new Users. + */ + public function formExtendFields($form) + { + if ($form->getContext() == 'myaccount') { + return; + } + + if (!$this->user->isSuperUser()) { + $form->removeField('is_superuser'); + } + + /* + * Add permissions tab + */ + $form->addTabFields($this->generatePermissionsField()); + + /* + * Mark default groups + */ + if (!$form->model->exists) { + $defaultGroupIds = UserGroup::where('is_new_user_default', true)->lists('id'); + + $groupField = $form->getField('groups'); + if ($groupField) { + $groupField->value = $defaultGroupIds; + } + } + } + + /** + * Adds the permissions editor widget to the form. + * @return array + */ + protected function generatePermissionsField() + { + return [ + 'permissions' => [ + 'tab' => 'backend::lang.user.permissions', + 'type' => 'Backend\FormWidgets\PermissionEditor', + 'trigger' => [ + 'action' => 'disable', + 'field' => 'is_superuser', + 'condition' => 'checked' + ] + ] + ]; + } +} diff --git a/modules/backend/controllers/accesslogs/_hint.htm b/modules/backend/controllers/accesslogs/_hint.htm new file mode 100644 index 0000000..66c293f --- /dev/null +++ b/modules/backend/controllers/accesslogs/_hint.htm @@ -0,0 +1,4 @@ + +

    + 60])) ?> +

    \ No newline at end of file diff --git a/modules/backend/controllers/accesslogs/_list_toolbar.htm b/modules/backend/controllers/accesslogs/_list_toolbar.htm new file mode 100644 index 0000000..5f9c780 --- /dev/null +++ b/modules/backend/controllers/accesslogs/_list_toolbar.htm @@ -0,0 +1,9 @@ + diff --git a/modules/backend/controllers/accesslogs/config_filter.yaml b/modules/backend/controllers/accesslogs/config_filter.yaml new file mode 100644 index 0000000..2e35941 --- /dev/null +++ b/modules/backend/controllers/accesslogs/config_filter.yaml @@ -0,0 +1,16 @@ +# =================================== +# Filter Scope Definitions +# =================================== + +scopes: + + created_at: + label: backend::lang.access_log.created_at + type: daterange + conditions: created_at >= ':after' AND created_at <= ':before' + + user: + label: backend::lang.access_log.login + modelClass: Backend\Models\User + conditions: user_id in (:filtered) + nameFrom: login diff --git a/modules/backend/controllers/accesslogs/config_list.yaml b/modules/backend/controllers/accesslogs/config_list.yaml new file mode 100644 index 0000000..c146ba8 --- /dev/null +++ b/modules/backend/controllers/accesslogs/config_list.yaml @@ -0,0 +1,17 @@ +# =================================== +# List Behavior Config +# =================================== + +title: backend::lang.access_log.menu_label +list: ~/modules/backend/models/accesslog/columns.yaml +modelClass: Backend\Models\AccessLog +noRecordsMessage: backend::lang.list.no_records +recordsPerPage: 30 +showSetup: true + +toolbar: + buttons: list_toolbar + search: + prompt: backend::lang.list.search_prompt + +filter: config_filter.yaml diff --git a/modules/backend/controllers/accesslogs/index.htm b/modules/backend/controllers/accesslogs/index.htm new file mode 100644 index 0000000..7dab755 --- /dev/null +++ b/modules/backend/controllers/accesslogs/index.htm @@ -0,0 +1,5 @@ +
    + makeHintPartial('backend_accesslogs_hint', 'hint') ?> +
    + +listRender() ?> \ No newline at end of file diff --git a/modules/backend/controllers/auth/reset.htm b/modules/backend/controllers/auth/reset.htm new file mode 100644 index 0000000..6761a36 --- /dev/null +++ b/modules/backend/controllers/auth/reset.htm @@ -0,0 +1,33 @@ +

    + + + + + + +
    +
    + + + + + + +
    + +

    + + + +

    +
    + diff --git a/modules/backend/controllers/auth/restore.htm b/modules/backend/controllers/auth/restore.htm new file mode 100644 index 0000000..6007ae4 --- /dev/null +++ b/modules/backend/controllers/auth/restore.htm @@ -0,0 +1,31 @@ +

    + + + + +
    +
    + + + + +
    + +

    + + + +

    +
    + + +fireViewEvent('backend.auth.extendRestoreView') ?> diff --git a/modules/backend/controllers/auth/signin.htm b/modules/backend/controllers/auth/signin.htm new file mode 100644 index 0000000..7e186d3 --- /dev/null +++ b/modules/backend/controllers/auth/signin.htm @@ -0,0 +1,60 @@ +

    + + + + +
    +
    + + + + + + + + + +
    + + + +
    +
    + + +
    +
    + + +

    + + + + +

    + +
    + + +fireViewEvent('backend.auth.extendSigninView') ?> diff --git a/modules/backend/controllers/index/config_dashboard.yaml b/modules/backend/controllers/index/config_dashboard.yaml new file mode 100644 index 0000000..de3a20e --- /dev/null +++ b/modules/backend/controllers/index/config_dashboard.yaml @@ -0,0 +1,23 @@ +# =================================== +# Dashboard Config +# =================================== + +defaultWidgets: + + welcome: + class: Backend\ReportWidgets\Welcome + sortOrder: 50 + configuration: + ocWidgetWidth: 7 + + systemStatus: + class: System\ReportWidgets\Status + sortOrder: 60 + configuration: + ocWidgetWidth: 7 + + activeTheme: + class: Cms\ReportWidgets\ActiveTheme + sortOrder: 70 + configuration: + ocWidgetWidth: 5 diff --git a/modules/backend/controllers/index/index.htm b/modules/backend/controllers/index/index.htm new file mode 100644 index 0000000..423cc7c --- /dev/null +++ b/modules/backend/controllers/index/index.htm @@ -0,0 +1,21 @@ +'layout-relative dashboard-container']) ?> +
    + + +
    +
    + +
    +
    +
    + +
    + + + diff --git a/modules/backend/controllers/media/index.htm b/modules/backend/controllers/media/index.htm new file mode 100644 index 0000000..7ff071e --- /dev/null +++ b/modules/backend/controllers/media/index.htm @@ -0,0 +1,5 @@ + + 'layout', 'onsubmit'=>'return false']) ?> + widget->manager->render() ?> + + diff --git a/modules/backend/controllers/preferences/_example_code.htm b/modules/backend/controllers/preferences/_example_code.htm new file mode 100644 index 0000000..0f95acc --- /dev/null +++ b/modules/backend/controllers/preferences/_example_code.htm @@ -0,0 +1,13 @@ +form, fieldset, h5, h6, pre, blockquote, ol, dl, dt, dd, address, dd, dtm, div, td, th, hr { + margin: 0; + padding: 0; +} + +body { + background-color: white; + font: 62.5% Helvetica, Arial, Tahoma, Verdana, Helvetica, sans-serif; +} + +p { + font-size: 12px; +} diff --git a/modules/backend/controllers/preferences/_field_editor_preview.htm b/modules/backend/controllers/preferences/_field_editor_preview.htm new file mode 100644 index 0000000..f052ea7 --- /dev/null +++ b/modules/backend/controllers/preferences/_field_editor_preview.htm @@ -0,0 +1,22 @@ +
    + +
    diff --git a/modules/backend/controllers/preferences/config_form.yaml b/modules/backend/controllers/preferences/config_form.yaml new file mode 100644 index 0000000..c9647ef --- /dev/null +++ b/modules/backend/controllers/preferences/config_form.yaml @@ -0,0 +1,8 @@ +# =================================== +# Form Behavior Config +# =================================== + +name: backend::lang.backend_preferences.menu_label +form: ~/modules/backend/models/preference/fields.yaml +modelClass: Backend\Models\Preference +defaultRedirect: system/settings diff --git a/modules/backend/controllers/preferences/index.htm b/modules/backend/controllers/preferences/index.htm new file mode 100644 index 0000000..1266aba --- /dev/null +++ b/modules/backend/controllers/preferences/index.htm @@ -0,0 +1,41 @@ +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + + + + + +
    +
    + + + +

    fatalError)) ?>

    +

    + \ No newline at end of file diff --git a/modules/backend/controllers/usergroups/_list_toolbar.htm b/modules/backend/controllers/usergroups/_list_toolbar.htm new file mode 100644 index 0000000..b1d2b38 --- /dev/null +++ b/modules/backend/controllers/usergroups/_list_toolbar.htm @@ -0,0 +1,8 @@ + diff --git a/modules/backend/controllers/usergroups/config_form.yaml b/modules/backend/controllers/usergroups/config_form.yaml new file mode 100644 index 0000000..9d20458 --- /dev/null +++ b/modules/backend/controllers/usergroups/config_form.yaml @@ -0,0 +1,16 @@ +# =================================== +# Form Behavior Config +# =================================== + +name: backend::lang.user.group.name +form: ~/modules/backend/models/usergroup/fields.yaml +modelClass: Backend\Models\UserGroup +defaultRedirect: backend/usergroups + +create: + redirect: backend/usergroups/update/:id + redirectClose: backend/usergroups + +update: + redirect: backend/usergroups + redirectClose: backend/usergroups diff --git a/modules/backend/controllers/usergroups/config_list.yaml b/modules/backend/controllers/usergroups/config_list.yaml new file mode 100644 index 0000000..e88b417 --- /dev/null +++ b/modules/backend/controllers/usergroups/config_list.yaml @@ -0,0 +1,16 @@ +# =================================== +# List Behavior Config +# =================================== + +title: backend::lang.user.group.list_title +list: ~/modules/backend/models/usergroup/columns.yaml +modelClass: Backend\Models\UserGroup +recordUrl: backend/usergroups/update/:id +noRecordsMessage: backend::lang.list.no_records +recordsPerPage: 25 +showSetup: true + +toolbar: + buttons: list_toolbar + search: + prompt: backend::lang.list.search_prompt diff --git a/modules/backend/controllers/usergroups/create.htm b/modules/backend/controllers/usergroups/create.htm new file mode 100644 index 0000000..3401241 --- /dev/null +++ b/modules/backend/controllers/usergroups/create.htm @@ -0,0 +1,46 @@ + +
      +
    • +
    • +
    • pageTitle)) ?>
    • +
    + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + +
    +
    + + + + +

    fatalError)) ?>

    +

    + diff --git a/modules/backend/controllers/usergroups/index.htm b/modules/backend/controllers/usergroups/index.htm new file mode 100644 index 0000000..ee75b85 --- /dev/null +++ b/modules/backend/controllers/usergroups/index.htm @@ -0,0 +1,8 @@ + +
      +
    • +
    • pageTitle)) ?>
    • +
    + + +listRender() ?> diff --git a/modules/backend/controllers/usergroups/update.htm b/modules/backend/controllers/usergroups/update.htm new file mode 100644 index 0000000..9efd8e6 --- /dev/null +++ b/modules/backend/controllers/usergroups/update.htm @@ -0,0 +1,54 @@ + +
      +
    • +
    • +
    • pageTitle)) ?>
    • +
    + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + +
    +
    + + + + +

    fatalError)) ?>

    +

    + diff --git a/modules/backend/controllers/userroles/_list_toolbar.htm b/modules/backend/controllers/userroles/_list_toolbar.htm new file mode 100644 index 0000000..29e5762 --- /dev/null +++ b/modules/backend/controllers/userroles/_list_toolbar.htm @@ -0,0 +1,8 @@ + diff --git a/modules/backend/controllers/userroles/config_form.yaml b/modules/backend/controllers/userroles/config_form.yaml new file mode 100644 index 0000000..68b4063 --- /dev/null +++ b/modules/backend/controllers/userroles/config_form.yaml @@ -0,0 +1,16 @@ +# =================================== +# Form Behavior Config +# =================================== + +name: backend::lang.user.role.name +form: ~/modules/backend/models/userrole/fields.yaml +modelClass: Backend\Models\UserRole +defaultRedirect: backend/userroles + +create: + redirect: backend/userroles/update/:id + redirectClose: backend/userroles + +update: + redirect: backend/userroles + redirectClose: backend/userroles diff --git a/modules/backend/controllers/userroles/config_list.yaml b/modules/backend/controllers/userroles/config_list.yaml new file mode 100644 index 0000000..520fb6e --- /dev/null +++ b/modules/backend/controllers/userroles/config_list.yaml @@ -0,0 +1,16 @@ +# =================================== +# List Behavior Config +# =================================== + +title: backend::lang.user.role.list_title +list: ~/modules/backend/models/userrole/columns.yaml +modelClass: Backend\Models\UserRole +recordUrl: backend/userroles/update/:id +noRecordsMessage: backend::lang.list.no_records +recordsPerPage: 25 +showSetup: true + +toolbar: + buttons: list_toolbar + search: + prompt: backend::lang.list.search_prompt diff --git a/modules/backend/controllers/userroles/create.htm b/modules/backend/controllers/userroles/create.htm new file mode 100644 index 0000000..0ba5e30 --- /dev/null +++ b/modules/backend/controllers/userroles/create.htm @@ -0,0 +1,46 @@ + +
      +
    • +
    • +
    • pageTitle)) ?>
    • +
    + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + +
    +
    + + + + +

    fatalError)) ?>

    +

    + diff --git a/modules/backend/controllers/userroles/index.htm b/modules/backend/controllers/userroles/index.htm new file mode 100644 index 0000000..ee75b85 --- /dev/null +++ b/modules/backend/controllers/userroles/index.htm @@ -0,0 +1,8 @@ + +
      +
    • +
    • pageTitle)) ?>
    • +
    + + +listRender() ?> diff --git a/modules/backend/controllers/userroles/update.htm b/modules/backend/controllers/userroles/update.htm new file mode 100644 index 0000000..6b19f3d --- /dev/null +++ b/modules/backend/controllers/userroles/update.htm @@ -0,0 +1,54 @@ + +
      +
    • +
    • +
    • pageTitle)) ?>
    • +
    + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + +
    +
    + + + + +

    fatalError)) ?>

    +

    + diff --git a/modules/backend/controllers/users/_btn_impersonate.htm b/modules/backend/controllers/users/_btn_impersonate.htm new file mode 100644 index 0000000..823af53 --- /dev/null +++ b/modules/backend/controllers/users/_btn_impersonate.htm @@ -0,0 +1,14 @@ +user->hasAccess('backend.impersonate_users')): ?> +
    + +
    + \ No newline at end of file diff --git a/modules/backend/controllers/users/_btn_unsuspend.htm b/modules/backend/controllers/users/_btn_unsuspend.htm new file mode 100644 index 0000000..dcae86c --- /dev/null +++ b/modules/backend/controllers/users/_btn_unsuspend.htm @@ -0,0 +1,14 @@ +isSuspended()): ?> +
    + +
    + diff --git a/modules/backend/controllers/users/_hint_trashed.htm b/modules/backend/controllers/users/_hint_trashed.htm new file mode 100644 index 0000000..7c15ebd --- /dev/null +++ b/modules/backend/controllers/users/_hint_trashed.htm @@ -0,0 +1,9 @@ +
    +
    +
    + +

    +

    +
    +
    +
    \ No newline at end of file diff --git a/modules/backend/controllers/users/_list_toolbar.htm b/modules/backend/controllers/users/_list_toolbar.htm new file mode 100644 index 0000000..092dcd1 --- /dev/null +++ b/modules/backend/controllers/users/_list_toolbar.htm @@ -0,0 +1,29 @@ +
    + + + + user->isSuperUser()): ?> + + + + + + + + + + +
    + */ ?> +
    diff --git a/modules/backend/controllers/users/config_filter.yaml b/modules/backend/controllers/users/config_filter.yaml new file mode 100644 index 0000000..08ebb3f --- /dev/null +++ b/modules/backend/controllers/users/config_filter.yaml @@ -0,0 +1,30 @@ +# =================================== +# Filter Scope Definitions +# =================================== + +scopes: + + is_superuser: + label: backend::lang.user.superuser + type: switch + conditions: + - is_superuser = false + - is_superuser = true + + login_date: + label: backend::lang.user.last_login + type: daterange + conditions: last_login >= ':after' AND last_login <= ':before' + + role_id: + label: backend::lang.user.role.name + modelClass: Backend\Models\UserRole + conditions: role_id in (:filtered) + nameFrom: name + + show_deleted: + label: backend::lang.user.show_deleted + type: checkbox + modelClass: Backend\Models\User + scope: withTrashed + default: 0 diff --git a/modules/backend/controllers/users/config_form.yaml b/modules/backend/controllers/users/config_form.yaml new file mode 100644 index 0000000..cb83a00 --- /dev/null +++ b/modules/backend/controllers/users/config_form.yaml @@ -0,0 +1,16 @@ +# =================================== +# Form Behavior Config +# =================================== + +name: backend::lang.user.name +form: ~/modules/backend/models/user/fields.yaml +modelClass: Backend\Models\User +defaultRedirect: backend/users + +create: + redirect: backend/users/update/:id + redirectClose: backend/users + +update: + redirect: backend/users + redirectClose: backend/users diff --git a/modules/backend/controllers/users/config_list.yaml b/modules/backend/controllers/users/config_list.yaml new file mode 100644 index 0000000..5dcd9ee --- /dev/null +++ b/modules/backend/controllers/users/config_list.yaml @@ -0,0 +1,19 @@ +# =================================== +# List Behavior Config +# =================================== + +title: backend::lang.user.list_title +list: ~/modules/backend/models/user/columns.yaml +modelClass: Backend\Models\User +recordUrl: backend/users/update/:id +noRecordsMessage: backend::lang.list.no_records +recordsPerPage: 20 +showSetup: true +# showCheckboxes: true + +toolbar: + buttons: list_toolbar + search: + prompt: backend::lang.list.search_prompt + +filter: config_filter.yaml diff --git a/modules/backend/controllers/users/create.htm b/modules/backend/controllers/users/create.htm new file mode 100644 index 0000000..3197f49 --- /dev/null +++ b/modules/backend/controllers/users/create.htm @@ -0,0 +1,66 @@ + +
      +
    • +
    • pageTitle)) ?>
    • +
    + + +fatalError): ?> + + +
    + +
    + formRenderOutsideFields() ?> + formRenderPrimaryTabs() ?> +
    + +
    +
    + + + + + +
    +
    + +
    + + + +
    formRenderSecondaryTabs() ?>
    + + + + 'layout stretch']) ?> + makeLayout('form-with-sidebar') ?> + + + + +
    + +
    +
    +

    fatalError)) ?>

    +

    +
    + \ No newline at end of file diff --git a/modules/backend/controllers/users/index.htm b/modules/backend/controllers/users/index.htm new file mode 100644 index 0000000..498d5dc --- /dev/null +++ b/modules/backend/controllers/users/index.htm @@ -0,0 +1 @@ +listRender() ?> \ No newline at end of file diff --git a/modules/backend/controllers/users/myaccount.htm b/modules/backend/controllers/users/myaccount.htm new file mode 100644 index 0000000..ff70c54 --- /dev/null +++ b/modules/backend/controllers/users/myaccount.htm @@ -0,0 +1,68 @@ +user->hasAccess('backend.manage_users')): ?> + +
      +
    • +
    • pageTitle)) ?>
    • +
    + + + +fatalError): ?> + + +
    + +
    + formRenderOutsideFields() ?> + formRenderPrimaryTabs() ?> +
    + +
    +
    + + user->hasAccess('backend.manage_users')): ?> + + +
    +
    + +
    + + + +
    formRenderSecondaryTabs() ?>
    + + + + 'layout stretch']) ?> + makeLayout('form-with-sidebar') ?> + + + + +
    + +
    +
    +

    fatalError)) ?>

    +

    +
    + \ No newline at end of file diff --git a/modules/backend/controllers/users/update.htm b/modules/backend/controllers/users/update.htm new file mode 100644 index 0000000..e299fde --- /dev/null +++ b/modules/backend/controllers/users/update.htm @@ -0,0 +1,88 @@ + +
      +
    • +
    • pageTitle)) ?>
    • +
    + + +fatalError): ?> + + + trashed()): ?> + makePartial('hint_trashed') ?> + + +
    + +
    + formRenderOutsideFields() ?> + formRenderPrimaryTabs() ?> +
    + +
    +
    + + + + + + trashed()) : ?> + + + + +
    +
    + +
    + + + +
    formRenderSecondaryTabs() ?>
    + + + + 'layout stretch']) ?> + makeLayout('form-with-sidebar') ?> + + + + +
    + +
    +
    +

    fatalError)) ?>

    +

    +
    + \ No newline at end of file diff --git a/modules/backend/database/migrations/2013_10_01_000001_Db_Backend_Users.php b/modules/backend/database/migrations/2013_10_01_000001_Db_Backend_Users.php new file mode 100644 index 0000000..f01fb85 --- /dev/null +++ b/modules/backend/database/migrations/2013_10_01_000001_Db_Backend_Users.php @@ -0,0 +1,35 @@ +engine = 'InnoDB'; + $table->increments('id'); + $table->string('first_name')->nullable(); + $table->string('last_name')->nullable(); + $table->string('login')->unique('login_unique')->index('login_index'); + $table->string('email')->unique('email_unique'); + $table->string('password'); + $table->string('activation_code')->nullable()->index('act_code_index'); + $table->string('persist_code')->nullable(); + $table->string('reset_password_code')->nullable()->index('reset_code_index'); + $table->text('permissions')->nullable(); + $table->boolean('is_activated')->default(0); + $table->integer('role_id')->unsigned()->nullable()->index('admin_role_index'); + $table->timestamp('activated_at')->nullable(); + $table->timestamp('last_login')->nullable(); + $table->timestamps(); + $table->timestamp('deleted_at')->nullable(); + }); + } + + public function down() + { + Schema::dropIfExists('backend_users'); + } +} diff --git a/modules/backend/database/migrations/2013_10_01_000002_Db_Backend_User_Groups.php b/modules/backend/database/migrations/2013_10_01_000002_Db_Backend_User_Groups.php new file mode 100644 index 0000000..599707c --- /dev/null +++ b/modules/backend/database/migrations/2013_10_01_000002_Db_Backend_User_Groups.php @@ -0,0 +1,22 @@ +engine = 'InnoDB'; + $table->increments('id'); + $table->string('name')->unique('name_unique'); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('backend_user_groups'); + } +} diff --git a/modules/backend/database/migrations/2013_10_01_000003_Db_Backend_Users_Groups.php b/modules/backend/database/migrations/2013_10_01_000003_Db_Backend_Users_Groups.php new file mode 100644 index 0000000..7d05e6b --- /dev/null +++ b/modules/backend/database/migrations/2013_10_01_000003_Db_Backend_Users_Groups.php @@ -0,0 +1,22 @@ +engine = 'InnoDB'; + $table->integer('user_id')->unsigned(); + $table->integer('user_group_id')->unsigned(); + $table->primary(['user_id', 'user_group_id'], 'user_group'); + }); + } + + public function down() + { + Schema::dropIfExists('backend_users_groups'); + } +} diff --git a/modules/backend/database/migrations/2013_10_01_000004_Db_Backend_User_Throttle.php b/modules/backend/database/migrations/2013_10_01_000004_Db_Backend_User_Throttle.php new file mode 100644 index 0000000..866b3cc --- /dev/null +++ b/modules/backend/database/migrations/2013_10_01_000004_Db_Backend_User_Throttle.php @@ -0,0 +1,28 @@ +engine = 'InnoDB'; + $table->increments('id'); + $table->integer('user_id')->unsigned()->nullable()->index(); + $table->string('ip_address')->nullable()->index(); + $table->integer('attempts')->default(0); + $table->timestamp('last_attempt_at')->nullable(); + $table->boolean('is_suspended')->default(0); + $table->timestamp('suspended_at')->nullable(); + $table->boolean('is_banned')->default(0); + $table->timestamp('banned_at')->nullable(); + }); + } + + public function down() + { + Schema::dropIfExists('backend_user_throttle'); + } +} diff --git a/modules/backend/database/migrations/2014_01_04_000005_Db_Backend_User_Preferences.php b/modules/backend/database/migrations/2014_01_04_000005_Db_Backend_User_Preferences.php new file mode 100644 index 0000000..513669d --- /dev/null +++ b/modules/backend/database/migrations/2014_01_04_000005_Db_Backend_User_Preferences.php @@ -0,0 +1,26 @@ +engine = 'InnoDB'; + $table->increments('id'); + $table->integer('user_id')->unsigned(); + $table->string('namespace', 100); + $table->string('group', 50); + $table->string('item', 150); + $table->text('value')->nullable(); + $table->index(['user_id', 'namespace', 'group', 'item'], 'user_item_index'); + }); + } + + public function down() + { + Schema::dropIfExists('backend_user_preferences'); + } +} diff --git a/modules/backend/database/migrations/2014_10_01_000006_Db_Backend_Access_Log.php b/modules/backend/database/migrations/2014_10_01_000006_Db_Backend_Access_Log.php new file mode 100644 index 0000000..1e2cb78 --- /dev/null +++ b/modules/backend/database/migrations/2014_10_01_000006_Db_Backend_Access_Log.php @@ -0,0 +1,23 @@ +engine = 'InnoDB'; + $table->increments('id'); + $table->integer('user_id')->unsigned(); + $table->string('ip_address')->nullable(); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('backend_access_log'); + } +} diff --git a/modules/backend/database/migrations/2014_10_01_000007_Db_Backend_Add_Description_Field.php b/modules/backend/database/migrations/2014_10_01_000007_Db_Backend_Add_Description_Field.php new file mode 100644 index 0000000..273ce70 --- /dev/null +++ b/modules/backend/database/migrations/2014_10_01_000007_Db_Backend_Add_Description_Field.php @@ -0,0 +1,25 @@ +string('code')->nullable()->index('code_index'); + $table->text('description')->nullable(); + $table->boolean('is_new_user_default')->default(false); + }); + } + + public function down() + { + // Schema::table('backend_user_groups', function (Blueprint $table) { + // $table->dropColumn('code'); + // $table->dropColumn('description'); + // $table->dropColumn('is_new_user_default'); + // }); + } +} diff --git a/modules/backend/database/migrations/2015_10_01_000008_Db_Backend_Add_Superuser_Flag.php b/modules/backend/database/migrations/2015_10_01_000008_Db_Backend_Add_Superuser_Flag.php new file mode 100644 index 0000000..2bc388b --- /dev/null +++ b/modules/backend/database/migrations/2015_10_01_000008_Db_Backend_Add_Superuser_Flag.php @@ -0,0 +1,29 @@ +boolean('is_superuser')->default(false); + }); + + AdminModel::all()->each(function ($user) { + if ($user->hasPermission('superuser')) { + $user->is_superuser = true; + $user->save(); + } + }); + } + + public function down() + { + // Schema::table('backend_users', function (Blueprint $table) { + // $table->dropColumn('is_superuser'); + // }); + } +} diff --git a/modules/backend/database/migrations/2016_10_01_000009_Db_Backend_Timestamp_Fix.php b/modules/backend/database/migrations/2016_10_01_000009_Db_Backend_Timestamp_Fix.php new file mode 100644 index 0000000..83d55d9 --- /dev/null +++ b/modules/backend/database/migrations/2016_10_01_000009_Db_Backend_Timestamp_Fix.php @@ -0,0 +1,45 @@ +backendTables as $table) { + DbDongle::convertTimestamps($table); + } + + // Use this opportunity to reset backend preferences and styles for stable + Db::table('system_settings') + ->where('item', 'backend_brand_settings') + ->delete() + ; + + Db::table('backend_user_preferences') + ->where('namespace', 'backend') + ->where('group', 'backend') + ->where('item', 'preferences') + ->delete() + ; + } + + public function down() + { + // ... + } +} diff --git a/modules/backend/database/migrations/2017_10_01_000010_Db_Backend_User_Roles.php b/modules/backend/database/migrations/2017_10_01_000010_Db_Backend_User_Roles.php new file mode 100644 index 0000000..5fad314 --- /dev/null +++ b/modules/backend/database/migrations/2017_10_01_000010_Db_Backend_User_Roles.php @@ -0,0 +1,165 @@ +engine = 'InnoDB'; + $table->increments('id'); + $table->string('name')->unique('role_unique'); + $table->string('code')->nullable()->index('role_code_index'); + $table->text('description')->nullable(); + $table->text('permissions')->nullable(); + $table->boolean('is_system')->default(0); + $table->timestamps(); + }); + + // This detects older builds and performs a migration to include + // the new role system. This column will exist for new installs + // so this heavy migration process does not need to execute. + $this->migratePreviousBuild(); + } + + public function down() + { + Schema::dropIfExists('backend_user_roles'); + } + + protected function migratePreviousBuild() + { + // Role not found in the users table, perform a complete migration. + // Merging group permissions with the user and assigning the user + // with the first available role. + if (!Schema::hasColumn('backend_users', 'role_id')) { + Schema::table('backend_users', function (Blueprint $table) { + $table->integer('role_id')->unsigned()->nullable()->index('admin_role_index'); + }); + + $this->createSystemUserRoles(); + $this->migratePermissionsFromGroupsToRoles(); + } + + // Drop permissions column on groups table as it is no longer needed. + if (Schema::hasColumn('backend_user_groups', 'permissions')) { + Schema::table('backend_user_groups', function (Blueprint $table) { + $table->dropColumn('permissions'); + }); + } + } + + protected function createSystemUserRoles() + { + Db::table('backend_user_roles')->insert([ + 'name' => 'Publisher', + 'code' => UserRole::CODE_PUBLISHER, + 'description' => 'Site editor with access to publishing tools.', + ]); + + Db::table('backend_user_roles')->insert([ + 'name' => 'Developer', + 'code' => UserRole::CODE_DEVELOPER, + 'description' => 'Site administrator with access to developer tools.', + ]); + } + + protected function migratePermissionsFromGroupsToRoles() + { + $groups = Db::table('backend_user_groups')->get(); + $roles = []; + $permissions = []; + + /* + * Carbon copy groups to roles + */ + foreach ($groups as $group) { + if (!isset($group->name) || !$group->name) { + continue; + } + + try { + $roles[$group->id] = Db::table('backend_user_roles')->insertGetId([ + 'name' => $group->name, + 'description' => $group->description, + 'permissions' => $group->permissions ?? null + ]); + } + catch (Exception $ex) { + } + + $permissions[$group->id] = $group->permissions ?? null; + } + + /* + * Assign a user with the first available role + */ + $found = []; + $joins = Db::table('backend_users_groups')->get(); + + foreach ($joins as $join) { + if (!$roleId = array_get($roles, $join->user_group_id)) { + continue; + } + + $userId = $join->user_id; + + if (!isset($found[$userId])) { + Db::table('backend_users')->where('id', $userId)->update([ + 'role_id' => $roleId + ]); + } + + $found[$userId][] = $join->user_group_id; + } + + /* + * Merge group permissions in to user + */ + foreach ($found as $userId => $groups) { + $userPerms = []; + + foreach ($groups as $groupId) { + if (!$permString = array_get($permissions, $groupId)) { + continue; + } + + try { + $perms = json_decode($permString, true); + $userPerms = array_merge($userPerms, $perms); + } + catch (Exception $ex) { + } + } + + if (count($userPerms) > 0) { + $this->splicePermissionsForUser($userId, $userPerms); + } + } + } + + protected function splicePermissionsForUser($userId, $permissions) + { + /* + * Look up user and splice the provided permissions in + */ + $user = Db::table('backend_users')->where('id', $userId)->first(); + if (!$user) { + return; + } + + try { + $currentPerms = $user->permissions ? json_decode($user->permissions, true) : []; + $newPerms = array_merge($permissions, $currentPerms); + + Db::table('backend_users')->where('id', $userId)->update([ + 'permissions' => json_encode($newPerms) + ]); + } + catch (Exception $ex) { + } + } +} diff --git a/modules/backend/database/migrations/2018_12_16_000011_Db_Backend_Add_Deleted_At.php b/modules/backend/database/migrations/2018_12_16_000011_Db_Backend_Add_Deleted_At.php new file mode 100644 index 0000000..6266f64 --- /dev/null +++ b/modules/backend/database/migrations/2018_12_16_000011_Db_Backend_Add_Deleted_At.php @@ -0,0 +1,25 @@ +timestamp('deleted_at')->nullable()->after('updated_at'); + }); + } + } + + public function down() + { + if (Schema::hasColumn('backend_users', 'deleted_at')) { + Schema::table('backend_users', function (Blueprint $table) { + $table->dropColumn('deleted_at'); + }); + } + } +} diff --git a/modules/backend/database/seeds/DatabaseSeeder.php b/modules/backend/database/seeds/DatabaseSeeder.php new file mode 100644 index 0000000..f05589c --- /dev/null +++ b/modules/backend/database/seeds/DatabaseSeeder.php @@ -0,0 +1,32 @@ +setDefaults([ + 'password' => $adminPassword + ]); + $this->call($adminSeeder); + }); + + return $shouldRandomizePassword ? 'The following password has been automatically generated for the "admin" account: ' + . "${adminPassword}" : ''; + } +} diff --git a/modules/backend/database/seeds/SeedSetupAdmin.php b/modules/backend/database/seeds/SeedSetupAdmin.php new file mode 100644 index 0000000..e161a41 --- /dev/null +++ b/modules/backend/database/seeds/SeedSetupAdmin.php @@ -0,0 +1,62 @@ + $value) { + static::$$attribute = $value; + } + } + + public function run() + { + UserRole::create([ + 'name' => 'Publisher', + 'code' => UserRole::CODE_PUBLISHER, + 'description' => 'Site editor with access to publishing tools.', + ]); + + $role = UserRole::create([ + 'name' => 'Developer', + 'code' => UserRole::CODE_DEVELOPER, + 'description' => 'Site administrator with access to developer tools.', + ]); + + $group = UserGroup::create([ + 'name' => 'Owners', + 'code' => UserGroup::CODE_OWNERS, + 'description' => 'Default group for website owners.', + 'is_new_user_default' => false + ]); + + $user = User::create([ + 'email' => static::$email, + 'login' => static::$login, + 'password' => static::$password, + 'password_confirmation' => static::$password, + 'first_name' => static::$firstName, + 'last_name' => static::$lastName, + 'permissions' => [], + 'is_superuser' => true, + 'is_activated' => true, + 'role_id' => $role->id + ]); + + $user->addGroup($group); + } +} diff --git a/modules/backend/facades/Backend.php b/modules/backend/facades/Backend.php new file mode 100644 index 0000000..1a1ae24 --- /dev/null +++ b/modules/backend/facades/Backend.php @@ -0,0 +1,29 @@ +applyEditorPreferences(); + + if ($this->formField->disabled) { + $this->readOnly = true; + } + + $this->fillFromConfig([ + 'language', + 'showGutter', + 'wordWrap', + 'codeFolding', + 'autoClosing', + 'useSoftTabs', + 'tabSize', + 'fontSize', + 'margin', + 'theme', + 'showInvisibles', + 'highlightActiveLine', + 'readOnly', + 'autocompletion', + 'enableSnippets', + 'displayIndentGuides', + 'showPrintMargin' + ]); + } + + /** + * @inheritDoc + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('codeeditor'); + } + + /** + * Prepares the widget data + */ + public function prepareVars() + { + $this->vars['fontSize'] = $this->fontSize; + $this->vars['wordWrap'] = $this->wordWrap; + $this->vars['codeFolding'] = $this->codeFolding; + $this->vars['autoClosing'] = $this->autoClosing; + $this->vars['tabSize'] = $this->tabSize; + $this->vars['theme'] = $this->theme; + $this->vars['showInvisibles'] = $this->showInvisibles; + $this->vars['highlightActiveLine'] = $this->highlightActiveLine; + $this->vars['useSoftTabs'] = $this->useSoftTabs; + $this->vars['showGutter'] = $this->showGutter; + $this->vars['language'] = $this->language; + $this->vars['margin'] = $this->margin; + $this->vars['stretch'] = $this->formField->stretch; + $this->vars['size'] = $this->formField->size; + $this->vars['readOnly'] = $this->readOnly; + $this->vars['autocompletion'] = $this->autocompletion; + $this->vars['enableSnippets'] = $this->enableSnippets; + $this->vars['displayIndentGuides'] = $this->displayIndentGuides; + $this->vars['showPrintMargin'] = $this->showPrintMargin; + + // Double encode when escaping + $this->vars['value'] = htmlentities($this->getLoadValue(), ENT_QUOTES, 'UTF-8', true); + $this->vars['name'] = $this->getFieldName(); + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addCss('css/codeeditor.css', 'core'); + $this->addJs('js/build-min.js', 'core'); + } + + /** + * Looks at the user preferences and overrides any set values. + * @return void + */ + protected function applyEditorPreferences() + { + // Load the editor system settings + $preferences = BackendPreference::instance(); + + $this->fontSize = $preferences->editor_font_size; + $this->wordWrap = $preferences->editor_word_wrap; + $this->codeFolding = $preferences->editor_code_folding; + $this->autoClosing = $preferences->editor_auto_closing; + $this->tabSize = $preferences->editor_tab_size; + $this->theme = $preferences->editor_theme; + $this->showInvisibles = $preferences->editor_show_invisibles; + $this->highlightActiveLine = $preferences->editor_highlight_active_line; + $this->useSoftTabs = !$preferences->editor_use_hard_tabs; + $this->showGutter = $preferences->editor_show_gutter; + $this->autocompletion = $preferences->editor_autocompletion; + $this->enableSnippets = $preferences->editor_enable_snippets; + $this->displayIndentGuides = $preferences->editor_display_indent_guides; + $this->showPrintMargin = $preferences->editor_show_print_margin; + } +} diff --git a/modules/backend/formwidgets/ColorPicker.php b/modules/backend/formwidgets/ColorPicker.php new file mode 100644 index 0000000..2819658 --- /dev/null +++ b/modules/backend/formwidgets/ColorPicker.php @@ -0,0 +1,149 @@ +fillFromConfig([ + 'availableColors', + 'allowEmpty', + 'showAlpha', + 'readOnly', + 'disabled', + ]); + } + + /** + * @inheritDoc + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('colorpicker'); + } + + /** + * Prepares the list data + */ + public function prepareVars() + { + $this->vars['name'] = $this->getFieldName(); + $this->vars['value'] = $value = $this->getLoadValue(); + $this->vars['availableColors'] = $availableColors = $this->getAvailableColors(); + $this->vars['allowEmpty'] = $this->allowEmpty; + $this->vars['showAlpha'] = $this->showAlpha; + $this->vars['readOnly'] = $this->readOnly; + $this->vars['disabled'] = $this->disabled; + $this->vars['isCustomColor'] = !in_array($value, $availableColors); + } + + /** + * Gets the appropriate list of colors. + * + * @return array + */ + protected function getAvailableColors() + { + $availableColors = $this->availableColors; + if (is_array($availableColors)) { + return $availableColors; + } + elseif (is_string($availableColors) && !empty($availableColors)) { + if ($this->model->methodExists($availableColors)) { + return $this->availableColors = $this->model->{$availableColors}( + $this->formField->fieldName, + $this->formField->value, + $this->formField->config + ); + } else { + throw new ApplicationException(Lang::get('backend::lang.field.colors_method_not_exists', [ + 'model' => get_class($this->model), + 'method' => $availableColors, + 'field' => $this->formField->fieldName + ])); + } + } + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addCss('vendor/spectrum/spectrum.css', 'core'); + $this->addJs('vendor/spectrum/spectrum.js', 'core'); + $this->addCss('css/colorpicker.css', 'core'); + $this->addJs('js/colorpicker.js', 'core'); + } + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + return strlen($value) ? $value : null; + } +} diff --git a/modules/backend/formwidgets/DataTable.php b/modules/backend/formwidgets/DataTable.php new file mode 100644 index 0000000..65d18f5 --- /dev/null +++ b/modules/backend/formwidgets/DataTable.php @@ -0,0 +1,205 @@ +fillFromConfig([ + 'size', + 'rowSorting', + ]); + + $this->table = $this->makeTableWidget(); + $this->table->bindToController(); + } + + /** + * @return Backend\Widgets\Table The table to be displayed. + */ + public function getTable() + { + return $this->table; + } + + /** + * @inheritDoc + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('datatable'); + } + + /** + * Prepares the list data + */ + public function prepareVars() + { + $this->populateTableWidget(); + $this->vars['table'] = $this->table; + $this->vars['size'] = $this->size; + $this->vars['rowSorting'] = $this->rowSorting; + } + + /** + * @inheritDoc + */ + public function getLoadValue() + { + $value = (array) parent::getLoadValue(); + + // Sync the array keys as the ID to make the + // table widget happy! + foreach ($value as $key => $_value) { + $value[$key] = ['id' => $key] + (array) $_value; + } + + return $value; + } + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + // TODO: provide a streaming implementation of saving + // data to the model. The current implementation returns + // all records at once. -ab + + $dataSource = $this->table->getDataSource(); + + $result = []; + while ($records = $dataSource->readRecords()) { + $result = array_merge($result, $records); + } + + // We should be dealing with a simple array, so + // strip out the id columns in the final array. + foreach ($result as $key => $_result) { + unset($result[$key]['id']); + } + + return $result; + } + + /* + * Populate data + */ + protected function populateTableWidget() + { + $dataSource = $this->table->getDataSource(); + + // TODO: provide a streaming implementation of loading + // data from the model. The current implementation loads + // all records at once. -ab + + $records = $this->getLoadValue() ?: []; + + $dataSource->purge(); + $dataSource->initRecords((array) $records); + } + + protected function makeTableWidget() + { + $config = $this->makeConfig((array) $this->config); + + $config->dataSource = 'client'; + if (isset($this->getParentForm()->arrayName)) { + $config->alias = studly_case(HtmlHelper::nameToId($this->getParentForm()->arrayName . '[' . $this->fieldName . ']')) . 'datatable'; + $config->fieldName = $this->getParentForm()->arrayName . '[' . $this->fieldName . ']'; + } else { + $config->alias = studly_case(HtmlHelper::nameToId($this->fieldName)) . 'datatable'; + $config->fieldName = $this->fieldName; + } + + $table = new Table($this->controller, $config); + + $table->bindEvent('table.getDropdownOptions', [$this, 'getDataTableOptions']); + + return $table; + } + + /** + * Dropdown/autocomplete option callback handler + * + * Looks at the model for getXXXDataTableOptions or getDataTableOptions methods + * to obtain values for autocomplete and dropdown column types. + * + * @param string $columnName The name of the column to pass through to the callback. + * @param array $rowData The data provided for the current row in the datatable. + * @return array The options to make available to the dropdown or autocomplete, in format ["value" => "label"] + */ + public function getDataTableOptions($columnName, $rowData) + { + $methodName = 'get' . studly_case($this->fieldName) . 'DataTableOptions'; + + if (!$this->model->methodExists($methodName) && !$this->model->methodExists('getDataTableOptions')) { + throw new ApplicationException( + Lang::get( + 'backend::lang.model.missing_method', + [ + 'class' => get_class($this->model), + 'method' => 'getDataTableOptions' + ] + ) + ); + } + + if ($this->model->methodExists($methodName)) { + $result = $this->model->$methodName($columnName, $rowData); + } else { + $result = $this->model->getDataTableOptions($this->fieldName, $columnName, $rowData); + } + + if (!is_array($result)) { + $result = []; + } + + return $result; + } +} diff --git a/modules/backend/formwidgets/DatePicker.php b/modules/backend/formwidgets/DatePicker.php new file mode 100644 index 0000000..569bb62 --- /dev/null +++ b/modules/backend/formwidgets/DatePicker.php @@ -0,0 +1,191 @@ +fillFromConfig([ + 'format', + 'mode', + 'minDate', + 'maxDate', + 'yearRange', + 'firstDay', + 'showWeekNumber', + 'ignoreTimezone', + ]); + + $this->mode = strtolower($this->mode); + + if ($this->minDate !== null) { + $this->minDate = is_int($this->minDate) + ? Carbon::createFromTimestamp($this->minDate) + : Carbon::parse($this->minDate); + } + + if ($this->maxDate !== null) { + $this->maxDate = is_int($this->maxDate) + ? Carbon::createFromTimestamp($this->maxDate) + : Carbon::parse($this->maxDate); + } + } + + /** + * @inheritDoc + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('datepicker'); + } + + /** + * Prepares the list data + */ + public function prepareVars() + { + if ($value = $this->getLoadValue()) { + $value = DateTimeHelper::makeCarbon($value, false); + if ($this->mode === 'date' && !$this->ignoreTimezone) { + $backendTimeZone = \Backend\Models\Preference::get('timezone'); + $value->setTimezone($backendTimeZone); + $value->setTime(0, 0, 0); + $value->setTimezone(Config::get('app.timezone')); + } + $value = $value->toDateTimeString(); + } + + $this->vars['name'] = $this->getFieldName(); + $this->vars['value'] = $value ?: ''; + $this->vars['field'] = $this->formField; + $this->vars['mode'] = $this->mode; + $this->vars['minDate'] = $this->minDate; + $this->vars['maxDate'] = $this->maxDate; + $this->vars['yearRange'] = $this->yearRange; + $this->vars['firstDay'] = $this->firstDay; + $this->vars['showWeekNumber'] = $this->showWeekNumber; + $this->vars['ignoreTimezone'] = $this->ignoreTimezone; + $this->vars['format'] = $this->format; + $this->vars['formatMoment'] = $this->getDateFormatMoment(); + $this->vars['formatAlias'] = $this->getDateFormatAlias(); + } + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + if ($this->formField->disabled || $this->formField->hidden) { + return FormField::NO_SAVE_DATA; + } + + if (!strlen($value)) { + return null; + } + + return $value; + } + + /** + * Convert PHP format to JS format + */ + protected function getDateFormatMoment() + { + if ($this->format) { + return DateTimeHelper::momentFormat($this->format); + } + } + + /* + * Display alias, used by preview mode + */ + protected function getDateFormatAlias() + { + if ($this->format) { + return null; + } + + if ($this->mode == 'time') { + return 'time'; + } + elseif ($this->mode == 'date') { + return 'dateLong'; + } + else { + return 'dateTimeLong'; + } + } +} diff --git a/modules/backend/formwidgets/FileUpload.php b/modules/backend/formwidgets/FileUpload.php new file mode 100644 index 0000000..ec1e173 --- /dev/null +++ b/modules/backend/formwidgets/FileUpload.php @@ -0,0 +1,533 @@ + 'crop', + 'extension' => 'auto' + ]; + + /** + * @var boolean Allow the user to set a caption. + */ + public $useCaption = true; + + /** + * @var boolean Automatically attaches the uploaded file on upload if the parent record exists instead of using deferred binding to attach on save of the parent record. Defaults to false. + */ + public $attachOnUpload = false; + + // + // Object properties + // + + /** + * @inheritDoc + */ + protected $defaultAlias = 'fileupload'; + + /** + * @var Backend\Widgets\Form The embedded form for modifying the properties of the selected file + */ + protected $configFormWidget; + + /** + * @inheritDoc + */ + public function init() + { + $this->maxFilesize = $this->getUploadMaxFilesize(); + + $this->fillFromConfig([ + 'prompt', + 'imageWidth', + 'imageHeight', + 'fileTypes', + 'maxFilesize', + 'maxFiles', + 'mimeTypes', + 'thumbOptions', + 'useCaption', + 'attachOnUpload', + ]); + + if ($this->formField->disabled) { + $this->previewMode = true; + } + + $this->getConfigFormWidget(); + } + + /** + * @inheritDoc + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('fileupload'); + } + + /** + * Prepares the view data + */ + protected function prepareVars() + { + if ($this->formField->disabled) { + $this->previewMode = true; + } + + if ($this->previewMode) { + $this->useCaption = false; + } + + if ($this->maxFilesize > $this->getUploadMaxFilesize()) { + throw new ApplicationException('Maximum allowed size for uploaded files: ' . $this->getUploadMaxFilesize()); + } + + $this->vars['fileList'] = $fileList = $this->getFileList(); + $this->vars['singleFile'] = $fileList->first(); + $this->vars['displayMode'] = $this->getDisplayMode(); + $this->vars['emptyIcon'] = $this->getConfig('emptyIcon', 'icon-upload'); + $this->vars['imageHeight'] = (is_int($this->imageHeight)) ? $this->imageHeight : null; + $this->vars['imageWidth'] = (is_int($this->imageWidth)) ? $this->imageWidth : null; + $this->vars['acceptedFileTypes'] = $this->getAcceptedFileTypes(true); + $this->vars['maxFilesize'] = (is_int($this->maxFilesize)) ? $this->maxFilesize : null; + $this->vars['cssDimensions'] = $this->getCssDimensions(); + $this->vars['cssBlockDimensions'] = $this->getCssDimensions('block'); + $this->vars['useCaption'] = $this->useCaption; + $this->vars['maxFiles'] = (is_int($this->maxFiles)) ? $this->maxFiles : null; + $this->vars['prompt'] = $this->getPromptText(); + } + + /** + * Get the file record for this request, returns false if none available + * + * @return System\Models\File|false + */ + protected function getFileRecord() + { + $record = false; + + if (!empty(post('file_id'))) { + $record = $this->getRelationModel()::find(post('file_id')) ?: false; + } + + return $record; + } + + /** + * Get the instantiated config Form widget + * + * @return void + */ + public function getConfigFormWidget() + { + if ($this->configFormWidget) { + return $this->configFormWidget; + } + + $config = $this->makeConfig('~/modules/system/models/file/fields.yaml'); + $config->model = $this->getFileRecord() ?: $this->getRelationModel(); + $config->alias = $this->alias . $this->defaultAlias; + $config->arrayName = $this->getFieldName(); + + $widget = $this->makeWidget(Form::class, $config); + $widget->bindToController(); + + return $this->configFormWidget = $widget; + } + + protected function getFileList() + { + $list = $this + ->getRelationObject() + ->withDeferred($this->sessionKey) + ->orderBy('sort_order') + ->get() + ; + + /* + * Decorate each file with thumb and custom download path + */ + $list->each(function ($file) { + $this->decorateFileAttributes($file); + }); + + return $list; + } + + /** + * Returns the display mode for the file upload. Eg: file-multi, image-single, etc. + * @return string + */ + protected function getDisplayMode() + { + $mode = $this->getConfig('mode', 'image'); + + if (str_contains($mode, '-')) { + return $mode; + } + + $relationType = $this->getRelationType(); + $mode .= ($relationType == 'attachMany' || $relationType == 'morphMany') ? '-multi' : '-single'; + + return $mode; + } + + /** + * Returns the escaped and translated prompt text to display according to the type. + * @return string + */ + protected function getPromptText() + { + if ($this->prompt === null) { + $isMulti = ends_with($this->getDisplayMode(), 'multi'); + $this->prompt = $isMulti + ? 'backend::lang.fileupload.upload_file' + : 'backend::lang.fileupload.default_prompt'; + } + + return str_replace('%s', '', e(trans($this->prompt))); + } + + /** + * Returns the CSS dimensions for the uploaded image, + * uses auto where no dimension is provided. + * @param string $mode + * @return string + */ + protected function getCssDimensions($mode = null) + { + if (!$this->imageWidth && !$this->imageHeight) { + return ''; + } + + $cssDimensions = ''; + + if ($mode == 'block') { + $cssDimensions .= $this->imageWidth + ? 'width: '.$this->imageWidth.'px;' + : 'width: '.$this->imageHeight.'px;'; + + $cssDimensions .= ($this->imageHeight) + ? 'max-height: '.$this->imageHeight.'px;' + : 'height: auto;'; + } + else { + $cssDimensions .= $this->imageWidth + ? 'width: '.$this->imageWidth.'px;' + : 'width: auto;'; + + $cssDimensions .= ($this->imageHeight) + ? 'max-height: '.$this->imageHeight.'px;' + : 'height: auto;'; + } + + return $cssDimensions; + } + + /** + * Returns the specified accepted file types, or the default + * based on the mode. Image mode will return: + * - jpg,jpeg,bmp,png,gif,svg + * @return string + */ + public function getAcceptedFileTypes($includeDot = false) + { + $types = $this->fileTypes; + + if ($types === false) { + $isImage = starts_with($this->getDisplayMode(), 'image'); + $types = implode(',', FileDefinitions::get($isImage ? 'imageExtensions' : 'defaultExtensions')); + } + + if (!$types || $types == '*') { + return null; + } + + if (!is_array($types)) { + $types = explode(',', $types); + } + + $types = array_map(function ($value) use ($includeDot) { + $value = trim($value); + + if (substr($value, 0, 1) == '.') { + $value = substr($value, 1); + } + + if ($includeDot) { + $value = '.'.$value; + } + + return $value; + }, $types); + + return implode(',', $types); + } + + /** + * Removes a file attachment. + */ + public function onRemoveAttachment() + { + $fileModel = $this->getRelationModel(); + if (($fileId = post('file_id')) && ($file = $fileModel::find($fileId))) { + $this->getRelationObject()->remove($file, $this->sessionKey); + } + } + + /** + * Sorts file attachments. + */ + public function onSortAttachments() + { + if ($sortData = post('sortOrder')) { + $ids = array_keys($sortData); + $orders = array_values($sortData); + + $fileModel = $this->getRelationModel(); + $fileModel->setSortableOrder($ids, $orders); + } + } + + /** + * Loads the configuration form for an attachment, allowing title and description to be set. + */ + public function onLoadAttachmentConfig() + { + $fileModel = $this->getRelationModel(); + if ($file = $this->getFileRecord()) { + $file = $this->decorateFileAttributes($file); + + $this->vars['file'] = $file; + $this->vars['displayMode'] = $this->getDisplayMode(); + $this->vars['cssDimensions'] = $this->getCssDimensions(); + $this->vars['relationManageId'] = post('manage_id'); + $this->vars['relationField'] = post('_relation_field'); + + return $this->makePartial('config_form'); + } + + throw new ApplicationException('Unable to find file, it may no longer exist'); + } + + /** + * Commit the changes of the attachment configuration form. + */ + public function onSaveAttachmentConfig() + { + try { + $formWidget = $this->getConfigFormWidget(); + if ($file = $formWidget->model) { + $modelsToSave = $this->prepareModelsToSave($file, $formWidget->getSaveData()); + Db::transaction(function () use ($modelsToSave, $formWidget) { + foreach ($modelsToSave as $modelToSave) { + $modelToSave->save(null, $formWidget->getSessionKey()); + } + }); + + return ['displayName' => $file->title ?: $file->file_name]; + } + + throw new ApplicationException('Unable to find file, it may no longer exist'); + } + catch (Exception $ex) { + return json_encode(['error' => $ex->getMessage()]); + } + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addCss('css/fileupload.css', 'core'); + $this->addJs('js/fileupload.js', 'core'); + } + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + return FormField::NO_SAVE_DATA; + } + + /** + * Upload handler for the server-side processing of uploaded files + */ + public function onUpload() + { + try { + if (!Input::hasFile('file_data')) { + throw new ApplicationException('File missing from request'); + } + + $fileModel = $this->getRelationModel(); + $uploadedFile = Input::file('file_data'); + + $validationRules = ['max:'.$fileModel::getMaxFilesize()]; + if ($fileTypes = $this->getAcceptedFileTypes()) { + $validationRules[] = 'extensions:'.$fileTypes; + } + + if ($this->mimeTypes) { + $validationRules[] = 'mimes:'.$this->mimeTypes; + } + + $validation = Validator::make( + ['file_data' => $uploadedFile], + ['file_data' => $validationRules] + ); + + if ($validation->fails()) { + throw new ValidationException($validation); + } + + if (!$uploadedFile->isValid()) { + throw new ApplicationException('File is not valid'); + } + + $fileRelation = $this->getRelationObject(); + + $file = $fileModel; + $file->data = $uploadedFile; + $file->is_public = $fileRelation->isPublic(); + $file->save(); + + /** + * Attach directly to the parent model if it exists and attachOnUpload has been set to true + * else attach via deferred binding + */ + $parent = $fileRelation->getParent(); + if ($this->attachOnUpload && $parent && $parent->exists) { + $fileRelation->add($file); + } + else { + $fileRelation->add($file, $this->sessionKey); + } + + $file = $this->decorateFileAttributes($file); + + $result = [ + 'id' => $file->id, + 'thumb' => $file->thumbUrl, + 'path' => $file->pathUrl + ]; + + $response = Response::make($result, 200); + } + catch (Exception $ex) { + $response = Response::make($ex->getMessage(), 400); + } + + return $response; + } + + /** + * Adds the bespoke attributes used internally by this widget. + * - thumbUrl + * - pathUrl + * @return System\Models\File + */ + protected function decorateFileAttributes($file) + { + $path = $thumb = $file->getPath(); + + if ($this->imageWidth || $this->imageHeight) { + $thumb = $file->getThumb($this->imageWidth, $this->imageHeight, $this->thumbOptions); + } + + $file->pathUrl = $path; + $file->thumbUrl = $thumb; + + return $file; + } + + /** + * Return max upload filesize in Mb + * @return integer + */ + protected function getUploadMaxFilesize() + { + $size = ini_get('upload_max_filesize'); + if (preg_match('/^([\d\.]+)([KMG])$/i', $size, $match)) { + $pos = array_search($match[2], ['K', 'M', 'G']); + if ($pos !== false) { + $size = $match[1] * pow(1024, $pos + 1); + } + } + return floor($size / 1024 / 1024); + } +} diff --git a/modules/backend/formwidgets/MarkdownEditor.php b/modules/backend/formwidgets/MarkdownEditor.php new file mode 100644 index 0000000..d6ec6ac --- /dev/null +++ b/modules/backend/formwidgets/MarkdownEditor.php @@ -0,0 +1,140 @@ +fillFromConfig([ + 'mode', + 'safe', + 'readOnly', + 'disabled', + ]); + } + + /** + * {@inheritDoc} + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('markdowneditor'); + } + + /** + * Prepares the widget data + */ + public function prepareVars() + { + $this->vars['mode'] = $this->mode; + $this->vars['stretch'] = $this->formField->stretch; + $this->vars['size'] = $this->formField->size; + $this->vars['name'] = $this->getFieldName(); + $this->vars['value'] = $this->getLoadValue(); + $this->vars['readOnly'] = $this->readOnly; + $this->vars['disabled'] = $this->disabled; + $this->vars['useMediaManager'] = BackendAuth::getUser()->hasAccess('media.manage_media'); + } + + /** + * {@inheritDoc} + */ + protected function loadAssets() + { + $this->addCss('css/markdowneditor.css', 'core'); + $this->addJs('js/markdowneditor.js', 'core'); + $this->addJs('/modules/backend/formwidgets/codeeditor/assets/js/build-min.js', 'core'); + } + + /** + * Check to see if the generated HTML should be cleaned to remove any potential XSS + * + * @return boolean + */ + protected function shouldCleanHtml() + { + $user = BackendAuth::getUser(); + return !$user || !$user->hasAccess('backend.allow_unsafe_markdown'); + } + + /** + * {@inheritDoc} + */ + public function getSaveValue($value) + { + if ($this->shouldCleanHtml()) { + $value = Html::clean($value); + } + + return $value; + } + + /** + * AJAX handler to render the markdown as HTML + * + * @return array ['preview' => $generatedHTML] + */ + public function onRefresh() + { + $value = post($this->getFieldName()); + $previewHtml = $this->safe + ? Markdown::parseSafe($value) + : Markdown::parse($value); + + if ($this->shouldCleanHtml()) { + $previewHtml = Html::clean($previewHtml); + } + + return [ + 'preview' => $previewHtml + ]; + } +} diff --git a/modules/backend/formwidgets/MediaFinder.php b/modules/backend/formwidgets/MediaFinder.php new file mode 100644 index 0000000..0fb4799 --- /dev/null +++ b/modules/backend/formwidgets/MediaFinder.php @@ -0,0 +1,126 @@ +fillFromConfig([ + 'mode', + 'prompt', + 'imageWidth', + 'imageHeight' + ]); + + $user = BackendAuth::getUser(); + + if ($this->formField->disabled + || $this->formField->readOnly + || !$user + || !$user->hasAccess('media.manage_media') + ) { + $this->previewMode = true; + } + } + + /** + * @inheritDoc + */ + public function render() + { + $this->prepareVars(); + + return $this->makePartial('mediafinder'); + } + + /** + * Prepares the list data + */ + public function prepareVars() + { + $value = $this->getLoadValue(); + $isImage = $this->mode === 'image'; + + $this->vars['value'] = $value; + $this->vars['imageUrl'] = $isImage && $value ? MediaLibrary::url($value) : ''; + $this->vars['imageExists'] = $isImage && $value ? MediaLibrary::instance()->exists($value) : ''; + $this->vars['field'] = $this->formField; + $this->vars['prompt'] = str_replace('%s', '', trans($this->prompt)); + $this->vars['mode'] = $this->mode; + $this->vars['imageWidth'] = $this->imageWidth; + $this->vars['imageHeight'] = $this->imageHeight; + } + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + if ($this->formField->disabled || $this->formField->hidden) { + return FormField::NO_SAVE_DATA; + } + + return $value; + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addJs('js/mediafinder.js', 'core'); + $this->addCss('css/mediafinder.css', 'core'); + } +} diff --git a/modules/backend/formwidgets/NestedForm.php b/modules/backend/formwidgets/NestedForm.php new file mode 100644 index 0000000..cd3b5ce --- /dev/null +++ b/modules/backend/formwidgets/NestedForm.php @@ -0,0 +1,85 @@ +fillFromConfig([ + 'form', + 'usePanelStyles', + ]); + + if ($this->formField->disabled) { + $this->previewMode = true; + } + + $config = $this->makeConfig($this->form); + $config->model = $this->model; + $config->data = $this->getLoadValue(); + $config->alias = $this->alias . $this->defaultAlias; + $config->arrayName = $this->getFieldName(); + $config->isNested = true; + + if (object_get($this->getParentForm()->config, 'enableDefaults') === true) { + $config->enableDefaults = true; + } + + $widget = $this->makeWidget(Form::class, $config); + $widget->previewMode = $this->previewMode; + $widget->bindToController(); + + $this->formWidget = $widget; + } + + protected function loadAssets() + { + $this->addCss('css/nestedform.css', 'core'); + } + + /** + * @inheritdoc + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('nestedform'); + } + + public function prepareVars() + { + $this->formWidget->previewMode = $this->previewMode; + } +} diff --git a/modules/backend/formwidgets/PermissionEditor.php b/modules/backend/formwidgets/PermissionEditor.php new file mode 100644 index 0000000..be7c81a --- /dev/null +++ b/modules/backend/formwidgets/PermissionEditor.php @@ -0,0 +1,171 @@ +fillFromConfig([ + 'mode', + 'availablePermissions', + ]); + + $this->user = BackendAuth::getUser(); + } + + /** + * @inheritDoc + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('permissioneditor'); + } + + /** + * Prepares the list data + */ + public function prepareVars() + { + if ($this->formField->disabled) { + $this->previewMode = true; + } + + $permissionsData = $this->formField->getValueFromData($this->model); + if (!is_array($permissionsData)) { + $permissionsData = []; + } + + $this->vars['mode'] = $this->mode; + $this->vars['permissions'] = $this->getFilteredPermissions(); + $this->vars['baseFieldName'] = $this->getFieldName(); + $this->vars['permissionsData'] = $permissionsData; + $this->vars['field'] = $this->formField; + } + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + if ($this->user->isSuperUser()) { + return is_array($value) ? $value : []; + } + + return $this->getSaveValueSecure($value); + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addCss('css/permissioneditor.css', 'core'); + $this->addJs('js/permissioneditor.js', 'core'); + } + + /** + * Returns a safely parsed set of permissions, ensuring the user cannot elevate + * their own permissions or permissions of another user above their own. + * + * @param string $value + * @return array + */ + protected function getSaveValueSecure($value) + { + $newPermissions = is_array($value) ? array_map('intval', $value) : []; + + if (!empty($newPermissions)) { + $existingPermissions = $this->model->permissions ?: []; + + $allowedPermissions = array_map(function ($permissionObject) { + return $permissionObject->code; + }, array_flatten($this->getFilteredPermissions())); + + foreach ($newPermissions as $permission => $code) { + if (in_array($permission, $allowedPermissions)) { + $existingPermissions[$permission] = $code; + } + } + + $newPermissions = $existingPermissions; + } + + return $newPermissions; + } + + /** + * Returns the available permissions; removing those that the logged-in user does not have access to + * + * @return array The permissions that the logged-in user does have access to ['permission-tab' => $arrayOfAllowedPermissionObjects] + */ + protected function getFilteredPermissions() + { + $permissions = BackendAuth::listTabbedPermissions(); + + foreach ($permissions as $tab => $permissionsArray) { + foreach ($permissionsArray as $index => $permission) { + if (!$this->user->hasAccess($permission->code) || + ( + is_array($this->availablePermissions) && + !in_array($permission->code, $this->availablePermissions) + )) { + unset($permissionsArray[$index]); + } + } + + if (empty($permissionsArray)) { + unset($permissions[$tab]); + } + else { + $permissions[$tab] = $permissionsArray; + } + } + + return $permissions; + } +} diff --git a/modules/backend/formwidgets/RecordFinder.php b/modules/backend/formwidgets/RecordFinder.php new file mode 100644 index 0000000..b02e3ab --- /dev/null +++ b/modules/backend/formwidgets/RecordFinder.php @@ -0,0 +1,358 @@ +fillFromConfig([ + 'title', + 'prompt', + 'keyFrom', + 'nameFrom', + 'descriptionFrom', + 'scope', + 'conditions', + 'searchMode', + 'searchScope', + 'recordsPerPage', + 'useRelation', + 'modelClass', + ]); + + if (!$this->useRelation && !class_exists($this->modelClass)) { + throw new ApplicationException(Lang::get('backend::lang.recordfinder.invalid_model_class', ['modelClass' => $this->modelClass])); + } + + if (post('recordfinder_flag')) { + $this->listWidget = $this->makeListWidget(); + $this->listWidget->bindToController(); + + $this->searchWidget = $this->makeSearchWidget(); + $this->searchWidget->bindToController(); + + $this->listWidget->setSearchTerm($this->searchWidget->getActiveTerm()); + + /* + * Link the Search Widget to the List Widget + */ + $this->searchWidget->bindEvent('search.submit', function () { + $this->listWidget->setSearchTerm($this->searchWidget->getActiveTerm()); + return $this->listWidget->onRefresh(); + }); + } + } + + /** + * @inheritDoc + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('container'); + } + + public function onRefresh() + { + $value = post($this->getFieldName()); + if ($this->useRelation) { + list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom); + $model->{$attribute} = $value; + } else { + $this->formField->value = $value; + } + + $this->prepareVars(); + return ['#'.$this->getId('container') => $this->makePartial('recordfinder')]; + } + + public function onClearRecord() + { + if ($this->useRelation) { + list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom); + $model->{$attribute} = null; + } else { + $this->formField->value = null; + } + + $this->prepareVars(); + return ['#'.$this->getId('container') => $this->makePartial('recordfinder')]; + } + + /** + * Prepares the list data + */ + public function prepareVars() + { + $this->relationModel = $this->getLoadValue(); + + if ($this->formField->disabled) { + $this->previewMode = true; + } + + $this->vars['value'] = $this->getKeyValue(); + $this->vars['field'] = $this->formField; + $this->vars['nameValue'] = $this->getNameValue(); + $this->vars['descriptionValue'] = $this->getDescriptionValue(); + $this->vars['listWidget'] = $this->listWidget; + $this->vars['searchWidget'] = $this->searchWidget; + $this->vars['title'] = $this->title; + $this->vars['prompt'] = str_replace('%s', '', e(trans($this->prompt))); + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addJs('js/recordfinder.js', 'core'); + } + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + return strlen($value) ? $value : null; + } + + /** + * @inheritDoc + */ + public function getLoadValue() + { + $value = null; + + if ($this->useRelation) { + list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom); + if ($model !== null) { + $value = $model->{$attribute}; + } + } else { + $value = $this->modelClass::where($this->keyFrom, parent::getLoadValue())->first(); + } + + return $value; + } + + public function getKeyValue() + { + if (!$this->relationModel) { + return null; + } + + return $this->useRelation ? + $this->relationModel->{$this->keyFrom} : + $this->formField->value; + } + + public function getNameValue() + { + if (!$this->relationModel || !$this->nameFrom) { + return null; + } + + return $this->relationModel->{$this->nameFrom}; + } + + public function getDescriptionValue() + { + if (!$this->relationModel || !$this->descriptionFrom) { + return null; + } + + return $this->relationModel->{$this->descriptionFrom}; + } + + public function onFindRecord() + { + $this->prepareVars(); + + /* + * Purge the search term stored in session + */ + if ($this->searchWidget) { + $this->listWidget->setSearchTerm(null); + $this->searchWidget->setActiveTerm(null); + } + + return $this->makePartial('recordfinder_form'); + } + + protected function makeListWidget() + { + $config = $this->makeConfig($this->getConfig('list')); + + if ($this->useRelation) { + $config->model = $this->getRelationModel(); + } else { + $config->model = new $this->modelClass; + } + + $config->alias = $this->alias . 'List'; + $config->showSetup = false; + $config->showCheckboxes = false; + $config->recordsPerPage = $this->recordsPerPage; + $config->recordOnClick = sprintf("$('#%s').recordFinder('updateRecord', this, ':" . $this->keyFrom . "')", $this->getId()); + $widget = $this->makeWidget('Backend\Widgets\Lists', $config); + + $widget->setSearchOptions([ + 'mode' => $this->searchMode, + 'scope' => $this->searchScope, + ]); + + if ($sqlConditions = $this->conditions) { + $widget->bindEvent('list.extendQueryBefore', function ($query) use ($sqlConditions) { + $query->whereRaw($sqlConditions); + }); + } + elseif ($scopeMethod = $this->scope) { + $widget->bindEvent('list.extendQueryBefore', function ($query) use ($scopeMethod) { + $query->$scopeMethod($this->model); + }); + } + else { + if ($this->useRelation) { + $widget->bindEvent('list.extendQueryBefore', function ($query) { + $this->getRelationObject()->addDefinedConstraintsToQuery($query); + }); + } + } + + return $widget; + } + + protected function makeSearchWidget() + { + $config = $this->makeConfig(); + $config->alias = $this->alias . 'Search'; + $config->growable = false; + $config->prompt = 'backend::lang.list.search_prompt'; + $widget = $this->makeWidget('Backend\Widgets\Search', $config); + $widget->cssClasses[] = 'recordfinder-search'; + return $widget; + } +} diff --git a/modules/backend/formwidgets/Relation.php b/modules/backend/formwidgets/Relation.php new file mode 100644 index 0000000..c80be47 --- /dev/null +++ b/modules/backend/formwidgets/Relation.php @@ -0,0 +1,188 @@ +fillFromConfig([ + 'nameFrom', + 'emptyOption', + 'scope', + 'order', + ]); + + if (isset($this->config->select)) { + $this->sqlSelect = $this->config->select; + } + } + + /** + * @inheritDoc + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('relation'); + } + + /** + * Prepares the view data + */ + public function prepareVars() + { + $this->vars['field'] = $this->makeRenderFormField(); + } + + /** + * Makes the form object used for rendering a simple field type + */ + protected function makeRenderFormField() + { + return $this->renderFormField = RelationBase::noConstraints(function () { + + $field = clone $this->formField; + $relationObject = $this->getRelationObject(); + $query = $relationObject->newQuery(); + + list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom); + $relationType = $model->getRelationType($attribute); + $relationModel = $model->makeRelation($attribute); + + if (in_array($relationType, ['belongsToMany', 'morphToMany', 'morphedByMany', 'hasMany'])) { + $field->type = 'checkboxlist'; + } + elseif (in_array($relationType, ['belongsTo', 'hasOne'])) { + $field->type = 'dropdown'; + } + + // Order query by the configured option. + if ($this->order) { + // Using "raw" to allow authors to use a string to define the order clause. + $query->orderByRaw($this->order); + } + + // It is safe to assume that if the model and related model are of + // the exact same class, then it cannot be related to itself + if ($model->exists && (get_class($model) == get_class($relationModel))) { + $query->where($relationModel->getKeyName(), '<>', $model->getKey()); + } + + // Even though "no constraints" is applied, belongsToMany constrains the query + // by joining its pivot table. Remove all joins from the query. + $query->getQuery()->getQuery()->joins = []; + + if ($scopeMethod = $this->scope) { + $query->$scopeMethod($model); + } + + // Determine if the model uses a tree trait + $treeTraits = ['October\Rain\Database\Traits\NestedTree', 'October\Rain\Database\Traits\SimpleTree']; + $usesTree = count(array_intersect($treeTraits, class_uses($relationModel))) > 0; + + // The "sqlSelect" config takes precedence over "nameFrom". + // A virtual column called "selection" will contain the result. + // Tree models must select all columns to return parent columns, etc. + if ($this->sqlSelect) { + $nameFrom = 'selection'; + $selectColumn = $usesTree ? '*' : $relationModel->getKeyName(); + $result = $query->select($selectColumn, Db::raw($this->sqlSelect . ' AS ' . $nameFrom)); + } + else { + $nameFrom = $this->nameFrom; + $result = $query->getQuery()->get(); + } + + // Some simpler relations can specify a custom local or foreign "other" key, + // which can be detected and implemented here automagically. + $primaryKeyName = in_array($relationType, ['hasMany', 'belongsTo', 'hasOne']) + ? $relationObject->getOtherKey() + : $relationModel->getKeyName(); + + $field->options = $usesTree + ? $result->listsNested($nameFrom, $primaryKeyName) + : $result->lists($nameFrom, $primaryKeyName); + + return $field; + }); + } + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + if ($this->formField->disabled || $this->formField->hidden) { + return FormField::NO_SAVE_DATA; + } + + if (is_string($value) && !strlen($value)) { + return null; + } + + if (is_array($value) && !count($value)) { + return null; + } + + return $value; + } +} diff --git a/modules/backend/formwidgets/Repeater.php b/modules/backend/formwidgets/Repeater.php new file mode 100644 index 0000000..159f20c --- /dev/null +++ b/modules/backend/formwidgets/Repeater.php @@ -0,0 +1,504 @@ +prompt = Lang::get('backend::lang.repeater.add_new_item'); + + $this->fillFromConfig([ + 'form', + 'style', + 'prompt', + 'sortable', + 'titleFrom', + 'minItems', + 'maxItems', + ]); + + if ($this->formField->disabled) { + $this->previewMode = true; + } + + // Check for loaded flag in POST + if ((bool) post($this->alias . '_loaded') === true) { + $this->loaded = true; + } + + $this->checkAddItemRequest(); + $this->processGroupMode(); + + if (!self::$onAddItemCalled) { + $this->processItems(); + } + } + + /** + * @inheritDoc + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('repeater'); + } + + /** + * Prepares the form widget view data + */ + public function prepareVars() + { + // Refresh the loaded data to support being modified by filterFields + // @see https://github.com/octobercms/october/issues/2613 + if (!self::$onAddItemCalled) { + $this->processItems(); + } + + if ($this->previewMode) { + foreach ($this->formWidgets as $widget) { + $widget->previewMode = true; + } + } + + $this->vars['prompt'] = $this->prompt; + $this->vars['formWidgets'] = $this->formWidgets; + $this->vars['titleFrom'] = $this->titleFrom; + $this->vars['minItems'] = $this->minItems; + $this->vars['maxItems'] = $this->maxItems; + $this->vars['style'] = $this->style; + + $this->vars['useGroups'] = $this->useGroups; + $this->vars['groupDefinitions'] = $this->groupDefinitions; + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addCss('css/repeater.css', 'core'); + $this->addJs('js/repeater.js', 'core'); + } + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + return (array) $this->processSaveValue($value); + } + + /** + * Splices in some meta data (group and index values) to the dataset. + * @param array $value + * @return array + */ + protected function processSaveValue($value) + { + if (!is_array($value) || !$value) { + return $value; + } + + if ($this->minItems && count($value) < $this->minItems) { + throw new ApplicationException(Lang::get('backend::lang.repeater.min_items_failed', ['name' => $this->fieldName, 'min' => $this->minItems, 'items' => count($value)])); + } + if ($this->maxItems && count($value) > $this->maxItems) { + throw new ApplicationException(Lang::get('backend::lang.repeater.max_items_failed', ['name' => $this->fieldName, 'max' => $this->maxItems, 'items' => count($value)])); + } + + /* + * Give repeated form field widgets an opportunity to process the data. + */ + foreach ($value as $index => $data) { + if (isset($this->formWidgets[$index])) { + if ($this->useGroups) { + $value[$index] = array_merge($this->formWidgets[$index]->getSaveData(), ['_group' => $data['_group']]); + } else { + $value[$index] = $this->formWidgets[$index]->getSaveData(); + } + } + } + + return array_values($value); + } + + /** + * Processes form data and applies it to the form widgets. + * @return void + */ + protected function processItems() + { + $currentValue = ($this->loaded === true) + ? post($this->formField->getName()) + : $this->getLoadValue(); + + // Detect when a child widget is trying to run an AJAX handler + // outside of the form element that contains all the repeater + // fields that would normally be used to identify that case + $handler = $this->controller->getAjaxHandler(); + if (!$this->loaded && starts_with($handler, $this->alias . 'Form')) { + // Attempt to get the index of the repeater + $handler = str_after($handler, $this->alias . 'Form'); + preg_match("~^(\d+)~", $handler, $matches); + + if (isset($matches[1])) { + $index = $matches[1]; + $this->makeItemFormWidget($index); + } + } + + // Ensure that the minimum number of items are preinitialized + // ONLY DONE WHEN NOT IN GROUP MODE + if (!$this->useGroups && $this->minItems > 0) { + if (!is_array($currentValue)) { + $currentValue = []; + for ($i = 0; $i < $this->minItems; $i++) { + $currentValue[$i] = []; + } + } elseif (count($currentValue) < $this->minItems) { + for ($i = 0; $i < ($this->minItems - count($currentValue)); $i++) { + $currentValue[] = []; + } + } + } + + if (!$this->childAddItemCalled && $currentValue === null) { + $this->formWidgets = []; + return; + } + + if ($this->childAddItemCalled && !isset($currentValue[$this->childIndexCalled])) { + // If no value is available but a child repeater has added an item, add a "stub" repeater item + $this->makeItemFormWidget($this->childIndexCalled); + } + + if (!is_array($currentValue)) { + return; + } + + collect($currentValue)->each(function ($value, $index) { + $this->makeItemFormWidget($index, array_get($value, '_group', null)); + }); + } + + /** + * Creates a form widget based on a field index and optional group code. + * @param int $index + * @param string $index + * @return \Backend\Widgets\Form + */ + protected function makeItemFormWidget($index = 0, $groupCode = null) + { + $configDefinition = $this->useGroups + ? $this->getGroupFormFieldConfig($groupCode) + : $this->form; + + $config = $this->makeConfig($configDefinition); + $config->model = $this->model; + $config->data = $this->getValueFromIndex($index); + $config->alias = $this->alias . 'Form' . $index; + $config->arrayName = $this->getFieldName().'['.$index.']'; + $config->isNested = true; + if (self::$onAddItemCalled || $this->minItems > 0) { + $config->enableDefaults = true; + } + + $widget = $this->makeWidget('Backend\Widgets\Form', $config); + $widget->previewMode = $this->previewMode; + $widget->bindToController(); + + $this->indexMeta[$index] = [ + 'groupCode' => $groupCode + ]; + + return $this->formWidgets[$index] = $widget; + } + + /** + * Returns the data at a given index. + * @param int $index + */ + protected function getValueFromIndex($index) + { + $value = ($this->loaded === true) + ? post($this->formField->getName()) + : $this->getLoadValue(); + + if (!is_array($value)) { + $value = []; + } + + return array_get($value, $index, []); + } + + // + // AJAX handlers + // + + public function onAddItem() + { + $groupCode = post('_repeater_group'); + + $index = $this->getNextIndex(); + + $this->prepareVars(); + $this->vars['widget'] = $this->makeItemFormWidget($index, $groupCode); + $this->vars['indexValue'] = $index; + + $itemContainer = '@#' . $this->getId('items'); + + return [ + $itemContainer => $this->makePartial('repeater_item') + ]; + } + + public function onRemoveItem() + { + // Useful for deleting relations + } + + public function onRefresh() + { + $index = post('_repeater_index'); + $group = post('_repeater_group'); + + $widget = $this->makeItemFormWidget($index, $group); + + return $widget->onRefresh(); + } + + /** + * Determines the next available index number for assigning to a new repeater item. + * + * @return int + */ + protected function getNextIndex() + { + if ($this->loaded === true) { + $data = post($this->formField->getName()); + + if (is_array($data) && count($data)) { + return (max(array_keys($data)) + 1); + } + } else { + $data = $this->getLoadValue(); + + if (is_array($data)) { + return count($data); + } + } + + return 0; + } + + /** + * Determines the repeater that has triggered an AJAX request to add an item. + * + * @return void + */ + protected function checkAddItemRequest() + { + $handler = $this->getParentForm() + ->getController() + ->getAjaxHandler(); + + if ($handler === null || strpos($handler, '::') === false) { + return; + } + + list($widgetName, $handlerName) = explode('::', $handler); + if ($handlerName !== 'onAddItem') { + return; + } + + if ($this->alias === $widgetName) { + // This repeater has made the AJAX request + self::$onAddItemCalled = true; + } else if (strpos($widgetName, $this->alias . 'Form') === 0) { + // A child repeater has made the AJAX request + + // Get index from AJAX handler + $handlerSuffix = str_replace($this->alias . 'Form', '', $widgetName); + if (preg_match('/^[0-9]+/', $handlerSuffix, $matches)) { + $this->childAddItemCalled = true; + $this->childIndexCalled = (int) $matches[0]; + } + } + } + + // + // Group mode + // + + /** + * Returns the form field configuration for a group, identified by code. + * @param string $code + * @return array|null + */ + protected function getGroupFormFieldConfig($code) + { + if (!$code) { + return null; + } + + $fields = array_get($this->groupDefinitions, $code.'.fields'); + + if (!$fields) { + return null; + } + + return ['fields' => $fields, 'enableDefaults' => object_get($this->config, 'enableDefaults')]; + } + + /** + * Process features related to group mode. + * @return void + */ + protected function processGroupMode() + { + $palette = []; + + if (!$group = $this->getConfig('groups', [])) { + $this->useGroups = false; + return; + } + + if (is_string($group)) { + $group = $this->makeConfig($group); + } + + foreach ($group as $code => $config) { + $palette[$code] = [ + 'code' => $code, + 'name' => array_get($config, 'name'), + 'icon' => array_get($config, 'icon', 'icon-square-o'), + 'description' => array_get($config, 'description'), + 'fields' => array_get($config, 'fields') + ]; + } + + $this->groupDefinitions = $palette; + $this->useGroups = true; + } + + /** + * Returns a field group code from its index. + * @param $index int + * @return string + */ + public function getGroupCodeFromIndex($index) + { + return array_get($this->indexMeta, $index.'.groupCode'); + } + + /** + * Returns the group title from its unique code. + * @param $groupCode string + * @return string + */ + public function getGroupTitle($groupCode) + { + return array_get($this->groupDefinitions, $groupCode.'.name'); + } +} diff --git a/modules/backend/formwidgets/RichEditor.php b/modules/backend/formwidgets/RichEditor.php new file mode 100644 index 0000000..d8d2678 --- /dev/null +++ b/modules/backend/formwidgets/RichEditor.php @@ -0,0 +1,312 @@ +formField->disabled) { + $this->readOnly = true; + } + + $this->fillFromConfig([ + 'fullPage', + 'readOnly', + 'toolbarButtons', + ]); + } + + /** + * @inheritDoc + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('richeditor'); + } + + /** + * Prepares the list data + */ + public function prepareVars() + { + $this->vars['field'] = $this->formField; + $this->vars['editorLang'] = $this->getValidEditorLang(); + $this->vars['fullPage'] = $this->fullPage; + $this->vars['stretch'] = $this->formField->stretch; + $this->vars['size'] = $this->formField->size; + $this->vars['readOnly'] = $this->readOnly; + $this->vars['name'] = $this->getFieldName(); + $this->vars['value'] = $this->getLoadValue(); + $this->vars['toolbarButtons'] = $this->evalToolbarButtons(); + $this->vars['useMediaManager'] = BackendAuth::getUser()->hasAccess('media.manage_media'); + + $this->vars['globalToolbarButtons'] = EditorSetting::getConfigured('html_toolbar_buttons'); + $this->vars['allowEmptyTags'] = EditorSetting::getConfigured('html_allow_empty_tags'); + $this->vars['allowTags'] = EditorSetting::getConfigured('html_allow_tags'); + $this->vars['noWrapTags'] = EditorSetting::getConfigured('html_no_wrap_tags'); + $this->vars['removeTags'] = EditorSetting::getConfigured('html_remove_tags'); + $this->vars['lineBreakerTags'] = EditorSetting::getConfigured('html_line_breaker_tags'); + + $this->vars['imageStyles'] = EditorSetting::getConfiguredStyles('html_style_image'); + $this->vars['linkStyles'] = EditorSetting::getConfiguredStyles('html_style_link'); + $this->vars['paragraphStyles'] = EditorSetting::getConfiguredStyles('html_style_paragraph'); + $this->vars['paragraphFormats'] = EditorSetting::getConfiguredFormats('html_paragraph_formats'); + $this->vars['tableStyles'] = EditorSetting::getConfiguredStyles('html_style_table'); + $this->vars['tableCellStyles'] = EditorSetting::getConfiguredStyles('html_style_table_cell'); + } + + /** + * Determine the toolbar buttons to use based on config. + * @return string + */ + protected function evalToolbarButtons() + { + $buttons = $this->toolbarButtons; + + if (is_string($buttons)) { + $buttons = array_map(function ($button) { + return strlen($button) ? $button : '|'; + }, explode('|', $buttons)); + } + + return $buttons; + } + + public function onLoadPageLinksForm() + { + $this->vars['links'] = $this->getPageLinksArray(); + return $this->makePartial('page_links_form'); + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addCss('css/richeditor.css', 'core'); + $this->addJs('js/build-min.js', 'core'); + + if (Config::get('develop.decompileBackendAssets', false)) { + $scripts = Backend::decompileAsset($this->getAssetPath('js/build-plugins.js')); + foreach ($scripts as $script) { + $this->addJs($script, 'core'); + } + } else { + $this->addJs('js/build-plugins-min.js', 'core'); + } + + $this->addJs('/modules/backend/formwidgets/codeeditor/assets/js/build-min.js', 'core'); + + if ($lang = $this->getValidEditorLang()) { + $this->addJs('vendor/froala/js/languages/'.$lang.'.js', 'core'); + } + } + + /** + * Returns a valid language code for Redactor. + * @return string|mixed + */ + protected function getValidEditorLang() + { + $locale = App::getLocale(); + + // English is baked in + if ($locale == 'en') { + return null; + } + + $locale = str_replace('-', '_', strtolower($locale)); + $path = base_path('modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/'.$locale.'.js'); + + return File::exists($path) ? $locale : false; + } + + /** + * Returns a list of registered page link types. + * This is reserved functionality for separating the links by type. + * @return array Returns an array of registered page link types + */ + protected function getPageLinkTypes() + { + $result = []; + + /** + * @event backend.richeditor.listTypes + * Register additional "page link types" to the RichEditor FormWidget + * + * Example usage: + * + * Event::listen('backend.richeditor.listTypes', function () { + * return [ + * 'my-identifier' => 'author.plugin::lang.richeditor.link_types.my_identifier', + * ]; + * }); + * + */ + $apiResult = Event::fire('backend.richeditor.listTypes'); + if (is_array($apiResult)) { + foreach ($apiResult as $typeList) { + if (!is_array($typeList)) { + continue; + } + + foreach ($typeList as $typeCode => $typeName) { + $result[$typeCode] = $typeName; + } + } + } + + return $result; + } + + protected function getPageLinks($type) + { + $result = []; + + /** + * @event backend.richeditor.getTypeInfo + * Register additional "page link types" to the RichEditor FormWidget + * + * Example usage: + * + * Event::listen('backend.richeditor.getTypeInfo', function ($type) { + * if ($type === 'my-identifier') { + * return [ + * 'https://example.com/page1' => 'Page 1', + * 'https://example.com/parent-page' => [ + * 'title' => 'Parent Page', + * 'links' => [ + * 'https://example.com/child-page' => 'Child Page', + * ], + * ], + * ]; + * } + * }); + * + */ + $apiResult = Event::fire('backend.richeditor.getTypeInfo', [$type]); + if (is_array($apiResult)) { + foreach ($apiResult as $typeInfo) { + if (!is_array($typeInfo)) { + continue; + } + + foreach ($typeInfo as $name => $value) { + $result[$name] = $value; + } + } + } + + return $result; + } + + /** + * Returns a single collection of available page links. + * This implementation has room to place links under + * different groups based on the link type. + * @return array + */ + protected function getPageLinksArray() + { + $links = []; + $types = $this->getPageLinkTypes(); + + $links[] = ['name' => Lang::get('backend::lang.pagelist.select_page'), 'url' => false]; + + $iterator = function ($links, $level = 0) use (&$iterator) { + $result = []; + + foreach ($links as $linkUrl => $link) { + /* + * Remove scheme and host from URL + */ + $baseUrl = Request::getSchemeAndHttpHost(); + if (strpos($linkUrl, $baseUrl) === 0) { + $linkUrl = substr($linkUrl, strlen($baseUrl)); + } + + /* + * Root page fallback. + */ + if (strlen($linkUrl) === 0) { + $linkUrl = '/'; + } + + $linkName = str_repeat(' ', $level * 4); + $linkName .= is_array($link) ? array_get($link, 'title', '') : $link; + $result[] = ['name' => $linkName, 'url' => $linkUrl]; + + if (is_array($link)) { + $result = array_merge( + $result, + $iterator(array_get($link, 'links', []), $level + 1) + ); + } + } + + return $result; + }; + + foreach ($types as $typeCode => $typeName) { + $links = array_merge($links, $iterator($this->getPageLinks($typeCode))); + } + + return $links; + } +} diff --git a/modules/backend/formwidgets/Sensitive.php b/modules/backend/formwidgets/Sensitive.php new file mode 100644 index 0000000..a28a8d6 --- /dev/null +++ b/modules/backend/formwidgets/Sensitive.php @@ -0,0 +1,117 @@ +fillFromConfig([ + 'readOnly', + 'disabled', + 'allowCopy', + 'hiddenPlaceholder', + 'hideOnTabChange', + ]); + + if ($this->formField->disabled || $this->formField->readOnly) { + $this->previewMode = true; + } + } + + /** + * @inheritDoc + */ + public function render() + { + $this->prepareVars(); + + return $this->makePartial('sensitive'); + } + + /** + * Prepares the view data for the widget partial. + */ + public function prepareVars() + { + $this->vars['readOnly'] = $this->readOnly; + $this->vars['disabled'] = $this->disabled; + $this->vars['hasValue'] = !empty($this->getLoadValue()); + $this->vars['allowCopy'] = $this->allowCopy; + $this->vars['hiddenPlaceholder'] = $this->hiddenPlaceholder; + $this->vars['hideOnTabChange'] = $this->hideOnTabChange; + } + + /** + * Reveals the value of a hidden, unmodified sensitive field. + * + * @return array + */ + public function onShowValue() + { + return [ + 'value' => $this->getLoadValue() + ]; + } + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + if ($value === $this->hiddenPlaceholder) { + $value = $this->getLoadValue(); + } + + return $value; + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addCss('css/sensitive.css', 'core'); + $this->addJs('js/sensitive.js', 'core'); + } +} diff --git a/modules/backend/formwidgets/TagList.php b/modules/backend/formwidgets/TagList.php new file mode 100644 index 0000000..2e2b5c0 --- /dev/null +++ b/modules/backend/formwidgets/TagList.php @@ -0,0 +1,218 @@ +fillFromConfig([ + 'separator', + 'customTags', + 'options', + 'mode', + 'nameFrom', + 'useKey', + 'placeholder' + ]); + } + + /** + * @inheritDoc + */ + public function render() + { + $this->prepareVars(); + + return $this->makePartial('taglist'); + } + + /** + * Prepares the form widget view data + */ + public function prepareVars() + { + $this->vars['placeholder'] = $this->placeholder; + $this->vars['useKey'] = $this->useKey; + $this->vars['field'] = $this->formField; + $this->vars['fieldOptions'] = $this->getFieldOptions(); + $this->vars['selectedValues'] = $this->getLoadValue(); + $this->vars['customSeparators'] = $this->getCustomSeparators(); + } + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + if ($this->mode === static::MODE_RELATION) { + return $this->hydrateRelationSaveValue($value); + } + + if (is_array($value) && $this->mode === static::MODE_STRING) { + return implode($this->getSeparatorCharacter(), $value); + } + + return $value; + } + + /** + * Returns an array suitable for saving against a relation (array of keys). + * This method also creates non-existent tags. + * @return array + */ + protected function hydrateRelationSaveValue($names) + { + if (!$names) { + return $names; + } + + $relationModel = $this->getRelationModel(); + $existingTags = $relationModel + ->whereIn($this->nameFrom, $names) + ->lists($this->nameFrom, $relationModel->getKeyName()) + ; + + $newTags = $this->customTags ? array_diff($names, $existingTags) : []; + + foreach ($newTags as $newTag) { + $newModel = new $relationModel; + $newModel->{$this->nameFrom} = $newTag; + $newModel->save(); + $existingTags[$newModel->getKey()] = $newTag; + } + + return array_keys($existingTags); + } + + /** + * @inheritDoc + */ + public function getLoadValue() + { + $value = parent::getLoadValue(); + + if ($this->mode === static::MODE_RELATION) { + return $this->getRelationObject()->lists($this->nameFrom); + } + + return $this->mode === static::MODE_STRING + ? explode($this->getSeparatorCharacter(), $value) + : $value; + } + + /** + * Returns defined field options, or from the relation if available. + * @return array + */ + public function getFieldOptions() + { + $options = $this->formField->options(); + + if (!$options && $this->mode === static::MODE_RELATION) { + $options = RelationBase::noConstraints(function () { + $query = $this->getRelationObject()->newQuery(); + + // Even though "no constraints" is applied, belongsToMany constrains the query + // by joining its pivot table. Remove all joins from the query. + $query->getQuery()->getQuery()->joins = []; + + return $query->lists($this->nameFrom); + }); + } + + return $options; + } + + /** + * Returns character(s) to use for separating keywords. + * @return mixed + */ + protected function getCustomSeparators() + { + if (!$this->customTags) { + return false; + } + + $separators = []; + + $separators[] = $this->getSeparatorCharacter(); + + return implode('|', $separators); + } + + /** + * Convert the character word to the singular character. + * @return string + */ + protected function getSeparatorCharacter() + { + switch (strtolower($this->separator)) { + case 'comma': + return ','; + case 'space': + return ' '; + } + } +} diff --git a/modules/backend/formwidgets/codeeditor/assets/css/codeeditor.css b/modules/backend/formwidgets/codeeditor/assets/css/codeeditor.css new file mode 100644 index 0000000..097f073 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/css/codeeditor.css @@ -0,0 +1,27 @@ +.field-codeeditor {width:100%;position:relative;border:2px solid #d1d6d9;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +.field-codeeditor textarea {opacity:0;filter:alpha(opacity=0)} +.field-codeeditor.editor-focus {border:2px solid #d1d6d9} +.field-codeeditor.size-tiny {min-height:50px} +.field-codeeditor.size-small {min-height:100px} +.field-codeeditor.size-large {min-height:200px} +.field-codeeditor.size-huge {min-height:250px} +.field-codeeditor.size-giant {min-height:350px} +.field-codeeditor .ace_search {font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px;color:#333;z-index:13} +.field-codeeditor .ace_search .ace_search_form.ace_nomatch {outline:none !important} +.field-codeeditor .ace_search .ace_search_form.ace_nomatch .ace_search_field {border:.0625rem solid red;-webkit-box-shadow:0 0 .1875rem .125rem red;box-shadow:0 0 .1875rem .125rem red;z-index:1;position:relative} +.field-codeeditor .editor-code {-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +.field-codeeditor .editor-toolbar {position:absolute;padding:0 5px;bottom:10px;right:25px;z-index:10;background:rgba(0,0,0,0.8);border-radius:5px} +.field-codeeditor .editor-toolbar >ul, +.field-codeeditor .editor-toolbar ul >li {list-style-type:none;padding:0;margin:0} +.field-codeeditor .editor-toolbar >ul >li {float:left} +.field-codeeditor .editor-toolbar >ul >li .tooltip.left {margin-right:25px} +.field-codeeditor .editor-toolbar >ul >li >a {display:block;height:25px;width:25px;color:#666;font-size:20px;text-align:center;text-decoration:none;text-shadow:0 0 5px #000} +.field-codeeditor .editor-toolbar >ul >li >a >abbr {position:absolute;font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0} +.field-codeeditor .editor-toolbar >ul >li >a >i {opacity:1;filter:alpha(opacity=100);display:block} +.field-codeeditor .editor-toolbar >ul >li >a >i:before {font-size:15px} +.field-codeeditor .editor-toolbar >ul >li >a:hover >i, +.field-codeeditor .editor-toolbar >ul >li >a:focus >i {opacity:1;filter:alpha(opacity=100);color:#fff} +.field-codeeditor.editor-fullscreen {z-index:301;position:fixed !important;top:0;left:0;height:100%;border-width:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.field-codeeditor.editor-fullscreen .editor-toolbar {z-index:302} +.field-codeeditor.editor-fullscreen .editor-code {-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.field-codeeditor.editor-fullscreen .ace_search {z-index:303} \ No newline at end of file diff --git a/modules/backend/formwidgets/codeeditor/assets/js/build-min.js b/modules/backend/formwidgets/codeeditor/assets/js/build-min.js new file mode 100644 index 0000000..d651f97 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/js/build-min.js @@ -0,0 +1,4702 @@ + +var _=(function(){var root=this;var previousUnderscore=root._;var breaker={};var ArrayProto=Array.prototype,ObjProto=Object.prototype,FuncProto=Function.prototype;var slice=ArrayProto.slice,unshift=ArrayProto.unshift,toString=ObjProto.toString,hasOwnProperty=ObjProto.hasOwnProperty;var +nativeForEach=ArrayProto.forEach,nativeMap=ArrayProto.map,nativeReduce=ArrayProto.reduce,nativeReduceRight=ArrayProto.reduceRight,nativeFilter=ArrayProto.filter,nativeEvery=ArrayProto.every,nativeSome=ArrayProto.some,nativeIndexOf=ArrayProto.indexOf,nativeLastIndexOf=ArrayProto.lastIndexOf,nativeIsArray=Array.isArray,nativeKeys=Object.keys,nativeBind=FuncProto.bind;var _=function(obj){return new wrapper(obj);};if(typeof exports!=='undefined'){if(typeof module!=='undefined'&&module.exports){exports=module.exports=_;} +exports._=_;}else{root['_']=_;} +_.VERSION='1.3.3';var each=_.each=_.forEach=function(obj,iterator,context){if(obj==null)return;if(nativeForEach&&obj.forEach===nativeForEach){obj.forEach(iterator,context);}else if(obj.length===+obj.length){for(var i=0,l=obj.length;i2;if(obj==null)obj=[];if(nativeReduce&&obj.reduce===nativeReduce){if(context)iterator=_.bind(iterator,context);return initial?obj.reduce(iterator,memo):obj.reduce(iterator);} +each(obj,function(value,index,list){if(!initial){memo=value;initial=true;}else{memo=iterator.call(context,memo,value,index,list);}});if(!initial)throw new TypeError('Reduce of empty array with no initial value');return memo;};_.reduceRight=_.foldr=function(obj,iterator,memo,context){var initial=arguments.length>2;if(obj==null)obj=[];if(nativeReduceRight&&obj.reduceRight===nativeReduceRight){if(context)iterator=_.bind(iterator,context);return initial?obj.reduceRight(iterator,memo):obj.reduceRight(iterator);} +var reversed=_.toArray(obj).reverse();if(context&&!initial)iterator=_.bind(iterator,context);return initial?_.reduce(reversed,iterator,memo,context):_.reduce(reversed,iterator);};_.find=_.detect=function(obj,iterator,context){var result;any(obj,function(value,index,list){if(iterator.call(context,value,index,list)){result=value;return true;}});return result;};_.filter=_.select=function(obj,iterator,context){var results=[];if(obj==null)return results;if(nativeFilter&&obj.filter===nativeFilter)return obj.filter(iterator,context);each(obj,function(value,index,list){if(iterator.call(context,value,index,list))results[results.length]=value;});return results;};_.reject=function(obj,iterator,context){var results=[];if(obj==null)return results;each(obj,function(value,index,list){if(!iterator.call(context,value,index,list))results[results.length]=value;});return results;};_.every=_.all=function(obj,iterator,context){var result=true;if(obj==null)return result;if(nativeEvery&&obj.every===nativeEvery)return obj.every(iterator,context);each(obj,function(value,index,list){if(!(result=result&&iterator.call(context,value,index,list)))return breaker;});return!!result;};var any=_.some=_.any=function(obj,iterator,context){iterator||(iterator=_.identity);var result=false;if(obj==null)return result;if(nativeSome&&obj.some===nativeSome)return obj.some(iterator,context);each(obj,function(value,index,list){if(result||(result=iterator.call(context,value,index,list)))return breaker;});return!!result;};_.include=_.contains=function(obj,target){var found=false;if(obj==null)return found;if(nativeIndexOf&&obj.indexOf===nativeIndexOf)return obj.indexOf(target)!=-1;found=any(obj,function(value){return value===target;});return found;};_.invoke=function(obj,method){var args=slice.call(arguments,2);return _.map(obj,function(value){return(_.isFunction(method)?method||value:value[method]).apply(value,args);});};_.pluck=function(obj,key){return _.map(obj,function(value){return value[key];});};_.max=function(obj,iterator,context){if(!iterator&&_.isArray(obj)&&obj[0]===+obj[0])return Math.max.apply(Math,obj);if(!iterator&&_.isEmpty(obj))return-Infinity;var result={computed:-Infinity};each(obj,function(value,index,list){var computed=iterator?iterator.call(context,value,index,list):value;computed>=result.computed&&(result={value:value,computed:computed});});return result.value;};_.min=function(obj,iterator,context){if(!iterator&&_.isArray(obj)&&obj[0]===+obj[0])return Math.min.apply(Math,obj);if(!iterator&&_.isEmpty(obj))return Infinity;var result={computed:Infinity};each(obj,function(value,index,list){var computed=iterator?iterator.call(context,value,index,list):value;computedb?1:0;}),'value');};_.groupBy=function(obj,val){var result={};var iterator=_.isFunction(val)?val:function(obj){return obj[val];};each(obj,function(value,index){var key=iterator(value,index);(result[key]||(result[key]=[])).push(value);});return result;};_.sortedIndex=function(array,obj,iterator){iterator||(iterator=_.identity);var low=0,high=array.length;while(low>1;iterator(array[mid])=0;});});};_.difference=function(array){var rest=_.flatten(slice.call(arguments,1),true);return _.filter(array,function(value){return!_.include(rest,value);});};_.zip=function(){var args=slice.call(arguments);var length=_.max(_.pluck(args,'length'));var results=new Array(length);for(var i=0;i=0;i--){args=[funcs[i].apply(this,args)];} +return args[0];};};_.after=function(times,func){if(times<=0)return func();return function(){if(--times<1){return func.apply(this,arguments);}};};_.keys=nativeKeys||function(obj){if(obj!==Object(obj))throw new TypeError('Invalid object');var keys=[];for(var key in obj)if(_.has(obj,key))keys[keys.length]=key;return keys;};_.values=function(obj){return _.map(obj,_.identity);};_.functions=_.methods=function(obj){var names=[];for(var key in obj){if(_.isFunction(obj[key]))names.push(key);} +return names.sort();};_.extend=function(obj){each(slice.call(arguments,1),function(source){for(var prop in source){obj[prop]=source[prop];}});return obj;};_.pick=function(obj){var result={};each(_.flatten(slice.call(arguments,1)),function(key){if(key in obj)result[key]=obj[key];});return result;};_.defaults=function(obj){each(slice.call(arguments,1),function(source){for(var prop in source){if(obj[prop]==null)obj[prop]=source[prop];}});return obj;};_.clone=function(obj){if(!_.isObject(obj))return obj;return _.isArray(obj)?obj.slice():_.extend({},obj);};_.tap=function(obj,interceptor){interceptor(obj);return obj;};function eq(a,b,stack){if(a===b)return a!==0||1/a==1/b;if(a==null||b==null)return a===b;if(a._chain)a=a._wrapped;if(b._chain)b=b._wrapped;if(a.isEqual&&_.isFunction(a.isEqual))return a.isEqual(b);if(b.isEqual&&_.isFunction(b.isEqual))return b.isEqual(a);var className=toString.call(a);if(className!=toString.call(b))return false;switch(className){case'[object String]':return a==String(b);case'[object Number]':return a!=+a?b!=+b:(a==0?1/a==1/b:a==+b);case'[object Date]':case'[object Boolean]':return+a==+b;case'[object RegExp]':return a.source==b.source&&a.global==b.global&&a.multiline==b.multiline&&a.ignoreCase==b.ignoreCase;} +if(typeof a!='object'||typeof b!='object')return false;var length=stack.length;while(length--){if(stack[length]==a)return true;} +stack.push(a);var size=0,result=true;if(className=='[object Array]'){size=a.length;result=size==b.length;if(result){while(size--){if(!(result=size in a==size in b&&eq(a[size],b[size],stack)))break;}}}else{if('constructor'in a!='constructor'in b||a.constructor!=b.constructor)return false;for(var key in a){if(_.has(a,key)){size++;if(!(result=_.has(b,key)&&eq(a[key],b[key],stack)))break;}} +if(result){for(key in b){if(_.has(b,key)&&!(size--))break;} +result=!size;}} +stack.pop();return result;} +_.isEqual=function(a,b){return eq(a,b,[]);};_.isEmpty=function(obj){if(obj==null)return true;if(_.isArray(obj)||_.isString(obj))return obj.length===0;for(var key in obj)if(_.has(obj,key))return false;return true;};_.isElement=function(obj){return!!(obj&&obj.nodeType==1);};_.isArray=nativeIsArray||function(obj){return toString.call(obj)=='[object Array]';};_.isObject=function(obj){return obj===Object(obj);};_.isArguments=function(obj){return toString.call(obj)=='[object Arguments]';};if(!_.isArguments(arguments)){_.isArguments=function(obj){return!!(obj&&_.has(obj,'callee'));};} +_.isFunction=function(obj){return toString.call(obj)=='[object Function]';};_.isString=function(obj){return toString.call(obj)=='[object String]';};_.isNumber=function(obj){return toString.call(obj)=='[object Number]';};_.isFinite=function(obj){return _.isNumber(obj)&&isFinite(obj);};_.isNaN=function(obj){return obj!==obj;};_.isBoolean=function(obj){return obj===true||obj===false||toString.call(obj)=='[object Boolean]';};_.isDate=function(obj){return toString.call(obj)=='[object Date]';};_.isRegExp=function(obj){return toString.call(obj)=='[object RegExp]';};_.isNull=function(obj){return obj===null;};_.isUndefined=function(obj){return obj===void 0;};_.has=function(obj,key){return hasOwnProperty.call(obj,key);};_.noConflict=function(){root._=previousUnderscore;return this;};_.identity=function(value){return value;};_.times=function(n,iterator,context){for(var i=0;i/g,'>').replace(/"/g,'"').replace(/'/g,''').replace(/\//g,'/');};_.result=function(object,property){if(object==null)return null;var value=object[property];return _.isFunction(value)?value.call(object):value;};_.mixin=function(obj){each(_.functions(obj),function(name){addToWrapper(name,_[name]=obj[name]);});};var idCounter=0;_.uniqueId=function(prefix){var id=idCounter++;return prefix?prefix+id:id;};_.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var noMatch=/.^/;var escapes={'\\':'\\',"'":"'",'r':'\r','n':'\n','t':'\t','u2028':'\u2028','u2029':'\u2029'};for(var p in escapes)escapes[escapes[p]]=p;var escaper=/\\|'|\r|\n|\t|\u2028|\u2029/g;var unescaper=/\\(\\|'|r|n|t|u2028|u2029)/g;var unescape=function(code){return code.replace(unescaper,function(match,escape){return escapes[escape];});};_.template=function(text,data,settings){settings=_.defaults(settings||{},_.templateSettings);var source="__p+='"+text.replace(escaper,function(match){return'\\'+escapes[match];}).replace(settings.escape||noMatch,function(match,code){return"'+\n_.escape("+unescape(code)+")+\n'";}).replace(settings.interpolate||noMatch,function(match,code){return"'+\n("+unescape(code)+")+\n'";}).replace(settings.evaluate||noMatch,function(match,code){return"';\n"+unescape(code)+"\n;__p+='";})+"';\n";if(!settings.variable)source='with(obj||{}){\n'+source+'}\n';source="var __p='';"+"var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n"+ +source+"return __p;\n";var render=new Function(settings.variable||'obj','_',source);if(data)return render(data,_);var template=function(data){return render.call(this,data,_);};template.source='function('+(settings.variable||'obj')+'){\n'+ +source+'}';return template;};_.chain=function(obj){return _(obj).chain();};var wrapper=function(obj){this._wrapped=obj;};_.prototype=wrapper.prototype;var result=function(obj,chain){return chain?_(obj).chain():obj;};var addToWrapper=function(name,func){wrapper.prototype[name]=function(){var args=slice.call(arguments);unshift.call(args,this._wrapped);return result(func.apply(_,args),this._chain);};};_.mixin(_);each(['pop','push','reverse','shift','sort','splice','unshift'],function(name){var method=ArrayProto[name];wrapper.prototype[name]=function(){var wrapped=this._wrapped;method.apply(wrapped,arguments);var length=wrapped.length;if((name=='shift'||name=='splice')&&length===0)delete wrapped[0];return result(wrapped,this._chain);};});each(['concat','join','slice'],function(name){var method=ArrayProto[name];wrapper.prototype[name]=function(){return result(method.apply(this._wrapped,arguments),this._chain);};});wrapper.prototype.chain=function(){this._chain=true;return this;};wrapper.prototype.value=function(){return this._wrapped;};return _;}).call({});var emmet=(function(global){var defaultSyntax='html';var defaultProfile='plain';if(typeof _=='undefined'){try{_=global[['require'][0]]('underscore');}catch(e){}} +if(typeof _=='undefined'){throw'Cannot access to Underscore.js lib';} +var modules={_:_};var ctor=function(){};function inherits(parent,protoProps,staticProps){var child;if(protoProps&&protoProps.hasOwnProperty('constructor')){child=protoProps.constructor;}else{child=function(){parent.apply(this,arguments);};} +_.extend(child,parent);ctor.prototype=parent.prototype;child.prototype=new ctor();if(protoProps) +_.extend(child.prototype,protoProps);if(staticProps) +_.extend(child,staticProps);child.prototype.constructor=child;child.__super__=parent.prototype;return child;};var moduleLoader=null;function r(name){if(!(name in modules)&&moduleLoader) +moduleLoader(name);return modules[name];} +return{define:function(name,factory){if(!(name in modules)){modules[name]=_.isFunction(factory)?this.exec(factory):factory;}},require:r,exec:function(fn,context){return fn.call(context||global,_.bind(r,this),_,this);},extend:function(protoProps,classProps){var child=inherits(this,protoProps,classProps);child.extend=this.extend;if(protoProps.hasOwnProperty('toString')) +child.prototype.toString=protoProps.toString;return child;},expandAbbreviation:function(abbr,syntax,profile,contextNode){if(!abbr)return'';syntax=syntax||defaultSyntax;var filters=r('filters');var parser=r('abbreviationParser');profile=r('profile').get(profile,syntax);r('tabStops').resetTabstopIndex();var data=filters.extractFromAbbreviation(abbr);var outputTree=parser.parse(data[0],{syntax:syntax,contextNode:contextNode});var filtersList=filters.composeList(syntax,profile,data[1]);filters.apply(outputTree,filtersList,profile);return outputTree.toString();},defaultSyntax:function(){return defaultSyntax;},defaultProfile:function(){return defaultProfile;},log:function(){if(global.console&&global.console.log) +global.console.log.apply(global.console,arguments);},setModuleLoader:function(fn){moduleLoader=fn;}};})(this);if(typeof exports!=='undefined'){if(typeof module!=='undefined'&&module.exports){exports=module.exports=emmet;} +exports.emmet=emmet;} +if(typeof define!=='undefined'){define('emmet',[],emmet);} +emmet.define('abbreviationParser',function(require,_){var reValidName=/^[\w\-\$\:@\!%]+\+?$/i;var reWord=/[\w\-:\$@]/;var pairs={'[':']','(':')','{':'}'};var spliceFn=Array.prototype.splice;var preprocessors=[];var postprocessors=[];var outputProcessors=[];function AbbreviationNode(parent){this.parent=null;this.children=[];this._attributes=[];this.abbreviation='';this.counter=1;this._name=null;this._text='';this.repeatCount=1;this.hasImplicitRepeat=false;this._data={};this.start='';this.end='';this.content='';this.padding='';} +AbbreviationNode.prototype={addChild:function(child,position){child=child||new AbbreviationNode;child.parent=this;if(_.isUndefined(position)){this.children.push(child);}else{this.children.splice(position,0,child);} +return child;},clone:function(){var node=new AbbreviationNode();var attrs=['abbreviation','counter','_name','_text','repeatCount','hasImplicitRepeat','start','end','content','padding'];_.each(attrs,function(a){node[a]=this[a];},this);node._attributes=_.map(this._attributes,function(attr){return _.clone(attr);});node._data=_.clone(this._data);node.children=_.map(this.children,function(child){child=child.clone();child.parent=node;return child;});return node;},remove:function(){if(this.parent){this.parent.children=_.without(this.parent.children,this);} +return this;},replace:function(){var parent=this.parent;var ix=_.indexOf(parent.children,this);var items=_.flatten(arguments);spliceFn.apply(parent.children,[ix,1].concat(items));_.each(items,function(item){item.parent=parent;});},updateProperty:function(name,value){this[name]=value;_.each(this.children,function(child){child.updateProperty(name,value);});return this;},find:function(fn){return this.findAll(fn)[0];},findAll:function(fn){if(!_.isFunction(fn)){var elemName=fn.toLowerCase();fn=function(item){return item.name().toLowerCase()==elemName;};} +var result=[];_.each(this.children,function(child){if(fn(child)) +result.push(child);result=result.concat(child.findAll(fn));});return _.compact(result);},data:function(name,value){if(arguments.length==2){this._data[name]=value;if(name=='resource'&&require('elements').is(value,'snippet')){this.content=value.data;if(this._text){this.content=require('abbreviationUtils').insertChildContent(value.data,this._text);}}} +return this._data[name];},name:function(){var res=this.matchedResource();if(require('elements').is(res,'element')){return res.name;} +return this._name;},attributeList:function(){var attrs=[];var res=this.matchedResource();if(require('elements').is(res,'element')&&_.isArray(res.attributes)){attrs=attrs.concat(res.attributes);} +return optimizeAttributes(attrs.concat(this._attributes));},attribute:function(name,value){if(arguments.length==2){var ix=_.indexOf(_.pluck(this._attributes,'name'),name.toLowerCase());if(~ix){this._attributes[ix].value=value;}else{this._attributes.push({name:name,value:value});}} +return(_.find(this.attributeList(),function(attr){return attr.name==name;})||{}).value;},matchedResource:function(){return this.data('resource');},index:function(){return this.parent?_.indexOf(this.parent.children,this):-1;},_setRepeat:function(count){if(count){this.repeatCount=parseInt(count,10)||1;}else{this.hasImplicitRepeat=true;}},setAbbreviation:function(abbr){abbr=abbr||'';var that=this;abbr=abbr.replace(/\*(\d+)?$/,function(str,repeatCount){that._setRepeat(repeatCount);return'';});this.abbreviation=abbr;var abbrText=extractText(abbr);if(abbrText){abbr=abbrText.element;this.content=this._text=abbrText.text;} +var abbrAttrs=parseAttributes(abbr);if(abbrAttrs){abbr=abbrAttrs.element;this._attributes=abbrAttrs.attributes;} +this._name=abbr;if(this._name&&!reValidName.test(this._name)){throw'Invalid abbreviation';}},toString:function(){var utils=require('utils');var start=this.start;var end=this.end;var content=this.content;var node=this;_.each(outputProcessors,function(fn){start=fn(start,node,'start');content=fn(content,node,'content');end=fn(end,node,'end');});var innerContent=_.map(this.children,function(child){return child.toString();}).join('');content=require('abbreviationUtils').insertChildContent(content,innerContent,{keepVariable:false});return start+utils.padString(content,this.padding)+end;},hasEmptyChildren:function(){return!!_.find(this.children,function(child){return child.isEmpty();});},hasImplicitName:function(){return!this._name&&!this.isTextNode();},isGroup:function(){return!this.abbreviation;},isEmpty:function(){return!this.abbreviation&&!this.children.length;},isRepeating:function(){return this.repeatCount>1||this.hasImplicitRepeat;},isTextNode:function(){return!this.name()&&!this.attributeList().length;},isElement:function(){return!this.isEmpty()&&!this.isTextNode();},deepestChild:function(){if(!this.children.length) +return null;var deepestChild=this;while(deepestChild.children.length){deepestChild=_.last(deepestChild.children);} +return deepestChild;}};function stripped(str){return str.substring(1,str.length-1);} +function consumeQuotedValue(stream,quote){var ch;while(ch=stream.next()){if(ch===quote) +return true;if(ch=='\\') +continue;} +return false;} +function parseAbbreviation(abbr){abbr=require('utils').trim(abbr);var root=new AbbreviationNode;var context=root.addChild(),ch;var stream=require('stringStream').create(abbr);var loopProtector=1000,multiplier;while(!stream.eol()&&--loopProtector>0){ch=stream.peek();switch(ch){case'(':stream.start=stream.pos;if(stream.skipToPair('(',')')){var inner=parseAbbreviation(stripped(stream.current()));if(multiplier=stream.match(/^\*(\d+)?/,true)){context._setRepeat(multiplier[1]);} +_.each(inner.children,function(child){context.addChild(child);});}else{throw'Invalid abbreviation: mo matching ")" found for character at '+stream.pos;} +break;case'>':context=context.addChild();stream.next();break;case'+':context=context.parent.addChild();stream.next();break;case'^':var parent=context.parent||context;context=(parent.parent||parent).addChild();stream.next();break;default:stream.start=stream.pos;stream.eatWhile(function(c){if(c=='['||c=='{'){if(stream.skipToPair(c,pairs[c])){stream.backUp(1);return true;} +throw'Invalid abbreviation: mo matching "'+pairs[c]+'" found for character at '+stream.pos;} +if(c=='+'){stream.next();var isMarker=stream.eol()||~'+>^*'.indexOf(stream.peek());stream.backUp(1);return isMarker;} +return c!='('&&isAllowedChar(c);});context.setAbbreviation(stream.current());stream.start=stream.pos;}} +if(loopProtector<1) +throw'Endless loop detected';return root;} +function extractAttributes(attrSet,attrs){attrSet=require('utils').trim(attrSet);var result=[];var stream=require('stringStream').create(attrSet);stream.eatSpace();while(!stream.eol()){stream.start=stream.pos;if(stream.eatWhile(reWord)){var attrName=stream.current();var attrValue='';if(stream.peek()=='='){stream.next();stream.start=stream.pos;var quote=stream.peek();if(quote=='"'||quote=="'"){stream.next();if(consumeQuotedValue(stream,quote)){attrValue=stream.current();attrValue=attrValue.substring(1,attrValue.length-1);}else{throw'Invalid attribute value';}}else if(stream.eatWhile(/[^\s\]]/)){attrValue=stream.current();}else{throw'Invalid attribute value';}} +result.push({name:attrName,value:attrValue});stream.eatSpace();}else{break;}} +return result;} +function parseAttributes(abbr){var result=[];var attrMap={'#':'id','.':'class'};var nameEnd=null;var stream=require('stringStream').create(abbr);while(!stream.eol()){switch(stream.peek()){case'#':case'.':if(nameEnd===null) +nameEnd=stream.pos;var attrName=attrMap[stream.peek()];stream.next();stream.start=stream.pos;stream.eatWhile(reWord);result.push({name:attrName,value:stream.current()});break;case'[':if(nameEnd===null) +nameEnd=stream.pos;stream.start=stream.pos;if(!stream.skipToPair('[',']')) +throw'Invalid attribute set definition';result=result.concat(extractAttributes(stripped(stream.current())));break;default:stream.next();}} +if(!result.length) +return null;return{element:abbr.substring(0,nameEnd),attributes:optimizeAttributes(result)};} +function optimizeAttributes(attrs){attrs=_.map(attrs,function(attr){return _.clone(attr);});var lookup={};return _.filter(attrs,function(attr){if(!(attr.name in lookup)){return lookup[attr.name]=attr;} +var la=lookup[attr.name];if(attr.name.toLowerCase()=='class'){la.value+=(la.value.length?' ':'')+attr.value;}else{la.value=attr.value;} +return false;});} +function extractText(abbr){if(!~abbr.indexOf('{')) +return null;var stream=require('stringStream').create(abbr);while(!stream.eol()){switch(stream.peek()){case'[':case'(':stream.skipToPair(stream.peek(),pairs[stream.peek()]);break;case'{':stream.start=stream.pos;stream.skipToPair('{','}');return{element:abbr.substring(0,stream.start),text:stripped(stream.current())};default:stream.next();}}} +function unroll(node){for(var i=node.children.length-1,j,child,maxCount;i>=0;i--){child=node.children[i];if(child.isRepeating()){maxCount=j=child.repeatCount;child.repeatCount=1;child.updateProperty('counter',1);child.updateProperty('maxCount',maxCount);while(--j>0){child.parent.addChild(child.clone(),i+1).updateProperty('counter',j+1).updateProperty('maxCount',maxCount);}}} +_.each(node.children,unroll);return node;} +function squash(node){for(var i=node.children.length-1;i>=0;i--){var n=node.children[i];if(n.isGroup()){n.replace(squash(n).children);}else if(n.isEmpty()){n.remove();}} +_.each(node.children,squash);return node;} +function isAllowedChar(ch){var charCode=ch.charCodeAt(0);var specialChars='#.*:$-_!@|%';return(charCode>64&&charCode<91)||(charCode>96&&charCode<123)||(charCode>47&&charCode<58)||specialChars.indexOf(ch)!=-1;} +outputProcessors.push(function(text,node){return require('utils').replaceCounter(text,node.counter,node.maxCount);});return{parse:function(abbr,options){options=options||{};var tree=parseAbbreviation(abbr);if(options.contextNode){tree._name=options.contextNode.name;var attrLookup={};_.each(tree._attributes,function(attr){attrLookup[attr.name]=attr;});_.each(options.contextNode.attributes,function(attr){if(attr.name in attrLookup){attrLookup[attr.name].value=attr.value;}else{attr=_.clone(attr);tree._attributes.push(attr);attrLookup[attr.name]=attr;}});} +_.each(preprocessors,function(fn){fn(tree,options);});tree=squash(unroll(tree));_.each(postprocessors,function(fn){fn(tree,options);});return tree;},AbbreviationNode:AbbreviationNode,addPreprocessor:function(fn){if(!_.include(preprocessors,fn)) +preprocessors.push(fn);},removeFilter:function(fn){preprocessor=_.without(preprocessors,fn);},addPostprocessor:function(fn){if(!_.include(postprocessors,fn)) +postprocessors.push(fn);},removePostprocessor:function(fn){postprocessors=_.without(postprocessors,fn);},addOutputProcessor:function(fn){if(!_.include(outputProcessors,fn)) +outputProcessors.push(fn);},removeOutputProcessor:function(fn){outputProcessors=_.without(outputProcessors,fn);},isAllowedChar:function(ch){ch=String(ch);return isAllowedChar(ch)||~'>+^[](){}'.indexOf(ch);}};});emmet.exec(function(require,_){function matchResources(node,syntax){var resources=require('resources');var elements=require('elements');var parser=require('abbreviationParser');_.each(_.clone(node.children),function(child){var r=resources.getMatchedResource(child,syntax);if(_.isString(r)){child.data('resource',elements.create('snippet',r));}else if(elements.is(r,'reference')){var subtree=parser.parse(r.data,{syntax:syntax});if(child.repeatCount>1){var repeatedChildren=subtree.findAll(function(node){return node.hasImplicitRepeat;});_.each(repeatedChildren,function(node){node.repeatCount=child.repeatCount;node.hasImplicitRepeat=false;});} +var deepestChild=subtree.deepestChild();if(deepestChild){_.each(child.children,function(c){deepestChild.addChild(c);});} +_.each(subtree.children,function(node){_.each(child.attributeList(),function(attr){node.attribute(attr.name,attr.value);});});child.replace(subtree.children);}else{child.data('resource',r);} +matchResources(child,syntax);});} +require('abbreviationParser').addPreprocessor(function(tree,options){var syntax=options.syntax||emmet.defaultSyntax();matchResources(tree,syntax);});});emmet.exec(function(require,_){var parser=require('abbreviationParser');var outputPlaceholder='$#';function locateOutputPlaceholder(text){var range=require('range');var result=[];var stream=require('stringStream').create(text);while(!stream.eol()){if(stream.peek()=='\\'){stream.next();}else{stream.start=stream.pos;if(stream.match(outputPlaceholder,true)){result.push(range.create(stream.start,outputPlaceholder));continue;}} +stream.next();} +return result;} +function replaceOutputPlaceholders(source,value){var utils=require('utils');var ranges=locateOutputPlaceholder(source);ranges.reverse();_.each(ranges,function(r){source=utils.replaceSubstring(source,value,r);});return source;} +function hasOutputPlaceholder(node){if(locateOutputPlaceholder(node.content).length) +return true;return!!_.find(node.attributeList(),function(attr){return!!locateOutputPlaceholder(attr.value).length;});} +function insertPastedContent(node,content,overwrite){var nodesWithPlaceholders=node.findAll(function(item){return hasOutputPlaceholder(item);});if(hasOutputPlaceholder(node)) +nodesWithPlaceholders.unshift(node);if(nodesWithPlaceholders.length){_.each(nodesWithPlaceholders,function(item){item.content=replaceOutputPlaceholders(item.content,content);_.each(item._attributes,function(attr){attr.value=replaceOutputPlaceholders(attr.value,content);});});}else{var deepest=node.deepestChild()||node;if(overwrite){deepest.content=content;}else{deepest.content=require('abbreviationUtils').insertChildContent(deepest.content,content);}}} +parser.addPreprocessor(function(tree,options){if(options.pastedContent){var utils=require('utils');var lines=_.map(utils.splitByLines(options.pastedContent,true),utils.trim);tree.findAll(function(item){if(item.hasImplicitRepeat){item.data('paste',lines);return item.repeatCount=lines.length;}});}});parser.addPostprocessor(function(tree,options){var targets=tree.findAll(function(item){var pastedContentObj=item.data('paste');var pastedContent='';if(_.isArray(pastedContentObj)){pastedContent=pastedContentObj[item.counter-1];}else if(_.isFunction(pastedContentObj)){pastedContent=pastedContentObj(item.counter-1,item.content);}else if(pastedContentObj){pastedContent=pastedContentObj;} +if(pastedContent){insertPastedContent(item,pastedContent,!!item.data('pasteOverwrites'));} +item.data('paste',null);return!!pastedContentObj;});if(!targets.length&&options.pastedContent){insertPastedContent(tree,options.pastedContent);}});});emmet.exec(function(require,_){function resolveNodeNames(tree){var tagName=require('tagName');_.each(tree.children,function(node){if(node.hasImplicitName()||node.data('forceNameResolving')){node._name=tagName.resolve(node.parent.name());} +resolveNodeNames(node);});return tree;} +require('abbreviationParser').addPostprocessor(resolveNodeNames);});emmet.define('cssParser',function(require,_){var walker,tokens=[],isOp,isNameChar,isDigit;walker={lines:null,total_lines:0,linenum:-1,line:'',ch:'',chnum:-1,init:function(source){var me=walker;me.lines=source.replace(/\r\n/g,'\n').replace(/\r/g,'\n').split('\n');me.total_lines=me.lines.length;me.chnum=-1;me.linenum=-1;me.ch='';me.line='';me.nextLine();me.nextChar();},nextLine:function(){var me=this;me.linenum+=1;if(me.total_lines<=me.linenum){me.line=false;}else{me.line=me.lines[me.linenum];} +if(me.chnum!==-1){me.chnum=0;} +return me.line;},nextChar:function(){var me=this;me.chnum+=1;while(me.line.charAt(me.chnum)===''){if(this.nextLine()===false){me.ch=false;return false;} +me.chnum=-1;me.ch='\n';return'\n';} +me.ch=me.line.charAt(me.chnum);return me.ch;},peek:function(){return this.line.charAt(this.chnum+1);}};isNameChar=function(c){return(c=='&'||c==='_'||c==='-'||(c>='a'&&c<='z')||(c>='A'&&c<='Z'));};isDigit=function(ch){return(ch!==false&&ch>='0'&&ch<='9');};isOp=(function(){var opsa="{}[]()+*=.,;:>~|\\%$#@^!".split(''),opsmatcha="*^|$~".split(''),ops={},opsmatch={},i=0;for(;i"));else +return null;}else if(stream.match("--")) +return chain(inBlock("comment","-->"));else if(stream.match("DOCTYPE",true,true)){stream.eatWhile(/[\w\._\-]/);return chain(doctype(1));}else +return null;}else if(stream.eat("?")){stream.eatWhile(/[\w\._\-]/);state.tokenize=inBlock("meta","?>");return"meta";}else{type=stream.eat("/")?"closeTag":"openTag";stream.eatSpace();tagName="";var c;while((c=stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) +tagName+=c;state.tokenize=inTag;return"tag";}}else if(ch=="&"){var ok;if(stream.eat("#")){if(stream.eat("x")){ok=stream.eatWhile(/[a-fA-F\d]/)&&stream.eat(";");}else{ok=stream.eatWhile(/[\d]/)&&stream.eat(";");}}else{ok=stream.eatWhile(/[\w\.\-:]/)&&stream.eat(";");} +return ok?"atom":"error";}else{stream.eatWhile(/[^&<]/);return"text";}} +function inTag(stream,state){var ch=stream.next();if(ch==">"||(ch=="/"&&stream.eat(">"))){state.tokenize=inText;type=ch==">"?"endTag":"selfcloseTag";return"tag";}else if(ch=="="){type="equals";return null;}else if(/[\'\"]/.test(ch)){state.tokenize=inAttribute(ch);return state.tokenize(stream,state);}else{stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/);return"word";}} +function inAttribute(quote){return function(stream,state){while(!stream.eol()){if(stream.next()==quote){state.tokenize=inTag;break;}} +return"string";};} +function inBlock(style,terminator){return function(stream,state){while(!stream.eol()){if(stream.match(terminator)){state.tokenize=inText;break;} +stream.next();} +return style;};} +function doctype(depth){return function(stream,state){var ch;while((ch=stream.next())!=null){if(ch=="<"){state.tokenize=doctype(depth+1);return state.tokenize(stream,state);}else if(ch==">"){if(depth==1){state.tokenize=inText;break;}else{state.tokenize=doctype(depth-1);return state.tokenize(stream,state);}}} +return"meta";};} +var curState=null,setStyle;function pass(){for(var i=arguments.length-1;i>=0;i--) +curState.cc.push(arguments[i]);} +function cont(){pass.apply(null,arguments);return true;} +function pushContext(tagName,startOfLine){var noIndent=Kludges.doNotIndent.hasOwnProperty(tagName)||(curState.context&&curState.context.noIndent);curState.context={prev:curState.context,tagName:tagName,indent:curState.indented,startOfLine:startOfLine,noIndent:noIndent};} +function popContext(){if(curState.context) +curState.context=curState.context.prev;} +function element(type){if(type=="openTag"){curState.tagName=tagName;return cont(attributes,endtag(curState.startOfLine));}else if(type=="closeTag"){var err=false;if(curState.context){if(curState.context.tagName!=tagName){if(Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())){popContext();} +err=!curState.context||curState.context.tagName!=tagName;}}else{err=true;} +if(err) +setStyle="error";return cont(endclosetag(err));} +return cont();} +function endtag(startOfLine){return function(type){if(type=="selfcloseTag"||(type=="endTag"&&Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase()))){maybePopContext(curState.tagName.toLowerCase());return cont();} +if(type=="endTag"){maybePopContext(curState.tagName.toLowerCase());pushContext(curState.tagName,startOfLine);return cont();} +return cont();};} +function endclosetag(err){return function(type){if(err) +setStyle="error";if(type=="endTag"){popContext();return cont();} +setStyle="error";return cont(arguments.callee);};} +function maybePopContext(nextTagName){var parentTagName;while(true){if(!curState.context){return;} +parentTagName=curState.context.tagName.toLowerCase();if(!Kludges.contextGrabbers.hasOwnProperty(parentTagName)||!Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)){return;} +popContext();}} +function attributes(type){if(type=="word"){setStyle="attribute";return cont(attribute,attributes);} +if(type=="endTag"||type=="selfcloseTag") +return pass();setStyle="error";return cont(attributes);} +function attribute(type){if(type=="equals") +return cont(attvalue,attributes);if(!Kludges.allowMissing) +setStyle="error";return(type=="endTag"||type=="selfcloseTag")?pass():cont();} +function attvalue(type){if(type=="string") +return cont(attvaluemaybe);if(type=="word"&&Kludges.allowUnquoted){setStyle="string";return cont();} +setStyle="error";return(type=="endTag"||type=="selfCloseTag")?pass():cont();} +function attvaluemaybe(type){if(type=="string") +return cont(attvaluemaybe);else +return pass();} +function startState(){return{tokenize:inText,cc:[],indented:0,startOfLine:true,tagName:null,context:null};} +function token(stream,state){if(stream.sol()){state.startOfLine=true;state.indented=0;} +if(stream.eatSpace()) +return null;setStyle=type=tagName=null;var style=state.tokenize(stream,state);state.type=type;if((style||type)&&style!="comment"){curState=state;while(true){var comb=state.cc.pop()||element;if(comb(type||style)) +break;}} +state.startOfLine=false;return setStyle||style;} +return{parse:function(data,offset){offset=offset||0;var state=startState();var stream=require('stringStream').create(data);var tokens=[];while(!stream.eol()){tokens.push({type:token(stream,state),start:stream.start+offset,end:stream.pos+offset});stream.start=stream.pos;} +return tokens;}};});emmet.define('string-score',function(require,_){return{score:function(string,abbreviation,fuzziness){if(string==abbreviation){return 1;} +if(abbreviation==""){return 0;} +var total_character_score=0,abbreviation_length=abbreviation.length,string_length=string.length,start_of_string_bonus,abbreviation_score,fuzzies=1,final_score;for(var i=0,character_score,index_in_string,c,index_c_lowercase,index_c_uppercase,min_index;i-1)?min_index:Math.max(index_c_lowercase,index_c_uppercase);if(index_in_string===-1){if(fuzziness){fuzzies+=1-fuzziness;continue;}else{return 0;}}else{character_score=0.1;} +if(string[index_in_string]===c){character_score+=0.1;} +if(index_in_string===0){character_score+=0.6;if(i===0){start_of_string_bonus=1;}} +else{if(string.charAt(index_in_string-1)===' '){character_score+=0.8;}} +string=string.substring(index_in_string+1,string_length);total_character_score+=character_score;} +abbreviation_score=total_character_score/abbreviation_length;final_score=((abbreviation_score*(abbreviation_length/string_length))+abbreviation_score)/2;final_score=final_score/fuzzies;if(start_of_string_bonus&&(final_score+0.15<1)){final_score+=0.15;} +return final_score;}};});emmet.define('utils',function(require,_){var caretPlaceholder='${0}';function StringBuilder(value){this._data=[];this.length=0;if(value) +this.append(value);} +StringBuilder.prototype={append:function(text){this._data.push(text);this.length+=text.length;},toString:function(){return this._data.join('');},valueOf:function(){return this.toString();}};return{reTag:/<\/?[\w:\-]+(?:\s+[\w\-:]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*\s*(\/?)>$/,endsWithTag:function(str){return this.reTag.test(str);},isNumeric:function(ch){if(typeof(ch)=='string') +ch=ch.charCodeAt(0);return(ch&&ch>47&&ch<58);},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},getNewline:function(){var res=require('resources');if(!res){return'\n';} +var nl=res.getVariable('newline');return _.isString(nl)?nl:'\n';},setNewline:function(str){var res=require('resources');res.setVariable('newline',str);res.setVariable('nl',str);},splitByLines:function(text,removeEmpty){var nl=this.getNewline();var lines=(text||'').replace(/\r\n/g,'\n').replace(/\n\r/g,'\n').replace(/\r/g,'\n').replace(/\n/g,nl).split(nl);if(removeEmpty){lines=_.filter(lines,function(line){return line.length&&!!this.trim(line);},this);} +return lines;},normalizeNewline:function(text){return this.splitByLines(text).join(this.getNewline());},repeatString:function(str,howMany){var result=[];for(var i=0;iil++)padding+='0';return padding+str;},unindentString:function(text,pad){var lines=this.splitByLines(text);for(var i=0;istr.length) +return str;return str.substring(0,start)+value+str.substring(end);},narrowToNonSpace:function(text,start,end){var range=require('range').create(start,end);var reSpace=/[\s\n\r\u00a0]/;while(range.startrange.start){range.end--;if(!reSpace.test(text.charAt(range.end))){range.end++;break;}} +return range;},findNewlineBounds:function(text,from){var len=text.length,start=0,end=len-1;for(var i=from-1;i>0;i--){var ch=text.charAt(i);if(ch=='\n'||ch=='\r'){start=i+1;break;}} +for(var j=from;j':return a>b;case'gte':case'>=':return a>=b;}} +function Range(start,len){if(_.isObject(start)&&'start'in start){this.start=Math.min(start.start,start.end);this.end=Math.max(start.start,start.end);}else if(_.isArray(start)){this.start=start[0];this.end=start[1];}else{len=_.isString(len)?len.length:+len;this.start=start;this.end=start+len;}} +Range.prototype={length:function(){return Math.abs(this.end-this.start);},equal:function(range){return this.cmp(range,'eq','eq');},shift:function(delta){this.start+=delta;this.end+=delta;return this;},overlap:function(range){return range.start<=this.end&&range.end>=this.start;},intersection:function(range){if(this.overlap(range)){var start=Math.max(range.start,this.start);var end=Math.min(range.end,this.end);return new Range(start,end-start);} +return null;},union:function(range){if(this.overlap(range)){var start=Math.min(range.start,this.start);var end=Math.max(range.end,this.end);return new Range(start,end-start);} +return null;},inside:function(loc){return this.cmp(loc,'lte','gt');},contains:function(loc){return this.cmp(loc,'lt','gt');},include:function(r){return this.cmp(loc,'lte','gte');},cmp:function(loc,left,right){var a,b;if(loc instanceof Range){a=loc.start;b=loc.end;}else{a=b=loc;} +return cmp(this.start,a,left||'<=')&&cmp(this.end,b,right||'>');},substring:function(str){return this.length()>0?str.substring(this.start,this.end):'';},clone:function(){return new Range(this.start,this.length());},toArray:function(){return[this.start,this.end];},toString:function(){return'{'+this.start+', '+this.length()+'}';}};return{create:function(start,len){if(_.isUndefined(start)||start===null) +return null;if(start instanceof Range) +return start;if(_.isObject(start)&&'start'in start&&'end'in start){len=start.end-start.start;start=start.start;} +return new Range(start,len);},create2:function(start,end){if(_.isNumber(start)&&_.isNumber(end)){end-=start;} +return this.create(start,end);}};});emmet.define('handlerList',function(require,_){function HandlerList(){this._list=[];} +HandlerList.prototype={add:function(fn,options){this._list.push(_.extend({order:0},options||{},{fn:fn}));},remove:function(fn){this._list=_.without(this._list,_.find(this._list,function(item){return item.fn===fn;}));},list:function(){return _.sortBy(this._list,'order').reverse();},listFn:function(){return _.pluck(this.list(),'fn');},exec:function(skipValue,args){args=args||[];var result=null;_.find(this.list(),function(h){result=h.fn.apply(h,args);if(result!==skipValue) +return true;});return result;}};return{create:function(){return new HandlerList();}};});emmet.define('tokenIterator',function(require,_){function TokenIterator(tokens){this.tokens=tokens;this._position=0;this.reset();} +TokenIterator.prototype={next:function(){if(this.hasNext()){var token=this.tokens[++this._i];this._position=token.start;return token;} +return null;},current:function(){return this.tokens[this._i];},position:function(){return this._position;},hasNext:function(){return this._i=this.string.length;},sol:function(){return this.pos==0;},peek:function(){return this.string.charAt(this.pos);},next:function(){if(this.posstart;},eatSpace:function(){var start=this.pos;while(/[\s\u00a0]/.test(this.string.charAt(this.pos))) +++this.pos;return this.pos>start;},skipToEnd:function(){this.pos=this.string.length;},skipTo:function(ch){var found=this.string.indexOf(ch,this.pos);if(found>-1){this.pos=found;return true;}},skipToPair:function(open,close){var braceCount=0,ch;var pos=this.pos,len=this.string.length;while(pos/;var systemSettings={};var userSettings={};var resolvers=require('handlerList').create();function normalizeCaretPlaceholder(text){var utils=require('utils');return utils.replaceUnescapedSymbol(text,'|',utils.getCaretPlaceholder());} +function parseItem(name,value,type){value=normalizeCaretPlaceholder(value);if(type=='snippets'){return require('elements').create('snippet',value);} +if(type=='abbreviations'){return parseAbbreviation(name,value);}} +function parseAbbreviation(key,value){key=require('utils').trim(key);var elements=require('elements');var m;if(m=reTag.exec(value)){return elements.create('element',m[1],m[2],m[4]=='/');}else{return elements.create('reference',value);}} +function normalizeName(str){return str.replace(/:$/,'').replace(/:/g,'-');} +return{setVocabulary:function(data,type){cache={};if(type==VOC_SYSTEM) +systemSettings=data;else +userSettings=data;},getVocabulary:function(name){return name==VOC_SYSTEM?systemSettings:userSettings;},getMatchedResource:function(node,syntax){return resolvers.exec(null,_.toArray(arguments))||this.findSnippet(syntax,node.name());},getVariable:function(name){return(this.getSection('variables')||{})[name];},setVariable:function(name,value){var voc=this.getVocabulary('user')||{};if(!('variables'in voc)) +voc.variables={};voc.variables[name]=value;this.setVocabulary(voc,'user');},hasSyntax:function(syntax){return syntax in this.getVocabulary(VOC_USER)||syntax in this.getVocabulary(VOC_SYSTEM);},addResolver:function(fn,options){resolvers.add(fn,options);},removeResolver:function(fn){resolvers.remove(fn);},getSection:function(name){if(!name) +return null;if(!(name in cache)){cache[name]=require('utils').deepMerge({},systemSettings[name],userSettings[name]);} +var data=cache[name],subsections=_.rest(arguments),key;while(data&&(key=subsections.shift())){if(key in data){data=data[key];}else{return null;}} +return data;},findItem:function(topSection,subsection){var data=this.getSection(topSection);while(data){if(subsection in data) +return data[subsection];data=this.getSection(data['extends']);}},findSnippet:function(syntax,name,memo){if(!syntax||!name) +return null;memo=memo||[];var names=[name];if(~name.indexOf('-')) +names.push(name.replace(/\-/g,':'));var data=this.getSection(syntax),matchedItem=null;_.find(['snippets','abbreviations'],function(sectionName){var data=this.getSection(syntax,sectionName);if(data){return _.find(names,function(n){if(data[n]) +return matchedItem=parseItem(n,data[n],sectionName);});}},this);memo.push(syntax);if(!matchedItem&&data['extends']&&!_.include(memo,data['extends'])){return this.findSnippet(data['extends'],name,memo);} +return matchedItem;},fuzzyFindSnippet:function(syntax,name,minScore){minScore=minScore||0.3;var payload=this.getAllSnippets(syntax);var sc=require('string-score');name=normalizeName(name);var scores=_.map(payload,function(value,key){return{key:key,score:sc.score(value.nk,name,0.1)};});var result=_.last(_.sortBy(scores,'score'));if(result&&result.score>=minScore){var k=result.key;return payload[k].parsedValue;}},getAllSnippets:function(syntax){var cacheKey='all-'+syntax;if(!cache[cacheKey]){var stack=[],sectionKey=syntax;var memo=[];do{var section=this.getSection(sectionKey);if(!section) +break;_.each(['snippets','abbreviations'],function(sectionName){var stackItem={};_.each(section[sectionName]||null,function(v,k){stackItem[k]={nk:normalizeName(k),value:v,parsedValue:parseItem(k,v,sectionName),type:sectionName};});stack.push(stackItem);});memo.push(sectionKey);sectionKey=section['extends'];}while(sectionKey&&!_.include(memo,sectionKey));cache[cacheKey]=_.extend.apply(_,stack.reverse());} +return cache[cacheKey];}};});emmet.define('actions',function(require,_,zc){var actions={};function humanizeActionName(name){return require('utils').trim(name.charAt(0).toUpperCase() ++name.substring(1).replace(/_[a-z]/g,function(str){return' '+str.charAt(1).toUpperCase();}));} +return{add:function(name,fn,options){name=name.toLowerCase();options=options||{};if(!options.label){options.label=humanizeActionName(name);} +actions[name]={name:name,fn:fn,options:options};},get:function(name){return actions[name.toLowerCase()];},run:function(name,args){if(!_.isArray(args)){args=_.rest(arguments);} +var action=this.get(name);if(action){return action.fn.apply(emmet,args);}else{emmet.log('Action "%s" is not defined',name);return false;}},getAll:function(){return actions;},getList:function(){return _.values(this.getAll());},getMenu:function(skipActions){var result=[];skipActions=skipActions||[];_.each(this.getList(),function(action){if(action.options.hidden||_.include(skipActions,action.name)) +return;var actionName=humanizeActionName(action.name);var ctx=result;if(action.options.label){var parts=action.options.label.split('/');actionName=parts.pop();var menuName,submenu;while(menuName=parts.shift()){submenu=_.find(ctx,function(item){return item.type=='submenu'&&item.name==menuName;});if(!submenu){submenu={name:menuName,type:'submenu',items:[]};ctx.push(submenu);} +ctx=submenu.items;}} +ctx.push({type:'action',name:action.name,label:actionName});});return result;},getActionNameForMenuTitle:function(title,menu){var item=null;_.find(menu||this.getMenu(),function(val){if(val.type=='action'){if(val.label==title||val.name==title){return item=val.name;}}else{return item=this.getActionNameForMenuTitle(title,val.items);}},this);return item||null;}};});emmet.define('profile',function(require,_){var profiles={};var defaultProfile={tag_case:'asis',attr_case:'asis',attr_quotes:'double',tag_nl:'decide',tag_nl_leaf:false,place_cursor:true,indent:true,inline_break:3,self_closing_tag:'xhtml',filters:'',extraFilters:''};function OutputProfile(options){_.extend(this,defaultProfile,options);} +OutputProfile.prototype={tagName:function(name){return stringCase(name,this.tag_case);},attributeName:function(name){return stringCase(name,this.attr_case);},attributeQuote:function(){return this.attr_quotes=='single'?"'":'"';},selfClosing:function(param){if(this.self_closing_tag=='xhtml') +return' /';if(this.self_closing_tag===true) +return'/';return'';},cursor:function(){return this.place_cursor?require('utils').getCaretPlaceholder():'';}};function stringCase(str,caseValue){switch(String(caseValue||'').toLowerCase()){case'lower':return str.toLowerCase();case'upper':return str.toUpperCase();} +return str;} +function createProfile(name,options){return profiles[name.toLowerCase()]=new OutputProfile(options);} +function createDefaultProfiles(){createProfile('xhtml');createProfile('html',{self_closing_tag:false});createProfile('xml',{self_closing_tag:true,tag_nl:true});createProfile('plain',{tag_nl:false,indent:false,place_cursor:false});createProfile('line',{tag_nl:false,indent:false,extraFilters:'s'});} +createDefaultProfiles();return{create:function(name,options){if(arguments.length==2) +return createProfile(name,options);else +return new OutputProfile(_.defaults(name||{},defaultProfile));},get:function(name,syntax){if(!name&&syntax){var profile=require('resources').findItem(syntax,'profile');if(profile){name=profile;}} +if(!name){return profiles.plain;} +if(name instanceof OutputProfile){return name;} +if(_.isString(name)&&name.toLowerCase()in profiles){return profiles[name.toLowerCase()];} +return this.create(name);},remove:function(name){name=(name||'').toLowerCase();if(name in profiles) +delete profiles[name];},reset:function(){profiles={};createDefaultProfiles();},stringCase:stringCase};});emmet.define('editorUtils',function(require,_){return{isInsideTag:function(html,caretPos){var reTag=/^<\/?\w[\w\:\-]*.*?>/;var pos=caretPos;while(pos>-1){if(html.charAt(pos)=='<') +break;pos--;} +if(pos!=-1){var m=reTag.exec(html.substring(pos));if(m&&caretPos>pos&&caretPos'&&utils.endsWithTag(str.substring(0,curOffset+1)))){startIndex=curOffset+1;break;}}} +if(startIndex!=-1&&!textCount&&!braceCount&&!groupCount) +return str.substring(startIndex).replace(/^[\*\+\>\^]+/,'');else +return'';},getImageSize:function(stream){var pngMagicNum="\211PNG\r\n\032\n",jpgMagicNum="\377\330",gifMagicNum="GIF8",nextByte=function(){return stream.charCodeAt(pos++);};if(stream.substr(0,8)===pngMagicNum){var pos=stream.indexOf('IHDR')+4;return{width:(nextByte()<<24)|(nextByte()<<16)|(nextByte()<<8)|nextByte(),height:(nextByte()<<24)|(nextByte()<<16)|(nextByte()<<8)|nextByte()};}else if(stream.substr(0,4)===gifMagicNum){pos=6;return{width:nextByte()|(nextByte()<<8),height:nextByte()|(nextByte()<<8)};}else if(stream.substr(0,2)===jpgMagicNum){pos=2;var l=stream.length;while(pos=0xC0&&marker<=0xCF&&!(marker&0x4)&&!(marker&0x8)){pos+=1;return{height:(nextByte()<<8)|nextByte(),width:(nextByte()<<8)|nextByte()};}else{pos+=size-2;}}}},captureContext:function(editor){var allowedSyntaxes={'html':1,'xml':1,'xsl':1};var syntax=String(editor.getSyntax());if(syntax in allowedSyntaxes){var content=String(editor.getContent());var tag=require('htmlMatcher').find(content,editor.getCaretPos());if(tag&&tag.type=='tag'){var startTag=tag.open;var contextNode={name:startTag.name,attributes:[]};var tagTree=require('xmlEditTree').parse(startTag.range.substring(content));if(tagTree){contextNode.attributes=_.map(tagTree.getAll(),function(item){return{name:item.name(),value:item.value()};});} +return contextNode;}} +return null;},findExpressionBounds:function(editor,fn){var content=String(editor.getContent());var il=content.length;var exprStart=editor.getCaretPos()-1;var exprEnd=exprStart+1;while(exprStart>=0&&fn(content.charAt(exprStart),exprStart,content))exprStart--;while(exprEndexprStart){return require('range').create([++exprStart,exprEnd]);}},compoundUpdate:function(editor,data){if(data){var sel=editor.getSelectionRange();editor.replaceContent(data.data,data.start,data.end,true);editor.createSelection(data.caret,data.caret+sel.end-sel.start);return true;} +return false;},detectSyntax:function(editor,hint){var syntax=hint||'html';if(!require('resources').hasSyntax(syntax)){syntax='html';} +if(syntax=='html'&&(this.isStyle(editor)||this.isInlineCSS(editor))){syntax='css';} +return syntax;},detectProfile:function(editor){var syntax=editor.getSyntax();var profile=require('resources').findItem(syntax,'profile');if(profile){return profile;} +switch(syntax){case'xml':case'xsl':return'xml';case'css':if(this.isInlineCSS(editor)){return'line';} +break;case'html':var profile=require('resources').getVariable('profile');if(!profile){profile=this.isXHTML(editor)?'xhtml':'html';} +return profile;} +return'xhtml';},isXHTML:function(editor){return editor.getContent().search(/]+XHTML/i)!=-1;},isStyle:function(editor){var content=String(editor.getContent());var caretPos=editor.getCaretPos();var tag=require('htmlMatcher').tag(content,caretPos);return tag&&tag.open.name.toLowerCase()=='style'&&tag.innerRange.cmp(caretPos,'lte','gte');},isInlineCSS:function(editor){var content=String(editor.getContent());var caretPos=editor.getCaretPos();var tree=require('xmlEditTree').parseFromPosition(content,caretPos,true);if(tree){var attr=tree.itemFromPosition(caretPos,true);return attr&&attr.name().toLowerCase()=='style'&&attr.valueRange(true).cmp(caretPos,'lte','gte');} +return false;}};});emmet.define('abbreviationUtils',function(require,_){return{isSnippet:function(node){return require('elements').is(node.matchedResource(),'snippet');},isUnary:function(node){if(node.children.length||node._text||this.isSnippet(node)){return false;} +var r=node.matchedResource();return r&&r.is_empty;},isInline:function(node){return node.isTextNode()||!node.name()||require('tagName').isInlineLevel(node.name());},isBlock:function(node){return this.isSnippet(node)||!this.isInline(node);},isSnippet:function(node){return require('elements').is(node.matchedResource(),'snippet');},hasTagsInContent:function(node){return require('utils').matchesTag(node.content);},hasBlockChildren:function(node){return(this.hasTagsInContent(node)&&this.isBlock(node))||_.any(node.children,function(child){return this.isBlock(child);},this);},insertChildContent:function(text,childContent,options){options=_.extend({keepVariable:true,appendIfNoChild:true},options||{});var childVariableReplaced=false;var utils=require('utils');text=utils.replaceVariables(text,function(variable,name,data){var output=variable;if(name=='child'){output=utils.padString(childContent,utils.getLinePaddingFromPosition(text,data.start));childVariableReplaced=true;if(options.keepVariable) +output+=variable;} +return output;});if(!childVariableReplaced&&options.appendIfNoChild){text+=childContent;} +return text;}};});emmet.define('base64',function(require,_){var chars='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';return{encode:function(input){var output=[];var chr1,chr2,chr3,enc1,enc2,enc3,enc4,cdp1,cdp2,cdp3;var i=0,il=input.length,b64=chars;while(i>2;enc2=((chr1&3)<<4)|(chr2>>4);enc3=((chr2&15)<<2)|(chr3>>6);enc4=chr3&63;if(isNaN(cdp2)){enc3=enc4=64;}else if(isNaN(cdp3)){enc4=64;} +output.push(b64.charAt(enc1)+b64.charAt(enc2)+b64.charAt(enc3)+b64.charAt(enc4));} +return output.join('');},decode:function(data){var o1,o2,o3,h1,h2,h3,h4,bits,i=0,ac=0,tmpArr=[];var b64=chars,il=data.length;if(!data){return data;} +data+='';do{h1=b64.indexOf(data.charAt(i++));h2=b64.indexOf(data.charAt(i++));h3=b64.indexOf(data.charAt(i++));h4=b64.indexOf(data.charAt(i++));bits=h1<<18|h2<<12|h3<<6|h4;o1=bits>>16&0xff;o2=bits>>8&0xff;o3=bits&0xff;if(h3==64){tmpArr[ac++]=String.fromCharCode(o1);}else if(h4==64){tmpArr[ac++]=String.fromCharCode(o1,o2);}else{tmpArr[ac++]=String.fromCharCode(o1,o2,o3);}}while(i\s]+))?)*)\s*(\/?)>/;var reCloseTag=/^<\/([\w\:\-]+)[^>]*>/;function openTag(i,match){return{name:match[1],selfClose:!!match[3],range:require('range').create(i,match[0]),type:'open'};} +function closeTag(i,match){return{name:match[1],range:require('range').create(i,match[0]),type:'close'};} +function comment(i,match){return{range:require('range').create(i,_.isNumber(match)?match-i:match[0]),type:'comment'};} +function createMatcher(text){var memo={},m;return{open:function(i){var m=this.matches(i);return m&&m.type=='open'?m:null;},close:function(i){var m=this.matches(i);return m&&m.type=='close'?m:null;},matches:function(i){var key='p'+i;if(!(key in memo)){if(text.charAt(i)=='<'){var substr=text.slice(i);if(m=substr.match(reOpenTag)){memo[key]=openTag(i,m);}else if(m=substr.match(reCloseTag)){memo[key]=closeTag(i,m);}else{memo[key]=false;}}} +return memo[key];},text:function(){return text;}};} +function matches(text,pos,pattern){return text.substring(pos,pos+pattern.length)==pattern;} +function findClosingPair(open,matcher){var stack=[],tag=null;var text=matcher.text();for(var pos=open.range.end,len=text.length;pos')){pos=j+3;break;}}} +if(tag=matcher.matches(pos)){if(tag.type=='open'&&!tag.selfClose){stack.push(tag.name);}else if(tag.type=='close'){if(!stack.length){return tag.name==open.name?tag:null;} +if(_.last(stack)==tag.name){stack.pop();}else{var found=false;while(stack.length&&!found){var last=stack.pop();if(last==tag.name){found=true;}} +if(!stack.length&&!found){return tag.name==open.name?tag:null;}}}}}} +return{find:function(text,pos){var range=require('range');var matcher=createMatcher(text);var open=null,close=null;for(var i=pos;i>=0;i--){if(open=matcher.open(i)){if(open.selfClose){if(open.range.cmp(pos,'lt','gt')){break;} +continue;} +close=findClosingPair(open,matcher);if(close){var r=range.create2(open.range.start,close.range.end);if(r.contains(pos)){break;}}else if(open.range.contains(pos)){break;} +open=null;}else if(matches(text,i,'-->')){for(var j=i-1;j>=0;j--){if(matches(text,j,'-->')){break;}else if(matches(text,j,'')){j+=3;break;}} +open=comment(i,j);break;}} +if(open){var outerRange=null;var innerRange=null;if(close){outerRange=range.create2(open.range.start,close.range.end);innerRange=range.create2(open.range.end,close.range.start);}else{outerRange=innerRange=range.create2(open.range.start,open.range.end);} +if(open.type=='comment'){var _c=outerRange.substring(text);innerRange.start+=_c.length-_c.replace(/^<\!--\s*/,'').length;innerRange.end-=_c.length-_c.replace(/\s*-->$/,'').length;} +return{open:open,close:close,type:open.type=='comment'?'comment':'tag',innerRange:innerRange,innerContent:function(){return this.innerRange.substring(text);},outerRange:outerRange,outerContent:function(){return this.outerRange.substring(text);},range:!innerRange.length()||!innerRange.cmp(pos,'lte','gte')?outerRange:innerRange,content:function(){return this.range.substring(text);},source:text};}},tag:function(text,pos){var result=this.find(text,pos);if(result&&result.type=='tag'){return result;}}};});emmet.define('tabStops',function(require,_){var startPlaceholderNum=100;var tabstopIndex=0;var defaultOptions={replaceCarets:false,escape:function(ch){return'\\'+ch;},tabstop:function(data){return data.token;},variable:function(data){return data.token;}};require('abbreviationParser').addOutputProcessor(function(text,node,type){var maxNum=0;var tabstops=require('tabStops');var utils=require('utils');var tsOptions={tabstop:function(data){var group=parseInt(data.group);if(group==0) +return'${0}';if(group>maxNum)maxNum=group;if(data.placeholder){var ix=group+tabstopIndex;var placeholder=tabstops.processText(data.placeholder,tsOptions);return'${'+ix+':'+placeholder+'}';}else{return'${'+(group+tabstopIndex)+'}';}}};text=tabstops.processText(text,tsOptions);text=utils.replaceVariables(text,tabstops.variablesResolver(node));tabstopIndex+=maxNum+1;return text;});return{extract:function(text,options){var utils=require('utils');var placeholders={carets:''};var marks=[];options=_.extend({},defaultOptions,options,{tabstop:function(data){var token=data.token;var ret='';if(data.placeholder=='cursor'){marks.push({start:data.start,end:data.start+token.length,group:'carets',value:''});}else{if('placeholder'in data) +placeholders[data.group]=data.placeholder;if(data.group in placeholders) +ret=placeholders[data.group];marks.push({start:data.start,end:data.start+token.length,group:data.group,value:ret});} +return token;}});if(options.replaceCarets){text=text.replace(new RegExp(utils.escapeForRegexp(utils.getCaretPlaceholder()),'g'),'${0:cursor}');} +text=this.processText(text,options);var buf=utils.stringBuilder(),lastIx=0;var tabStops=_.map(marks,function(mark){buf.append(text.substring(lastIx,mark.start));var pos=buf.length;var ph=placeholders[mark.group]||'';buf.append(ph);lastIx=mark.end;return{group:mark.group,start:pos,end:pos+ph.length};});buf.append(text.substring(lastIx));return{text:buf.toString(),tabstops:_.sortBy(tabStops,'start')};},processText:function(text,options){options=_.extend({},defaultOptions,options);var buf=require('utils').stringBuilder();var stream=require('stringStream').create(text);var ch,m,a;while(ch=stream.next()){if(ch=='\\'&&!stream.eol()){buf.append(options.escape(stream.next()));continue;} +a=ch;if(ch=='$'){stream.start=stream.pos-1;if(m=stream.match(/^[0-9]+/)){a=options.tabstop({start:buf.length,group:stream.current().substr(1),token:stream.current()});}else if(m=stream.match(/^\{([a-z_\-][\w\-]*)\}/)){a=options.variable({start:buf.length,name:m[1],token:stream.current()});}else if(m=stream.match(/^\{([0-9]+)(:.+?)?\}/,false)){stream.skipToPair('{','}');var obj={start:buf.length,group:m[1],token:stream.current()};var placeholder=obj.token.substring(obj.group.length+2,obj.token.length-1);if(placeholder){obj.placeholder=placeholder.substr(1);} +a=options.tabstop(obj);}} +buf.append(a);} +return buf.toString();},upgrade:function(node,offset){var maxNum=0;var options={tabstop:function(data){var group=parseInt(data.group);if(group>maxNum)maxNum=group;if(data.placeholder) +return'${'+(group+offset)+':'+data.placeholder+'}';else +return'${'+(group+offset)+'}';}};_.each(['start','end','content'],function(p){node[p]=this.processText(node[p],options);},this);return maxNum;},variablesResolver:function(node){var placeholderMemo={};var res=require('resources');return function(str,varName){if(varName=='child') +return str;if(varName=='cursor') +return require('utils').getCaretPlaceholder();var attr=node.attribute(varName);if(!_.isUndefined(attr)&&attr!==str){return attr;} +var varValue=res.getVariable(varName);if(varValue) +return varValue;if(!placeholderMemo[varName]) +placeholderMemo[varName]=startPlaceholderNum++;return'${'+placeholderMemo[varName]+':'+varName+'}';};},resetTabstopIndex:function(){tabstopIndex=0;startPlaceholderNum=100;}};});emmet.define('preferences',function(require,_){var preferences={};var defaults={};var _dbgDefaults=null;var _dbgPreferences=null;function toBoolean(val){if(_.isString(val)){val=val.toLowerCase();return val=='yes'||val=='true'||val=='1';} +return!!val;} +function isValueObj(obj){return _.isObject(obj)&&'value'in obj&&_.keys(obj).length<3;} +return{define:function(name,value,description){var prefs=name;if(_.isString(name)){prefs={};prefs[name]={value:value,description:description};} +_.each(prefs,function(v,k){defaults[k]=isValueObj(v)?v:{value:v};});},set:function(name,value){var prefs=name;if(_.isString(name)){prefs={};prefs[name]=value;} +_.each(prefs,function(v,k){if(!(k in defaults)){throw'Property "'+k+'" is not defined. You should define it first with `define` method of current module';} +if(v!==defaults[k].value){switch(typeof defaults[k].value){case'boolean':v=toBoolean(v);break;case'number':v=parseInt(v+'',10)||0;break;default:if(v!==null){v+='';}} +preferences[k]=v;}else if(k in preferences){delete preferences[k];}});},get:function(name){if(name in preferences) +return preferences[name];if(name in defaults) +return defaults[name].value;return void 0;},getArray:function(name){var val=this.get(name);if(_.isUndefined(val)||val===null||val===''){return null;} +val=_.map(val.split(','),require('utils').trim);if(!val.length){return null;} +return val;},getDict:function(name){var result={};_.each(this.getArray(name),function(val){var parts=val.split(':');result[parts[0]]=parts[1];});return result;},description:function(name){return name in defaults?defaults[name].description:void 0;},remove:function(name){if(!_.isArray(name)) +name=[name];_.each(name,function(key){if(key in preferences) +delete preferences[key];if(key in defaults) +delete defaults[key];});},list:function(){return _.map(_.keys(defaults).sort(),function(key){return{name:key,value:this.get(key),type:typeof defaults[key].value,description:defaults[key].description};},this);},load:function(json){_.each(json,function(value,key){this.set(key,value);},this);},exportModified:function(){return _.clone(preferences);},reset:function(){preferences={};},_startTest:function(){_dbgDefaults=defaults;_dbgPreferences=preferences;defaults={};preferences={};},_stopTest:function(){defaults=_dbgDefaults;preferences=_dbgPreferences;}};});emmet.define('filters',function(require,_){var registeredFilters={};var basicFilters='html';function list(filters){if(!filters) +return[];if(_.isString(filters)) +return filters.split(/[\|,]/g);return filters;} +return{add:function(name,fn){registeredFilters[name]=fn;},apply:function(tree,filters,profile){var utils=require('utils');profile=require('profile').get(profile);_.each(list(filters),function(filter){var name=utils.trim(filter.toLowerCase());if(name&&name in registeredFilters){tree=registeredFilters[name](tree,profile);}});return tree;},composeList:function(syntax,profile,additionalFilters){profile=require('profile').get(profile);var filters=list(profile.filters||require('resources').findItem(syntax,'filters')||basicFilters);if(profile.extraFilters){filters=filters.concat(list(profile.extraFilters));} +if(additionalFilters){filters=filters.concat(list(additionalFilters));} +if(!filters||!filters.length){filters=list(basicFilters);} +return filters;},extractFromAbbreviation:function(abbr){var filters='';abbr=abbr.replace(/\|([\w\|\-]+)$/,function(str,p1){filters=p1;return'';});return[abbr,list(filters)];}};});emmet.define('elements',function(require,_){var factories={};var reAttrs=/([\w\-:]+)\s*=\s*(['"])(.*?)\2/g;var result={add:function(name,factory){var that=this;factories[name]=function(){var elem=factory.apply(that,arguments);if(elem) +elem.type=name;return elem;};},get:function(name){return factories[name];},create:function(name){var args=[].slice.call(arguments,1);var factory=this.get(name);return factory?factory.apply(this,args):null;},is:function(elem,type){return elem&&elem.type===type;}};function commonFactory(value){return{data:value};} +result.add('element',function(elementName,attrs,isEmpty){var ret={name:elementName,is_empty:!!isEmpty};if(attrs){ret.attributes=[];if(_.isArray(attrs)){ret.attributes=attrs;}else if(_.isString(attrs)){var m;while(m=reAttrs.exec(attrs)){ret.attributes.push({name:m[1],value:m[3]});}}else{_.each(attrs,function(value,name){ret.attributes.push({name:name,value:value});});}} +return ret;});result.add('snippet',commonFactory);result.add('reference',commonFactory);result.add('empty',function(){return{};});return result;});emmet.define('editTree',function(require,_,core){var range=require('range').create;function EditContainer(source,options){this.options=_.extend({offset:0},options);this.source=source;this._children=[];this._positions={name:0};this.initialize.apply(this,arguments);} +EditContainer.extend=core.extend;EditContainer.prototype={initialize:function(){},_updateSource:function(value,start,end){var r=range(start,_.isUndefined(end)?0:end-start);var delta=value.length-r.length();var update=function(obj){_.each(obj,function(v,k){if(v>=r.end) +obj[k]+=delta;});};update(this._positions);_.each(this.list(),function(item){update(item._positions);});this.source=require('utils').replaceSubstring(this.source,value,r);},add:function(name,value,pos){var item=new EditElement(name,value);this._children.push(item);return item;},get:function(name){if(_.isNumber(name)) +return this.list()[name];if(_.isString(name)) +return _.find(this.list(),function(prop){return prop.name()===name;});return name;},getAll:function(name){if(!_.isArray(name)) +name=[name];var names=[],indexes=[];_.each(name,function(item){if(_.isString(item)) +names.push(item);else if(_.isNumber(item)) +indexes.push(item);});return _.filter(this.list(),function(attribute,i){return _.include(indexes,i)||_.include(names,attribute.name());});},value:function(name,value,pos){var element=this.get(name);if(element) +return element.value(value);if(!_.isUndefined(value)){return this.add(name,value,pos);}},values:function(name){return _.map(this.getAll(name),function(element){return element.value();});},remove:function(name){var element=this.get(name);if(element){this._updateSource('',element.fullRange());this._children=_.without(this._children,element);}},list:function(){return this._children;},indexOf:function(item){return _.indexOf(this.list(),this.get(item));},name:function(val){if(!_.isUndefined(val)&&this._name!==(val=String(val))){this._updateSource(val,this._positions.name,this._positions.name+this._name.length);this._name=val;} +return this._name;},nameRange:function(isAbsolute){return range(this._positions.name+(isAbsolute?this.options.offset:0),this.name());},range:function(isAbsolute){return range(isAbsolute?this.options.offset:0,this.toString());},itemFromPosition:function(pos,isAbsolute){return _.find(this.list(),function(elem){return elem.range(isAbsolute).inside(pos);});},toString:function(){return this.source;}};function EditElement(parent,nameToken,valueToken){this.parent=parent;this._name=nameToken.value;this._value=valueToken?valueToken.value:'';this._positions={name:nameToken.start,value:valueToken?valueToken.start:-1};this.initialize.apply(this,arguments);} +EditElement.extend=core.extend;EditElement.prototype={initialize:function(){},_pos:function(num,isAbsolute){return num+(isAbsolute?this.parent.options.offset:0);},value:function(val){if(!_.isUndefined(val)&&this._value!==(val=String(val))){this.parent._updateSource(val,this.valueRange());this._value=val;} +return this._value;},name:function(val){if(!_.isUndefined(val)&&this._name!==(val=String(val))){this.parent._updateSource(val,this.nameRange());this._name=val;} +return this._name;},namePosition:function(isAbsolute){return this._pos(this._positions.name,isAbsolute);},valuePosition:function(isAbsolute){return this._pos(this._positions.value,isAbsolute);},range:function(isAbsolute){return range(this.namePosition(isAbsolute),this.toString());},fullRange:function(isAbsolute){return this.range(isAbsolute);},nameRange:function(isAbsolute){return range(this.namePosition(isAbsolute),this.name());},valueRange:function(isAbsolute){return range(this.valuePosition(isAbsolute),this.value());},toString:function(){return this.name()+this.value();},valueOf:function(){return this.toString();}};return{EditContainer:EditContainer,EditElement:EditElement,createToken:function(start,value,type){var obj={start:start||0,value:value||'',type:type};obj.end=obj.start+obj.value.length;return obj;}};});emmet.define('cssEditTree',function(require,_){var defaultOptions={styleBefore:'\n\t',styleSeparator:': ',offset:0};var WHITESPACE_REMOVE_FROM_START=1;var WHITESPACE_REMOVE_FROM_END=2;function range(start,len){return require('range').create(start,len);} +function trimWhitespaceTokens(tokens,mask){mask=mask||(WHITESPACE_REMOVE_FROM_START|WHITESPACE_REMOVE_FROM_END);var whitespace=['white','line'];if((mask&WHITESPACE_REMOVE_FROM_END)==WHITESPACE_REMOVE_FROM_END) +while(tokens.length&&_.include(whitespace,_.last(tokens).type)){tokens.pop();} +if((mask&WHITESPACE_REMOVE_FROM_START)==WHITESPACE_REMOVE_FROM_START) +while(tokens.length&&_.include(whitespace,tokens[0].type)){tokens.shift();} +return tokens;} +function findSelectorRange(it){var tokens=[],token;var start=it.position(),end;while(token=it.next()){if(token.type=='{') +break;tokens.push(token);} +trimWhitespaceTokens(tokens);if(tokens.length){start=tokens[0].start;end=_.last(tokens).end;}else{end=start;} +return range(start,end-start);} +function findValueRange(it){var skipTokens=['white','line',':'];var tokens=[],token,start,end;it.nextUntil(function(tok){return!_.include(skipTokens,this.itemNext().type);});start=it.current().end;while(token=it.next()){if(token.type=='}'||token.type==';'){trimWhitespaceTokens(tokens,WHITESPACE_REMOVE_FROM_START|(token.type=='}'?WHITESPACE_REMOVE_FROM_END:0));if(tokens.length){start=tokens[0].start;end=_.last(tokens).end;}else{end=start;} +return range(start,end-start);} +tokens.push(token);} +if(tokens.length){return range(tokens[0].start,_.last(tokens).end-tokens[0].start);}} +function findParts(str){var stream=require('stringStream').create(str);var ch;var result=[];var sep=/[\s\u00a0,]/;var add=function(){stream.next();result.push(range(stream.start,stream.current()));stream.start=stream.pos;};stream.eatSpace();stream.start=stream.pos;while(ch=stream.next()){if(ch=='"'||ch=="'"){stream.next();if(!stream.skipTo(ch))break;add();}else if(ch=='('){stream.backUp(1);if(!stream.skipToPair('(',')'))break;stream.backUp(1);add();}else{if(sep.test(ch)){result.push(range(stream.start,stream.current().length-1));stream.eatWhile(sep);stream.start=stream.pos;}}} +add();return _.chain(result).filter(function(item){return!!item.length();}).uniq(false,function(item){return item.toString();}).value();} +function isValidIdentifier(it){var tokens=it.tokens;for(var i=it._i+1,il=tokens.length;i1){p.styleBefore='\n'+_.last(lines);} +p.styleSeparator=source.substring(p.nameRange().end,p.valuePosition());p.styleBefore=_.last(p.styleBefore.split('*/'));p.styleSeparator=p.styleSeparator.replace(/\/\*.*?\*\//g,'');start=p.range().end;});},add:function(name,value,pos){var list=this.list();var start=this._positions.contentStart;var styles=_.pick(this.options,'styleBefore','styleSeparator');var editTree=require('editTree');if(_.isUndefined(pos)) +pos=list.length;var donor=list[pos];if(donor){start=donor.fullRange().start;}else if(donor=list[pos-1]){donor.end(';');start=donor.range().end;} +if(donor){styles=_.pick(donor,'styleBefore','styleSeparator');} +var nameToken=editTree.createToken(start+styles.styleBefore.length,name);var valueToken=editTree.createToken(nameToken.end+styles.styleSeparator.length,value);var property=new CSSEditElement(this,nameToken,valueToken,editTree.createToken(valueToken.end,';'));_.extend(property,styles);this._updateSource(property.styleBefore+property.toString(),start);this._children.splice(pos,0,property);return property;}});var CSSEditElement=require('editTree').EditElement.extend({initialize:function(rule,name,value,end){this.styleBefore=rule.options.styleBefore;this.styleSeparator=rule.options.styleSeparator;this._end=end.value;this._positions.end=end.start;},valueParts:function(isAbsolute){var parts=findParts(this.value());if(isAbsolute){var offset=this.valuePosition(true);_.each(parts,function(p){p.shift(offset);});} +return parts;},end:function(val){if(!_.isUndefined(val)&&this._end!==val){this.parent._updateSource(val,this._positions.end,this._positions.end+this._end.length);this._end=val;} +return this._end;},fullRange:function(isAbsolute){var r=this.range(isAbsolute);r.start-=this.styleBefore.length;return r;},toString:function(){return this.name()+this.styleSeparator+this.value()+this.end();}});return{parse:function(source,options){return new CSSEditContainer(source,options);},parseFromPosition:function(content,pos,isBackward){var bounds=this.extractRule(content,pos,isBackward);if(!bounds||!bounds.inside(pos)) +return null;return this.parse(bounds.substring(content),{offset:bounds.start});},extractRule:function(content,pos,isBackward){var result='';var len=content.length;var offset=pos;var stopChars='{}/\\<>\n\r';var bracePos=-1,ch;while(offset>=0){ch=content.charAt(offset);if(ch=='{'){bracePos=offset;break;} +else if(ch=='}'&&!isBackward){offset++;break;} +offset--;} +while(offset=0){ch=content.charAt(offset);if(stopChars.indexOf(ch)!=-1)break;offset--;} +selector=content.substring(offset+1,bracePos).replace(/^[\s\n\r]+/m,'');return require('range').create(bracePos-selector.length,result.length+selector.length);} +return null;},baseName:function(name){return name.replace(/^\s*\-\w+\-/,'');},findParts:findParts};});emmet.define('xmlEditTree',function(require,_){var defaultOptions={styleBefore:' ',styleSeparator:'=',styleQuote:'"',offset:0};var startTag=/^<([\w\:\-]+)((?:\s+[\w\-:]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/m;var XMLEditContainer=require('editTree').EditContainer.extend({initialize:function(source,options){_.defaults(this.options,defaultOptions);this._positions.name=1;var attrToken=null;var tokens=require('xmlParser').parse(source);var range=require('range');_.each(tokens,function(token){token.value=range.create(token).substring(source);switch(token.type){case'tag':if(/^<[^\/]+/.test(token.value)){this._name=token.value.substring(1);} +break;case'attribute':if(attrToken){this._children.push(new XMLEditElement(this,attrToken));} +attrToken=token;break;case'string':this._children.push(new XMLEditElement(this,attrToken,token));attrToken=null;break;}},this);if(attrToken){this._children.push(new XMLEditElement(this,attrToken));} +this._saveStyle();},_saveStyle:function(){var start=this.nameRange().end;var source=this.source;_.each(this.list(),function(p){p.styleBefore=source.substring(start,p.namePosition());if(p.valuePosition()!==-1){p.styleSeparator=source.substring(p.namePosition()+p.name().length,p.valuePosition()-p.styleQuote.length);} +start=p.range().end;});},add:function(name,value,pos){var list=this.list();var start=this.nameRange().end;var editTree=require('editTree');var styles=_.pick(this.options,'styleBefore','styleSeparator','styleQuote');if(_.isUndefined(pos)) +pos=list.length;var donor=list[pos];if(donor){start=donor.fullRange().start;}else if(donor=list[pos-1]){start=donor.range().end;} +if(donor){styles=_.pick(donor,'styleBefore','styleSeparator','styleQuote');} +value=styles.styleQuote+value+styles.styleQuote;var attribute=new XMLEditElement(this,editTree.createToken(start+styles.styleBefore.length,name),editTree.createToken(start+styles.styleBefore.length+name.length ++styles.styleSeparator.length,value));_.extend(attribute,styles);this._updateSource(attribute.styleBefore+attribute.toString(),start);this._children.splice(pos,0,attribute);return attribute;}});var XMLEditElement=require('editTree').EditElement.extend({initialize:function(parent,nameToken,valueToken){this.styleBefore=parent.options.styleBefore;this.styleSeparator=parent.options.styleSeparator;var value='',quote=parent.options.styleQuote;if(valueToken){value=valueToken.value;quote=value.charAt(0);if(quote=='"'||quote=="'"){value=value.substring(1);}else{quote='';} +if(quote&&value.charAt(value.length-1)==quote){value=value.substring(0,value.length-1);}} +this.styleQuote=quote;this._value=value;this._positions.value=valueToken?valueToken.start+quote.length:-1;},fullRange:function(isAbsolute){var r=this.range(isAbsolute);r.start-=this.styleBefore.length;return r;},toString:function(){return this.name()+this.styleSeparator ++this.styleQuote+this.value()+this.styleQuote;}});return{parse:function(source,options){return new XMLEditContainer(source,options);},parseFromPosition:function(content,pos,isBackward){var bounds=this.extractTag(content,pos,isBackward);if(!bounds||!bounds.inside(pos)) +return null;return this.parse(bounds.substring(content),{offset:bounds.start});},extractTag:function(content,pos,isBackward){var len=content.length,i;var range=require('range');var maxLen=Math.min(2000,len);var r=null;var match=function(pos){var m;if(content.charAt(pos)=='<'&&(m=content.substr(pos,maxLen).match(startTag))) +return range.create(pos,m[0]);};for(i=pos;i>=0;i--){if(r=match(i))break;} +if(r&&(r.inside(pos)||isBackward)) +return r;if(!r&&isBackward) +return null;for(i=pos;i',range);} +function toggleCSSComment(editor){var range=require('range').create(editor.getSelectionRange());var info=require('editorUtils').outputInfo(editor);if(!range.length()){var rule=require('cssEditTree').parseFromPosition(info.content,editor.getCaretPos());if(rule){var property=cssItemFromPosition(rule,editor.getCaretPos());range=property?property.range(true):require('range').create(rule.nameRange(true).start,rule.source);}} +if(!range.length()){range=require('range').create(editor.getCurrentLineRange());require('utils').narrowToNonSpace(info.content,range);} +return genericCommentToggle(editor,'/*','*/',range);} +function cssItemFromPosition(rule,absPos){var relPos=absPos-(rule.options.offset||0);var reSafeChar=/^[\s\n\r]/;return _.find(rule.list(),function(item){if(item.range().end===relPos){return reSafeChar.test(rule.source.charAt(relPos));} +return item.range().inside(relPos);});} +function searchComment(text,from,startToken,endToken){var commentStart=-1;var commentEnd=-1;var hasMatch=function(str,start){return text.substr(start,str.length)==str;};while(from--){if(hasMatch(startToken,from)){commentStart=from;break;}} +if(commentStart!=-1){from=commentStart;var contentLen=text.length;while(contentLen>=from++){if(hasMatch(endToken,from)){commentEnd=from+endToken.length;break;}}} +return(commentStart!=-1&&commentEnd!=-1)?require('range').create(commentStart,commentEnd-commentStart):null;} +function genericCommentToggle(editor,commentStart,commentEnd,range){var editorUtils=require('editorUtils');var content=editorUtils.outputInfo(editor).content;var caretPos=editor.getCaretPos();var newContent=null;var utils=require('utils');function removeComment(str){return str.replace(new RegExp('^'+utils.escapeForRegexp(commentStart)+'\\s*'),function(str){caretPos-=str.length;return'';}).replace(new RegExp('\\s*'+utils.escapeForRegexp(commentEnd)+'$'),'');} +var commentRange=searchComment(content,caretPos,commentStart,commentEnd);if(commentRange&&commentRange.overlap(range)){range=commentRange;newContent=removeComment(range.substring(content));}else{newContent=commentStart+' '+ +range.substring(content).replace(new RegExp(utils.escapeForRegexp(commentStart)+'\\s*|\\s*'+utils.escapeForRegexp(commentEnd),'g'),'')+' '+commentEnd;caretPos+=commentStart.length+1;} +if(newContent!==null){newContent=utils.escapeText(newContent);editor.setCaretPos(range.start);editor.replaceContent(editorUtils.unindent(editor,newContent),range.start,range.end);editor.setCaretPos(caretPos);return true;} +return false;} +require('actions').add('toggle_comment',function(editor){var info=require('editorUtils').outputInfo(editor);if(info.syntax=='css'){var caretPos=editor.getCaretPos();var tag=require('htmlMatcher').tag(info.content,caretPos);if(tag&&tag.open.range.inside(caretPos)){info.syntax='html';}} +if(info.syntax=='css') +return toggleCSSComment(editor);return toggleHTMLComment(editor);});});emmet.exec(function(require,_){function findNewEditPoint(editor,inc,offset){inc=inc||1;offset=offset||0;var curPoint=editor.getCaretPos()+offset;var content=String(editor.getContent());var maxLen=content.length;var nextPoint=-1;var reEmptyLine=/^\s+$/;function getLine(ix){var start=ix;while(start>=0){var c=content.charAt(start);if(c=='\n'||c=='\r') +break;start--;} +return content.substring(start,ix);} +while(curPoint<=maxLen&&curPoint>=0){curPoint+=inc;var curChar=content.charAt(curPoint);var nextChar=content.charAt(curPoint+1);var prevChar=content.charAt(curPoint-1);switch(curChar){case'"':case'\'':if(nextChar==curChar&&prevChar=='='){nextPoint=curPoint+1;} +break;case'>':if(nextChar=='<'){nextPoint=curPoint+1;} +break;case'\n':case'\r':if(reEmptyLine.test(getLine(curPoint-1))){nextPoint=curPoint;} +break;} +if(nextPoint!=-1) +break;} +return nextPoint;} +var actions=require('actions');actions.add('prev_edit_point',function(editor){var curPos=editor.getCaretPos();var newPoint=findNewEditPoint(editor,-1);if(newPoint==curPos) +newPoint=findNewEditPoint(editor,-1,-2);if(newPoint!=-1){editor.setCaretPos(newPoint);return true;} +return false;},{label:'Previous Edit Point'});actions.add('next_edit_point',function(editor){var newPoint=findNewEditPoint(editor,1);if(newPoint!=-1){editor.setCaretPos(newPoint);return true;} +return false;});});emmet.exec(function(require,_){var startTag=/^<([\w\:\-]+)((?:\s+[\w\-:]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;function findItem(editor,isBackward,extractFn,rangeFn){var range=require('range');var content=require('editorUtils').outputInfo(editor).content;var contentLength=content.length;var itemRange,rng;var prevRange=range.create(-1,0);var sel=range.create(editor.getSelectionRange());var searchPos=sel.start,loop=100000;while(searchPos>=0&&searchPos0){if((itemRange=extractFn(content,searchPos,isBackward))){if(prevRange.equal(itemRange)){break;} +prevRange=itemRange.clone();rng=rangeFn(itemRange.substring(content),itemRange.start,sel.clone());if(rng){editor.createSelection(rng.start,rng.end);return true;}else{searchPos=isBackward?itemRange.start:itemRange.end-1;}} +searchPos+=isBackward?-1:1;} +return false;} +function findNextHTMLItem(editor){var isFirst=true;return findItem(editor,false,function(content,searchPos){if(isFirst){isFirst=false;return findOpeningTagFromPosition(content,searchPos);}else{return getOpeningTagFromPosition(content,searchPos);}},function(tag,offset,selRange){return getRangeForHTMLItem(tag,offset,selRange,false);});} +function findPrevHTMLItem(editor){return findItem(editor,true,getOpeningTagFromPosition,function(tag,offset,selRange){return getRangeForHTMLItem(tag,offset,selRange,true);});} +function makePossibleRangesHTML(source,tokens,offset){offset=offset||0;var range=require('range');var result=[];var attrStart=-1,attrName='',attrValue='',attrValueRange,tagName;_.each(tokens,function(tok){switch(tok.type){case'tag':tagName=source.substring(tok.start,tok.end);if(/^<[\w\:\-]/.test(tagName)){result.push(range.create({start:tok.start+1,end:tok.end}));} +break;case'attribute':attrStart=tok.start;attrName=source.substring(tok.start,tok.end);break;case'string':result.push(range.create(attrStart,tok.end-attrStart));attrValueRange=range.create(tok);attrValue=attrValueRange.substring(source);if(isQuote(attrValue.charAt(0))) +attrValueRange.start++;if(isQuote(attrValue.charAt(attrValue.length-1))) +attrValueRange.end--;result.push(attrValueRange);if(attrName=='class'){result=result.concat(classNameRanges(attrValueRange.substring(source),attrValueRange.start));} +break;}});_.each(result,function(r){r.shift(offset);});return _.chain(result).filter(function(item){return!!item.length();}).uniq(false,function(item){return item.toString();}).value();} +function classNameRanges(className,offset){offset=offset||0;var result=[];var stream=require('stringStream').create(className);var range=require('range');stream.eatSpace();stream.start=stream.pos;var ch;while(ch=stream.next()){if(/[\s\u00a0]/.test(ch)){result.push(range.create(stream.start+offset,stream.pos-stream.start-1));stream.eatSpace();stream.start=stream.pos;}} +result.push(range.create(stream.start+offset,stream.pos-stream.start));return result;} +function getRangeForHTMLItem(tag,offset,selRange,isBackward){var ranges=makePossibleRangesHTML(tag,require('xmlParser').parse(tag),offset);if(isBackward) +ranges.reverse();var curRange=_.find(ranges,function(r){return r.equal(selRange);});if(curRange){var ix=_.indexOf(ranges,curRange);if(ix1) +return matchedRanges[1];} +return _.find(ranges,function(r){return r.end>selRange.end;});} +function findOpeningTagFromPosition(html,pos){var tag;while(pos>=0){if(tag=getOpeningTagFromPosition(html,pos)) +return tag;pos--;} +return null;} +function getOpeningTagFromPosition(html,pos){var m;if(html.charAt(pos)=='<'&&(m=html.substring(pos,html.length).match(startTag))){return require('range').create(pos,m[0]);}} +function isQuote(ch){return ch=='"'||ch=="'";} +function makePossibleRangesCSS(property){var valueRange=property.valueRange(true);var result=[property.range(true),valueRange];var stringStream=require('stringStream');var cssEditTree=require('cssEditTree');var range=require('range');var value=property.value();_.each(property.valueParts(),function(r){var clone=r.clone();result.push(clone.shift(valueRange.start));var stream=stringStream.create(r.substring(value));if(stream.match(/^[\w\-]+\(/,true)){stream.start=stream.pos;stream.skipToPair('(',')');var fnBody=stream.current();result.push(range.create(clone.start+stream.start,fnBody));_.each(cssEditTree.findParts(fnBody),function(part){result.push(range.create(clone.start+stream.start+part.start,part.substring(fnBody)));});}});return _.chain(result).filter(function(item){return!!item.length();}).uniq(false,function(item){return item.toString();}).value();} +function matchedRangeForCSSProperty(rule,selRange,isBackward){var property=null;var possibleRanges,curRange=null,ix;var list=rule.list();var searchFn,nearestItemFn;if(isBackward){list.reverse();searchFn=function(p){return p.range(true).start<=selRange.start;};nearestItemFn=function(r){return r.start=selRange.end;};nearestItemFn=function(r){return r.end>selRange.start;};} +while(property=_.find(list,searchFn)){possibleRanges=makePossibleRangesCSS(property);if(isBackward) +possibleRanges.reverse();curRange=_.find(possibleRanges,function(r){return r.equal(selRange);});if(!curRange){var matchedRanges=_.filter(possibleRanges,function(r){return r.inside(selRange.end);});if(matchedRanges.length>1){curRange=matchedRanges[1];break;} +if(curRange=_.find(possibleRanges,nearestItemFn)) +break;}else{ix=_.indexOf(possibleRanges,curRange);if(ix!=possibleRanges.length-1){curRange=possibleRanges[ix+1];break;}} +curRange=null;selRange.start=selRange.end=isBackward?property.range(true).start-1:property.range(true).end+1;} +return curRange;} +function findNextCSSItem(editor){return findItem(editor,false,require('cssEditTree').extractRule,getRangeForNextItemInCSS);} +function findPrevCSSItem(editor){return findItem(editor,true,require('cssEditTree').extractRule,getRangeForPrevItemInCSS);} +function getRangeForNextItemInCSS(rule,offset,selRange){var tree=require('cssEditTree').parse(rule,{offset:offset});var range=tree.nameRange(true);if(selRange.endrange.start){return range;}} +return curRange;} +var actions=require('actions');actions.add('select_next_item',function(editor){if(editor.getSyntax()=='css') +return findNextCSSItem(editor);else +return findNextHTMLItem(editor);});actions.add('select_previous_item',function(editor){if(editor.getSyntax()=='css') +return findPrevCSSItem(editor);else +return findPrevHTMLItem(editor);});});emmet.exec(function(require,_){var actions=require('actions');var matcher=require('htmlMatcher');var lastMatch=null;function matchPair(editor,direction){direction=String((direction||'out').toLowerCase());var info=require('editorUtils').outputInfo(editor);var range=require('range');var sel=range.create(editor.getSelectionRange());var content=info.content;if(lastMatch&&!lastMatch.range.equal(sel)){lastMatch=null;} +if(lastMatch&&sel.length()){if(direction=='in'){if(lastMatch.type=='tag'&&!lastMatch.close){return false;}else{if(lastMatch.range.equal(lastMatch.outerRange)){lastMatch.range=lastMatch.innerRange;}else{var narrowed=require('utils').narrowToNonSpace(content,lastMatch.innerRange);lastMatch=matcher.find(content,narrowed.start+1);if(lastMatch&&lastMatch.range.equal(sel)&&lastMatch.outerRange.equal(sel)){lastMatch.range=lastMatch.innerRange;}}}}else{if(!lastMatch.innerRange.equal(lastMatch.outerRange)&&lastMatch.range.equal(lastMatch.innerRange)&&sel.equal(lastMatch.range)){lastMatch.range=lastMatch.outerRange;}else{lastMatch=matcher.find(content,sel.start);if(lastMatch&&lastMatch.range.equal(sel)&&lastMatch.innerRange.equal(sel)){lastMatch.range=lastMatch.outerRange;}}}}else{lastMatch=matcher.find(content,sel.start);} +if(lastMatch&&!lastMatch.range.equal(sel)){editor.createSelection(lastMatch.range.start,lastMatch.range.end);return true;} +lastMatch=null;return false;} +actions.add('match_pair',matchPair,{hidden:true});actions.add('match_pair_inward',function(editor){return matchPair(editor,'in');},{label:'HTML/Match Pair Tag (inward)'});actions.add('match_pair_outward',function(editor){return matchPair(editor,'out');},{label:'HTML/Match Pair Tag (outward)'});actions.add('matching_pair',function(editor){var content=String(editor.getContent());var caretPos=editor.getCaretPos();if(content.charAt(caretPos)=='<') +caretPos++;var tag=matcher.tag(content,caretPos);if(tag&&tag.close){if(tag.open.range.inside(caretPos)){editor.setCaretPos(tag.close.range.start);}else{editor.setCaretPos(tag.open.range.start);} +return true;} +return false;},{label:'HTML/Go To Matching Tag Pair'});});emmet.exec(function(require,_){require('actions').add('remove_tag',function(editor){var utils=require('utils');var info=require('editorUtils').outputInfo(editor);var tag=require('htmlMatcher').tag(info.content,editor.getCaretPos());if(tag){if(!tag.close){editor.replaceContent(utils.getCaretPlaceholder(),tag.range.start,tag.range.end);}else{var tagContentRange=utils.narrowToNonSpace(info.content,tag.innerRange);var startLineBounds=utils.findNewlineBounds(info.content,tagContentRange.start);var startLinePad=utils.getLinePadding(startLineBounds.substring(info.content));var tagContent=tagContentRange.substring(info.content);tagContent=utils.unindentString(tagContent,startLinePad);editor.replaceContent(utils.getCaretPlaceholder()+utils.escapeText(tagContent),tag.outerRange.start,tag.outerRange.end);} +return true;} +return false;},{label:'HTML/Remove Tag'});});emmet.exec(function(require,_){function joinTag(editor,profile,tag){var utils=require('utils');var slash=profile.selfClosing()||' /';var content=tag.open.range.substring(tag.source).replace(/\s*>$/,slash+'>');var caretPos=editor.getCaretPos();if(content.length+tag.outerRange.start$/,'>');caretPos=tag.outerRange.start+content.length;content+=tagContent+'';content=utils.escapeText(content);editor.replaceContent(content,tag.outerRange.start,tag.outerRange.end);editor.setCaretPos(caretPos);return true;} +require('actions').add('split_join_tag',function(editor,profileName){var matcher=require('htmlMatcher');var info=require('editorUtils').outputInfo(editor,null,profileName);var profile=require('profile').get(info.profile);var tag=matcher.tag(info.content,editor.getCaretPos());if(tag){return tag.close?joinTag(editor,profile,tag):splitTag(editor,profile,tag);} +return false;},{label:'HTML/Split\\Join Tag Declaration'});});emmet.define('reflectCSSValue',function(require,_){var handlers=require('handlerList').create();require('actions').add('reflect_css_value',function(editor){if(editor.getSyntax()!='css')return false;return require('actionUtils').compoundUpdate(editor,doCSSReflection(editor));},{label:'CSS/Reflect Value'});function doCSSReflection(editor){var cssEditTree=require('cssEditTree');var outputInfo=require('editorUtils').outputInfo(editor);var caretPos=editor.getCaretPos();var cssRule=cssEditTree.parseFromPosition(outputInfo.content,caretPos);if(!cssRule)return;var property=cssRule.itemFromPosition(caretPos,true);if(!property)return;var oldRule=cssRule.source;var offset=cssRule.options.offset;var caretDelta=caretPos-offset-property.range().start;handlers.exec(false,[property]);if(oldRule!==cssRule.source){return{data:cssRule.source,start:offset,end:offset+oldRule.length,caret:offset+property.range().start+caretDelta};}} +function getReflectedCSSName(name){name=require('cssEditTree').baseName(name);var vendorPrefix='^(?:\\-\\w+\\-)?',m;if(name=='opacity'||name=='filter'){return new RegExp(vendorPrefix+'(?:opacity|filter)$');}else if(m=name.match(/^border-radius-(top|bottom)(left|right)/)){return new RegExp(vendorPrefix+'(?:'+name+'|border-'+m[1]+'-'+m[2]+'-radius)$');}else if(m=name.match(/^border-(top|bottom)-(left|right)-radius/)){return new RegExp(vendorPrefix+'(?:'+name+'|border-radius-'+m[1]+m[2]+')$');} +return new RegExp(vendorPrefix+name+'$');} +function reflectValue(donor,receiver){var value=getReflectedValue(donor.name(),donor.value(),receiver.name(),receiver.value());receiver.value(value);} +function getReflectedValue(curName,curValue,refName,refValue){var cssEditTree=require('cssEditTree');var utils=require('utils');curName=cssEditTree.baseName(curName);refName=cssEditTree.baseName(refName);if(curName=='opacity'&&refName=='filter'){return refValue.replace(/opacity=[^)]*/i,'opacity='+Math.floor(parseFloat(curValue)*100));}else if(curName=='filter'&&refName=='opacity'){var m=curValue.match(/opacity=([^)]*)/i);return m?utils.prettifyNumber(parseInt(m[1])/100):refValue;} +return curValue;} +handlers.add(function(property){var reName=getReflectedCSSName(property.name());_.each(property.parent.list(),function(p){if(reName.test(p.name())){reflectValue(property,p);}});},{order:-1});return{addHandler:function(fn,options){handlers.add(fn,options);},removeHandler:function(fn){handlers.remove(fn,options);}};});emmet.exec(function(require,_){require('actions').add('evaluate_math_expression',function(editor){var actionUtils=require('actionUtils');var utils=require('utils');var content=String(editor.getContent());var chars='.+-*/\\';var sel=require('range').create(editor.getSelectionRange());if(!sel.length()){sel=actionUtils.findExpressionBounds(editor,function(ch){return utils.isNumeric(ch)||chars.indexOf(ch)!=-1;});} +if(sel&&sel.length()){var expr=sel.substring(content);expr=expr.replace(/([\d\.\-]+)\\([\d\.\-]+)/g,'Math.round($1/$2)');try{var result=utils.prettifyNumber(new Function('return '+expr)());editor.replaceContent(result,sel.start,sel.end);editor.setCaretPos(sel.start+result.length);return true;}catch(e){}} +return false;},{label:'Numbers/Evaluate Math Expression'});});emmet.exec(function(require,_){function incrementNumber(editor,step){var utils=require('utils');var actionUtils=require('actionUtils');var hasSign=false;var hasDecimal=false;var r=actionUtils.findExpressionBounds(editor,function(ch,pos,content){if(utils.isNumeric(ch)) +return true;if(ch=='.'){if(!utils.isNumeric(content.charAt(pos+1))) +return false;return hasDecimal?false:hasDecimal=true;} +if(ch=='-') +return hasSign?false:hasSign=true;return false;});if(r&&r.length()){var strNum=r.substring(String(editor.getContent()));var num=parseFloat(strNum);if(!_.isNaN(num)){num=utils.prettifyNumber(num+step);if(/^(\-?)0+[1-9]/.test(strNum)){var minus='';if(RegExp.$1){minus='-';num=num.substring(1);} +var parts=num.split('.');parts[0]=utils.zeroPadString(parts[0],intLength(strNum));num=minus+parts.join('.');} +editor.replaceContent(num,r.start,r.end);editor.createSelection(r.start,r.start+num.length);return true;}} +return false;} +function intLength(num){num=num.replace(/^\-/,'');if(~num.indexOf('.')){return num.split('.')[0].length;} +return num.length;} +var actions=require('actions');_.each([1,-1,10,-10,0.1,-0.1],function(num){var prefix=num>0?'increment':'decrement';actions.add(prefix+'_number_by_'+String(Math.abs(num)).replace('.','').substring(0,2),function(editor){return incrementNumber(editor,num);},{label:'Numbers/'+prefix.charAt(0).toUpperCase()+prefix.substring(1)+' number by '+Math.abs(num)});});});emmet.exec(function(require,_){var actions=require('actions');var prefs=require('preferences');prefs.define('css.closeBraceIndentation','\n','Indentation before closing brace of CSS rule. Some users prefere ' ++'indented closing brace of CSS rule for better readability. ' ++'This preference’s value will be automatically inserted before ' ++'closing brace when user adds newline in newly created CSS rule ' ++'(e.g. when “Insert formatted linebreak” action will be performed ' ++'in CSS file). If you’re such user, you may want to write put a value ' ++'like \\n\\t in this preference.');actions.add('insert_formatted_line_break_only',function(editor){var utils=require('utils');var res=require('resources');var info=require('editorUtils').outputInfo(editor);var caretPos=editor.getCaretPos();var nl=utils.getNewline();if(_.include(['html','xml','xsl'],info.syntax)){var pad=res.getVariable('indentation');var tag=require('htmlMatcher').tag(info.content,caretPos);if(tag&&!tag.innerRange.length()){editor.replaceContent(nl+pad+utils.getCaretPlaceholder()+nl,caretPos);return true;}}else if(info.syntax=='css'){var content=info.content;if(caretPos&&content.charAt(caretPos-1)=='{'){var append=prefs.get('css.closeBraceIndentation');var pad=res.getVariable('indentation');var hasCloseBrace=content.charAt(caretPos)=='}';if(!hasCloseBrace){for(var i=caretPos,il=content.length,ch;icurPadding.length) +editor.replaceContent(nl+nextPadding,caretPos,caretPos,true);else +editor.replaceContent(nl,caretPos);} +return true;},{hidden:true});});emmet.exec(function(require,_){require('actions').add('merge_lines',function(editor){var matcher=require('htmlMatcher');var utils=require('utils');var editorUtils=require('editorUtils');var info=editorUtils.outputInfo(editor);var selection=require('range').create(editor.getSelectionRange());if(!selection.length()){var pair=matcher.find(info.content,editor.getCaretPos());if(pair){selection=pair.outerRange;}} +if(selection.length()){var text=selection.substring(info.content);var lines=utils.splitByLines(text);for(var i=1;i=0){if(startsWith('src=',text,caretPos)){if(m=text.substr(caretPos).match(/^(src=(["'])?)([^'"<>\s]+)\1?/)){data=m[3];caretPos+=m[1].length;} +break;}else if(startsWith('url(',text,caretPos)){if(m=text.substr(caretPos).match(/^(url\((['"])?)([^'"\)\s]+)\1?/)){data=m[3];caretPos+=m[1].length;} +break;}}} +if(data){if(startsWith('data:',data)) +return decodeFromBase64(editor,data,caretPos);else +return encodeToBase64(editor,data,caretPos);} +return false;},{label:'Encode\\Decode data:URL image'});function startsWith(token,text,pos){pos=pos||0;return text.charAt(pos)==token.charAt(0)&&text.substr(pos,token.length)==token;} +function encodeToBase64(editor,imgPath,pos){var file=require('file');var actionUtils=require('actionUtils');var editorFile=editor.getFilePath();var defaultMimeType='application/octet-stream';if(editorFile===null){throw"You should save your file before using this action";} +var realImgPath=file.locateFile(editorFile,imgPath);if(realImgPath===null){throw"Can't find "+imgPath+' file';} +file.read(realImgPath,function(err,content){if(err){throw'Unable to read '+realImgPath+': '+err;} +var b64=require('base64').encode(String(content));if(!b64){throw"Can't encode file content to base64";} +b64='data:'+(actionUtils.mimeTypes[String(file.getExt(realImgPath))]||defaultMimeType)+';base64,'+b64;editor.replaceContent('$0'+b64,pos,pos+imgPath.length);});return true;} +function decodeFromBase64(editor,data,pos){var filePath=String(editor.prompt('Enter path to file (absolute or relative)'));if(!filePath) +return false;var file=require('file');var absPath=file.createPath(editor.getFilePath(),filePath);if(!absPath){throw"Can't save file";} +file.save(absPath,require('base64').decode(data.replace(/^data\:.+?;.+?,/,'')));editor.replaceContent('$0'+filePath,pos,pos+data.length);return true;}});emmet.exec(function(require,_){function updateImageSizeHTML(editor){var offset=editor.getCaretPos();var info=require('editorUtils').outputInfo(editor);var xmlElem=require('xmlEditTree').parseFromPosition(info.content,offset,true);if(xmlElem&&(xmlElem.name()||'').toLowerCase()=='img'){getImageSizeForSource(editor,xmlElem.value('src'),function(size){if(size){var compoundData=xmlElem.range(true);xmlElem.value('width',size.width);xmlElem.value('height',size.height,xmlElem.indexOf('width')+1);require('actionUtils').compoundUpdate(editor,_.extend(compoundData,{data:xmlElem.toString(),caret:offset}));}});}} +function updateImageSizeCSS(editor){var offset=editor.getCaretPos();var info=require('editorUtils').outputInfo(editor);var cssRule=require('cssEditTree').parseFromPosition(info.content,offset,true);if(cssRule){var prop=cssRule.itemFromPosition(offset,true),m;if(prop&&(m=/url\((["']?)(.+?)\1\)/i.exec(prop.value()||''))){getImageSizeForSource(editor,m[2],function(size){if(size){var compoundData=cssRule.range(true);cssRule.value('width',size.width+'px');cssRule.value('height',size.height+'px',cssRule.indexOf('width')+1);require('actionUtils').compoundUpdate(editor,_.extend(compoundData,{data:cssRule.toString(),caret:offset}));}});}}} +function getImageSizeForSource(editor,src,callback){var fileContent;var au=require('actionUtils');if(src){if(/^data:/.test(src)){fileContent=require('base64').decode(src.replace(/^data\:.+?;.+?,/,''));return callback(au.getImageSize(fileContent));} +var file=require('file');var absPath=file.locateFile(editor.getFilePath(),src);if(absPath===null){throw"Can't find "+src+' file';} +file.read(absPath,function(err,content){if(err){throw'Unable to read '+absPath+': '+err;} +content=String(content);callback(au.getImageSize(content));});}} +require('actions').add('update_image_size',function(editor){if(_.include(['css','less','scss'],String(editor.getSyntax()))){updateImageSizeCSS(editor);}else{updateImageSizeHTML(editor);} +return true;});});emmet.define('cssResolver',function(require,_){var module=null;var prefixObj={prefix:'emmet',obsolete:false,transformName:function(name){return'-'+this.prefix+'-'+name;},properties:function(){return getProperties('css.'+this.prefix+'Properties')||[];},supports:function(name){return _.include(this.properties(),name);}};var vendorPrefixes={};var defaultValue='${1};';var prefs=require('preferences');prefs.define('css.valueSeparator',': ','Defines a symbol that should be placed between CSS property and ' ++'value when expanding CSS abbreviations.');prefs.define('css.propertyEnd',';','Defines a symbol that should be placed at the end of CSS property ' ++'when expanding CSS abbreviations.');prefs.define('stylus.valueSeparator',' ','Defines a symbol that should be placed between CSS property and ' ++'value when expanding CSS abbreviations in Stylus dialect.');prefs.define('stylus.propertyEnd','','Defines a symbol that should be placed at the end of CSS property ' ++'when expanding CSS abbreviations in Stylus dialect.');prefs.define('sass.propertyEnd','','Defines a symbol that should be placed at the end of CSS property ' ++'when expanding CSS abbreviations in SASS dialect.');prefs.define('css.autoInsertVendorPrefixes',true,'Automatically generate vendor-prefixed copies of expanded CSS ' ++'property. By default, Emmet will generate vendor-prefixed ' ++'properties only when you put dash before abbreviation ' ++'(e.g. -bxsh). With this option enabled, you don’t ' ++'need dashes before abbreviations: Emmet will produce ' ++'vendor-prefixed properties for you.');var descTemplate=_.template('A comma-separated list of CSS properties that may have ' ++'<%= vendor %> vendor prefix. This list is used to generate ' ++'a list of prefixed properties when expanding -property ' ++'abbreviations. Empty list means that all possible CSS values may ' ++'have <%= vendor %> prefix.');var descAddonTemplate=_.template('A comma-separated list of additional CSS properties ' ++'for css.<%= vendor %>Preperties preference. ' ++'You should use this list if you want to add or remove a few CSS ' ++'properties to original set. To add a new property, simply write its name, ' ++'to remove it, precede property with hyphen.
    ' ++'For example, to add foo property and remove border-radius one, ' ++'the preference value will look like this: foo, -border-radius.');var props={'webkit':'animation, animation-delay, animation-direction, animation-duration, animation-fill-mode, animation-iteration-count, animation-name, animation-play-state, animation-timing-function, appearance, backface-visibility, background-clip, background-composite, background-origin, background-size, border-fit, border-horizontal-spacing, border-image, border-vertical-spacing, box-align, box-direction, box-flex, box-flex-group, box-lines, box-ordinal-group, box-orient, box-pack, box-reflect, box-shadow, color-correction, column-break-after, column-break-before, column-break-inside, column-count, column-gap, column-rule-color, column-rule-style, column-rule-width, column-span, column-width, dashboard-region, font-smoothing, highlight, hyphenate-character, hyphenate-limit-after, hyphenate-limit-before, hyphens, line-box-contain, line-break, line-clamp, locale, margin-before-collapse, margin-after-collapse, marquee-direction, marquee-increment, marquee-repetition, marquee-style, mask-attachment, mask-box-image, mask-box-image-outset, mask-box-image-repeat, mask-box-image-slice, mask-box-image-source, mask-box-image-width, mask-clip, mask-composite, mask-image, mask-origin, mask-position, mask-repeat, mask-size, nbsp-mode, perspective, perspective-origin, rtl-ordering, text-combine, text-decorations-in-effect, text-emphasis-color, text-emphasis-position, text-emphasis-style, text-fill-color, text-orientation, text-security, text-stroke-color, text-stroke-width, transform, transition, transform-origin, transform-style, transition-delay, transition-duration, transition-property, transition-timing-function, user-drag, user-modify, user-select, writing-mode, svg-shadow, box-sizing, border-radius','moz':'animation-delay, animation-direction, animation-duration, animation-fill-mode, animation-iteration-count, animation-name, animation-play-state, animation-timing-function, appearance, backface-visibility, background-inline-policy, binding, border-bottom-colors, border-image, border-left-colors, border-right-colors, border-top-colors, box-align, box-direction, box-flex, box-ordinal-group, box-orient, box-pack, box-shadow, box-sizing, column-count, column-gap, column-rule-color, column-rule-style, column-rule-width, column-width, float-edge, font-feature-settings, font-language-override, force-broken-image-icon, hyphens, image-region, orient, outline-radius-bottomleft, outline-radius-bottomright, outline-radius-topleft, outline-radius-topright, perspective, perspective-origin, stack-sizing, tab-size, text-blink, text-decoration-color, text-decoration-line, text-decoration-style, text-size-adjust, transform, transform-origin, transform-style, transition, transition-delay, transition-duration, transition-property, transition-timing-function, user-focus, user-input, user-modify, user-select, window-shadow, background-clip, border-radius','ms':'accelerator, backface-visibility, background-position-x, background-position-y, behavior, block-progression, box-align, box-direction, box-flex, box-line-progression, box-lines, box-ordinal-group, box-orient, box-pack, content-zoom-boundary, content-zoom-boundary-max, content-zoom-boundary-min, content-zoom-chaining, content-zoom-snap, content-zoom-snap-points, content-zoom-snap-type, content-zooming, filter, flow-from, flow-into, font-feature-settings, grid-column, grid-column-align, grid-column-span, grid-columns, grid-layer, grid-row, grid-row-align, grid-row-span, grid-rows, high-contrast-adjust, hyphenate-limit-chars, hyphenate-limit-lines, hyphenate-limit-zone, hyphens, ime-mode, interpolation-mode, layout-flow, layout-grid, layout-grid-char, layout-grid-line, layout-grid-mode, layout-grid-type, line-break, overflow-style, perspective, perspective-origin, perspective-origin-x, perspective-origin-y, scroll-boundary, scroll-boundary-bottom, scroll-boundary-left, scroll-boundary-right, scroll-boundary-top, scroll-chaining, scroll-rails, scroll-snap-points-x, scroll-snap-points-y, scroll-snap-type, scroll-snap-x, scroll-snap-y, scrollbar-arrow-color, scrollbar-base-color, scrollbar-darkshadow-color, scrollbar-face-color, scrollbar-highlight-color, scrollbar-shadow-color, scrollbar-track-color, text-align-last, text-autospace, text-justify, text-kashida-space, text-overflow, text-size-adjust, text-underline-position, touch-action, transform, transform-origin, transform-origin-x, transform-origin-y, transform-origin-z, transform-style, transition, transition-delay, transition-duration, transition-property, transition-timing-function, user-select, word-break, word-wrap, wrap-flow, wrap-margin, wrap-through, writing-mode','o':'dashboard-region, animation, animation-delay, animation-direction, animation-duration, animation-fill-mode, animation-iteration-count, animation-name, animation-play-state, animation-timing-function, border-image, link, link-source, object-fit, object-position, tab-size, table-baseline, transform, transform-origin, transition, transition-delay, transition-duration, transition-property, transition-timing-function, accesskey, input-format, input-required, marquee-dir, marquee-loop, marquee-speed, marquee-style'};_.each(props,function(v,k){prefs.define('css.'+k+'Properties',v,descTemplate({vendor:k}));prefs.define('css.'+k+'PropertiesAddon','',descAddonTemplate({vendor:k}));});prefs.define('css.unitlessProperties','z-index, line-height, opacity, font-weight, zoom','The list of properties whose values ​​must not contain units.');prefs.define('css.intUnit','px','Default unit for integer values');prefs.define('css.floatUnit','em','Default unit for float values');prefs.define('css.keywords','auto, inherit','A comma-separated list of valid keywords that can be used in CSS abbreviations.');prefs.define('css.keywordAliases','a:auto, i:inherit, s:solid, da:dashed, do:dotted, t:transparent','A comma-separated list of keyword aliases, used in CSS abbreviation. ' ++'Each alias should be defined as alias:keyword_name.');prefs.define('css.unitAliases','e:em, p:%, x:ex, r:rem','A comma-separated list of unit aliases, used in CSS abbreviation. ' ++'Each alias should be defined as alias:unit_value.');prefs.define('css.color.short',true,'Should color values like #ffffff be shortened to ' ++'#fff after abbreviation with color was expanded.');prefs.define('css.color.case','keep','Letter case of color values generated by abbreviations with color ' ++'(like c#0). Possible values are upper, ' ++'lower and keep.');prefs.define('css.fuzzySearch',true,'Enable fuzzy search among CSS snippet names. When enabled, every ' ++'unknown snippet will be scored against available snippet ' ++'names (not values or CSS properties!). The match with best score ' ++'will be used to resolve snippet value. For example, with this ' ++'preference enabled, the following abbreviations are equal: ' ++'ov:h == ov-h == o-h == ' ++'oh');prefs.define('css.fuzzySearchMinScore',0.3,'The minium score (from 0 to 1) that fuzzy-matched abbreviation should ' ++'achive. Lower values may produce many false-positive matches, ' ++'higher values may reduce possible matches.');prefs.define('css.alignVendor',false,'If set to true, all generated vendor-prefixed properties ' ++'will be aligned by real property name.');function isNumeric(ch){var code=ch&&ch.charCodeAt(0);return(ch&&ch=='.'||(code>47&&code<58));} +function isSingleProperty(snippet){var utils=require('utils');snippet=utils.trim(snippet);if(~snippet.indexOf('/*')||/[\n\r]/.test(snippet)){return false;} +if(!/^[a-z0-9\-]+\s*\:/i.test(snippet)){return false;} +snippet=require('tabStops').processText(snippet,{replaceCarets:true,tabstop:function(){return'value';}});return snippet.split(':').length==2;} +function normalizeValue(value){if(value.charAt(0)=='-'&&!/^\-[\.\d]/.test(value)){value=value.replace(/^\-+/,'');} +if(value.charAt(0)=='#'){return normalizeHexColor(value);} +return getKeyword(value);} +function normalizeHexColor(value){var hex=value.replace(/^#+/,'')||'0';if(hex.toLowerCase()=='t'){return'transparent';} +var repeat=require('utils').repeatString;var color=null;switch(hex.length){case 1:color=repeat(hex,6);break;case 2:color=repeat(hex,3);break;case 3:color=hex.charAt(0)+hex.charAt(0)+hex.charAt(1)+hex.charAt(1)+hex.charAt(2)+hex.charAt(2);break;case 4:color=hex+hex.substr(0,2);break;case 5:color=hex+hex.charAt(0);break;default:color=hex.substr(0,6);} +if(prefs.get('css.color.short')){var p=color.split('');if(p[0]==p[1]&&p[2]==p[3]&&p[4]==p[5]){color=p[0]+p[2]+p[4];}} +switch(prefs.get('css.color.case')){case'upper':color=color.toUpperCase();break;case'lower':color=color.toLowerCase();break;} +return'#'+color;} +function getKeyword(name){var aliases=prefs.getDict('css.keywordAliases');return name in aliases?aliases[name]:name;} +function getUnit(name){var aliases=prefs.getDict('css.unitAliases');return name in aliases?aliases[name]:name;} +function isValidKeyword(keyword){return _.include(prefs.getArray('css.keywords'),getKeyword(keyword));} +function hasPrefix(property,prefix){var info=vendorPrefixes[prefix];if(!info) +info=_.find(vendorPrefixes,function(data){return data.prefix==prefix;});return info&&info.supports(property);} +function findPrefixes(property,noAutofill){var result=[];_.each(vendorPrefixes,function(obj,prefix){if(hasPrefix(property,prefix)){result.push(prefix);}});if(!result.length&&!noAutofill){_.each(vendorPrefixes,function(obj,prefix){if(!obj.obsolete) +result.push(prefix);});} +return result;} +function addPrefix(name,obj){if(_.isString(obj)) +obj={prefix:obj};vendorPrefixes[name]=_.extend({},prefixObj,obj);} +function getSyntaxPreference(name,syntax){if(syntax){var val=prefs.get(syntax+'.'+name);if(!_.isUndefined(val)) +return val;} +return prefs.get('css.'+name);} +function formatProperty(property,syntax){var ix=property.indexOf(':');property=property.substring(0,ix).replace(/\s+$/,'') ++getSyntaxPreference('valueSeparator',syntax) ++require('utils').trim(property.substring(ix+1));return property.replace(/\s*;\s*$/,getSyntaxPreference('propertyEnd',syntax));} +function transformSnippet(snippet,isImportant,syntax){if(!_.isString(snippet)) +snippet=snippet.data;if(!isSingleProperty(snippet)) +return snippet;if(isImportant){if(~snippet.indexOf(';')){snippet=snippet.split(';').join(' !important;');}else{snippet+=' !important';}} +return formatProperty(snippet,syntax);} +function parseList(list){var result=_.map((list||'').split(','),require('utils').trim);return result.length?result:null;} +function getProperties(key){var list=prefs.getArray(key);_.each(prefs.getArray(key+'Addon'),function(prop){if(prop.charAt(0)=='-'){list=_.without(list,prop.substr(1));}else{if(prop.charAt(0)=='+') +prop=prop.substr(1);list.push(prop);}});return list;} +addPrefix('w',{prefix:'webkit'});addPrefix('m',{prefix:'moz'});addPrefix('s',{prefix:'ms'});addPrefix('o',{prefix:'o'});var cssSyntaxes=['css','less','sass','scss','stylus'];require('resources').addResolver(function(node,syntax){if(_.include(cssSyntaxes,syntax)&&node.isElement()){return module.expandToSnippet(node.abbreviation,syntax);} +return null;});var ea=require('expandAbbreviation');ea.addHandler(function(editor,syntax,profile){if(!_.include(cssSyntaxes,syntax)){return false;} +var caretPos=editor.getSelectionRange().end;var abbr=ea.findAbbreviation(editor);if(abbr){var content=emmet.expandAbbreviation(abbr,syntax,profile);if(content){var replaceFrom=caretPos-abbr.length;var replaceTo=caretPos;if(editor.getContent().charAt(caretPos)==';'&&content.charAt(content.length-1)==';'){replaceTo++;} +editor.replaceContent(content,replaceFrom,replaceTo);return true;}} +return false;});return module={addPrefix:addPrefix,supportsPrefix:hasPrefix,prefixed:function(property,prefix){return hasPrefix(property,prefix)?'-'+prefix+'-'+property:property;},listPrefixes:function(){return _.map(vendorPrefixes,function(obj){return obj.prefix;});},getPrefix:function(name){return vendorPrefixes[name];},removePrefix:function(name){if(name in vendorPrefixes) +delete vendorPrefixes[name];},extractPrefixes:function(abbr){if(abbr.charAt(0)!='-'){return{property:abbr,prefixes:null};} +var i=1,il=abbr.length,ch;var prefixes=[];while(ibackground-color property with gradient first color ' ++'as fallback for old browsers.');function normalizeSpace(str){return require('utils').trim(str).replace(/\s+/g,' ');} +function parseLinearGradient(gradient){var direction=defaultLinearDirections[0];var stream=require('stringStream').create(require('utils').trim(gradient));var colorStops=[],ch;while(ch=stream.next()){if(stream.peek()==','){colorStops.push(stream.current());stream.next();stream.eatSpace();stream.start=stream.pos;}else if(ch=='('){stream.skipTo(')');}} +colorStops.push(stream.current());colorStops=_.compact(_.map(colorStops,normalizeSpace));if(!colorStops.length) +return null;if(reDeg.test(colorStops[0])||reKeyword.test(colorStops[0])){direction=colorStops.shift();} +return{type:'linear',direction:direction,colorStops:_.map(colorStops,parseColorStop)};} +function parseColorStop(colorStop){colorStop=normalizeSpace(colorStop);var color=null;colorStop=colorStop.replace(/^(\w+\(.+?\))\s*/,function(str,c){color=c;return'';});if(!color){var parts=colorStop.split(' ');color=parts[0];colorStop=parts[1]||'';} +var result={color:color};if(colorStop){colorStop.replace(/^(\-?[\d\.]+)([a-z%]+)?$/,function(str,pos,unit){result.position=pos;if(~pos.indexOf('.')){unit='';}else if(!unit){unit='%';} +if(unit) +result.unit=unit;});} +return result;} +function resolvePropertyName(name,syntax){var res=require('resources');var prefs=require('preferences');var snippet=res.findSnippet(syntax,name);if(!snippet&&prefs.get('css.fuzzySearch')){snippet=res.fuzzyFindSnippet(syntax,name,parseFloat(prefs.get('css.fuzzySearchMinScore')));} +if(snippet){if(!_.isString(snippet)){snippet=snippet.data;} +return require('cssResolver').splitSnippet(snippet).name;}} +function fillImpliedPositions(colorStops){var from=0;_.each(colorStops,function(cs,i){if(!i) +return cs.position=cs.position||0;if(i==colorStops.length-1&&!('position'in cs)) +cs.position=1;if('position'in cs){var start=colorStops[from].position||0;var step=(cs.position-start)/(i-from);_.each(colorStops.slice(from,i),function(cs2,j){cs2.position=start+step*j;});from=i;}});} +function textualDirection(direction){var angle=parseFloat(direction);if(!_.isNaN(angle)){switch(angle%360){case 0:return'left';case 90:return'bottom';case 180:return'right';case 240:return'top';}} +return direction;} +function oldWebkitDirection(direction){direction=textualDirection(direction);if(reDeg.test(direction)) +throw"The direction is an angle that can’t be converted.";var v=function(pos){return~direction.indexOf(pos)?'100%':'0';};return v('right')+' '+v('bottom')+', '+v('left')+' '+v('top');} +function getPrefixedNames(name){var prefixes=prefs.getArray('css.gradient.prefixes');var names=prefixes?_.map(prefixes,function(p){return'-'+p+'-'+name;}):[];names.push(name);return names;} +function getPropertiesForGradient(gradient,propertyName){var props=[];var css=require('cssResolver');if(prefs.get('css.gradient.fallback')&&~propertyName.toLowerCase().indexOf('background')){props.push({name:'background-color',value:'${1:'+gradient.colorStops[0].color+'}'});} +_.each(prefs.getArray('css.gradient.prefixes'),function(prefix){var name=css.prefixed(propertyName,prefix);if(prefix=='webkit'&&prefs.get('css.gradient.oldWebkit')){try{props.push({name:name,value:module.oldWebkitLinearGradient(gradient)});}catch(e){}} +props.push({name:name,value:module.toString(gradient,prefix)});});return props.sort(function(a,b){return b.name.length-a.name.length;});} +function pasteGradient(property,gradient,valueRange){var rule=property.parent;var utils=require('utils');var alignVendor=require('preferences').get('css.alignVendor');var sep=property.styleSeparator;var before=property.styleBefore;_.each(rule.getAll(getPrefixedNames(property.name())),function(item){if(item!=property&&/gradient/i.test(item.value())){if(item.styleSeparator.length<%= attr("class", ".") %> -->','A definition of comment that should be placed after matched ' ++'element when comment filter is applied. This definition ' ++'is an ERB-style template passed to _.template() ' ++'function (see Underscore.js docs for details). In template context, ' ++'the following properties and functions are availabe:\n' ++'
      ' ++'
    • attr(name, before, after) – a function that outputs' ++'specified attribute value concatenated with before ' ++'and after strings. If attribute doesn\'t exists, the ' ++'empty string will be returned.
    • ' ++'
    • node – current node (instance of AbbreviationNode)
    • ' ++'
    • name – name of current tag
    • ' ++'
    • padding – current string padding, can be used ' ++'for formatting
    • ' ++'
    ');prefs.define('filter.commentBefore','','A definition of comment that should be placed before matched ' ++'element when comment filter is applied. ' ++'For more info, read description of filter.commentAfter ' ++'property');prefs.define('filter.commentTrigger','id, class','A comma-separated list of attribute names that should exist in abbreviatoin ' ++'where comment should be added. If you wish to add comment for ' ++'every element, set this option to *');function addComments(node,templateBefore,templateAfter){var utils=require('utils');var trigger=prefs.get('filter.commentTrigger');if(trigger!='*'){var shouldAdd=_.find(trigger.split(','),function(name){return!!node.attribute(utils.trim(name));});if(!shouldAdd)return;} +var ctx={node:node,name:node.name(),padding:node.parent?node.parent.padding:'',attr:function(name,before,after){var attr=node.attribute(name);if(attr){return(before||'')+attr+(after||'');} +return'';}};var nodeBefore=utils.normalizeNewline(templateBefore?templateBefore(ctx):'');var nodeAfter=utils.normalizeNewline(templateAfter?templateAfter(ctx):'');node.start=node.start.replace(//,'>'+nodeAfter);} +function process(tree,before,after){var abbrUtils=require('abbreviationUtils');_.each(tree.children,function(item){if(abbrUtils.isBlock(item)) +addComments(item,before,after);process(item,before,after);});return tree;} +require('filters').add('c',function(tree){var templateBefore=_.template(prefs.get('filter.commentBefore'));var templateAfter=_.template(prefs.get('filter.commentAfter'));return process(tree,templateBefore,templateAfter);});});emmet.exec(function(require,_){var charMap={'<':'<','>':'>','&':'&'};function escapeChars(str){return str.replace(/([<>&])/g,function(str,p1){return charMap[p1];});} +require('filters').add('e',function process(tree){_.each(tree.children,function(item){item.start=escapeChars(item.start);item.end=escapeChars(item.end);item.content=escapeChars(item.content);process(item);});return tree;});});emmet.exec(function(require,_){var placeholder='%s';var prefs=require('preferences');prefs.define('format.noIndentTags','html','A comma-separated list of tag names that should not get inner indentation.');prefs.define('format.forceIndentationForTags','body','A comma-separated list of tag names that should always get inner indentation.');function getIndentation(node){if(_.include(prefs.getArray('format.noIndentTags')||[],node.name())){return'';} +return require('resources').getVariable('indentation');} +function hasBlockSibling(item){return item.parent&&require('abbreviationUtils').hasBlockChildren(item.parent);} +function isVeryFirstChild(item){return item.parent&&!item.parent.parent&&!item.index();} +function shouldAddLineBreak(node,profile){var abbrUtils=require('abbreviationUtils');if(profile.tag_nl===true||abbrUtils.isBlock(node)) +return true;if(!node.parent||!profile.inline_break) +return false;return shouldFormatInline(node.parent,profile);} +function shouldBreakChild(node,profile){return node.children.length&&shouldAddLineBreak(node.children[0],profile);} +function shouldFormatInline(node,profile){var nodeCount=0;var abbrUtils=require('abbreviationUtils');return!!_.find(node.children,function(child){if(child.isTextNode()||!abbrUtils.isInline(child)) +nodeCount=0;else if(abbrUtils.isInline(child)) +nodeCount++;if(nodeCount>=profile.inline_break) +return true;});} +function isRoot(item){return!item.parent;} +function processSnippet(item,profile,level){item.start=item.end='';if(!isVeryFirstChild(item)&&profile.tag_nl!==false&&shouldAddLineBreak(item,profile)){if(isRoot(item.parent)||!require('abbreviationUtils').isInline(item.parent)){item.start=require('utils').getNewline()+item.start;}} +return item;} +function shouldBreakInsideInline(node,profile){var abbrUtils=require('abbreviationUtils');var hasBlockElems=_.any(node.children,function(child){if(abbrUtils.isSnippet(child)) +return false;return!abbrUtils.isInline(child);});if(!hasBlockElems){return shouldFormatInline(node,profile);} +return true;} +function processTag(item,profile,level){item.start=item.end=placeholder;var utils=require('utils');var abbrUtils=require('abbreviationUtils');var isUnary=abbrUtils.isUnary(item);var nl=utils.getNewline();var indent=getIndentation(item);if(profile.tag_nl!==false){var forceNl=profile.tag_nl===true&&(profile.tag_nl_leaf||item.children.length);if(!forceNl){forceNl=_.include(prefs.getArray('format.forceIndentationForTags')||[],item.name());} +if(!item.isTextNode()){if(shouldAddLineBreak(item,profile)){if(!isVeryFirstChild(item)&&(!abbrUtils.isSnippet(item.parent)||item.index())) +item.start=nl+item.start;if(abbrUtils.hasBlockChildren(item)||shouldBreakChild(item,profile)||(forceNl&&!isUnary)) +item.end=nl+item.end;if(abbrUtils.hasTagsInContent(item)||(forceNl&&!item.children.length&&!isUnary)) +item.start+=nl+indent;}else if(abbrUtils.isInline(item)&&hasBlockSibling(item)&&!isVeryFirstChild(item)){item.start=nl+item.start;}else if(abbrUtils.isInline(item)&&shouldBreakInsideInline(item,profile)){item.end=nl+item.end;} +item.padding=indent;}} +return item;} +require('filters').add('_format',function process(tree,profile,level){level=level||0;var abbrUtils=require('abbreviationUtils');_.each(tree.children,function(item){if(abbrUtils.isSnippet(item)) +processSnippet(item,profile,level);else +processTag(item,profile,level);process(item,profile,level+1);});return tree;});});emmet.exec(function(require,_){var childToken='${child}';function transformClassName(className){return require('utils').trim(className).replace(/\s+/g,'.');} +function makeAttributesString(tag,profile){var attrs='';var otherAttrs=[];var attrQuote=profile.attributeQuote();var cursor=profile.cursor();_.each(tag.attributeList(),function(a){var attrName=profile.attributeName(a.name);switch(attrName.toLowerCase()){case'id':attrs+='#'+(a.value||cursor);break;case'class':attrs+='.'+transformClassName(a.value||cursor);break;default:otherAttrs.push(':'+attrName+' => '+attrQuote+(a.value||cursor)+attrQuote);}});if(otherAttrs.length) +attrs+='{'+otherAttrs.join(', ')+'}';return attrs;} +function hasBlockSibling(item){return item.parent&&item.parent.hasBlockChildren();} +function processTag(item,profile,level){if(!item.parent) +return item;var abbrUtils=require('abbreviationUtils');var utils=require('utils');var attrs=makeAttributesString(item,profile);var cursor=profile.cursor();var isUnary=abbrUtils.isUnary(item);var selfClosing=profile.self_closing_tag&&isUnary?'/':'';var start='';var tagName='%'+profile.tagName(item.name());if(tagName.toLowerCase()=='%div'&&attrs&&attrs.indexOf('{')==-1) +tagName='';item.end='';start=tagName+attrs+selfClosing+' ';var placeholder='%s';item.start=utils.replaceSubstring(item.start,start,item.start.indexOf(placeholder),placeholder);if(!item.children.length&&!isUnary) +item.start+=cursor;return item;} +require('filters').add('haml',function process(tree,profile,level){level=level||0;var abbrUtils=require('abbreviationUtils');if(!level){tree=require('filters').apply(tree,'_format',profile);} +_.each(tree.children,function(item){if(!abbrUtils.isSnippet(item)) +processTag(item,profile,level);process(item,profile,level+1);});return tree;});});emmet.exec(function(require,_){function makeAttributesString(node,profile){var attrQuote=profile.attributeQuote();var cursor=profile.cursor();return _.map(node.attributeList(),function(a){var attrName=profile.attributeName(a.name);return' '+attrName+'='+attrQuote+(a.value||cursor)+attrQuote;}).join('');} +function processTag(item,profile,level){if(!item.parent) +return item;var abbrUtils=require('abbreviationUtils');var utils=require('utils');var attrs=makeAttributesString(item,profile);var cursor=profile.cursor();var isUnary=abbrUtils.isUnary(item);var start='';var end='';if(!item.isTextNode()){var tagName=profile.tagName(item.name());if(isUnary){start='<'+tagName+attrs+profile.selfClosing()+'>';item.end='';}else{start='<'+tagName+attrs+'>';end='';}} +var placeholder='%s';item.start=utils.replaceSubstring(item.start,start,item.start.indexOf(placeholder),placeholder);item.end=utils.replaceSubstring(item.end,end,item.end.indexOf(placeholder),placeholder);if(!item.children.length&&!isUnary&&!~item.content.indexOf(cursor)&&!require('tabStops').extract(item.content).tabstops.length){item.start+=cursor;} +return item;} +require('filters').add('html',function process(tree,profile,level){level=level||0;var abbrUtils=require('abbreviationUtils');if(!level){tree=require('filters').apply(tree,'_format',profile);} +_.each(tree.children,function(item){if(!abbrUtils.isSnippet(item)) +processTag(item,profile,level);process(item,profile,level+1);});return tree;});});emmet.exec(function(require,_){var rePad=/^\s+/;var reNl=/[\n\r]/g;require('filters').add('s',function process(tree,profile,level){var abbrUtils=require('abbreviationUtils');_.each(tree.children,function(item){if(!abbrUtils.isSnippet(item)){item.start=item.start.replace(rePad,'');item.end=item.end.replace(rePad,'');} +item.start=item.start.replace(reNl,'');item.end=item.end.replace(reNl,'');item.content=item.content.replace(reNl,'');process(item);});return tree;});});emmet.exec(function(require,_){require('preferences').define('filter.trimRegexp','[\\s|\\u00a0]*[\\d|#|\\-|\*|\\u2022]+\\.?\\s*','Regular expression used to remove list markers (numbers, dashes, ' ++'bullets, etc.) in t (trim) filter. The trim filter ' ++'is useful for wrapping with abbreviation lists, pased from other ' ++'documents (for example, Word documents).');function process(tree,re){_.each(tree.children,function(item){if(item.content) +item.content=item.content.replace(re,'');process(item,re);});return tree;} +require('filters').add('t',function(tree){var re=new RegExp(require('preferences').get('filter.trimRegexp'));return process(tree,re);});});emmet.exec(function(require,_){var tags={'xsl:variable':1,'xsl:with-param':1};function trimAttribute(node){node.start=node.start.replace(/\s+select\s*=\s*(['"]).*?\1/,'');} +require('filters').add('xsl',function process(tree){var abbrUtils=require('abbreviationUtils');_.each(tree.children,function(item){if(!abbrUtils.isSnippet(item)&&(item.name()||'').toLowerCase()in tags&&item.children.length) +trimAttribute(item);process(item);});return tree;});});emmet.define('lorem',function(require,_){var langs={en:{common:['lorem','ipsum','dolor','sit','amet','consectetur','adipisicing','elit'],words:['exercitationem','perferendis','perspiciatis','laborum','eveniet','sunt','iure','nam','nobis','eum','cum','officiis','excepturi','odio','consectetur','quasi','aut','quisquam','vel','eligendi','itaque','non','odit','tempore','quaerat','dignissimos','facilis','neque','nihil','expedita','vitae','vero','ipsum','nisi','animi','cumque','pariatur','velit','modi','natus','iusto','eaque','sequi','illo','sed','ex','et','voluptatibus','tempora','veritatis','ratione','assumenda','incidunt','nostrum','placeat','aliquid','fuga','provident','praesentium','rem','necessitatibus','suscipit','adipisci','quidem','possimus','voluptas','debitis','sint','accusantium','unde','sapiente','voluptate','qui','aspernatur','laudantium','soluta','amet','quo','aliquam','saepe','culpa','libero','ipsa','dicta','reiciendis','nesciunt','doloribus','autem','impedit','minima','maiores','repudiandae','ipsam','obcaecati','ullam','enim','totam','delectus','ducimus','quis','voluptates','dolores','molestiae','harum','dolorem','quia','voluptatem','molestias','magni','distinctio','omnis','illum','dolorum','voluptatum','ea','quas','quam','corporis','quae','blanditiis','atque','deserunt','laboriosam','earum','consequuntur','hic','cupiditate','quibusdam','accusamus','ut','rerum','error','minus','eius','ab','ad','nemo','fugit','officia','at','in','id','quos','reprehenderit','numquam','iste','fugiat','sit','inventore','beatae','repellendus','magnam','recusandae','quod','explicabo','doloremque','aperiam','consequatur','asperiores','commodi','optio','dolor','labore','temporibus','repellat','veniam','architecto','est','esse','mollitia','nulla','a','similique','eos','alias','dolore','tenetur','deleniti','porro','facere','maxime','corrupti']},ru:{common:['далеко-далеко','за','словесными','горами','в стране','гласных','и согласных','живут','рыбные','тексты'],words:['вдали','от всех','они','буквенных','домах','на берегу','семантика','большого','языкового','океана','маленький','ручеек','даль','журчит','по всей','обеспечивает','ее','всеми','необходимыми','правилами','эта','парадигматическая','страна','которой','жаренные','предложения','залетают','прямо','рот','даже','всемогущая','пунктуация','не','имеет','власти','над','рыбными','текстами','ведущими','безорфографичный','образ','жизни','однажды','одна','маленькая','строчка','рыбного','текста','имени','lorem','ipsum','решила','выйти','большой','мир','грамматики','великий','оксмокс','предупреждал','о','злых','запятых','диких','знаках','вопроса','коварных','точках','запятой','но','текст','дал','сбить','себя','толку','он','собрал','семь','своих','заглавных','букв','подпоясал','инициал','за','пояс','пустился','дорогу','взобравшись','первую','вершину','курсивных','гор','бросил','последний','взгляд','назад','силуэт','своего','родного','города','буквоград','заголовок','деревни','алфавит','подзаголовок','своего','переулка','грустный','реторический','вопрос','скатился','его','щеке','продолжил','свой','путь','дороге','встретил','рукопись','она','предупредила','моей','все','переписывается','несколько','раз','единственное','что','меня','осталось','это','приставка','возвращайся','ты','лучше','свою','безопасную','страну','послушавшись','рукописи','наш','продолжил','свой','путь','вскоре','ему','повстречался','коварный','составитель','рекламных','текстов','напоивший','языком','речью','заманивший','свое','агенство','которое','использовало','снова','снова','своих','проектах','если','переписали','то','живет','там','до','сих','пор']}};var prefs=require('preferences');prefs.define('lorem.defaultLang','en');require('abbreviationParser').addPreprocessor(function(tree,options){var re=/^(?:lorem|lipsum)([a-z]{2})?(\d*)$/i,match;tree.findAll(function(node){if(node._name&&(match=node._name.match(re))){var wordCound=match[2]||30;var lang=match[1]||prefs.get('lorem.defaultLang')||'en';node._name='';node.data('forceNameResolving',node.isRepeating()||node.attributeList().length);node.data('pasteOverwrites',true);node.data('paste',function(i,content){return paragraph(lang,wordCound,!i);});}});});function randint(from,to){return Math.round(Math.random()*(to-from)+from);} +function sample(arr,count){var len=arr.length;var iterations=Math.min(len,count);var result=[];while(result.length3&&len<=6){totalCommas=randint(0,1);}else if(len>6&&len<=12){totalCommas=randint(0,2);}else{totalCommas=randint(1,4);} +_.each(_.range(totalCommas),function(ix){if(ix5) +words[4]+=',';totalWords+=words.length;result.push(sentence(words,'.'));} +while(totalWords","!!!4t":"","!!!4s":"","!!!xt":"","!!!xs":"","!!!xxs":"","c":"","cc:ie6":"","cc:ie":"","cc:noie":"\n\t${child}|\n"},"abbreviations":{"!":"html:5","a":"","a:link":"","a:mail":"","abbr":"","acronym":"","base":"","basefont":"","br":"
    ","frame":"","hr":"
    ","bdo":"","bdo:r":"","bdo:l":"","col":"","link":"","link:css":"","link:print":"","link:favicon":"","link:touch":"","link:rss":"","link:atom":"","meta":"","meta:utf":"","meta:win":"","meta:vp":"","meta:compat":"","style":"\n\ +snippet sub\n\ + ${1}\n\ +snippet summary\n\ + \n\ + ${1}\n\ + \n\ +snippet sup\n\ + ${1}\n\ +snippet table\n\ + \n\ + ${2}\n\ +
    \n\ +snippet table.\n\ + \n\ + ${3}\n\ +
    \n\ +snippet table#\n\ + \n\ + ${3}\n\ +
    \n\ +snippet tbody\n\ + \n\ + ${1}\n\ + \n\ +snippet td\n\ + ${1}\n\ +snippet td.\n\ + ${2}\n\ +snippet td#\n\ + ${2}\n\ +snippet td+\n\ + ${1}\n\ + td+${2}\n\ +snippet textarea\n\ + ${6}\n\ +snippet tfoot\n\ + \n\ + ${1}\n\ + \n\ +snippet th\n\ + ${1}\n\ +snippet th.\n\ + ${2}\n\ +snippet th#\n\ + ${2}\n\ +snippet th+\n\ + ${1}\n\ + th+${2}\n\ +snippet thead\n\ + \n\ + ${1}\n\ + \n\ +snippet time\n\ + \n\ +snippet title\n\ + ${1:`substitute(Filename('', 'Page Title'), '^.', '\\u&', '')`}\n\ +snippet tr\n\ + \n\ + ${1}\n\ + \n\ +snippet tr+\n\ + \n\ + ${1}\n\ + td+${2}\n\ + \n\ +snippet track\n\ + ${5}${6}\n\ +snippet ul\n\ +
      \n\ + ${1}\n\ +
    \n\ +snippet ul.\n\ +
      \n\ + ${2}\n\ +
    \n\ +snippet ul#\n\ +
      \n\ + ${2}\n\ +
    \n\ +snippet ul+\n\ +
      \n\ +
    • ${1}
    • \n\ + li+${2}\n\ +
    \n\ +snippet var\n\ + ${1}\n\ +snippet video\n\ + ${8}\n\ +snippet wbr\n\ + ${1}\n\ +"; +exports.scope = "html"; + +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/javascript.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/javascript.js new file mode 100644 index 0000000..f3f998a --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/javascript.js @@ -0,0 +1,202 @@ +ace.define("ace/snippets/javascript",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.snippetText = "# Prototype\n\ +snippet proto\n\ + ${1:class_name}.prototype.${2:method_name} = function(${3:first_argument}) {\n\ + ${4:// body...}\n\ + };\n\ +# Function\n\ +snippet fun\n\ + function ${1?:function_name}(${2:argument}) {\n\ + ${3:// body...}\n\ + }\n\ +# Anonymous Function\n\ +regex /((=)\\s*|(:)\\s*|(\\()|\\b)/f/(\\))?/\n\ +snippet f\n\ + function${M1?: ${1:functionName}}($2) {\n\ + ${0:$TM_SELECTED_TEXT}\n\ + }${M2?;}${M3?,}${M4?)}\n\ +# Immediate function\n\ +trigger \\(?f\\(\n\ +endTrigger \\)?\n\ +snippet f(\n\ + (function(${1}) {\n\ + ${0:${TM_SELECTED_TEXT:/* code */}}\n\ + }(${1}));\n\ +# if\n\ +snippet if\n\ + if (${1:true}) {\n\ + ${0}\n\ + }\n\ +# if ... else\n\ +snippet ife\n\ + if (${1:true}) {\n\ + ${2}\n\ + } else {\n\ + ${0}\n\ + }\n\ +# tertiary conditional\n\ +snippet ter\n\ + ${1:/* condition */} ? ${2:a} : ${3:b}\n\ +# switch\n\ +snippet switch\n\ + switch (${1:expression}) {\n\ + case '${3:case}':\n\ + ${4:// code}\n\ + break;\n\ + ${5}\n\ + default:\n\ + ${2:// code}\n\ + }\n\ +# case\n\ +snippet case\n\ + case '${1:case}':\n\ + ${2:// code}\n\ + break;\n\ + ${3}\n\ +\n\ +# while (...) {...}\n\ +snippet wh\n\ + while (${1:/* condition */}) {\n\ + ${0:/* code */}\n\ + }\n\ +# try\n\ +snippet try\n\ + try {\n\ + ${0:/* code */}\n\ + } catch (e) {}\n\ +# do...while\n\ +snippet do\n\ + do {\n\ + ${2:/* code */}\n\ + } while (${1:/* condition */});\n\ +# Object Method\n\ +snippet :f\n\ +regex /([,{[])|^\\s*/:f/\n\ + ${1:method_name}: function(${2:attribute}) {\n\ + ${0}\n\ + }${3:,}\n\ +# setTimeout function\n\ +snippet setTimeout\n\ +regex /\\b/st|timeout|setTimeo?u?t?/\n\ + setTimeout(function() {${3:$TM_SELECTED_TEXT}}, ${1:10});\n\ +# Get Elements\n\ +snippet gett\n\ + getElementsBy${1:TagName}('${2}')${3}\n\ +# Get Element\n\ +snippet get\n\ + getElementBy${1:Id}('${2}')${3}\n\ +# console.log (Firebug)\n\ +snippet cl\n\ + console.log(${1});\n\ +# return\n\ +snippet ret\n\ + return ${1:result}\n\ +# for (property in object ) { ... }\n\ +snippet fori\n\ + for (var ${1:prop} in ${2:Things}) {\n\ + ${0:$2[$1]}\n\ + }\n\ +# hasOwnProperty\n\ +snippet has\n\ + hasOwnProperty(${1})\n\ +# docstring\n\ +snippet /**\n\ + /**\n\ + * ${1:description}\n\ + *\n\ + */\n\ +snippet @par\n\ +regex /^\\s*\\*\\s*/@(para?m?)?/\n\ + @param {${1:type}} ${2:name} ${3:description}\n\ +snippet @ret\n\ + @return {${1:type}} ${2:description}\n\ +# JSON.parse\n\ +snippet jsonp\n\ + JSON.parse(${1:jstr});\n\ +# JSON.stringify\n\ +snippet jsons\n\ + JSON.stringify(${1:object});\n\ +# self-defining function\n\ +snippet sdf\n\ + var ${1:function_name} = function(${2:argument}) {\n\ + ${3:// initial code ...}\n\ +\n\ + $1 = function($2) {\n\ + ${4:// main code}\n\ + };\n\ + }\n\ +# singleton\n\ +snippet sing\n\ + function ${1:Singleton} (${2:argument}) {\n\ + // the cached instance\n\ + var instance;\n\ +\n\ + // rewrite the constructor\n\ + $1 = function $1($2) {\n\ + return instance;\n\ + };\n\ + \n\ + // carry over the prototype properties\n\ + $1.prototype = this;\n\ +\n\ + // the instance\n\ + instance = new $1();\n\ +\n\ + // reset the constructor pointer\n\ + instance.constructor = $1;\n\ +\n\ + ${3:// code ...}\n\ +\n\ + return instance;\n\ + }\n\ +# class\n\ +snippet class\n\ +regex /^\\s*/clas{0,2}/\n\ + var ${1:class} = function(${20}) {\n\ + $40$0\n\ + };\n\ + \n\ + (function() {\n\ + ${60:this.prop = \"\"}\n\ + }).call(${1:class}.prototype);\n\ + \n\ + exports.${1:class} = ${1:class};\n\ +# \n\ +snippet for-\n\ + for (var ${1:i} = ${2:Things}.length; ${1:i}--; ) {\n\ + ${0:${2:Things}[${1:i}];}\n\ + }\n\ +# for (...) {...}\n\ +snippet for\n\ + for (var ${1:i} = 0; $1 < ${2:Things}.length; $1++) {\n\ + ${3:$2[$1]}$0\n\ + }\n\ +# for (...) {...} (Improved Native For-Loop)\n\ +snippet forr\n\ + for (var ${1:i} = ${2:Things}.length - 1; $1 >= 0; $1--) {\n\ + ${3:$2[$1]}$0\n\ + }\n\ +\n\ +\n\ +#modules\n\ +snippet def\n\ + define(function(require, exports, module) {\n\ + \"use strict\";\n\ + var ${1/.*\\///} = require(\"${1}\");\n\ + \n\ + $TM_SELECTED_TEXT\n\ + });\n\ +snippet req\n\ +guard ^\\s*\n\ + var ${1/.*\\///} = require(\"${1}\");\n\ + $0\n\ +snippet requ\n\ +guard ^\\s*\n\ + var ${1/.*\\/(.)/\\u$1/} = require(\"${1}\").${1/.*\\/(.)/\\u$1/};\n\ + $0\n\ +"; +exports.scope = "javascript"; + +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/markdown.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/markdown.js new file mode 100644 index 0000000..d05f16b --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/markdown.js @@ -0,0 +1,95 @@ +ace.define("ace/snippets/markdown",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.snippetText = "# Markdown\n\ +\n\ +# Includes octopress (http://octopress.org/) snippets\n\ +\n\ +snippet [\n\ + [${1:text}](http://${2:address} \"${3:title}\")\n\ +snippet [*\n\ + [${1:link}](${2:`@*`} \"${3:title}\")${4}\n\ +\n\ +snippet [:\n\ + [${1:id}]: http://${2:url} \"${3:title}\"\n\ +snippet [:*\n\ + [${1:id}]: ${2:`@*`} \"${3:title}\"\n\ +\n\ +snippet ![\n\ + ![${1:alttext}](${2:/images/image.jpg} \"${3:title}\")\n\ +snippet ![*\n\ + ![${1:alt}](${2:`@*`} \"${3:title}\")${4}\n\ +\n\ +snippet ![:\n\ + ![${1:id}]: ${2:url} \"${3:title}\"\n\ +snippet ![:*\n\ + ![${1:id}]: ${2:`@*`} \"${3:title}\"\n\ +\n\ +snippet ===\n\ +regex /^/=+/=*//\n\ + ${PREV_LINE/./=/g}\n\ + \n\ + ${0}\n\ +snippet ---\n\ +regex /^/-+/-*//\n\ + ${PREV_LINE/./-/g}\n\ + \n\ + ${0}\n\ +snippet blockquote\n\ + {% blockquote %}\n\ + ${1:quote}\n\ + {% endblockquote %}\n\ +\n\ +snippet blockquote-author\n\ + {% blockquote ${1:author}, ${2:title} %}\n\ + ${3:quote}\n\ + {% endblockquote %}\n\ +\n\ +snippet blockquote-link\n\ + {% blockquote ${1:author} ${2:URL} ${3:link_text} %}\n\ + ${4:quote}\n\ + {% endblockquote %}\n\ +\n\ +snippet bt-codeblock-short\n\ + ```\n\ + ${1:code_snippet}\n\ + ```\n\ +\n\ +snippet bt-codeblock-full\n\ + ``` ${1:language} ${2:title} ${3:URL} ${4:link_text}\n\ + ${5:code_snippet}\n\ + ```\n\ +\n\ +snippet codeblock-short\n\ + {% codeblock %}\n\ + ${1:code_snippet}\n\ + {% endcodeblock %}\n\ +\n\ +snippet codeblock-full\n\ + {% codeblock ${1:title} lang:${2:language} ${3:URL} ${4:link_text} %}\n\ + ${5:code_snippet}\n\ + {% endcodeblock %}\n\ +\n\ +snippet gist-full\n\ + {% gist ${1:gist_id} ${2:filename} %}\n\ +\n\ +snippet gist-short\n\ + {% gist ${1:gist_id} %}\n\ +\n\ +snippet img\n\ + {% img ${1:class} ${2:URL} ${3:width} ${4:height} ${5:title_text} ${6:alt_text} %}\n\ +\n\ +snippet youtube\n\ + {% youtube ${1:video_id} %}\n\ +\n\ +# The quote should appear only once in the text. It is inherently part of it.\n\ +# See http://octopress.org/docs/plugins/pullquote/ for more info.\n\ +\n\ +snippet pullquote\n\ + {% pullquote %}\n\ + ${1:text} {\" ${2:quote} \"} ${3:text}\n\ + {% endpullquote %}\n\ +"; +exports.scope = "markdown"; + +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/php-inline.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/php-inline.js new file mode 100644 index 0000000..a99ab6e --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/php-inline.js @@ -0,0 +1,384 @@ +ace.define("ace/snippets/php",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.snippetText = "snippet \n\ +# this one is for php5.4\n\ +snippet \n\ +snippet ns\n\ + namespace ${1:Foo\\Bar\\Baz};\n\ + ${2}\n\ +snippet use\n\ + use ${1:Foo\\Bar\\Baz};\n\ + ${2}\n\ +snippet c\n\ + ${1:abstract }class ${2:$FILENAME}\n\ + {\n\ + ${3}\n\ + }\n\ +snippet i\n\ + interface ${1:$FILENAME}\n\ + {\n\ + ${2}\n\ + }\n\ +snippet t.\n\ + $this->${1}\n\ +snippet f\n\ + function ${1:foo}(${2:array }${3:$bar})\n\ + {\n\ + ${4}\n\ + }\n\ +# method\n\ +snippet m\n\ + ${1:abstract }${2:protected}${3: static} function ${4:foo}(${5:array }${6:$bar})\n\ + {\n\ + ${7}\n\ + }\n\ +# setter method\n\ +snippet sm \n\ + /**\n\ + * Sets the value of ${1:foo}\n\ + *\n\ + * @param ${2:$1} $$1 ${3:description}\n\ + *\n\ + * @return ${4:$FILENAME}\n\ + */\n\ + ${5:public} function set${6:$2}(${7:$2 }$$1)\n\ + {\n\ + $this->${8:$1} = $$1;\n\ + return $this;\n\ + }${9}\n\ +# getter method\n\ +snippet gm\n\ + /**\n\ + * Gets the value of ${1:foo}\n\ + *\n\ + * @return ${2:$1}\n\ + */\n\ + ${3:public} function get${4:$2}()\n\ + {\n\ + return $this->${5:$1};\n\ + }${6}\n\ +#setter\n\ +snippet $s\n\ + ${1:$foo}->set${2:Bar}(${3});\n\ +#getter\n\ +snippet $g\n\ + ${1:$foo}->get${2:Bar}();\n\ +\n\ +# Tertiary conditional\n\ +snippet =?:\n\ + $${1:foo} = ${2:true} ? ${3:a} : ${4};\n\ +snippet ?:\n\ + ${1:true} ? ${2:a} : ${3}\n\ +\n\ +snippet C\n\ + $_COOKIE['${1:variable}']${2}\n\ +snippet E\n\ + $_ENV['${1:variable}']${2}\n\ +snippet F\n\ + $_FILES['${1:variable}']${2}\n\ +snippet G\n\ + $_GET['${1:variable}']${2}\n\ +snippet P\n\ + $_POST['${1:variable}']${2}\n\ +snippet R\n\ + $_REQUEST['${1:variable}']${2}\n\ +snippet S\n\ + $_SERVER['${1:variable}']${2}\n\ +snippet SS\n\ + $_SESSION['${1:variable}']${2}\n\ + \n\ +# the following are old ones\n\ +snippet inc\n\ + include '${1:file}';${2}\n\ +snippet inc1\n\ + include_once '${1:file}';${2}\n\ +snippet req\n\ + require '${1:file}';${2}\n\ +snippet req1\n\ + require_once '${1:file}';${2}\n\ +# Start Docblock\n\ +snippet /*\n\ + /**\n\ + * ${1}\n\ + */\n\ +# Class - post doc\n\ +snippet doc_cp\n\ + /**\n\ + * ${1:undocumented class}\n\ + *\n\ + * @package ${2:default}\n\ + * @subpackage ${3:default}\n\ + * @author ${4:`g:snips_author`}\n\ + */${5}\n\ +# Class Variable - post doc\n\ +snippet doc_vp\n\ + /**\n\ + * ${1:undocumented class variable}\n\ + *\n\ + * @var ${2:string}\n\ + */${3}\n\ +# Class Variable\n\ +snippet doc_v\n\ + /**\n\ + * ${3:undocumented class variable}\n\ + *\n\ + * @var ${4:string}\n\ + */\n\ + ${1:var} $${2};${5}\n\ +# Class\n\ +snippet doc_c\n\ + /**\n\ + * ${3:undocumented class}\n\ + *\n\ + * @package ${4:default}\n\ + * @subpackage ${5:default}\n\ + * @author ${6:`g:snips_author`}\n\ + */\n\ + ${1:}class ${2:}\n\ + {\n\ + ${7}\n\ + } // END $1class $2\n\ +# Constant Definition - post doc\n\ +snippet doc_dp\n\ + /**\n\ + * ${1:undocumented constant}\n\ + */${2}\n\ +# Constant Definition\n\ +snippet doc_d\n\ + /**\n\ + * ${3:undocumented constant}\n\ + */\n\ + define(${1}, ${2});${4}\n\ +# Function - post doc\n\ +snippet doc_fp\n\ + /**\n\ + * ${1:undocumented function}\n\ + *\n\ + * @return ${2:void}\n\ + * @author ${3:`g:snips_author`}\n\ + */${4}\n\ +# Function signature\n\ +snippet doc_s\n\ + /**\n\ + * ${4:undocumented function}\n\ + *\n\ + * @return ${5:void}\n\ + * @author ${6:`g:snips_author`}\n\ + */\n\ + ${1}function ${2}(${3});${7}\n\ +# Function\n\ +snippet doc_f\n\ + /**\n\ + * ${4:undocumented function}\n\ + *\n\ + * @return ${5:void}\n\ + * @author ${6:`g:snips_author`}\n\ + */\n\ + ${1}function ${2}(${3})\n\ + {${7}\n\ + }\n\ +# Header\n\ +snippet doc_h\n\ + /**\n\ + * ${1}\n\ + *\n\ + * @author ${2:`g:snips_author`}\n\ + * @version ${3:$Id$}\n\ + * @copyright ${4:$2}, `strftime('%d %B, %Y')`\n\ + * @package ${5:default}\n\ + */\n\ + \n\ +# Interface\n\ +snippet interface\n\ + /**\n\ + * ${2:undocumented class}\n\ + *\n\ + * @package ${3:default}\n\ + * @author ${4:`g:snips_author`}\n\ + */\n\ + interface ${1:$FILENAME}\n\ + {\n\ + ${5}\n\ + }\n\ +# class ...\n\ +snippet class\n\ + /**\n\ + * ${1}\n\ + */\n\ + class ${2:$FILENAME}\n\ + {\n\ + ${3}\n\ + /**\n\ + * ${4}\n\ + */\n\ + ${5:public} function ${6:__construct}(${7:argument})\n\ + {\n\ + ${8:// code...}\n\ + }\n\ + }\n\ +# define(...)\n\ +snippet def\n\ + define('${1}'${2});${3}\n\ +# defined(...)\n\ +snippet def?\n\ + ${1}defined('${2}')${3}\n\ +snippet wh\n\ + while (${1:/* condition */}) {\n\ + ${2:// code...}\n\ + }\n\ +# do ... while\n\ +snippet do\n\ + do {\n\ + ${2:// code... }\n\ + } while (${1:/* condition */});\n\ +snippet if\n\ + if (${1:/* condition */}) {\n\ + ${2:// code...}\n\ + }\n\ +snippet ifil\n\ + \n\ + ${2:}\n\ + \n\ +snippet ife\n\ + if (${1:/* condition */}) {\n\ + ${2:// code...}\n\ + } else {\n\ + ${3:// code...}\n\ + }\n\ + ${4}\n\ +snippet ifeil\n\ + \n\ + ${2:}\n\ + \n\ + ${3:}\n\ + \n\ + ${4}\n\ +snippet else\n\ + else {\n\ + ${1:// code...}\n\ + }\n\ +snippet elseif\n\ + elseif (${1:/* condition */}) {\n\ + ${2:// code...}\n\ + }\n\ +snippet switch\n\ + switch ($${1:variable}) {\n\ + case '${2:value}':\n\ + ${3:// code...}\n\ + break;\n\ + ${5}\n\ + default:\n\ + ${4:// code...}\n\ + break;\n\ + }\n\ +snippet case\n\ + case '${1:value}':\n\ + ${2:// code...}\n\ + break;${3}\n\ +snippet for\n\ + for ($${2:i} = 0; $$2 < ${1:count}; $$2${3:++}) {\n\ + ${4: // code...}\n\ + }\n\ +snippet foreach\n\ + foreach ($${1:variable} as $${2:value}) {\n\ + ${3:// code...}\n\ + }\n\ +snippet foreachil\n\ + \n\ + ${3:}\n\ + \n\ +snippet foreachk\n\ + foreach ($${1:variable} as $${2:key} => $${3:value}) {\n\ + ${4:// code...}\n\ + }\n\ +snippet foreachkil\n\ + $${3:value}): ?>\n\ + ${4:}\n\ + \n\ +# $... = array (...)\n\ +snippet array\n\ + $${1:arrayName} = array('${2}' => ${3});${4}\n\ +snippet try\n\ + try {\n\ + ${2}\n\ + } catch (${1:Exception} $e) {\n\ + }\n\ +# lambda with closure\n\ +snippet lambda\n\ + ${1:static }function (${2:args}) use (${3:&$x, $y /*put vars in scope (closure) */}) {\n\ + ${4}\n\ + };\n\ +# pre_dump();\n\ +snippet pd\n\ + echo '
    '; var_dump(${1}); echo '
    ';\n\ +# pre_dump(); die();\n\ +snippet pdd\n\ + echo '
    '; var_dump(${1}); echo '
    '; die(${2:});\n\ +snippet vd\n\ + var_dump(${1});\n\ +snippet vdd\n\ + var_dump(${1}); die(${2:});\n\ +snippet http_redirect\n\ + header (\"HTTP/1.1 301 Moved Permanently\"); \n\ + header (\"Location: \".URL); \n\ + exit();\n\ +# Getters & Setters\n\ +snippet gs\n\ + /**\n\ + * Gets the value of ${1:foo}\n\ + *\n\ + * @return ${2:$1}\n\ + */\n\ + public function get${3:$2}()\n\ + {\n\ + return $this->${4:$1};\n\ + }\n\ +\n\ + /**\n\ + * Sets the value of $1\n\ + *\n\ + * @param $2 $$1 ${5:description}\n\ + *\n\ + * @return ${6:$FILENAME}\n\ + */\n\ + public function set$3(${7:$2 }$$1)\n\ + {\n\ + $this->$4 = $$1;\n\ + return $this;\n\ + }${8}\n\ +# anotation, get, and set, useful for doctrine\n\ +snippet ags\n\ + /**\n\ + * ${1:description}\n\ + * \n\ + * @${7}\n\ + */\n\ + ${2:protected} $${3:foo};\n\ +\n\ + public function get${4:$3}()\n\ + {\n\ + return $this->$3;\n\ + }\n\ +\n\ + public function set$4(${5:$4 }$${6:$3})\n\ + {\n\ + $this->$3 = $$6;\n\ + return $this;\n\ + }\n\ +snippet rett\n\ + return true;\n\ +snippet retf\n\ + return false;\n\ +"; +exports.scope = "php"; + +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/php.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/php.js new file mode 100644 index 0000000..a99ab6e --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/php.js @@ -0,0 +1,384 @@ +ace.define("ace/snippets/php",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.snippetText = "snippet \n\ +# this one is for php5.4\n\ +snippet \n\ +snippet ns\n\ + namespace ${1:Foo\\Bar\\Baz};\n\ + ${2}\n\ +snippet use\n\ + use ${1:Foo\\Bar\\Baz};\n\ + ${2}\n\ +snippet c\n\ + ${1:abstract }class ${2:$FILENAME}\n\ + {\n\ + ${3}\n\ + }\n\ +snippet i\n\ + interface ${1:$FILENAME}\n\ + {\n\ + ${2}\n\ + }\n\ +snippet t.\n\ + $this->${1}\n\ +snippet f\n\ + function ${1:foo}(${2:array }${3:$bar})\n\ + {\n\ + ${4}\n\ + }\n\ +# method\n\ +snippet m\n\ + ${1:abstract }${2:protected}${3: static} function ${4:foo}(${5:array }${6:$bar})\n\ + {\n\ + ${7}\n\ + }\n\ +# setter method\n\ +snippet sm \n\ + /**\n\ + * Sets the value of ${1:foo}\n\ + *\n\ + * @param ${2:$1} $$1 ${3:description}\n\ + *\n\ + * @return ${4:$FILENAME}\n\ + */\n\ + ${5:public} function set${6:$2}(${7:$2 }$$1)\n\ + {\n\ + $this->${8:$1} = $$1;\n\ + return $this;\n\ + }${9}\n\ +# getter method\n\ +snippet gm\n\ + /**\n\ + * Gets the value of ${1:foo}\n\ + *\n\ + * @return ${2:$1}\n\ + */\n\ + ${3:public} function get${4:$2}()\n\ + {\n\ + return $this->${5:$1};\n\ + }${6}\n\ +#setter\n\ +snippet $s\n\ + ${1:$foo}->set${2:Bar}(${3});\n\ +#getter\n\ +snippet $g\n\ + ${1:$foo}->get${2:Bar}();\n\ +\n\ +# Tertiary conditional\n\ +snippet =?:\n\ + $${1:foo} = ${2:true} ? ${3:a} : ${4};\n\ +snippet ?:\n\ + ${1:true} ? ${2:a} : ${3}\n\ +\n\ +snippet C\n\ + $_COOKIE['${1:variable}']${2}\n\ +snippet E\n\ + $_ENV['${1:variable}']${2}\n\ +snippet F\n\ + $_FILES['${1:variable}']${2}\n\ +snippet G\n\ + $_GET['${1:variable}']${2}\n\ +snippet P\n\ + $_POST['${1:variable}']${2}\n\ +snippet R\n\ + $_REQUEST['${1:variable}']${2}\n\ +snippet S\n\ + $_SERVER['${1:variable}']${2}\n\ +snippet SS\n\ + $_SESSION['${1:variable}']${2}\n\ + \n\ +# the following are old ones\n\ +snippet inc\n\ + include '${1:file}';${2}\n\ +snippet inc1\n\ + include_once '${1:file}';${2}\n\ +snippet req\n\ + require '${1:file}';${2}\n\ +snippet req1\n\ + require_once '${1:file}';${2}\n\ +# Start Docblock\n\ +snippet /*\n\ + /**\n\ + * ${1}\n\ + */\n\ +# Class - post doc\n\ +snippet doc_cp\n\ + /**\n\ + * ${1:undocumented class}\n\ + *\n\ + * @package ${2:default}\n\ + * @subpackage ${3:default}\n\ + * @author ${4:`g:snips_author`}\n\ + */${5}\n\ +# Class Variable - post doc\n\ +snippet doc_vp\n\ + /**\n\ + * ${1:undocumented class variable}\n\ + *\n\ + * @var ${2:string}\n\ + */${3}\n\ +# Class Variable\n\ +snippet doc_v\n\ + /**\n\ + * ${3:undocumented class variable}\n\ + *\n\ + * @var ${4:string}\n\ + */\n\ + ${1:var} $${2};${5}\n\ +# Class\n\ +snippet doc_c\n\ + /**\n\ + * ${3:undocumented class}\n\ + *\n\ + * @package ${4:default}\n\ + * @subpackage ${5:default}\n\ + * @author ${6:`g:snips_author`}\n\ + */\n\ + ${1:}class ${2:}\n\ + {\n\ + ${7}\n\ + } // END $1class $2\n\ +# Constant Definition - post doc\n\ +snippet doc_dp\n\ + /**\n\ + * ${1:undocumented constant}\n\ + */${2}\n\ +# Constant Definition\n\ +snippet doc_d\n\ + /**\n\ + * ${3:undocumented constant}\n\ + */\n\ + define(${1}, ${2});${4}\n\ +# Function - post doc\n\ +snippet doc_fp\n\ + /**\n\ + * ${1:undocumented function}\n\ + *\n\ + * @return ${2:void}\n\ + * @author ${3:`g:snips_author`}\n\ + */${4}\n\ +# Function signature\n\ +snippet doc_s\n\ + /**\n\ + * ${4:undocumented function}\n\ + *\n\ + * @return ${5:void}\n\ + * @author ${6:`g:snips_author`}\n\ + */\n\ + ${1}function ${2}(${3});${7}\n\ +# Function\n\ +snippet doc_f\n\ + /**\n\ + * ${4:undocumented function}\n\ + *\n\ + * @return ${5:void}\n\ + * @author ${6:`g:snips_author`}\n\ + */\n\ + ${1}function ${2}(${3})\n\ + {${7}\n\ + }\n\ +# Header\n\ +snippet doc_h\n\ + /**\n\ + * ${1}\n\ + *\n\ + * @author ${2:`g:snips_author`}\n\ + * @version ${3:$Id$}\n\ + * @copyright ${4:$2}, `strftime('%d %B, %Y')`\n\ + * @package ${5:default}\n\ + */\n\ + \n\ +# Interface\n\ +snippet interface\n\ + /**\n\ + * ${2:undocumented class}\n\ + *\n\ + * @package ${3:default}\n\ + * @author ${4:`g:snips_author`}\n\ + */\n\ + interface ${1:$FILENAME}\n\ + {\n\ + ${5}\n\ + }\n\ +# class ...\n\ +snippet class\n\ + /**\n\ + * ${1}\n\ + */\n\ + class ${2:$FILENAME}\n\ + {\n\ + ${3}\n\ + /**\n\ + * ${4}\n\ + */\n\ + ${5:public} function ${6:__construct}(${7:argument})\n\ + {\n\ + ${8:// code...}\n\ + }\n\ + }\n\ +# define(...)\n\ +snippet def\n\ + define('${1}'${2});${3}\n\ +# defined(...)\n\ +snippet def?\n\ + ${1}defined('${2}')${3}\n\ +snippet wh\n\ + while (${1:/* condition */}) {\n\ + ${2:// code...}\n\ + }\n\ +# do ... while\n\ +snippet do\n\ + do {\n\ + ${2:// code... }\n\ + } while (${1:/* condition */});\n\ +snippet if\n\ + if (${1:/* condition */}) {\n\ + ${2:// code...}\n\ + }\n\ +snippet ifil\n\ + \n\ + ${2:}\n\ + \n\ +snippet ife\n\ + if (${1:/* condition */}) {\n\ + ${2:// code...}\n\ + } else {\n\ + ${3:// code...}\n\ + }\n\ + ${4}\n\ +snippet ifeil\n\ + \n\ + ${2:}\n\ + \n\ + ${3:}\n\ + \n\ + ${4}\n\ +snippet else\n\ + else {\n\ + ${1:// code...}\n\ + }\n\ +snippet elseif\n\ + elseif (${1:/* condition */}) {\n\ + ${2:// code...}\n\ + }\n\ +snippet switch\n\ + switch ($${1:variable}) {\n\ + case '${2:value}':\n\ + ${3:// code...}\n\ + break;\n\ + ${5}\n\ + default:\n\ + ${4:// code...}\n\ + break;\n\ + }\n\ +snippet case\n\ + case '${1:value}':\n\ + ${2:// code...}\n\ + break;${3}\n\ +snippet for\n\ + for ($${2:i} = 0; $$2 < ${1:count}; $$2${3:++}) {\n\ + ${4: // code...}\n\ + }\n\ +snippet foreach\n\ + foreach ($${1:variable} as $${2:value}) {\n\ + ${3:// code...}\n\ + }\n\ +snippet foreachil\n\ + \n\ + ${3:}\n\ + \n\ +snippet foreachk\n\ + foreach ($${1:variable} as $${2:key} => $${3:value}) {\n\ + ${4:// code...}\n\ + }\n\ +snippet foreachkil\n\ + $${3:value}): ?>\n\ + ${4:}\n\ + \n\ +# $... = array (...)\n\ +snippet array\n\ + $${1:arrayName} = array('${2}' => ${3});${4}\n\ +snippet try\n\ + try {\n\ + ${2}\n\ + } catch (${1:Exception} $e) {\n\ + }\n\ +# lambda with closure\n\ +snippet lambda\n\ + ${1:static }function (${2:args}) use (${3:&$x, $y /*put vars in scope (closure) */}) {\n\ + ${4}\n\ + };\n\ +# pre_dump();\n\ +snippet pd\n\ + echo '
    '; var_dump(${1}); echo '
    ';\n\ +# pre_dump(); die();\n\ +snippet pdd\n\ + echo '
    '; var_dump(${1}); echo '
    '; die(${2:});\n\ +snippet vd\n\ + var_dump(${1});\n\ +snippet vdd\n\ + var_dump(${1}); die(${2:});\n\ +snippet http_redirect\n\ + header (\"HTTP/1.1 301 Moved Permanently\"); \n\ + header (\"Location: \".URL); \n\ + exit();\n\ +# Getters & Setters\n\ +snippet gs\n\ + /**\n\ + * Gets the value of ${1:foo}\n\ + *\n\ + * @return ${2:$1}\n\ + */\n\ + public function get${3:$2}()\n\ + {\n\ + return $this->${4:$1};\n\ + }\n\ +\n\ + /**\n\ + * Sets the value of $1\n\ + *\n\ + * @param $2 $$1 ${5:description}\n\ + *\n\ + * @return ${6:$FILENAME}\n\ + */\n\ + public function set$3(${7:$2 }$$1)\n\ + {\n\ + $this->$4 = $$1;\n\ + return $this;\n\ + }${8}\n\ +# anotation, get, and set, useful for doctrine\n\ +snippet ags\n\ + /**\n\ + * ${1:description}\n\ + * \n\ + * @${7}\n\ + */\n\ + ${2:protected} $${3:foo};\n\ +\n\ + public function get${4:$3}()\n\ + {\n\ + return $this->$3;\n\ + }\n\ +\n\ + public function set$4(${5:$4 }$${6:$3})\n\ + {\n\ + $this->$3 = $$6;\n\ + return $this;\n\ + }\n\ +snippet rett\n\ + return true;\n\ +snippet retf\n\ + return false;\n\ +"; +exports.scope = "php"; + +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/plain_text.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/plain_text.js new file mode 100644 index 0000000..24223a6 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/plain_text.js @@ -0,0 +1,7 @@ +ace.define("ace/snippets/plain_text",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.snippetText =undefined; +exports.scope = "plain_text"; + +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/sass.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/sass.js new file mode 100644 index 0000000..b9adc9d --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/sass.js @@ -0,0 +1,7 @@ +ace.define("ace/snippets/sass",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.snippetText =undefined; +exports.scope = "sass"; + +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/scss.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/scss.js new file mode 100644 index 0000000..fbd98f7 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/scss.js @@ -0,0 +1,7 @@ +ace.define("ace/snippets/scss",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.snippetText =undefined; +exports.scope = "scss"; + +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/text.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/text.js new file mode 100644 index 0000000..57b897b --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/text.js @@ -0,0 +1,7 @@ +ace.define("ace/snippets/text",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.snippetText =undefined; +exports.scope = "text"; + +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/twig.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/twig.js new file mode 100644 index 0000000..ccc6073 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/twig.js @@ -0,0 +1,7 @@ +ace.define("ace/snippets/twig",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.snippetText =undefined; +exports.scope = "twig"; + +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/yaml.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/yaml.js new file mode 100644 index 0000000..1adceab --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/snippets/yaml.js @@ -0,0 +1,7 @@ +ace.define("ace/snippets/yaml",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.snippetText =undefined; +exports.scope = "yaml"; + +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-ambiance.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-ambiance.js new file mode 100755 index 0000000..1e53ecd --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-ambiance.js @@ -0,0 +1,182 @@ +ace.define("ace/theme/ambiance",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-ambiance"; +exports.cssText = ".ace-ambiance .ace_gutter {\ +background-color: #3d3d3d;\ +background-image: -moz-linear-gradient(left, #3D3D3D, #333);\ +background-image: -ms-linear-gradient(left, #3D3D3D, #333);\ +background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#3D3D3D), to(#333));\ +background-image: -webkit-linear-gradient(left, #3D3D3D, #333);\ +background-image: -o-linear-gradient(left, #3D3D3D, #333);\ +background-image: linear-gradient(left, #3D3D3D, #333);\ +background-repeat: repeat-x;\ +border-right: 1px solid #4d4d4d;\ +text-shadow: 0px 1px 1px #4d4d4d;\ +color: #222;\ +}\ +.ace-ambiance .ace_gutter-layer {\ +background: repeat left top;\ +}\ +.ace-ambiance .ace_gutter-active-line {\ +background-color: #3F3F3F;\ +}\ +.ace-ambiance .ace_fold-widget {\ +text-align: center;\ +}\ +.ace-ambiance .ace_fold-widget:hover {\ +color: #777;\ +}\ +.ace-ambiance .ace_fold-widget.ace_start,\ +.ace-ambiance .ace_fold-widget.ace_end,\ +.ace-ambiance .ace_fold-widget.ace_closed{\ +background: none;\ +border: none;\ +box-shadow: none;\ +}\ +.ace-ambiance .ace_fold-widget.ace_start:after {\ +content: '▾'\ +}\ +.ace-ambiance .ace_fold-widget.ace_end:after {\ +content: '▴'\ +}\ +.ace-ambiance .ace_fold-widget.ace_closed:after {\ +content: '‣'\ +}\ +.ace-ambiance .ace_print-margin {\ +border-left: 1px dotted #2D2D2D;\ +right: 0;\ +background: #262626;\ +}\ +.ace-ambiance .ace_scroller {\ +-webkit-box-shadow: inset 0 0 10px black;\ +-moz-box-shadow: inset 0 0 10px black;\ +-o-box-shadow: inset 0 0 10px black;\ +box-shadow: inset 0 0 10px black;\ +}\ +.ace-ambiance {\ +color: #E6E1DC;\ +background-color: #202020;\ +}\ +.ace-ambiance .ace_cursor {\ +border-left: 1px solid #7991E8;\ +}\ +.ace-ambiance .ace_overwrite-cursors .ace_cursor {\ +border: 1px solid #FFE300;\ +background: #766B13;\ +}\ +.ace-ambiance.normal-mode .ace_cursor-layer {\ +z-index: 0;\ +}\ +.ace-ambiance .ace_marker-layer .ace_selection {\ +background: rgba(221, 240, 255, 0.20);\ +}\ +.ace-ambiance .ace_marker-layer .ace_selected-word {\ +border-radius: 4px;\ +border: 8px solid #3f475d;\ +box-shadow: 0 0 4px black;\ +}\ +.ace-ambiance .ace_marker-layer .ace_step {\ +background: rgb(198, 219, 174);\ +}\ +.ace-ambiance .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgba(255, 255, 255, 0.25);\ +}\ +.ace-ambiance .ace_marker-layer .ace_active-line {\ +background: rgba(255, 255, 255, 0.031);\ +}\ +.ace-ambiance .ace_invisible {\ +color: #333;\ +}\ +.ace-ambiance .ace_paren {\ +color: #24C2C7;\ +}\ +.ace-ambiance .ace_keyword {\ +color: #cda869;\ +}\ +.ace-ambiance .ace_keyword.ace_operator {\ +color: #fa8d6a;\ +}\ +.ace-ambiance .ace_punctuation.ace_operator {\ +color: #fa8d6a;\ +}\ +.ace-ambiance .ace_identifier {\ +}\ +.ace-ambiance .ace-statement {\ +color: #cda869;\ +}\ +.ace-ambiance .ace_constant {\ +color: #CF7EA9;\ +}\ +.ace-ambiance .ace_constant.ace_language {\ +color: #CF7EA9;\ +}\ +.ace-ambiance .ace_constant.ace_library {\ +}\ +.ace-ambiance .ace_constant.ace_numeric {\ +color: #78CF8A;\ +}\ +.ace-ambiance .ace_invalid {\ +text-decoration: underline;\ +}\ +.ace-ambiance .ace_invalid.ace_illegal {\ +color:#F8F8F8;\ +background-color: rgba(86, 45, 86, 0.75);\ +}\ +.ace-ambiance .ace_invalid,\ +.ace-ambiance .ace_deprecated {\ +text-decoration: underline;\ +font-style: italic;\ +color: #D2A8A1;\ +}\ +.ace-ambiance .ace_support {\ +color: #9B859D;\ +}\ +.ace-ambiance .ace_support.ace_function {\ +color: #DAD085;\ +}\ +.ace-ambiance .ace_function.ace_buildin {\ +color: #9b859d;\ +}\ +.ace-ambiance .ace_string {\ +color: #8f9d6a;\ +}\ +.ace-ambiance .ace_string.ace_regexp {\ +color: #DAD085;\ +}\ +.ace-ambiance .ace_comment {\ +font-style: italic;\ +color: #555;\ +}\ +.ace-ambiance .ace_comment.ace_doc {\ +}\ +.ace-ambiance .ace_comment.ace_doc.ace_tag {\ +color: #666;\ +font-style: normal;\ +}\ +.ace-ambiance .ace_definition,\ +.ace-ambiance .ace_type {\ +color: #aac6e3;\ +}\ +.ace-ambiance .ace_variable {\ +color: #9999cc;\ +}\ +.ace-ambiance .ace_variable.ace_language {\ +color: #9b859d;\ +}\ +.ace-ambiance .ace_xml-pe {\ +color: #494949;\ +}\ +.ace-ambiance .ace_gutter-layer,\ +.ace-ambiance .ace_text-layer {\ +background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAQAAAAHUWYVAABFFUlEQVQYGbzBCeDVU/74/6fj9HIcx/FRHx9JCFmzMyGRURhLZIkUsoeRfUjS2FNDtr6WkMhO9sm+S8maJfu+Jcsg+/o/c+Z4z/t97/vezy3z+z8ekGlnYICG/o7gdk+wmSHZ1z4pJItqapjoKXWahm8NmV6eOTbWUOp6/6a/XIg6GQqmenJ2lDHyvCFZ2cBDbmtHA043VFhHwXxClWmeYAdLhV00Bd85go8VmaFCkbVkzlQENzfBDZ5gtN7HwF0KDrTwJ0dypSOzpaKCMwQHKTIreYIxlmhXTzTWkVm+LTynZhiSBT3RZQ7aGfjGEd3qyXQ1FDymqbKxpspERQN2MiRjNZlFFQXfCNFm9nM1zpAsoYjmtRTc5ajwuaXc5xrWskT97RaKzAGe5ARHhVUsDbjKklziiX5WROcJwSNCNI+9w1Jwv4Zb2r7lCMZ4oq5C0EdTx+2GzNuKpJ+iFf38JEWkHJn9DNF7mmBDITrWEg0VWL3pHU20tSZnuqWu+R3BtYa8XxV1HO7GyD32UkOpL/yDloINFTmvtId+nmAjxRw40VMwVKiwrKLE4bK5UOVntYwhOcSSXKrJHKPJedocpGjVz/ZMIbnYUPB10/eKCrs5apqpgVmWzBYWpmtKHecJPjaUuEgRDDaU0oZghCJ6zNMQ5ZhDYx05r5v2muQdM0EILtXUsaKiQX9WMEUotagQzFbUNN6NUPC2nm5pxEWGCjMc3GdJHjSU2kORLK/JGSrkfGEIjncU/CYUnOipoYemwj8tST9NsJmB7TUVXtbUtXATJVZXBMvYeTXJfobgJUPmGMP/yFaWonaa6BcFO3nqcIqCozSZoZoSr1g4zJOzuyGnxTEX3lUEJ7WcZgme8ddaWvWJo2AJR9DZU3CUIbhCSG6ybSwN6qtJVnCU2svDTP2ZInOw2cBTrqtQahtNZn9NcJ4l2NaSmSkkP1noZWnVwkLmdUPOwLZEwy2Z3S3R+4rIG9hcbpPXHFVWcQdZkn2FOta3cKWQnNRC5g1LsJah4GCzSVsKnCOY5OAFRTBekyyryeyilhFKva75r4Mc0aWanGEaThcy31s439KKxTzJYY5WTHPU1FtIHjQU3Oip4xlNzj/lBw23dYZVliQa7WAXf4shetcQfatI+jWRDBPmyNeW6A1P5kdDgyYJlba0BIM8BZu1JfrFwItyjcAMR3K0BWOIrtMEXyhyrlVEx3ui5dUBjmB/Q3CXW85R4mBD0s7B+4q5tKUjOlb9qqmhi5AZ6GFIC5HXtOobdYGlVdMVbNJ8toNTFcHxnoL+muBagcctjWnbNMuR00uI7nQESwg5q2qqrKWIfrNUmeQocY6HuyxJV02wj36w00yhpmUFenv4p6fUkZYqLyuinx2RGOjhCXYyJF84oiU00YMOOhhquNdfbOB7gU88pY4xJO8LVdp6/q2voeB4R04vIdhSE40xZObx1HGGJ/ja0LBthFInKaLPPFzuCaYaoj8JjPME8yoyxo6zlBqkiUZYgq00OYMswbWO5NGmq+xhipxHLRW29ARjNKXO0wRnear8XSg4XFPLKEPUS1GqvyLwiuBUoa7zpZ0l5xxFwWmWZC1H5h5FwU8eQ7K+g8UcVY6TMQreVQT/8uQ8Z+ALIXnSEa2pYZQneE9RZbSBNYXfWYJzW/h/4j4Dp1tYVcFIC5019Vyi4ThPqSFCzjGWaHQTBU8q6vrVwgxP9Lkm840imWKpcLCjYTtrKuwvsKSnrvHCXGkSMk9p6lhckfRpIeis+N2PiszT+mFLspyGleUhDwcLrZqmyeylxwjBcKHEapqkmyangyLZRVOijwOtCY5SsG5zL0OwlCJ4y5KznF3EUNDDrinwiyLZRzOXtlBbK5ITHFGLp8Q0R6ab6mS7enI2cFrxOyHvOCFaT1HThS1krjCwqWeurCkk+willhCC+RSZnRXBiZaC5RXRIZYKp2lyfrHwiKPKR0JDzrdU2EFgpidawlFDR6FgXUMNa+g1FY3bUQh2cLCwosRdnuQTS/S+JVrGLeWIvtQUvONJxlqSQYYKpwoN2kaocLjdVsis4Mk80ESF2YpSkzwldjHkjFCUutI/r+EHDU8oCs6yzL3PhWiEooZdFMkymlas4AcI3KmoMMNSQ3tHzjGWCrcJJdYyZC7QFGwjRL9p+MrRkAGWzIaWCn9W0F3TsK01c2ZvQw0byvxuQU0r1lM0qJO7wW0kRIMdDTtXEdzi4VIh+EoIHm0mWtAtpCixlabgn83fKTI7anJe9ST7WIK1DMGpQmYeA58ImV6ezOGOzK2Kgq01pd60cKWiUi9Lievb/0vIDPHQ05Kzt4ddPckQBQtoaurjyHnek/nKzpQLrVgKPjIkh2v4uyezpv+Xoo7fPFXaGFp1vaLKxQ4uUpQQS5VuQs7BCq4xRJv7fwpVvvFEB3j+620haOuocqMhWd6TTPAEx+mdFNGHdranFe95WrWmIvlY4F1Dle2ECgc6cto7SryuqGGGha0tFQ5V53migUKmg6XKAo4qS3mik+0OZpAhOLeZKicacgaYcyx5hypYQE02ZA4xi/pNhOQxR4klNKyqacj+mpxnLTnnGSo85++3ZCZq6lrZkXlGEX3o+C9FieccJbZWVFjC0Yo1FZnJhoYMFoI1hEZ9r6hwg75HwzBNhbZCdJEfJwTPGzJvaKImw1yYX1HDAmpXR+ZJQ/SmgqMNVQb5vgamGwLtt7VwvP7Qk1xpiM5x5Cyv93E06MZmgs0Nya2azIKOYKCGBQQW97RmhKNKF02JZqHEJ4o58qp7X5EcZmc56trXEqzjCBZ1MFGR87Ql2tSTs6CGxS05PTzRQorkbw7aKoKXFDXsYW42VJih/q+FP2BdTzDTwVqOYB13liM50vG7wy28qagyuIXMeQI/Oqq8bcn5wJI50xH00CRntyfpL1T4hydYpoXgNiFzoIUTDZnLNRzh4TBHwbYGDvZkxmlyJloyr6tRihpeUG94GnKtIznREF0tzJG/OOr73JBcrSh1k6WuTprgLU+mnSGnv6Zge0NNz+kTDdH8nuAuTdJDCNb21LCiIuqlYbqGzT3RAoZofQfjFazkqeNWdYaGvYTM001EW2oKPvVk1ldUGSgUtHFwjKM1h9jnFcmy5lChoLNaQMGGDsYbKixlaMBmmsx1QjCfflwTfO/gckW0ruZ3jugKR3R5W9hGUWqCgxuFgsuaCHorotGKzGaeZB9DMsaTnKCpMtwTvOzhYk0rdrArKCqcaWmVk1+F372ur1YkKxgatI8Qfe1gIX9wE9FgS8ESmuABIXnRUbCapcKe+nO7slClSZFzpV/LkLncEb1qiO42fS3R855Su2mCLh62t1SYZZYVmKwIHjREF2uihTzB20JOkz7dkxzYQnK0UOU494wh+VWRc6Un2kpTaVgLDFEkJ/uhzRcI0YKGgpGWOlocBU/a4fKoJ/pEaNV6jip3+Es9VXY078rGnmAdf7t9ylPXS34RBSuYPs1UecZTU78WanhBCHpZ5sAoTz0LGZKjPf9TRypqWEiTvOFglL1fCEY3wY/++rbk7C8bWebA6p6om6PgOL2kp44TFJlVNBXae2rqqdZztOJpT87GQsE9jqCPIe9VReZuQ/CIgacsyZdCpIScSYqcZk8r+nsyCzhyfhOqHGOIvrLknC8wTpFcaYiGC/RU1NRbUeUpocQOnkRpGOrIOcNRx+1uA0UrzhSSt+VyS3SJpnFWkzNDqOFGIWcfR86DnmARTQ1HKIL33ExPiemeOhYSSjzlSUZZuE4TveoJLnBUOFof6KiysCbnAEcZgcUNTDOwkqWu3RWtmGpZwlHhJENdZ3miGz0lJlsKnjbwqSHQjpxnFDlTLLwqJPMZMjd7KrzkSG7VsxXBZE+F8YZkb01Oe00yyRK9psh5SYh29ySPKBo2ylNht7ZkZnsKenjKNJu9PNEyZpaCHv4Kt6RQsLvAVp7M9kIimmCUwGeWqLMmGuIotYMmWNpSahkhZw9FqZsVnKJhsjAHvtHMsTM9fCI06Dx/u3vfUXCqfsKRc4oFY2jMsoo/7DJDwZ1CsIKnJu+J9ldkpmiCxQx1rWjI+T9FwcWWzOuaYH0Hj7klNRVWEQpmaqosakiGNTFHdjS/qnUdmf0NJW5xsL0HhimCCZZSRzmSPTXJQ4aaztAwtZnoabebJ+htCaZ7Cm535ByoqXKbX1WRc4Eh2MkRXWzImVc96Cj4VdOKVxR84VdQsIUM8Psoou2byVHyZFuq7O8otbSQ2UAoeEWTudATLGSpZzVLlXVkPU2Jc+27lsw2jmg5T5VhbeE3BT083K9WsTTkFU/Osi0rC5lRlpwRHUiesNS0sOvmqGML1aRbPAxTJD9ZKtxuob+hhl8cwYGWpJ8nub7t5p6coYbMovZ1BTdaKn1jYD6h4GFDNFyT/Kqe1XCXphXHOKLZmuRSRdBPEfVUXQzJm5YGPGGJdvAEr7hHNdGZnuBvrpciGmopOLf5N0uVMy0FfYToJk90uUCbJupaVpO53UJXR2bVpoU00V2KOo4zMFrBd0Jtz2pa0clT5Q5L8IpQ177mWQejPMEJhuQjS10ref6HHjdEhy1P1EYR7GtO0uSsKJQYLiTnG1rVScj5lyazpqWGl5uBbRWl7m6ixGOOnEsMJR7z8J0n6KMnCdxhiNYQCoZ6CmYLnO8omC3MkW3bktlPmEt/VQQHejL3+dOE5FlPdK/Mq8hZxxJtLyRrepLThYKbLZxkSb5W52vYxNOaOxUF0yxMUPwBTYqCzy01XayYK0sJyWBLqX0MwU5CzoymRzV0EjjeUeLgDpTo6ij42ZAzvD01dHUUTPLU96MdLbBME8nFBn7zJCMtJcZokn8YoqU0FS5WFKyniHobguMcmW8N0XkWZjkyN3hqOMtS08r+/xTBwpZSZ3qiVRX8SzMHHjfUNFjgHEPmY9PL3ykEzxkSre/1ZD6z/NuznuB0RcE1TWTm9zRgfUWVJiG6yrzgmWPXC8EAR4Wxhlad0ZbgQyEz3pG5RVEwwDJH2mgKpjcTiCOzn1lfUWANFbZ2BA8balnEweJC9J0iuaeZoI+ippFCztEKVvckR2iice1JvhVytrQwUAZpgsubCPaU7xUe9vWnaOpaSBEspalykhC9bUlOMpT42ZHca6hyrqKmw/wMR8H5ZmdFoBVJb03O4UL0tSNnvIeRmkrLWqrs78gcrEn2tpcboh0UPOW3UUR9PMk4T4nnNKWmCjlrefhCwxRNztfmIQVdDElvS4m1/WuOujoZCs5XVOjtKPGokJzsYCtFYoWonSPT21DheU/wWhM19FcElwqNGOsp9Q8N/cwXaiND1MmeL1Q5XROtYYgGeFq1aTMsoMmcrKjQrOFQTQ1fmBYhmW6o8Jkjc7iDJRTBIo5kgJD5yMEYA3srCg7VFKwiVJkmRCc5ohGOKhsYMn/XBLdo5taZjlb9YAlGWRimqbCsoY7HFAXLa5I1HPRxMMsQDHFkWtRNniqT9UEeNjcE7RUlrCJ4R2CSJuqlKHWvJXjAUNcITYkenuBRB84TbeepcqTj3zZyFJzgYQdHnqfgI0ddUwS6GqWpsKWhjq9cV0vBAEMN2znq+EBfIWT+pClYw5xsTlJU6GeIBsjGmmANTzJZiIYpgrM0Oa8ZMjd7NP87jxhqGOhJlnQtjuQpB+8aEE00wZFznSJPyHxgH3HkPOsJFvYk8zqCHzTs1BYOa4J3PFU+UVRZxlHDM4YavlNUuMoRveiZA2d7grMNc2g+RbSCEKzmgYsUmWmazFJyoiOZ4KnyhKOGRzWJa0+moyV4TVHDzn51Awtqaphfk/lRQ08FX1iiqxTB/kLwd0VynKfEvI6cd4XMV5bMhZ7gZUWVzYQ6Nm2BYzxJbw3bGthEUUMfgbGeorae6DxHtJoZ6alhZ0+ytiVoK1R4z5PTrOECT/SugseEOlb1MMNR4VRNcJy+V1Hg9ONClSZFZjdHlc6W6FBLdJja2MC5hhpu0DBYEY1TFGwiFAxRRCsYkiM9JRb0JNMVkW6CZYT/2EiTGWmo8k+h4FhDNE7BvppoTSFnmCV5xZKzvcCdDo7VVPnIU+I+Rc68juApC90MwcFCsJ5hDqxgScYKreruyQwTqrzoqDCmhWi4IbhB0Yrt3RGa6GfDv52rKXWhh28dyZaWUvcZeMTBaZoSGyiCtRU5J8iviioHaErs7Jkj61syVzTTgOcUOQ8buFBTYWdL5g3T4qlpe0+wvD63heAXRfCCIed9RbCsp2CiI7raUOYOTU13N8PNHvpaGvayo4a3LLT1lDrVEPT2zLUlheB1R+ZTRfKWJ+dcocLJfi11vyJ51lLqJ0WD7tRwryezjiV5W28uJO9qykzX8JDe2lHl/9oyBwa2UMfOngpXCixvKdXTk3wrsKmiVYdZIqsoWEERjbcUNDuiaQomGoIbFdEHmsyWnuR+IeriKDVLnlawlyNHKwKlSU631PKep8J4Q+ayjkSLKYLhalNHlYvttb6fHm0p6OApsZ4l2VfdqZkjuysy6ysKLlckf1KUutCTs39bmCgEyyoasIWlVaMF7mgmWtBT8Kol5xpH9IGllo8cJdopcvZ2sImlDmMIbtDk3KIpeNiS08lQw11NFPTwVFlPP6pJ2gvRfI7gQUfmNAtf6Gs0wQxDsKGlVBdF8rCa3jzdwMaGHOsItrZk7hAyOzpK9VS06j5F49b0VNGOOfKs3lDToMsMBe9ZWtHFEgxTJLs7qrygKZjUnmCYoeAqeU6jqWuLJup4WghOdvCYJnrSkSzoyRkm5M2StQwVltPkfCAk58tET/CSg+8MUecmotMEnhBKfWBIZsg2ihruMJQaoIm+tkTLKEqspMh00w95gvFCQRtDwTT1gVDDSEVdlwqZfxoQRbK0g+tbiBZxzKlpnpypejdDwTaeOvorMk/IJE10h9CqRe28hhLbe0pMsdSwv4ZbhKivo2BjDWfL8UKJgeavwlwb5KlwhyE4u4XkGE2ytZCznKLCDZZq42VzT8HLCrpruFbIfOIINmh/qCdZ1ZBc65kLHR1Bkyf5zn6pN3SvGKIlFNGplhrO9QSXanLOMQTLCa0YJCRrCZm/CZmrLTm7WzCK4GJDiWUdFeYx1LCFg3NMd0XmCuF3Y5rITLDUsYS9zoHVzwnJoYpSTQoObyEzr4cFBNqYTopoaU/wkyLZ2lPhX/5Y95ulxGTV7KjhWrOZgl8MyUUafjYraNjNU1N3IWcjT5WzWqjwtoarHSUObGYO3GCJZpsBlnJGPd6ZYLyl1GdCA2625IwwJDP8GUKymbzuyPlZlvTUsaUh5zFDhRWFzPKKZLAlWdcQbObgF9tOqOsmB1dqcqYJmWstFbZRRI9poolmqiLnU0POvxScpah2iSL5UJNzgScY5+AuIbpO0YD3NCW+dLMszFSdFCWGqG6eVq2uYVNDdICGD6W7EPRWZEY5gpsE9rUkS3mijzzJnm6UpUFXG1hCUeVoS5WfNcFpblELL2qqrCvMvRfd45oalvKU2tiQ6ePJOVMRXase9iTtLJztPxJKLWpo2CRDcJwn2sWSLKIO1WQWNTCvpVUvOZhgSC40JD0dOctaSqzkCRbXsKlb11Oip6PCJ0IwSJM31j3akRxlP7Rwn6aGaUL0qiLnJkvB3xWZ2+Q1TfCwpQH3G0o92UzmX4o/oJNQMMSQc547wVHhdk+VCw01DFYEnTxzZKAm74QmeNNR1w6WzEhNK15VJzuCdxQ53dRUDws5KvwgBMOEgpcVNe0hZI6RXT1Jd0cyj5nsaEAHgVmGaJIlWdsc5Ui2ElrRR6jrRAttNMEAIWrTDFubkZaok7/AkzfIwfuWVq0jHzuCK4QabtLUMVPB3kJ0oyHTSVFlqMALilJf2Rf8k5aaHtMfayocLBS8L89oKoxpJvnAkDPa0qp5DAUTHKWmCcnthlou8iCKaFFLHWcINd1nyIwXqrSxMNmSs6KmoL2QrKuWtlQ5V0120xQ5vRyZS1rgFkWwhiOwiuQbR0OOVhQM9iS3tiXp4RawRPMp5tDletOOBL95MpM01dZTBM9pkn5qF010rIeHFcFZhmSGpYpTsI6nwhqe5C9ynhlpp5ophuRb6WcJFldkVnVEwwxVfrVkvnWUuNLCg5bgboFHPDlDPDmnK7hUrWiIbjadDclujlZcaokOFup4Ri1kacV6jmrrK1hN9bGwpKEBQ4Q6DvIUXOmo6U5LqQM6EPyiKNjVkPnJkDPNEaxhiFay5ExW1NXVUGqcpYYdPcGiCq7z/TSlbhL4pplWXKd7NZO5QQFrefhRQW/NHOsqcIglc4UhWklR8K0QzbAw08CBDnpbgqXdeD/QUsM4RZXDFBW6WJKe/mFPdH0LtBgiq57wFLzlyQzz82qYx5D5WJP5yVJDW01BfyHnS6HKO/reZqId1WGa4Hkh2kWodJ8i6KoIPlAj2hPt76CzXsVR6koPRzWTfKqIentatYpQw2me4AA3y1Kind3SwoOKZDcFXTwl9tWU6mfgRk9d71sKtlNwrjnYw5tC5n5LdKiGry3JKNlHEd3oaMCFHrazBPMp/uNJ+V7IudcSbeOIdjUEdwl0VHCOZo5t6YluEuaC9mQeMgSfOyKnYGFHcIeQ84yQWbuJYJpZw5CzglDH7gKnWqqM9ZTaXcN0TeYhR84eQtJT76JJ1lREe7WnnvsMmRc9FQ7SBBM9mV3lCUdmHk/S2RAMt0QjFNFqQpWjDPQ01DXWUdDBkXziKPjGEP3VP+zIWU2t7im41FOloyWzn/L6dkUy3VLDaZ6appgDLHPjJEsyvJngWEPUyVBiAaHCTEXwrLvSEbV1e1gKJniicWorC1MUrVjB3uDhJE/wgSOzk1DXpk0k73qCM8xw2UvD5kJmDUfOomqMpWCkJRlvKXGmoeBm18USjVIk04SClxTB6YrgLAPLWYK9HLUt5cmc0vYES8GnTeRc6skZbQkWdxRsIcyBRzx1DbTk9FbU0caTPOgJHhJKnOGIVhQqvKmo0llRw9sabrZkDtdg3PqaKi9oatjY8B+G371paMg6+mZFNNtQ04mWBq3rYLOmtWWQp8KJnpy9DdFensyjdqZ+yY40VJlH8wcdLzC8PZnvHMFUTZUrDTkLyQaGus5X5LzpYAf3i+e/ZlhqGqWhh6Ou6xTR9Z6oi5AZZtp7Mj2EEm8oSpxiYZCHU/1fbGdNNNRRoZMhmilEb2gqHOEJDtXkHK/JnG6IrvbPCwV3NhONVdS1thBMs1T4QOBcTWa2IzhMk2nW5Kyn9tXUtpv9RsG2msxk+ZsQzRQacJncpgke0+T8y5Fzj8BiGo7XlJjaTIlpQs7KFjpqGnKuoyEPeIKnFMkZHvopgh81ySxNFWvJWcKRs70j2FOT012IllEEO1n4pD1513Yg2ssQPOThOkvyrqHUdEXOSEsihmBbTbKX1kLBPWqWkLOqJbjB3GBIZmoa8qWl4CG/iZ7oiA72ZL7TJNeZUY7kFQftDcHHluBzRbCegzMtrRjVQpX2lgoPKKLJAkcbMl01XK2p7yhL8pCBbQ3BN2avJgKvttcrWDK3CiUOVxQ8ZP+pqXKyIxnmBymCg5vJjNfkPK4+c8cIfK8ocVt7kmfd/I5SR1hKvCzUtb+lhgc00ZaO6CyhIQP1Uv4yIZjload72PXX0OIJvnFU+0Zf6MhsJwTfW0r0UwQfW4LNLZl5HK261JCZ4qnBaAreVAS3WrjV0LBnNDUNNDToCEeFfwgcb4gOEqLRhirWkexrCEYKVV711DLYEE1XBEsp5tpTGjorkomKYF9FDXv7fR3BGwbettSxnyL53MBPjsxDZjMh+VUW9NRxq1DhVk+FSxQcaGjV9Pawv6eGByw5qzoy7xk4RsOShqjJwWKe/1pEEfzkobeD/dQJmpqedcyBTy2sr4nGNRH0c0SPWTLrqAc0OQcb/gemKgqucQT7ySWKCn2EUotoCvpZct7RO2sy/QW0IWcXd7pQRQyZVwT2USRO87uhjioTLKV2brpMUcMQRbKH/N2T+UlTpaMls6cmc6CCNy3JdYYSUzzJQ4oSD3oKLncULOiJvjBEC2oqnCJkJluCYy2ZQ5so9YYlZ1VLlQU1mXEW1jZERwj/MUSRc24TdexlqLKfQBtDTScJUV8FszXBEY5ktpD5Ur9hYB4Nb1iikw3JoYpkKX+RodRKFt53MMuRnKSpY31PwYaGaILh3wxJGz9TkTPEETxoCWZrgvOlmyMzxFEwVJE5xZKzvyJ4WxEc16Gd4Xe3Weq4XH2jKRikqOkGQ87hQnC7wBmGYLAnesX3M+S87eFATauuN+Qcrh7xIxXJbUIdMw3JGE3ylCWzrieaqCn4zhGM19TQ3z1oH1AX+pWEqIc7wNGAkULBo/ZxRaV9NNyh4Br3rCHZzbzmSfawBL0dNRwpW1kK9mxPXR9povcdrGSZK9c2k0xwFGzjuniCtRSZCZ6ccZ7gaktmgAOtKbG/JnOkJrjcQTdFMsxRQ2cLY3WTIrlCw1eWKn8R6pvt4GFDso3QoL4a3nLk3G6JrtME3dSenpx7PNFTmga0EaJTLQ061sEeQoWXhSo9LTXsaSjoJQRXeZLtDclbCrYzfzHHeaKjHCVOUkQHO3JeEepr56mhiyaYYKjjNU+Fed1wS5VlhWSqI/hYUdDOkaxiKehoyOnrCV5yBHtbWFqTHCCwtpDcYolesVR5yUzTZBb3RNMd0d6WP+SvhuBmRcGxnuQzT95IC285cr41cLGQ6aJJhmi4TMGempxeimBRQw1tFKV+8jd6KuzoSTqqDxzRtpZkurvKEHxlqXKRIjjfUNNXQsNOsRScoWFLT+YeRZVD3GRN0MdQcKqQjHDMrdGGVu3iYJpQx3WGUvfbmxwFfR20WBq0oYY7LMFhhgYtr8jpaEnaOzjawWWaTP8mMr0t/EPDPoqcnxTBI5o58L7uoWnMrpoqPwgVrlAUWE+V+TQl9rawoyP6QGAlQw2TPRX+YSkxyBC8Z6jhHkXBgQL7WII3DVFnRfCrBfxewv9D6xsyjys4VkhWb9pUU627JllV0YDNHMku/ldNMMXDEo4aFnAkk4U6frNEU4XgZUPmEKHUl44KrzmYamjAbh0JFvGnaTLPu1s9jPCwjFpYiN7z1DTOk/nc07CfDFzmCf7i+bfNHXhDtLeBXzTBT5rkMvWOIxpl4EMh2LGJBu2syDnAEx2naEhHDWMMzPZEhygyS1mS5RTJr5ZkoKbEUoYqr2kqdDUE8ztK7OaIntJkFrIECwv8LJTaVx5XJE86go8dFeZ3FN3rjabCAYpoYEeC9zzJVULBbmZhDyd7ko09ydpNZ3nm2Kee4FPPXHnYEF1nqOFEC08LUVcDvYXkJHW8gTaKCk9YGOeIJhqiE4ToPEepdp7IWFjdwnWaufGMwJJCMtUTTBBK9BGCOy2tGGrJTHIwyEOzp6aPzNMOtlZkDvcEWpP5SVNhfkvDxhmSazTJXYrM9U1E0xwFVwqZQwzJxw6+kGGGUj2FglGGmnb1/G51udRSMNlTw6GGnCcUwVcOpmsqTHa06o72sw1RL02p9z0VbnMLOaIX3QKaYKSCFQzBKEUNHTSc48k53RH9wxGMtpQa5KjjW0W0n6XCCCG4yxNNdhQ4R4l1Ff+2sSd6UFHiIEOyqqFgT01mEUMD+joy75jPhOA+oVVLm309FR4yVOlp4RhLiScNmSmaYF5Pw0STrOIoWMSR2UkRXOMp+M4SHW8o8Zoi6OZgjKOaFar8zZDzkWzvKOjkKBjmCXby8JahhjXULY4KlzgKLvAwxVGhvyd4zxB1d9T0piazmKLCVZY5sKiD0y2ZSYrkUEPUbIk+dlQ4SJHTR50k1DPaUWIdTZW9NJwnJMOECgd7ou/MnppMJ02O1VT4Wsh85MnZzcFTngpXGKo84qmwgKbCL/orR/SzJ2crA+t6Mp94KvxJUeIbT3CQu1uIdlQEOzlKfS3UMcrTiFmOuroocrZrT2AcmamOKg8YomeEKm/rlT2sociMaybaUlFhuqHCM2qIJ+rg4EcDFymiDSxzaHdPcpE62pD5kyM5SBMoA1PaUtfIthS85ig1VPiPPYXgYEMNk4Qq7TXBgo7oT57gPUdwgCHzhIVFPFU6OYJzHAX9m5oNrVjeE61miDrqQ4VSa1oiURTsKHC0IfjNwU2WzK6eqK8jWln4g15TVBnqmDteCJ501PGAocJhhqjZdtBEB6lnhLreFJKxmlKbeGrqLiSThVIbCdGzloasa6lpMQXHCME2boLpJgT7yWaemu6wBONbqGNVRS0PKIL7LckbjmQtR7K8I5qtqel+T/ChJTNIKLjdUMNIRyvOEko9YYl2cwQveBikCNawJKcLBbc7+JM92mysNvd/Fqp8a0k6CNEe7cnZrxlW0wQXaXjaktnRwNOGZKYiONwS7a1JVheq3WgJHlQUGKHKmp4KAxXR/ULURcNgoa4zhKSLpZR3kxRRb0NmD0OFn+UCS7CzI1nbP6+o4x47QZE5xRCt3ZagnYcvmpYQktXdk5YKXTzBC57kKEe0VVuiSYqapssMS3C9p2CKkHOg8B8Pa8p5atrIw3qezIWanMGa5HRDNF6RM9wcacl0N+Q8Z8hsIkSnaIIdHRUOEebAPy1zbCkhM062FCJtif7PU+UtoVXzWKqM1PxXO8cfdruhFQ/a6x3JKYagvVDhQEtNiyiiSQ7OsuRsZUku0CRNDs4Sog6KKjsZgk2bYJqijgsEenoKeniinRXBn/U3lgpPdyDZynQx8IiioMnCep5Ky8mjGs6Wty0l1hUQTcNWswS3WRp2kCNZwJG8omG8JphPUaFbC8lEfabwP7VtM9yoaNCAjpR41VNhrD9LkbN722v0CoZMByFzhaW+MyzRYEWFDQwN2M4/JiT76PuljT3VU/A36eaIThb+R9oZGOAJ9tewkgGvqOMNRWYjT/Cwu99Q8LqDE4TgbLWxJ1jaDDAERsFOFrobgjUsBScaguXU8kKm2RL19tRypSHnHNlHiIZqgufs4opgQdVdwxBNNFBR6kVFqb8ogimOzB6a6HTzrlDHEpYaxjiiA4TMQobkDg2vejjfwJGWmnbVFAw3H3hq2NyQfG7hz4aC+w3BbwbesG0swYayvpAs6++Ri1Vfzx93mFChvyN5xVHTS+0p9aqCAxyZ6ZacZyw5+7uuQkFPR9DDk9NOiE7X1PCYJVjVUqq7JlrHwWALF5nfHNGjApdpqgzx5OwilDhCiDYTgnc9waGW4BdLNNUQvOtpzDOWHDH8D7TR/A/85KljEQu3NREc4Pl/6B1Hhc8Umb5CsKMmGC9EPcxoT2amwHNCmeOEnOPbklnMkbOgIvO5UMOpQrS9UGVdt6iH/fURjhI/WOpaW9OKLYRod6HCUEdOX000wpDZQ6hwg6LgZfOqo1RfT/CrJzjekXOGhpc1VW71ZLbXyyp+93ILbC1kPtIEYx0FIx1VDrLoVzXRKRYWk809yYlC9ImcrinxtabKnzRJk3lAU1OLEN1j2zrYzr2myHRXJFf4h4QKT1qSTzTB5+ZNTzTRkAxX8FcLV2uS8eoQQ2aAkFzvCM72sJIcJET3WPjRk5wi32uSS9rfZajpWEvj9hW42F4o5NytSXYy8IKHay10VYdrcl4SkqscrXpMwyGOgtkajheSxdQqmpxP1L3t4R5PqasFnrQEjytq6qgp9Y09Qx9o4S1FzhUCn1kyHSzBWLemoSGvOqLNhZyBjmCaAUYpMgt4Ck7wBBMMwWKWgjsUwTaGVsxWC1mYoKiyqqeGKYqonSIRQ3KIkHO0pmAxTdBHkbOvfllfr+AA+7gnc50huVKYK393FOyg7rbPO/izI7hE4CnHHHnJ0ogNPRUGeUpsrZZTBJcrovUcJe51BPsr6GkJdhCCsZ6aTtMEb2pqWkqeVtDXE/QVggsU/Nl86d9RMF3DxvZTA58agu810RWawCiSzzXBeU3MMW9oyJUedvNEvQyNu1f10BSMddR1vaLCYpYa/mGocLSiYDcLbQz8aMn5iyF4xBNMs1P0QEOV7o5gaWGuzSeLue4tt3ro7y4Tgm4G/mopdZgl6q0o6KzJWE3mMksNr3r+a6CbT8g5wZNzT9O7fi/zpaOmnz3BRoqos+tv9zMbdpxsqDBOEewtJLt7cg5wtKKbvldpSzRRCD43VFheCI7yZLppggMVBS/KMAdHODJvOwq2NQSbKKKPLdFWQs7Fqo+mpl01JXYRgq8dnGLhTiFzqmWsUMdpllZdbKlyvSdYxhI9YghOtxR8LgSLWHK62mGGVoxzBE8LNWzqH9CUesQzFy5RQzTc56mhi6fgXEWwpKfE5Z7M05ZgZUPmo6auiv8YKzDYwWBLMErIbKHJvOwIrvEdhOBcQ9JdU1NHQ7CXn2XIDFBKU2WAgcX9UAUzDXWd5alwuyJ41Z9rjKLCL4aCp4WarhPm2rH+SaHUYE001JDZ2ZAzXPjdMpZWvC9wmqIB2lLhQ01D5jO06hghWMndbM7yRJMsoCj1vYbnFQVrW9jak3OlEJ3s/96+p33dEPRV5GxiqaGjIthUU6FFEZyqCa5qJrpBdzSw95IUnOPIrCUUjRZQFrbw5PR0R1qiYx3cb6nrWUMrBmmiBQxVHtTew5ICP/ip6g4hed/Akob/32wvBHsIOX83cI8hGeNeNPCIkPmXe8fPKx84OMSRM1MTdXSwjCZ4S30jVGhvqTRak/OVhgGazHuOCud5onEO1lJr6ecVyaOK6H7zqlBlIaHE0oroCgfvGJIdPcmfLNGLjpz7hZwZQpUbFME0A1cIJa7VNORkgfsMBatbKgwwJM9bSvQXeNOvbIjelg6WWvo5kvbKaJJNHexkKNHL9xRyFlH8Ti2riB5wVPhUk7nGkJnoCe428LR/wRGdYIlmWebCyxou1rCk4g/ShugBDX0V0ZQWkh0dOVsagkM0yV6OoLd5ye+pRlsCr0n+KiQrGuq5yJDzrTAXHtLUMduTDBVKrSm3eHL+6ijxhFDX9Z5gVU/wliHYTMiMFpKLNMEywu80wd3meoFmt6VbRMPenhrOc6DVe4pgXU8DnnHakLOIIrlF4FZPIw6R+zxBP0dyq6OOZ4Q5sLKCcz084ok+VsMMyQhNZmmBgX5xIXOEJTmi7VsGTvMTNdHHhpzdbE8Du2oKxgvBqQKdDDnTFOylCFaxR1syz2iqrOI/FEpNc3C6f11/7+ASS6l2inq2ciTrCCzgyemrCL5SVPjQkdPZUmGy2c9Sw9FtR1sS30RmsKPCS4rkIC/2U0MduwucYolGaPjKEyhzmiPYXagyWbYz8LWBDdzRimAXzxx4z8K9hpzlhLq+NiQ97HuKorMUfK/OVvC2JfiHUPCQI/q7J2gjK+tTDNxkCc4TMssqCs4TGtLVwQihyoAWgj9bosU80XGW6Ac9TJGziaUh5+hnFcHOnlaM1iRn29NaqGENTTTSUHCH2tWTeV0osUhH6psuVLjRUmGWhm6OZEshGeNowABHcJ2Bpy2ZszRcKkRXd2QuKVEeXnbfaEq825FguqfgfE2whlChSRMdron+LATTPQ2Z369t4B9C5gs/ylzv+CMmepIDPclFQl13W0rspPd1JOcbghGOEutqCv5qacURQl3dDKyvyJlqKXGPgcM9FfawJAMVmdcspcYKOZc4GjDYkFlK05olNMHyHn4zFNykyOxt99RkHlfwmiHo60l2EKI+mhreEKp080Tbug08BVPcgoqC5zWt+NLDTZ7oNSF51N1qie7Va3uCCwyZbkINf/NED6jzOsBdZjFN8oqG3wxVunqCSYYKf3EdhJyf9YWGf7tRU2oH3VHgPr1fe5J9hOgHd7xQ0y7qBwXr23aGErP0cm64JVjZwsOGqL+mhNgZmhJLW2oY4UhedsyBgzrCKrq7BmcpNVhR6jBPq64Vgi+kn6XE68pp8J5/+0wRHGOpsKenQn9DZntPzjRLZpDAdD2fnSgkG9tmIXnUwQ6WVighs7Yi2MxQ0N3CqYaCXkJ0oyOztMDJjmSSpcpvlrk0RMMOjmArQ04PRV1DO1FwhCVaUVPpKUM03JK5SxPsIWRu8/CGHi8UHChiqGFDTbSRJWeYUDDcH6vJWUxR4k1FXbMUwV6e4AJFXS8oMqsZKqzvYQ9DDQdZckY4aGsIhtlubbd2r3j4QBMoTamdPZk7O/Bf62lacZwneNjQoGcdVU7zJOd7ghsUHOkosagic6cnWc8+4gg285R6zZP5s1/LUbCKIznTwK36PkdwlOrl4U1LwfdCCa+IrvFkmgw1PCAUXKWo0sURXWcI2muKJlgyFzhynCY4RBOsqCjoI1R5zREco0n2Vt09BQtYSizgKNHfUmUrQ5UOCh51BFcLmY7umhYqXKQomOop8bUnWNNQcIiBcYaC6xzMNOS8JQQfeqKBmmglB+97ok/lfk3ygaHSyZaCRTzRxQo6GzLfa2jWBPepw+UmT7SQEJyiyRkhBLMVOfcoMjcK0eZChfUNzFAUzCsEN5vP/X1uP/n/aoMX+K+nw/Hjr/9xOo7j7Pju61tLcgvJpTWXNbfN5jLpi6VfCOviTktKlFusQixdEKWmEBUKNaIpjZRSSOXSgzaaKLdabrm1/9nZ+/f+vd/vz/v9+Xy+zZ7PRorYoZqyLrCwQdEAixxVOEXNNnjX2nUSRlkqGmWowk8lxR50JPy9Bo6qJXaXwNvREBvnThPEPrewryLhcAnj5WE15Fqi8W7R1sAuEu86S4ENikItFN4xkv9Af4nXSnUVcLiA9xzesFpivRRVeFKtsMRaKBhuSbjOELnAUtlSQUpXgdfB4Z1oSbnFEetbQ0IrAe+Y+pqnDcEJFj6S8LDZzZHwY4e3XONNlARraomNEt2bkvGsosA3ioyHm+6jCMbI59wqt4eeara28IzEmyPgoRaUOEDhTVdEJhmCoTWfC0p8aNkCp0oYqih2iqGi4yXeMkOsn4LdLLnmKfh/YogjNsPebeFGR4m9BJHLzB61XQ3BtpISfS2FugsK9FAtLWX1dCRcrCnUp44CNzuCowUZmxSRgYaE6Za0W2u/E7CVXCiI/UOR8aAm1+OSyE3mOUcwyc1zBBeoX1kiKy0Zfxck1Gsyulti11i83QTBF5Kg3pDQThFMVHiPSlK+0cSedng/VaS8bOZbtsBcTcZAR8JP5KeqQ1OYKAi20njdNNRpgnsU//K+JnaXJaGTomr7aYIphoRn9aeShJWKEq9LcozSF7QleEfDI5LYm5bgVkFkRwVDBCVu0DDIkGupo8TZBq+/pMQURYErJQmPKGKjNDkWOLx7Jd5QizdUweIaKrlP7SwJDhZvONjLkOsBBX9UpGxnydhXkfBLQ8IxgojQbLFnJf81JytSljclYYyEFyx0kVBvKWOFJmONpshGAcsduQY5giVNCV51eOdJYo/pLhbvM0uDHSevNKRcrKZIqnCtJeEsO95RoqcgGK4ocZcho1tTYtcZvH41pNQ7vA0WrhIfOSraIIntIAi+NXWCErdbkvrWwjRLrt0NKUdL6KSOscTOdMSOUtBHwL6OLA0vNSdynaWQEnCpIvKaIrJJEbvHkmuNhn6OjM8VkSGSqn1uYJCGHnq9I3aLhNME3t6GjIkO7xrNFumpyTNX/NrwX7CrIRiqqWijI9JO4d1iieykyfiposQIQ8YjjsjlBh6oHWbwRjgYJQn2NgSnNycmJAk3NiXhx44Sxykihxm8ybUwT1OVKySc7vi3OXVkdBJ4AyXBeksDXG0IhgtYY0lY5ahCD0ehborIk5aUWRJviMA7Xt5kyRjonrXENkm8yYqgs8VzgrJmClK20uMM3jRJ0FiQICQF9hdETlLQWRIb5ki6WDfWRPobvO6a4GP5mcOrNzDFELtTkONLh9dXE8xypEg7z8A9jkhrQ6Fhjlg/QVktJXxt4WXzT/03Q8IaQWSqIuEvloQ2mqC9Jfi7wRul4RX3pSPlzpoVlmCtI2jvKHCFhjcM3sN6lqF6HxnKelLjXWbwrpR4xzuCrTUZx2qq9oAh8p6ixCUGr78g8oyjRAtB5CZFwi80VerVpI0h+IeBxa6Zg6kWvpDHaioYYuEsRbDC3eOmC2JvGYLeioxGknL2UATNJN6hmtj1DlpLvDVmocYbrGCVJKOrg4X6DgddLA203BKMFngdJJFtFd7vJLm6KEpc5yjQrkk7M80SGe34X24nSex1Ra5Omgb71JKyg8SrU3i/kARKwWpH0kOGhKkObyfd0ZGjvyXlAkVZ4xRbYJ2irFMkFY1SwyWxr2oo4zlNiV+7zmaweFpT4kR3kaDAFW6xpSqzJay05FtYR4HmZhc9UxKbbfF2V8RG1MBmSaE+kmC6JnaRXK9gsiXhJHl/U0qM0WTcbyhwkYIvFGwjSbjfwhiJt8ZSQU+Bd5+marPMOkVkD0muxYLIfEuhh60x/J92itguihJSEMySVPQnTewnEm+620rTQEMsOfo4/kP/0ARvWjitlpSX7GxBgcMEsd3EEeYWvdytd+Saawi6aCIj1CkGb6Aj9rwhx16Cf3vAwFy5pyLhVonXzy51FDpdEblbkdJbUcEPDEFzQ8qNmhzzLTmmKWKbFCXeEuRabp6rxbvAtLF442QjQ+wEA9eL1xSR7Q0JXzlSHjJ4exq89yR0laScJ/FW6z4a73pFMEfDiRZvuvijIt86RaSFOl01riV2mD1UEvxGk/Geg5aWwGki1zgKPG9J2U8PEg8qYvMsZeytiTRXBMslCU8JSlxi8EabjwUldlDNLfzTUmCgxWsjqWCOHavYAqsknKFIO0yQ61VL5AVFxk6WhEaCAkdJgt9aSkzXlKNX2jEa79waYuc7gq0N3GDJGCBhoiTXUEPsdknCUE1CK0fwsiaylSF2uiDyO4XX3pFhNd7R4itFGc0k/ElBZwWvq+GC6szVeEoS/MZ+qylwpKNKv9Z469UOjqCjwlusicyTxG6VpNxcQ8IncoR4RhLbR+NdpGGmJWOcIzJGUuKPGpQg8rrG21dOMqQssJQ4RxH5jaUqnZuQ0F4Q+cjxLwPtpZbIAk3QTJHQWBE5S1BokoVtDd6lhqr9UpHSUxMcIYl9pojsb8h4SBOsMQcqvOWC2E8EVehqiJ1hrrAEbQxeK0NGZ0Gkq+guSRgniM23bIHVkqwx4hiHd7smaOyglyIyQuM978j4VS08J/A2G1KeMBRo4fBaSNhKUEZfQewVQ/C1I+MgfbEleEzCUw7mKXI0M3hd1EESVji8x5uQ41nxs1q4RMJCCXs7Iq9acpxn22oSDnQ/sJTxsCbHIYZiLyhY05TY0ZLIOQrGaSJDDN4t8pVaIrsqqFdEegtizc1iTew5Q4ayBDMUsQMkXocaYkc0hZua412siZ1rSXlR460zRJ5SlHGe5j801RLMlJTxtaOM3Q1pvxJ45zUlWFD7rsAbpfEm1JHxG0eh8w2R7QQVzBUw28FhFp5QZzq8t2rx2joqulYTWSuJdTYfWwqMFMcovFmSyJPNyLhE4E10pHzYjOC3huArRa571ZsGajQpQx38SBP5pyZB6lMU3khDnp0MBV51BE9o2E+TY5Ml2E8S7C0o6w1xvCZjf0HkVEHCzFoyNmqC+9wdcqN+Tp7jSDheE9ws8Y5V0NJCn2bk2tqSY4okdrEhx1iDN8cSudwepWmAGXKcJXK65H9to8jYQRH7SBF01ESUJdd0TayVInaWhLkOjlXE5irKGOnI6GSWGCJa482zBI9rCr0jyTVcEuzriC1vcr6mwFGSiqy5zMwxBH/TJHwjSPhL8+01kaaSUuMFKTcLEvaUePcrSmwn8DZrgikWb7CGPxkSjhQwrRk57tctmxLsb9sZvL9LSlyuSLlWkqOjwduo8b6Uv1DkmudIeFF2dHCgxVtk8dpIvHpBxhEOdhKk7OLIUSdJ+cSRY57B+0DgGUUlNfpthTfGkauzxrvTsUUaCVhlKeteTXCoJDCa2NOKhOmC4G1H8JBd4OBZReSRGkqcb/CO1PyLJTLB4j1q8JYaIutEjSLX8YKM+a6phdMsdLFUoV5RTm9JSkuDN8WcIon0NZMNZWh1q8C7SJEwV5HxrmnnTrf3KoJBlmCYI2ilSLlfEvlE4011NNgjgthzEua0oKK7JLE7HZHlEl60BLMVFewg4EWNt0ThrVNEVkkiTwpKXSWJzdRENgvKGq4IhjsiezgSFtsfCUq8qki5S1LRQeYQQ4nemmCkImWMw3tFUoUBZk4NOeZYEp4XRKTGa6wJjrWNHBVJR4m3FCnbuD6aak2WsMTh3SZImGCIPKNgsDpVwnsa70K31lCFJZYcwwSMFcQulGTsZuEaSdBXkPGZhu0FsdUO73RHjq8MPGGIfaGIbVTk6iuI3GFgucHrIQkmWSJdBd7BBu+uOryWAhY7+Lki9rK5wtEQzWwvtbqGhIMFwWRJsElsY4m9IIg9L6lCX0VklaPAYkfkZEGDnOWowlBJjtMUkcGK4Lg6EtoZInMUBVYLgn0UsdmCyCz7gIGHFfk+k1QwTh5We7A9x+IdJ6CvIkEagms0hR50eH9UnTQJ+2oiKyVlLFUE+8gBGu8MQ3CppUHesnjTHN4QB/UGPhCTHLFPHMFrCqa73gqObUJGa03wgbhHkrCfpEpzNLE7JDS25FMKhlhKKWKfCgqstLCPu1zBXy0J2ztwjtixBu8UTRn9LVtkmCN2iyFhtME70JHRQ1KVZXqKI/KNIKYMCYs1GUMEKbM1bKOI9LDXC7zbHS+bt+1MTWS9odA9DtrYtpbImQJ2VHh/lisEwaHqUk1kjKTAKknkBEXkbkdMGwq0dnhzLJF3NJH3JVwrqOB4Sca2hti75nmJN0WzxS6UxDYoEpxpa4htVlRjkYE7DZGzJVU72uC9IyhQL4i8YfGWSYLLNcHXloyz7QhNifmKSE9JgfGmuyLhc403Xm9vqcp6gXe3xuuv8F6VJNxkyTHEkHG2g0aKXL0MsXc1bGfgas2//dCONXiNLCX+5mB7eZIl1kHh7ajwpikyzlUUWOVOsjSQlsS+M0R+pPje/dzBXRZGO0rMtgQrLLG9VSu9n6CMXS3BhwYmSoIBhsjNBmZbgusE9BCPCP5triU4VhNbJfE+swSP27aayE8tuTpYYjtrYjMVGZdp2NpS1s6aBnKSHDsbKuplKbHM4a0wMFd/5/DmGyKrJSUaW4IBrqUhx0vyfzTBBLPIUcnZdrAkNsKR0sWRspumSns6Ch0v/qqIbBYUWKvPU/CFoyrDJGwSNFhbA/MlzKqjrO80hRbpKx0Jewsi/STftwGSlKc1JZyAzx05dhLEdnfQvhZOqiHWWEAHC7+30FuRcZUgaO5gpaIK+xsiHRUsqaPElTV40xQZQ107Q9BZE1nryDVGU9ZSQ47bmhBpLcYpUt7S+xuK/FiT8qKjwXYw5ypS2iuCv7q1gtgjhuBuB8LCFY5cUuCNtsQOFcT+4Ih9JX+k8Ea6v0iCIRZOtCT0Et00JW5UeC85Cg0ScK0k411HcG1zKtre3SeITBRk7WfwDhEvaYLTHP9le0m8By0JDwn4TlLW/aJOvGHxdjYUes+ScZigCkYQdNdEOhkiezgShqkx8ueKjI8lDfK2oNiOFvrZH1hS+tk7NV7nOmLHicGWEgubkXKdwdtZknCLJXaCpkrjZBtLZFsDP9CdxWsSr05Sxl6CMmoFbCOgryX40uDtamB7SVmXW4Ihlgpmq+00tBKUUa83WbjLUNkzDmY7cow1JDygyPGlhgGKYKz4vcV7QBNbJIgM11TUqZaMdwTeSguH6rOaw1JRKzaaGyxVm2EJ/uCIrVWUcZUkcp2grMsEjK+DMwS59jQk3Kd6SEq1d0S6uVmO4Bc1lDXTUcHjluCXEq+1OlBDj1pi9zgiXxnKuE0SqTXwhqbETW6RggMEnGl/q49UT2iCzgJvRwVXS2K/d6+ZkyUl7jawSVLit46EwxVljDZwoSQ20sDBihztHfk2yA8NVZghiXwrYHQdfKAOtzsayjhY9bY0yE2CWEeJ9xfzO423xhL5syS2TFJofO2pboHob0nY4GiAgRrvGQEDa/FWSsoaaYl0syRsEt3kWoH3B01shCXhTUWe9w3Bt44SC9QCh3eShQctwbaK2ApLroGCMlZrYqvlY3qYhM0aXpFkPOuoqJ3Dm6fxXrGwVF9gCWZagjPqznfkuMKQ8DPTQRO8ZqG1hPGKEm9IgpGW4DZDgTNriTxvFiq+Lz+0cKfp4wj6OCK9JSnzNSn9LFU7UhKZZMnYwcJ8s8yRsECScK4j5UOB95HFO0CzhY4xJxuCix0lDlEUeMdS6EZBkTsUkZ4K74dugyTXS7aNgL8aqjDfkCE0ZbwkCXpaWCKhl8P7VD5jxykivSyxyZrYERbe168LYu9ZYh86IkscgVLE7tWPKmJv11CgoyJltMEbrohtVAQfO4ImltiHEroYEs7RxAarVpY8AwXMcMReFOTYWe5iiLRQxJ5Q8DtJ8LQhWOhIeFESPGsILhbNDRljNbHzNRlTFbk2S3L0NOS6V1KFJYKUbSTcIIhM0wQ/s2TM0SRMNcQmSap3jCH4yhJZKSkwyRHpYYgsFeQ4U7xoCB7VVOExhXepo9ABBsYbvGWKXPME3lyH95YioZ0gssQRWWbI+FaSMkXijZXwgiTlYdPdkNLaETxlyDVIwqeaEus0aTcYcg0RVOkpR3CSJqIddK+90JCxzsDVloyrFd5ZAr4TBKfaWa6boEA7C7s6EpYaeFPjveooY72mjIccLHJ9HUwVlDhKkmutJDJBwnp1rvulJZggKDRfbXAkvC/4l3ozQOG9a8lxjx0i7nV4jSXc7vhe3OwIxjgSHjdEhhsif9YkPGlus3iLFDnWOFhtCZbJg0UbQcIaR67JjthoCyMEZRwhiXWyxO5QxI6w5NhT4U1WsJvDO60J34fW9hwzwlKij6ZAW9ne4L0s8C6XeBMEkd/LQy1VucBRot6QMlbivaBhoBgjqGiCJNhsqVp/S2SsG6DIONCR0dXhvWbJ+MRRZJkkuEjgDXJjFQW6SSL7GXK8Z2CZg7cVsbWGoKmEpzQ5elpiy8Ryg7dMkLLUEauzeO86CuwlSOlgYLojZWeJ9xM3S1PWfEfKl5ISLQ0MEKR8YOB2QfCxJBjrKPCN4f9MkaSsqoVXJBmP7EpFZ9UQfOoOFwSzBN4MQ8LsGrymlipcJQhmy0GaQjPqCHaXRwuCZwRbqK2Fg9wlClZqYicrIgMdZfxTQ0c7TBIbrChxmuzoKG8XRaSrIhhiyNFJkrC7oIAWMEOQa5aBekPCRknCo4IKPrYkvCDI8aYmY7WFtprgekcJZ3oLIqssCSMtFbQTJKwXYy3BY5oCh2iKPCpJOE+zRdpYgi6O2KmOAgvVCYaU4ySRek1sgyFhJ403QFHiVEmJHwtybO1gs8Hr5+BETQX3War0qZngYGgtVZtoqd6vFSk/UwdZElYqyjrF4HXUeFspIi9IGKf4j92pKGAdCYMVsbcV3kRF0N+R8LUd5PCsIGWoxDtBkCI0nKofdJQxT+LtZflvuc8Q3CjwWkq8KwUpHzkK/NmSsclCL0nseQdj5FRH5CNHSgtLiW80Of5HU9Hhlsga9bnBq3fEVltKfO5IaSTmGjjc4J0otcP7QsJUSQM8pEj5/wCuUuC2DWz8AAAAAElFTkSuQmCC\");\ +}\ +.ace-ambiance .ace_indent-guide {\ +background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNQUFD4z6Crq/sfAAuYAuYl+7lfAAAAAElFTkSuQmCC\") right repeat-y;\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); + +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-chaos.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-chaos.js new file mode 100755 index 0000000..97ec7fb --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-chaos.js @@ -0,0 +1,156 @@ +ace.define("ace/theme/chaos",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-chaos"; +exports.cssText = ".ace-chaos .ace_gutter {\ +background: #141414;\ +color: #595959;\ +border-right: 1px solid #282828;\ +}\ +.ace-chaos .ace_gutter-cell.ace_warning {\ +background-image: none;\ +background: #FC0;\ +border-left: none;\ +padding-left: 0;\ +color: #000;\ +}\ +.ace-chaos .ace_gutter-cell.ace_error {\ +background-position: -6px center;\ +background-image: none;\ +background: #F10;\ +border-left: none;\ +padding-left: 0;\ +color: #000;\ +}\ +.ace-chaos .ace_print-margin {\ +border-left: 1px solid #555;\ +right: 0;\ +background: #1D1D1D;\ +}\ +.ace-chaos {\ +background-color: #161616;\ +color: #E6E1DC;\ +}\ +.ace-chaos .ace_cursor {\ +border-left: 2px solid #FFFFFF;\ +}\ +.ace-chaos .ace_cursor.ace_overwrite {\ +border-left: 0px;\ +border-bottom: 1px solid #FFFFFF;\ +}\ +.ace-chaos .ace_marker-layer .ace_selection {\ +background: #494836;\ +}\ +.ace-chaos .ace_marker-layer .ace_step {\ +background: rgb(198, 219, 174);\ +}\ +.ace-chaos .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #FCE94F;\ +}\ +.ace-chaos .ace_marker-layer .ace_active-line {\ +background: #333;\ +}\ +.ace-chaos .ace_gutter-active-line {\ +background-color: #222;\ +}\ +.ace-chaos .ace_invisible {\ +color: #404040;\ +}\ +.ace-chaos .ace_keyword {\ +color:#00698F;\ +}\ +.ace-chaos .ace_keyword.ace_operator {\ +color:#FF308F;\ +}\ +.ace-chaos .ace_constant {\ +color:#1EDAFB;\ +}\ +.ace-chaos .ace_constant.ace_language {\ +color:#FDC251;\ +}\ +.ace-chaos .ace_constant.ace_library {\ +color:#8DFF0A;\ +}\ +.ace-chaos .ace_constant.ace_numeric {\ +color:#58C554;\ +}\ +.ace-chaos .ace_invalid {\ +color:#FFFFFF;\ +background-color:#990000;\ +}\ +.ace-chaos .ace_invalid.ace_deprecated {\ +color:#FFFFFF;\ +background-color:#990000;\ +}\ +.ace-chaos .ace_support {\ +color: #999;\ +}\ +.ace-chaos .ace_support.ace_function {\ +color:#00AEEF;\ +}\ +.ace-chaos .ace_function {\ +color:#00AEEF;\ +}\ +.ace-chaos .ace_string {\ +color:#58C554;\ +}\ +.ace-chaos .ace_comment {\ +color:#555;\ +font-style:italic;\ +padding-bottom: 0px;\ +}\ +.ace-chaos .ace_variable {\ +color:#997744;\ +}\ +.ace-chaos .ace_meta.ace_tag {\ +color:#BE53E6;\ +}\ +.ace-chaos .ace_entity.ace_other.ace_attribute-name {\ +color:#FFFF89;\ +}\ +.ace-chaos .ace_markup.ace_underline {\ +text-decoration: underline;\ +}\ +.ace-chaos .ace_fold-widget {\ +text-align: center;\ +}\ +.ace-chaos .ace_fold-widget:hover {\ +color: #777;\ +}\ +.ace-chaos .ace_fold-widget.ace_start,\ +.ace-chaos .ace_fold-widget.ace_end,\ +.ace-chaos .ace_fold-widget.ace_closed{\ +background: none;\ +border: none;\ +box-shadow: none;\ +}\ +.ace-chaos .ace_fold-widget.ace_start:after {\ +content: '▾'\ +}\ +.ace-chaos .ace_fold-widget.ace_end:after {\ +content: '▴'\ +}\ +.ace-chaos .ace_fold-widget.ace_closed:after {\ +content: '‣'\ +}\ +.ace-chaos .ace_indent-guide {\ +border-right:1px dotted #333;\ +margin-right:-1px;\ +}\ +.ace-chaos .ace_fold { \ +background: #222; \ +border-radius: 3px; \ +color: #7AF; \ +border: none; \ +}\ +.ace-chaos .ace_fold:hover {\ +background: #CCC; \ +color: #000;\ +}\ +"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); + +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-chrome.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-chrome.js new file mode 100755 index 0000000..83742aa --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-chrome.js @@ -0,0 +1,128 @@ +ace.define("ace/theme/chrome",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = false; +exports.cssClass = "ace-chrome"; +exports.cssText = ".ace-chrome .ace_gutter {\ +background: #ebebeb;\ +color: #333;\ +overflow : hidden;\ +}\ +.ace-chrome .ace_print-margin {\ +width: 1px;\ +background: #e8e8e8;\ +}\ +.ace-chrome {\ +background-color: #FFFFFF;\ +color: black;\ +}\ +.ace-chrome .ace_cursor {\ +color: black;\ +}\ +.ace-chrome .ace_invisible {\ +color: rgb(191, 191, 191);\ +}\ +.ace-chrome .ace_constant.ace_buildin {\ +color: rgb(88, 72, 246);\ +}\ +.ace-chrome .ace_constant.ace_language {\ +color: rgb(88, 92, 246);\ +}\ +.ace-chrome .ace_constant.ace_library {\ +color: rgb(6, 150, 14);\ +}\ +.ace-chrome .ace_invalid {\ +background-color: rgb(153, 0, 0);\ +color: white;\ +}\ +.ace-chrome .ace_fold {\ +}\ +.ace-chrome .ace_support.ace_function {\ +color: rgb(60, 76, 114);\ +}\ +.ace-chrome .ace_support.ace_constant {\ +color: rgb(6, 150, 14);\ +}\ +.ace-chrome .ace_support.ace_type,\ +.ace-chrome .ace_support.ace_class\ +.ace-chrome .ace_support.ace_other {\ +color: rgb(109, 121, 222);\ +}\ +.ace-chrome .ace_variable.ace_parameter {\ +font-style:italic;\ +color:#FD971F;\ +}\ +.ace-chrome .ace_keyword.ace_operator {\ +color: rgb(104, 118, 135);\ +}\ +.ace-chrome .ace_comment {\ +color: #236e24;\ +}\ +.ace-chrome .ace_comment.ace_doc {\ +color: #236e24;\ +}\ +.ace-chrome .ace_comment.ace_doc.ace_tag {\ +color: #236e24;\ +}\ +.ace-chrome .ace_constant.ace_numeric {\ +color: rgb(0, 0, 205);\ +}\ +.ace-chrome .ace_variable {\ +color: rgb(49, 132, 149);\ +}\ +.ace-chrome .ace_xml-pe {\ +color: rgb(104, 104, 91);\ +}\ +.ace-chrome .ace_entity.ace_name.ace_function {\ +color: #0000A2;\ +}\ +.ace-chrome .ace_heading {\ +color: rgb(12, 7, 255);\ +}\ +.ace-chrome .ace_list {\ +color:rgb(185, 6, 144);\ +}\ +.ace-chrome .ace_marker-layer .ace_selection {\ +background: rgb(181, 213, 255);\ +}\ +.ace-chrome .ace_marker-layer .ace_step {\ +background: rgb(252, 255, 0);\ +}\ +.ace-chrome .ace_marker-layer .ace_stack {\ +background: rgb(164, 229, 101);\ +}\ +.ace-chrome .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgb(192, 192, 192);\ +}\ +.ace-chrome .ace_marker-layer .ace_active-line {\ +background: rgba(0, 0, 0, 0.07);\ +}\ +.ace-chrome .ace_gutter-active-line {\ +background-color : #dcdcdc;\ +}\ +.ace-chrome .ace_marker-layer .ace_selected-word {\ +background: rgb(250, 250, 255);\ +border: 1px solid rgb(200, 200, 250);\ +}\ +.ace-chrome .ace_storage,\ +.ace-chrome .ace_keyword,\ +.ace-chrome .ace_meta.ace_tag {\ +color: rgb(147, 15, 128);\ +}\ +.ace-chrome .ace_string.ace_regex {\ +color: rgb(255, 0, 0)\ +}\ +.ace-chrome .ace_string {\ +color: #1A1AA6;\ +}\ +.ace-chrome .ace_entity.ace_other.ace_attribute-name {\ +color: #994409;\ +}\ +.ace-chrome .ace_indent-guide {\ +background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\ +}\ +"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-clouds.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-clouds.js new file mode 100755 index 0000000..83d0d14 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-clouds.js @@ -0,0 +1,95 @@ +ace.define("ace/theme/clouds",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = false; +exports.cssClass = "ace-clouds"; +exports.cssText = ".ace-clouds .ace_gutter {\ +background: #ebebeb;\ +color: #333\ +}\ +.ace-clouds .ace_print-margin {\ +width: 1px;\ +background: #e8e8e8\ +}\ +.ace-clouds {\ +background-color: #FFFFFF;\ +color: #000000\ +}\ +.ace-clouds .ace_cursor {\ +color: #000000\ +}\ +.ace-clouds .ace_marker-layer .ace_selection {\ +background: #BDD5FC\ +}\ +.ace-clouds.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #FFFFFF;\ +}\ +.ace-clouds .ace_marker-layer .ace_step {\ +background: rgb(255, 255, 0)\ +}\ +.ace-clouds .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #BFBFBF\ +}\ +.ace-clouds .ace_marker-layer .ace_active-line {\ +background: #FFFBD1\ +}\ +.ace-clouds .ace_gutter-active-line {\ +background-color : #dcdcdc\ +}\ +.ace-clouds .ace_marker-layer .ace_selected-word {\ +border: 1px solid #BDD5FC\ +}\ +.ace-clouds .ace_invisible {\ +color: #BFBFBF\ +}\ +.ace-clouds .ace_keyword,\ +.ace-clouds .ace_meta,\ +.ace-clouds .ace_support.ace_constant.ace_property-value {\ +color: #AF956F\ +}\ +.ace-clouds .ace_keyword.ace_operator {\ +color: #484848\ +}\ +.ace-clouds .ace_keyword.ace_other.ace_unit {\ +color: #96DC5F\ +}\ +.ace-clouds .ace_constant.ace_language {\ +color: #39946A\ +}\ +.ace-clouds .ace_constant.ace_numeric {\ +color: #46A609\ +}\ +.ace-clouds .ace_constant.ace_character.ace_entity {\ +color: #BF78CC\ +}\ +.ace-clouds .ace_invalid {\ +background-color: #FF002A\ +}\ +.ace-clouds .ace_fold {\ +background-color: #AF956F;\ +border-color: #000000\ +}\ +.ace-clouds .ace_storage,\ +.ace-clouds .ace_support.ace_class,\ +.ace-clouds .ace_support.ace_function,\ +.ace-clouds .ace_support.ace_other,\ +.ace-clouds .ace_support.ace_type {\ +color: #C52727\ +}\ +.ace-clouds .ace_string {\ +color: #5D90CD\ +}\ +.ace-clouds .ace_comment {\ +color: #BCC8BA\ +}\ +.ace-clouds .ace_entity.ace_name.ace_tag,\ +.ace-clouds .ace_entity.ace_other.ace_attribute-name {\ +color: #606060\ +}\ +.ace-clouds .ace_indent-guide {\ +background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-clouds_midnight.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-clouds_midnight.js new file mode 100755 index 0000000..275e9f2 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-clouds_midnight.js @@ -0,0 +1,96 @@ +ace.define("ace/theme/clouds_midnight",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-clouds-midnight"; +exports.cssText = ".ace-clouds-midnight .ace_gutter {\ +background: #232323;\ +color: #929292\ +}\ +.ace-clouds-midnight .ace_print-margin {\ +width: 1px;\ +background: #232323\ +}\ +.ace-clouds-midnight {\ +background-color: #191919;\ +color: #929292\ +}\ +.ace-clouds-midnight .ace_cursor {\ +color: #7DA5DC\ +}\ +.ace-clouds-midnight .ace_marker-layer .ace_selection {\ +background: #000000\ +}\ +.ace-clouds-midnight.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #191919;\ +}\ +.ace-clouds-midnight .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-clouds-midnight .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #BFBFBF\ +}\ +.ace-clouds-midnight .ace_marker-layer .ace_active-line {\ +background: rgba(215, 215, 215, 0.031)\ +}\ +.ace-clouds-midnight .ace_gutter-active-line {\ +background-color: rgba(215, 215, 215, 0.031)\ +}\ +.ace-clouds-midnight .ace_marker-layer .ace_selected-word {\ +border: 1px solid #000000\ +}\ +.ace-clouds-midnight .ace_invisible {\ +color: #666\ +}\ +.ace-clouds-midnight .ace_keyword,\ +.ace-clouds-midnight .ace_meta,\ +.ace-clouds-midnight .ace_support.ace_constant.ace_property-value {\ +color: #927C5D\ +}\ +.ace-clouds-midnight .ace_keyword.ace_operator {\ +color: #4B4B4B\ +}\ +.ace-clouds-midnight .ace_keyword.ace_other.ace_unit {\ +color: #366F1A\ +}\ +.ace-clouds-midnight .ace_constant.ace_language {\ +color: #39946A\ +}\ +.ace-clouds-midnight .ace_constant.ace_numeric {\ +color: #46A609\ +}\ +.ace-clouds-midnight .ace_constant.ace_character.ace_entity {\ +color: #A165AC\ +}\ +.ace-clouds-midnight .ace_invalid {\ +color: #FFFFFF;\ +background-color: #E92E2E\ +}\ +.ace-clouds-midnight .ace_fold {\ +background-color: #927C5D;\ +border-color: #929292\ +}\ +.ace-clouds-midnight .ace_storage,\ +.ace-clouds-midnight .ace_support.ace_class,\ +.ace-clouds-midnight .ace_support.ace_function,\ +.ace-clouds-midnight .ace_support.ace_other,\ +.ace-clouds-midnight .ace_support.ace_type {\ +color: #E92E2E\ +}\ +.ace-clouds-midnight .ace_string {\ +color: #5D90CD\ +}\ +.ace-clouds-midnight .ace_comment {\ +color: #3C403B\ +}\ +.ace-clouds-midnight .ace_entity.ace_name.ace_tag,\ +.ace-clouds-midnight .ace_entity.ace_other.ace_attribute-name {\ +color: #606060\ +}\ +.ace-clouds-midnight .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHB3d/8PAAOIAdULw8qMAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-cobalt.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-cobalt.js new file mode 100755 index 0000000..c5b6f26 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-cobalt.js @@ -0,0 +1,113 @@ +ace.define("ace/theme/cobalt",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-cobalt"; +exports.cssText = ".ace-cobalt .ace_gutter {\ +background: #011e3a;\ +color: rgb(128,145,160)\ +}\ +.ace-cobalt .ace_print-margin {\ +width: 1px;\ +background: #555555\ +}\ +.ace-cobalt {\ +background-color: #002240;\ +color: #FFFFFF\ +}\ +.ace-cobalt .ace_cursor {\ +color: #FFFFFF\ +}\ +.ace-cobalt .ace_marker-layer .ace_selection {\ +background: rgba(179, 101, 57, 0.75)\ +}\ +.ace-cobalt.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #002240;\ +}\ +.ace-cobalt .ace_marker-layer .ace_step {\ +background: rgb(127, 111, 19)\ +}\ +.ace-cobalt .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgba(255, 255, 255, 0.15)\ +}\ +.ace-cobalt .ace_marker-layer .ace_active-line {\ +background: rgba(0, 0, 0, 0.35)\ +}\ +.ace-cobalt .ace_gutter-active-line {\ +background-color: rgba(0, 0, 0, 0.35)\ +}\ +.ace-cobalt .ace_marker-layer .ace_selected-word {\ +border: 1px solid rgba(179, 101, 57, 0.75)\ +}\ +.ace-cobalt .ace_invisible {\ +color: rgba(255, 255, 255, 0.15)\ +}\ +.ace-cobalt .ace_keyword,\ +.ace-cobalt .ace_meta {\ +color: #FF9D00\ +}\ +.ace-cobalt .ace_constant,\ +.ace-cobalt .ace_constant.ace_character,\ +.ace-cobalt .ace_constant.ace_character.ace_escape,\ +.ace-cobalt .ace_constant.ace_other {\ +color: #FF628C\ +}\ +.ace-cobalt .ace_invalid {\ +color: #F8F8F8;\ +background-color: #800F00\ +}\ +.ace-cobalt .ace_support {\ +color: #80FFBB\ +}\ +.ace-cobalt .ace_support.ace_constant {\ +color: #EB939A\ +}\ +.ace-cobalt .ace_fold {\ +background-color: #FF9D00;\ +border-color: #FFFFFF\ +}\ +.ace-cobalt .ace_support.ace_function {\ +color: #FFB054\ +}\ +.ace-cobalt .ace_storage {\ +color: #FFEE80\ +}\ +.ace-cobalt .ace_entity {\ +color: #FFDD00\ +}\ +.ace-cobalt .ace_string {\ +color: #3AD900\ +}\ +.ace-cobalt .ace_string.ace_regexp {\ +color: #80FFC2\ +}\ +.ace-cobalt .ace_comment {\ +font-style: italic;\ +color: #0088FF\ +}\ +.ace-cobalt .ace_heading,\ +.ace-cobalt .ace_markup.ace_heading {\ +color: #C8E4FD;\ +background-color: #001221\ +}\ +.ace-cobalt .ace_list,\ +.ace-cobalt .ace_markup.ace_list {\ +background-color: #130D26\ +}\ +.ace-cobalt .ace_variable {\ +color: #CCCCCC\ +}\ +.ace-cobalt .ace_variable.ace_language {\ +color: #FF80E1\ +}\ +.ace-cobalt .ace_meta.ace_tag {\ +color: #9EFFFF\ +}\ +.ace-cobalt .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHCLSvkPAAP3AgSDTRd4AAAAAElFTkSuQmCC) right repeat-y\ +}\ +"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-crimson_editor.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-crimson_editor.js new file mode 100755 index 0000000..a188552 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-crimson_editor.js @@ -0,0 +1,118 @@ +ace.define("ace/theme/crimson_editor",["require","exports","module","ace/lib/dom"], function(require, exports, module) { +exports.isDark = false; +exports.cssText = ".ace-crimson-editor .ace_gutter {\ +background: #ebebeb;\ +color: #333;\ +overflow : hidden;\ +}\ +.ace-crimson-editor .ace_gutter-layer {\ +width: 100%;\ +text-align: right;\ +}\ +.ace-crimson-editor .ace_print-margin {\ +width: 1px;\ +background: #e8e8e8;\ +}\ +.ace-crimson-editor {\ +background-color: #FFFFFF;\ +color: rgb(64, 64, 64);\ +}\ +.ace-crimson-editor .ace_cursor {\ +color: black;\ +}\ +.ace-crimson-editor .ace_invisible {\ +color: rgb(191, 191, 191);\ +}\ +.ace-crimson-editor .ace_identifier {\ +color: black;\ +}\ +.ace-crimson-editor .ace_keyword {\ +color: blue;\ +}\ +.ace-crimson-editor .ace_constant.ace_buildin {\ +color: rgb(88, 72, 246);\ +}\ +.ace-crimson-editor .ace_constant.ace_language {\ +color: rgb(255, 156, 0);\ +}\ +.ace-crimson-editor .ace_constant.ace_library {\ +color: rgb(6, 150, 14);\ +}\ +.ace-crimson-editor .ace_invalid {\ +text-decoration: line-through;\ +color: rgb(224, 0, 0);\ +}\ +.ace-crimson-editor .ace_fold {\ +}\ +.ace-crimson-editor .ace_support.ace_function {\ +color: rgb(192, 0, 0);\ +}\ +.ace-crimson-editor .ace_support.ace_constant {\ +color: rgb(6, 150, 14);\ +}\ +.ace-crimson-editor .ace_support.ace_type,\ +.ace-crimson-editor .ace_support.ace_class {\ +color: rgb(109, 121, 222);\ +}\ +.ace-crimson-editor .ace_keyword.ace_operator {\ +color: rgb(49, 132, 149);\ +}\ +.ace-crimson-editor .ace_string {\ +color: rgb(128, 0, 128);\ +}\ +.ace-crimson-editor .ace_comment {\ +color: rgb(76, 136, 107);\ +}\ +.ace-crimson-editor .ace_comment.ace_doc {\ +color: rgb(0, 102, 255);\ +}\ +.ace-crimson-editor .ace_comment.ace_doc.ace_tag {\ +color: rgb(128, 159, 191);\ +}\ +.ace-crimson-editor .ace_constant.ace_numeric {\ +color: rgb(0, 0, 64);\ +}\ +.ace-crimson-editor .ace_variable {\ +color: rgb(0, 64, 128);\ +}\ +.ace-crimson-editor .ace_xml-pe {\ +color: rgb(104, 104, 91);\ +}\ +.ace-crimson-editor .ace_marker-layer .ace_selection {\ +background: rgb(181, 213, 255);\ +}\ +.ace-crimson-editor .ace_marker-layer .ace_step {\ +background: rgb(252, 255, 0);\ +}\ +.ace-crimson-editor .ace_marker-layer .ace_stack {\ +background: rgb(164, 229, 101);\ +}\ +.ace-crimson-editor .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgb(192, 192, 192);\ +}\ +.ace-crimson-editor .ace_marker-layer .ace_active-line {\ +background: rgb(232, 242, 254);\ +}\ +.ace-crimson-editor .ace_gutter-active-line {\ +background-color : #dcdcdc;\ +}\ +.ace-crimson-editor .ace_meta.ace_tag {\ +color:rgb(28, 2, 255);\ +}\ +.ace-crimson-editor .ace_marker-layer .ace_selected-word {\ +background: rgb(250, 250, 255);\ +border: 1px solid rgb(200, 200, 250);\ +}\ +.ace-crimson-editor .ace_string.ace_regex {\ +color: rgb(192, 0, 192);\ +}\ +.ace-crimson-editor .ace_indent-guide {\ +background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\ +}"; + +exports.cssClass = "ace-crimson-editor"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-dawn.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-dawn.js new file mode 100755 index 0000000..f3c15c9 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-dawn.js @@ -0,0 +1,108 @@ +ace.define("ace/theme/dawn",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = false; +exports.cssClass = "ace-dawn"; +exports.cssText = ".ace-dawn .ace_gutter {\ +background: #ebebeb;\ +color: #333\ +}\ +.ace-dawn .ace_print-margin {\ +width: 1px;\ +background: #e8e8e8\ +}\ +.ace-dawn {\ +background-color: #F9F9F9;\ +color: #080808\ +}\ +.ace-dawn .ace_cursor {\ +color: #000000\ +}\ +.ace-dawn .ace_marker-layer .ace_selection {\ +background: rgba(39, 95, 255, 0.30)\ +}\ +.ace-dawn.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #F9F9F9;\ +}\ +.ace-dawn .ace_marker-layer .ace_step {\ +background: rgb(255, 255, 0)\ +}\ +.ace-dawn .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgba(75, 75, 126, 0.50)\ +}\ +.ace-dawn .ace_marker-layer .ace_active-line {\ +background: rgba(36, 99, 180, 0.12)\ +}\ +.ace-dawn .ace_gutter-active-line {\ +background-color : #dcdcdc\ +}\ +.ace-dawn .ace_marker-layer .ace_selected-word {\ +border: 1px solid rgba(39, 95, 255, 0.30)\ +}\ +.ace-dawn .ace_invisible {\ +color: rgba(75, 75, 126, 0.50)\ +}\ +.ace-dawn .ace_keyword,\ +.ace-dawn .ace_meta {\ +color: #794938\ +}\ +.ace-dawn .ace_constant,\ +.ace-dawn .ace_constant.ace_character,\ +.ace-dawn .ace_constant.ace_character.ace_escape,\ +.ace-dawn .ace_constant.ace_other {\ +color: #811F24\ +}\ +.ace-dawn .ace_invalid.ace_illegal {\ +text-decoration: underline;\ +font-style: italic;\ +color: #F8F8F8;\ +background-color: #B52A1D\ +}\ +.ace-dawn .ace_invalid.ace_deprecated {\ +text-decoration: underline;\ +font-style: italic;\ +color: #B52A1D\ +}\ +.ace-dawn .ace_support {\ +color: #691C97\ +}\ +.ace-dawn .ace_support.ace_constant {\ +color: #B4371F\ +}\ +.ace-dawn .ace_fold {\ +background-color: #794938;\ +border-color: #080808\ +}\ +.ace-dawn .ace_list,\ +.ace-dawn .ace_markup.ace_list,\ +.ace-dawn .ace_support.ace_function {\ +color: #693A17\ +}\ +.ace-dawn .ace_storage {\ +font-style: italic;\ +color: #A71D5D\ +}\ +.ace-dawn .ace_string {\ +color: #0B6125\ +}\ +.ace-dawn .ace_string.ace_regexp {\ +color: #CF5628\ +}\ +.ace-dawn .ace_comment {\ +font-style: italic;\ +color: #5A525F\ +}\ +.ace-dawn .ace_heading,\ +.ace-dawn .ace_markup.ace_heading {\ +color: #19356D\ +}\ +.ace-dawn .ace_variable {\ +color: #234A97\ +}\ +.ace-dawn .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYLh/5+x/AAizA4hxNNsZAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-dreamweaver.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-dreamweaver.js new file mode 100755 index 0000000..632b1ea --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-dreamweaver.js @@ -0,0 +1,141 @@ +ace.define("ace/theme/dreamweaver",["require","exports","module","ace/lib/dom"], function(require, exports, module) { +exports.isDark = false; +exports.cssClass = "ace-dreamweaver"; +exports.cssText = ".ace-dreamweaver .ace_gutter {\ +background: #e8e8e8;\ +color: #333;\ +}\ +.ace-dreamweaver .ace_print-margin {\ +width: 1px;\ +background: #e8e8e8;\ +}\ +.ace-dreamweaver {\ +background-color: #FFFFFF;\ +color: black;\ +}\ +.ace-dreamweaver .ace_fold {\ +background-color: #757AD8;\ +}\ +.ace-dreamweaver .ace_cursor {\ +color: black;\ +}\ +.ace-dreamweaver .ace_invisible {\ +color: rgb(191, 191, 191);\ +}\ +.ace-dreamweaver .ace_storage,\ +.ace-dreamweaver .ace_keyword {\ +color: blue;\ +}\ +.ace-dreamweaver .ace_constant.ace_buildin {\ +color: rgb(88, 72, 246);\ +}\ +.ace-dreamweaver .ace_constant.ace_language {\ +color: rgb(88, 92, 246);\ +}\ +.ace-dreamweaver .ace_constant.ace_library {\ +color: rgb(6, 150, 14);\ +}\ +.ace-dreamweaver .ace_invalid {\ +background-color: rgb(153, 0, 0);\ +color: white;\ +}\ +.ace-dreamweaver .ace_support.ace_function {\ +color: rgb(60, 76, 114);\ +}\ +.ace-dreamweaver .ace_support.ace_constant {\ +color: rgb(6, 150, 14);\ +}\ +.ace-dreamweaver .ace_support.ace_type,\ +.ace-dreamweaver .ace_support.ace_class {\ +color: #009;\ +}\ +.ace-dreamweaver .ace_support.ace_php_tag {\ +color: #f00;\ +}\ +.ace-dreamweaver .ace_keyword.ace_operator {\ +color: rgb(104, 118, 135);\ +}\ +.ace-dreamweaver .ace_string {\ +color: #00F;\ +}\ +.ace-dreamweaver .ace_comment {\ +color: rgb(76, 136, 107);\ +}\ +.ace-dreamweaver .ace_comment.ace_doc {\ +color: rgb(0, 102, 255);\ +}\ +.ace-dreamweaver .ace_comment.ace_doc.ace_tag {\ +color: rgb(128, 159, 191);\ +}\ +.ace-dreamweaver .ace_constant.ace_numeric {\ +color: rgb(0, 0, 205);\ +}\ +.ace-dreamweaver .ace_variable {\ +color: #06F\ +}\ +.ace-dreamweaver .ace_xml-pe {\ +color: rgb(104, 104, 91);\ +}\ +.ace-dreamweaver .ace_entity.ace_name.ace_function {\ +color: #00F;\ +}\ +.ace-dreamweaver .ace_heading {\ +color: rgb(12, 7, 255);\ +}\ +.ace-dreamweaver .ace_list {\ +color:rgb(185, 6, 144);\ +}\ +.ace-dreamweaver .ace_marker-layer .ace_selection {\ +background: rgb(181, 213, 255);\ +}\ +.ace-dreamweaver .ace_marker-layer .ace_step {\ +background: rgb(252, 255, 0);\ +}\ +.ace-dreamweaver .ace_marker-layer .ace_stack {\ +background: rgb(164, 229, 101);\ +}\ +.ace-dreamweaver .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgb(192, 192, 192);\ +}\ +.ace-dreamweaver .ace_marker-layer .ace_active-line {\ +background: rgba(0, 0, 0, 0.07);\ +}\ +.ace-dreamweaver .ace_gutter-active-line {\ +background-color : #DCDCDC;\ +}\ +.ace-dreamweaver .ace_marker-layer .ace_selected-word {\ +background: rgb(250, 250, 255);\ +border: 1px solid rgb(200, 200, 250);\ +}\ +.ace-dreamweaver .ace_meta.ace_tag {\ +color:#009;\ +}\ +.ace-dreamweaver .ace_meta.ace_tag.ace_anchor {\ +color:#060;\ +}\ +.ace-dreamweaver .ace_meta.ace_tag.ace_form {\ +color:#F90;\ +}\ +.ace-dreamweaver .ace_meta.ace_tag.ace_image {\ +color:#909;\ +}\ +.ace-dreamweaver .ace_meta.ace_tag.ace_script {\ +color:#900;\ +}\ +.ace-dreamweaver .ace_meta.ace_tag.ace_style {\ +color:#909;\ +}\ +.ace-dreamweaver .ace_meta.ace_tag.ace_table {\ +color:#099;\ +}\ +.ace-dreamweaver .ace_string.ace_regex {\ +color: rgb(255, 0, 0)\ +}\ +.ace-dreamweaver .ace_indent-guide {\ +background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-eclipse.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-eclipse.js new file mode 100755 index 0000000..63aa334 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-eclipse.js @@ -0,0 +1,98 @@ +ace.define("ace/theme/eclipse",["require","exports","module","ace/lib/dom"], function(require, exports, module) { +"use strict"; + +exports.isDark = false; +exports.cssText = ".ace-eclipse .ace_gutter {\ +background: #ebebeb;\ +border-right: 1px solid rgb(159, 159, 159);\ +color: rgb(136, 136, 136);\ +}\ +.ace-eclipse .ace_print-margin {\ +width: 1px;\ +background: #ebebeb;\ +}\ +.ace-eclipse {\ +background-color: #FFFFFF;\ +color: black;\ +}\ +.ace-eclipse .ace_fold {\ +background-color: rgb(60, 76, 114);\ +}\ +.ace-eclipse .ace_cursor {\ +color: black;\ +}\ +.ace-eclipse .ace_storage,\ +.ace-eclipse .ace_keyword,\ +.ace-eclipse .ace_variable {\ +color: rgb(127, 0, 85);\ +}\ +.ace-eclipse .ace_constant.ace_buildin {\ +color: rgb(88, 72, 246);\ +}\ +.ace-eclipse .ace_constant.ace_library {\ +color: rgb(6, 150, 14);\ +}\ +.ace-eclipse .ace_function {\ +color: rgb(60, 76, 114);\ +}\ +.ace-eclipse .ace_string {\ +color: rgb(42, 0, 255);\ +}\ +.ace-eclipse .ace_comment {\ +color: rgb(113, 150, 130);\ +}\ +.ace-eclipse .ace_comment.ace_doc {\ +color: rgb(63, 95, 191);\ +}\ +.ace-eclipse .ace_comment.ace_doc.ace_tag {\ +color: rgb(127, 159, 191);\ +}\ +.ace-eclipse .ace_constant.ace_numeric {\ +color: darkblue;\ +}\ +.ace-eclipse .ace_tag {\ +color: rgb(25, 118, 116);\ +}\ +.ace-eclipse .ace_type {\ +color: rgb(127, 0, 127);\ +}\ +.ace-eclipse .ace_xml-pe {\ +color: rgb(104, 104, 91);\ +}\ +.ace-eclipse .ace_marker-layer .ace_selection {\ +background: rgb(181, 213, 255);\ +}\ +.ace-eclipse .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgb(192, 192, 192);\ +}\ +.ace-eclipse .ace_meta.ace_tag {\ +color:rgb(25, 118, 116);\ +}\ +.ace-eclipse .ace_invisible {\ +color: #ddd;\ +}\ +.ace-eclipse .ace_entity.ace_other.ace_attribute-name {\ +color:rgb(127, 0, 127);\ +}\ +.ace-eclipse .ace_marker-layer .ace_step {\ +background: rgb(255, 255, 0);\ +}\ +.ace-eclipse .ace_active-line {\ +background: rgb(232, 242, 254);\ +}\ +.ace-eclipse .ace_gutter-active-line {\ +background-color : #DADADA;\ +}\ +.ace-eclipse .ace_marker-layer .ace_selected-word {\ +border: 1px solid rgb(181, 213, 255);\ +}\ +.ace-eclipse .ace_indent-guide {\ +background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\ +}"; + +exports.cssClass = "ace-eclipse"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-github.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-github.js new file mode 100755 index 0000000..d19512c --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-github.js @@ -0,0 +1,103 @@ +ace.define("ace/theme/github",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = false; +exports.cssClass = "ace-github"; +exports.cssText = "\ +.ace-github .ace_gutter {\ +background: #e8e8e8;\ +color: #AAA;\ +}\ +.ace-github {\ +background: #fff;\ +color: #000;\ +}\ +.ace-github .ace_keyword {\ +font-weight: bold;\ +}\ +.ace-github .ace_string {\ +color: #D14;\ +}\ +.ace-github .ace_variable.ace_class {\ +color: teal;\ +}\ +.ace-github .ace_constant.ace_numeric {\ +color: #099;\ +}\ +.ace-github .ace_constant.ace_buildin {\ +color: #0086B3;\ +}\ +.ace-github .ace_support.ace_function {\ +color: #0086B3;\ +}\ +.ace-github .ace_comment {\ +color: #998;\ +font-style: italic;\ +}\ +.ace-github .ace_variable.ace_language {\ +color: #0086B3;\ +}\ +.ace-github .ace_paren {\ +font-weight: bold;\ +}\ +.ace-github .ace_boolean {\ +font-weight: bold;\ +}\ +.ace-github .ace_string.ace_regexp {\ +color: #009926;\ +font-weight: normal;\ +}\ +.ace-github .ace_variable.ace_instance {\ +color: teal;\ +}\ +.ace-github .ace_constant.ace_language {\ +font-weight: bold;\ +}\ +.ace-github .ace_cursor {\ +color: black;\ +}\ +.ace-github.ace_focus .ace_marker-layer .ace_active-line {\ +background: rgb(255, 255, 204);\ +}\ +.ace-github .ace_marker-layer .ace_active-line {\ +background: rgb(245, 245, 245);\ +}\ +.ace-github .ace_marker-layer .ace_selection {\ +background: rgb(181, 213, 255);\ +}\ +.ace-github.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px white;\ +}\ +.ace-github.ace_nobold .ace_line > span {\ +font-weight: normal !important;\ +}\ +.ace-github .ace_marker-layer .ace_step {\ +background: rgb(252, 255, 0);\ +}\ +.ace-github .ace_marker-layer .ace_stack {\ +background: rgb(164, 229, 101);\ +}\ +.ace-github .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgb(192, 192, 192);\ +}\ +.ace-github .ace_gutter-active-line {\ +background-color : rgba(0, 0, 0, 0.07);\ +}\ +.ace-github .ace_marker-layer .ace_selected-word {\ +background: rgb(250, 250, 255);\ +border: 1px solid rgb(200, 200, 250);\ +}\ +.ace-github .ace_invisible {\ +color: #BFBFBF\ +}\ +.ace-github .ace_print-margin {\ +width: 1px;\ +background: #e8e8e8;\ +}\ +.ace-github .ace_indent-guide {\ +background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\ +}"; + + var dom = require("../lib/dom"); + dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-idle_fingers.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-idle_fingers.js new file mode 100755 index 0000000..7fcf1cb --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-idle_fingers.js @@ -0,0 +1,96 @@ +ace.define("ace/theme/idle_fingers",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-idle-fingers"; +exports.cssText = ".ace-idle-fingers .ace_gutter {\ +background: #3b3b3b;\ +color: rgb(153,153,153)\ +}\ +.ace-idle-fingers .ace_print-margin {\ +width: 1px;\ +background: #3b3b3b\ +}\ +.ace-idle-fingers {\ +background-color: #323232;\ +color: #FFFFFF\ +}\ +.ace-idle-fingers .ace_cursor {\ +color: #91FF00\ +}\ +.ace-idle-fingers .ace_marker-layer .ace_selection {\ +background: rgba(90, 100, 126, 0.88)\ +}\ +.ace-idle-fingers.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #323232;\ +}\ +.ace-idle-fingers .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-idle-fingers .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #404040\ +}\ +.ace-idle-fingers .ace_marker-layer .ace_active-line {\ +background: #353637\ +}\ +.ace-idle-fingers .ace_gutter-active-line {\ +background-color: #353637\ +}\ +.ace-idle-fingers .ace_marker-layer .ace_selected-word {\ +border: 1px solid rgba(90, 100, 126, 0.88)\ +}\ +.ace-idle-fingers .ace_invisible {\ +color: #404040\ +}\ +.ace-idle-fingers .ace_keyword,\ +.ace-idle-fingers .ace_meta {\ +color: #CC7833\ +}\ +.ace-idle-fingers .ace_constant,\ +.ace-idle-fingers .ace_constant.ace_character,\ +.ace-idle-fingers .ace_constant.ace_character.ace_escape,\ +.ace-idle-fingers .ace_constant.ace_other,\ +.ace-idle-fingers .ace_support.ace_constant {\ +color: #6C99BB\ +}\ +.ace-idle-fingers .ace_invalid {\ +color: #FFFFFF;\ +background-color: #FF0000\ +}\ +.ace-idle-fingers .ace_fold {\ +background-color: #CC7833;\ +border-color: #FFFFFF\ +}\ +.ace-idle-fingers .ace_support.ace_function {\ +color: #B83426\ +}\ +.ace-idle-fingers .ace_variable.ace_parameter {\ +font-style: italic\ +}\ +.ace-idle-fingers .ace_string {\ +color: #A5C261\ +}\ +.ace-idle-fingers .ace_string.ace_regexp {\ +color: #CCCC33\ +}\ +.ace-idle-fingers .ace_comment {\ +font-style: italic;\ +color: #BC9458\ +}\ +.ace-idle-fingers .ace_meta.ace_tag {\ +color: #FFE5BB\ +}\ +.ace-idle-fingers .ace_entity.ace_name {\ +color: #FFC66D\ +}\ +.ace-idle-fingers .ace_collab.ace_user1 {\ +color: #323232;\ +background-color: #FFF980\ +}\ +.ace-idle-fingers .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWMwMjLyZYiPj/8PAAreAwAI1+g0AAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-iplastic.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-iplastic.js new file mode 100755 index 0000000..593aa00 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-iplastic.js @@ -0,0 +1,121 @@ +ace.define("ace/theme/iplastic",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = false; +exports.cssClass = "ace-iplastic"; +exports.cssText = ".ace-iplastic .ace_gutter {\ +background: #dddddd;\ +color: #666666\ +}\ +.ace-iplastic .ace_print-margin {\ +width: 1px;\ +background: #bbbbbb\ +}\ +.ace-iplastic {\ +background-color: #eeeeee;\ +color: #333333\ +}\ +.ace-iplastic .ace_cursor {\ +color: #333\ +}\ +.ace-iplastic .ace_marker-layer .ace_selection {\ +background: #BAD6FD;\ +}\ +.ace-iplastic.ace_multiselect .ace_selection.ace_start {\ +border-radius: 4px\ +}\ +.ace-iplastic .ace_marker-layer .ace_step {\ +background: #444444\ +}\ +.ace-iplastic .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #49483E;\ +background: #FFF799\ +}\ +.ace-iplastic .ace_marker-layer .ace_active-line {\ +background: #e5e5e5\ +}\ +.ace-iplastic .ace_gutter-active-line {\ +background-color: #eeeeee\ +}\ +.ace-iplastic .ace_marker-layer .ace_selected-word {\ +border: 1px solid #555555;\ +border-radius:4px\ +}\ +.ace-iplastic .ace_invisible {\ +color: #999999\ +}\ +.ace-iplastic .ace_entity.ace_name.ace_tag,\ +.ace-iplastic .ace_keyword,\ +.ace-iplastic .ace_meta.ace_tag,\ +.ace-iplastic .ace_storage {\ +color: #0000FF\ +}\ +.ace-iplastic .ace_punctuation,\ +.ace-iplastic .ace_punctuation.ace_tag {\ +color: #000\ +}\ +.ace-iplastic .ace_constant {\ +color: #333333;\ +font-weight: 700\ +}\ +.ace-iplastic .ace_constant.ace_character,\ +.ace-iplastic .ace_constant.ace_language,\ +.ace-iplastic .ace_constant.ace_numeric,\ +.ace-iplastic .ace_constant.ace_other {\ +color: #0066FF;\ +font-weight: 700\ +}\ +.ace-iplastic .ace_constant.ace_numeric{\ +font-weight: 100\ +}\ +.ace-iplastic .ace_invalid {\ +color: #F8F8F0;\ +background-color: #F92672\ +}\ +.ace-iplastic .ace_invalid.ace_deprecated {\ +color: #F8F8F0;\ +background-color: #AE81FF\ +}\ +.ace-iplastic .ace_support.ace_constant,\ +.ace-iplastic .ace_support.ace_function {\ +color: #333333;\ +font-weight: 700\ +}\ +.ace-iplastic .ace_fold {\ +background-color: #464646;\ +border-color: #F8F8F2\ +}\ +.ace-iplastic .ace_storage.ace_type,\ +.ace-iplastic .ace_support.ace_class,\ +.ace-iplastic .ace_support.ace_type {\ +color: #3333fc;\ +font-weight: 700\ +}\ +.ace-iplastic .ace_entity.ace_name.ace_function,\ +.ace-iplastic .ace_entity.ace_other,\ +.ace-iplastic .ace_entity.ace_other.ace_attribute-name,\ +.ace-iplastic .ace_variable {\ +color: #3366cc;\ +font-style: italic\ +}\ +.ace-iplastic .ace_variable.ace_parameter {\ +font-style: italic;\ +color: #2469E0\ +}\ +.ace-iplastic .ace_string {\ +color: #a55f03\ +}\ +.ace-iplastic .ace_comment {\ +color: #777777;\ +font-style: italic\ +}\ +.ace-iplastic .ace_fold-widget {\ +background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==);\ +}\ +.ace-iplastic .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAABlJREFUeNpi+P//PwMzMzPzfwAAAAD//wMAGRsECSML/RIAAAAASUVORK5CYII=) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-katzenmilch.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-katzenmilch.js new file mode 100755 index 0000000..f65ce4a --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-katzenmilch.js @@ -0,0 +1,121 @@ +ace.define("ace/theme/katzenmilch",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = false; +exports.cssClass = "ace-katzenmilch"; +exports.cssText = ".ace-katzenmilch .ace_gutter,\ +.ace-katzenmilch .ace_gutter {\ +background: #e8e8e8;\ +color: #333\ +}\ +.ace-katzenmilch .ace_print-margin {\ +width: 1px;\ +background: #e8e8e8\ +}\ +.ace-katzenmilch {\ +background-color: #f3f2f3;\ +color: rgba(15, 0, 9, 1.0)\ +}\ +.ace-katzenmilch .ace_cursor {\ +border-left: 2px solid #100011\ +}\ +.ace-katzenmilch .ace_overwrite-cursors .ace_cursor {\ +border-left: 0px;\ +border-bottom: 1px solid #100011\ +}\ +.ace-katzenmilch .ace_marker-layer .ace_selection {\ +background: rgba(100, 5, 208, 0.27)\ +}\ +.ace-katzenmilch.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #f3f2f3;\ +}\ +.ace-katzenmilch .ace_marker-layer .ace_step {\ +background: rgb(198, 219, 174)\ +}\ +.ace-katzenmilch .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgba(0, 0, 0, 0.33);\ +}\ +.ace-katzenmilch .ace_marker-layer .ace_active-line {\ +background: rgb(232, 242, 254)\ +}\ +.ace-katzenmilch .ace_gutter-active-line {\ +background-color: rgb(232, 242, 254)\ +}\ +.ace-katzenmilch .ace_marker-layer .ace_selected-word {\ +border: 1px solid rgba(100, 5, 208, 0.27)\ +}\ +.ace-katzenmilch .ace_invisible {\ +color: #BFBFBF\ +}\ +.ace-katzenmilch .ace_fold {\ +background-color: rgba(2, 95, 73, 0.97);\ +border-color: rgba(15, 0, 9, 1.0)\ +}\ +.ace-katzenmilch .ace_keyword {\ +color: #674Aa8;\ +rbackground-color: rgba(163, 170, 216, 0.055)\ +}\ +.ace-katzenmilch .ace_constant.ace_language {\ +color: #7D7e52;\ +rbackground-color: rgba(189, 190, 130, 0.059)\ +}\ +.ace-katzenmilch .ace_constant.ace_numeric {\ +color: rgba(79, 130, 123, 0.93);\ +rbackground-color: rgba(119, 194, 187, 0.059)\ +}\ +.ace-katzenmilch .ace_constant.ace_character,\ +.ace-katzenmilch .ace_constant.ace_other {\ +color: rgba(2, 95, 105, 1.0);\ +rbackground-color: rgba(127, 34, 153, 0.063)\ +}\ +.ace-katzenmilch .ace_support.ace_function {\ +color: #9D7e62;\ +rbackground-color: rgba(189, 190, 130, 0.039)\ +}\ +.ace-katzenmilch .ace_support.ace_class {\ +color: rgba(239, 106, 167, 1.0);\ +rbackground-color: rgba(239, 106, 167, 0.063)\ +}\ +.ace-katzenmilch .ace_storage {\ +color: rgba(123, 92, 191, 1.0);\ +rbackground-color: rgba(139, 93, 223, 0.051)\ +}\ +.ace-katzenmilch .ace_invalid {\ +color: #DFDFD5;\ +rbackground-color: #CC1B27\ +}\ +.ace-katzenmilch .ace_string {\ +color: #5a5f9b;\ +rbackground-color: rgba(170, 175, 219, 0.035)\ +}\ +.ace-katzenmilch .ace_comment {\ +font-style: italic;\ +color: rgba(64, 79, 80, 0.67);\ +rbackground-color: rgba(95, 15, 255, 0.0078)\ +}\ +.ace-katzenmilch .ace_entity.ace_name.ace_function,\ +.ace-katzenmilch .ace_variable {\ +color: rgba(2, 95, 73, 0.97);\ +rbackground-color: rgba(34, 255, 73, 0.12)\ +}\ +.ace-katzenmilch .ace_variable.ace_language {\ +color: #316fcf;\ +rbackground-color: rgba(58, 175, 255, 0.039)\ +}\ +.ace-katzenmilch .ace_variable.ace_parameter {\ +font-style: italic;\ +color: rgba(51, 150, 159, 0.87);\ +rbackground-color: rgba(5, 214, 249, 0.043)\ +}\ +.ace-katzenmilch .ace_entity.ace_other.ace_attribute-name {\ +color: rgba(73, 70, 194, 0.93);\ +rbackground-color: rgba(73, 134, 194, 0.035)\ +}\ +.ace-katzenmilch .ace_entity.ace_name.ace_tag {\ +color: #3976a2;\ +rbackground-color: rgba(73, 166, 210, 0.039)\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-kr_theme.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-kr_theme.js new file mode 100755 index 0000000..8818b33 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-kr_theme.js @@ -0,0 +1,104 @@ +ace.define("ace/theme/kr_theme",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-kr-theme"; +exports.cssText = ".ace-kr-theme .ace_gutter {\ +background: #1c1917;\ +color: #FCFFE0\ +}\ +.ace-kr-theme .ace_print-margin {\ +width: 1px;\ +background: #1c1917\ +}\ +.ace-kr-theme {\ +background-color: #0B0A09;\ +color: #FCFFE0\ +}\ +.ace-kr-theme .ace_cursor {\ +color: #FF9900\ +}\ +.ace-kr-theme .ace_marker-layer .ace_selection {\ +background: rgba(170, 0, 255, 0.45)\ +}\ +.ace-kr-theme.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #0B0A09;\ +}\ +.ace-kr-theme .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-kr-theme .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgba(255, 177, 111, 0.32)\ +}\ +.ace-kr-theme .ace_marker-layer .ace_active-line {\ +background: #38403D\ +}\ +.ace-kr-theme .ace_gutter-active-line {\ +background-color : #38403D\ +}\ +.ace-kr-theme .ace_marker-layer .ace_selected-word {\ +border: 1px solid rgba(170, 0, 255, 0.45)\ +}\ +.ace-kr-theme .ace_invisible {\ +color: rgba(255, 177, 111, 0.32)\ +}\ +.ace-kr-theme .ace_keyword,\ +.ace-kr-theme .ace_meta {\ +color: #949C8B\ +}\ +.ace-kr-theme .ace_constant,\ +.ace-kr-theme .ace_constant.ace_character,\ +.ace-kr-theme .ace_constant.ace_character.ace_escape,\ +.ace-kr-theme .ace_constant.ace_other {\ +color: rgba(210, 117, 24, 0.76)\ +}\ +.ace-kr-theme .ace_invalid {\ +color: #F8F8F8;\ +background-color: #A41300\ +}\ +.ace-kr-theme .ace_support {\ +color: #9FC28A\ +}\ +.ace-kr-theme .ace_support.ace_constant {\ +color: #C27E66\ +}\ +.ace-kr-theme .ace_fold {\ +background-color: #949C8B;\ +border-color: #FCFFE0\ +}\ +.ace-kr-theme .ace_support.ace_function {\ +color: #85873A\ +}\ +.ace-kr-theme .ace_storage {\ +color: #FFEE80\ +}\ +.ace-kr-theme .ace_string {\ +color: rgba(164, 161, 181, 0.8)\ +}\ +.ace-kr-theme .ace_string.ace_regexp {\ +color: rgba(125, 255, 192, 0.65)\ +}\ +.ace-kr-theme .ace_comment {\ +font-style: italic;\ +color: #706D5B\ +}\ +.ace-kr-theme .ace_variable {\ +color: #D1A796\ +}\ +.ace-kr-theme .ace_list,\ +.ace-kr-theme .ace_markup.ace_list {\ +background-color: #0F0040\ +}\ +.ace-kr-theme .ace_variable.ace_language {\ +color: #FF80E1\ +}\ +.ace-kr-theme .ace_meta.ace_tag {\ +color: #BABD9C\ +}\ +.ace-kr-theme .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYFBXV/8PAAJoAXX4kT2EAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-kuroir.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-kuroir.js new file mode 100755 index 0000000..30e0a8b --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-kuroir.js @@ -0,0 +1,61 @@ +ace.define("ace/theme/kuroir",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = false; +exports.cssClass = "ace-kuroir"; +exports.cssText = "\ +.ace-kuroir .ace_gutter {\ +background: #e8e8e8;\ +color: #333;\ +}\ +.ace-kuroir .ace_print-margin {\ +width: 1px;\ +background: #e8e8e8;\ +}\ +.ace-kuroir {\ +background-color: #E8E9E8;\ +color: #363636;\ +}\ +.ace-kuroir .ace_cursor {\ +color: #202020;\ +}\ +.ace-kuroir .ace_marker-layer .ace_selection {\ +background: rgba(245, 170, 0, 0.57);\ +}\ +.ace-kuroir.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #E8E9E8;\ +}\ +.ace-kuroir .ace_marker-layer .ace_step {\ +background: rgb(198, 219, 174);\ +}\ +.ace-kuroir .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgba(0, 0, 0, 0.29);\ +}\ +.ace-kuroir .ace_marker-layer .ace_active-line {\ +background: rgba(203, 220, 47, 0.22);\ +}\ +.ace-kuroir .ace_gutter-active-line {\ +background-color: rgba(203, 220, 47, 0.22);\ +}\ +.ace-kuroir .ace_marker-layer .ace_selected-word {\ +border: 1px solid rgba(245, 170, 0, 0.57);\ +}\ +.ace-kuroir .ace_invisible {\ +color: #BFBFBF\ +}\ +.ace-kuroir .ace_fold {\ +border-color: #363636;\ +}\ +.ace-kuroir .ace_constant{color:#CD6839;}.ace-kuroir .ace_constant.ace_numeric{color:#9A5925;}.ace-kuroir .ace_support{color:#104E8B;}.ace-kuroir .ace_support.ace_function{color:#005273;}.ace-kuroir .ace_support.ace_constant{color:#CF6A4C;}.ace-kuroir .ace_storage{color:#A52A2A;}.ace-kuroir .ace_invalid.ace_illegal{color:#FD1224;\ +background-color:rgba(255, 6, 0, 0.15);}.ace-kuroir .ace_invalid.ace_deprecated{text-decoration:underline;\ +font-style:italic;\ +color:#FD1732;\ +background-color:#E8E9E8;}.ace-kuroir .ace_string{color:#639300;}.ace-kuroir .ace_string.ace_regexp{color:#417E00;\ +background-color:#C9D4BE;}.ace-kuroir .ace_comment{color:rgba(148, 148, 148, 0.91);\ +background-color:rgba(220, 220, 220, 0.56);}.ace-kuroir .ace_variable{color:#009ACD;}.ace-kuroir .ace_meta.ace_tag{color:#005273;}.ace-kuroir .ace_markup.ace_heading{color:#B8012D;\ +background-color:rgba(191, 97, 51, 0.051);}.ace-kuroir .ace_markup.ace_list{color:#8F5B26;}\ +"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-merbivore.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-merbivore.js new file mode 100755 index 0000000..fc0a72f --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-merbivore.js @@ -0,0 +1,95 @@ +ace.define("ace/theme/merbivore",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-merbivore"; +exports.cssText = ".ace-merbivore .ace_gutter {\ +background: #202020;\ +color: #E6E1DC\ +}\ +.ace-merbivore .ace_print-margin {\ +width: 1px;\ +background: #555651\ +}\ +.ace-merbivore {\ +background-color: #161616;\ +color: #E6E1DC\ +}\ +.ace-merbivore .ace_cursor {\ +color: #FFFFFF\ +}\ +.ace-merbivore .ace_marker-layer .ace_selection {\ +background: #454545\ +}\ +.ace-merbivore.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #161616;\ +}\ +.ace-merbivore .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-merbivore .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #404040\ +}\ +.ace-merbivore .ace_marker-layer .ace_active-line {\ +background: #333435\ +}\ +.ace-merbivore .ace_gutter-active-line {\ +background-color: #333435\ +}\ +.ace-merbivore .ace_marker-layer .ace_selected-word {\ +border: 1px solid #454545\ +}\ +.ace-merbivore .ace_invisible {\ +color: #404040\ +}\ +.ace-merbivore .ace_entity.ace_name.ace_tag,\ +.ace-merbivore .ace_keyword,\ +.ace-merbivore .ace_meta,\ +.ace-merbivore .ace_meta.ace_tag,\ +.ace-merbivore .ace_storage,\ +.ace-merbivore .ace_support.ace_function {\ +color: #FC6F09\ +}\ +.ace-merbivore .ace_constant,\ +.ace-merbivore .ace_constant.ace_character,\ +.ace-merbivore .ace_constant.ace_character.ace_escape,\ +.ace-merbivore .ace_constant.ace_other,\ +.ace-merbivore .ace_support.ace_type {\ +color: #1EDAFB\ +}\ +.ace-merbivore .ace_constant.ace_character.ace_escape {\ +color: #519F50\ +}\ +.ace-merbivore .ace_constant.ace_language {\ +color: #FDC251\ +}\ +.ace-merbivore .ace_constant.ace_library,\ +.ace-merbivore .ace_string,\ +.ace-merbivore .ace_support.ace_constant {\ +color: #8DFF0A\ +}\ +.ace-merbivore .ace_constant.ace_numeric {\ +color: #58C554\ +}\ +.ace-merbivore .ace_invalid {\ +color: #FFFFFF;\ +background-color: #990000\ +}\ +.ace-merbivore .ace_fold {\ +background-color: #FC6F09;\ +border-color: #E6E1DC\ +}\ +.ace-merbivore .ace_comment {\ +font-style: italic;\ +color: #AD2EA4\ +}\ +.ace-merbivore .ace_entity.ace_other.ace_attribute-name {\ +color: #FFFF89\ +}\ +.ace-merbivore .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWMQFxf3ZXB1df0PAAdsAmERTkEHAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-merbivore_soft.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-merbivore_soft.js new file mode 100755 index 0000000..eff2464 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-merbivore_soft.js @@ -0,0 +1,96 @@ +ace.define("ace/theme/merbivore_soft",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-merbivore-soft"; +exports.cssText = ".ace-merbivore-soft .ace_gutter {\ +background: #262424;\ +color: #E6E1DC\ +}\ +.ace-merbivore-soft .ace_print-margin {\ +width: 1px;\ +background: #262424\ +}\ +.ace-merbivore-soft {\ +background-color: #1C1C1C;\ +color: #E6E1DC\ +}\ +.ace-merbivore-soft .ace_cursor {\ +color: #FFFFFF\ +}\ +.ace-merbivore-soft .ace_marker-layer .ace_selection {\ +background: #494949\ +}\ +.ace-merbivore-soft.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #1C1C1C;\ +}\ +.ace-merbivore-soft .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-merbivore-soft .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #404040\ +}\ +.ace-merbivore-soft .ace_marker-layer .ace_active-line {\ +background: #333435\ +}\ +.ace-merbivore-soft .ace_gutter-active-line {\ +background-color: #333435\ +}\ +.ace-merbivore-soft .ace_marker-layer .ace_selected-word {\ +border: 1px solid #494949\ +}\ +.ace-merbivore-soft .ace_invisible {\ +color: #404040\ +}\ +.ace-merbivore-soft .ace_entity.ace_name.ace_tag,\ +.ace-merbivore-soft .ace_keyword,\ +.ace-merbivore-soft .ace_meta,\ +.ace-merbivore-soft .ace_meta.ace_tag,\ +.ace-merbivore-soft .ace_storage {\ +color: #FC803A\ +}\ +.ace-merbivore-soft .ace_constant,\ +.ace-merbivore-soft .ace_constant.ace_character,\ +.ace-merbivore-soft .ace_constant.ace_character.ace_escape,\ +.ace-merbivore-soft .ace_constant.ace_other,\ +.ace-merbivore-soft .ace_support.ace_type {\ +color: #68C1D8\ +}\ +.ace-merbivore-soft .ace_constant.ace_character.ace_escape {\ +color: #B3E5B4\ +}\ +.ace-merbivore-soft .ace_constant.ace_language {\ +color: #E1C582\ +}\ +.ace-merbivore-soft .ace_constant.ace_library,\ +.ace-merbivore-soft .ace_string,\ +.ace-merbivore-soft .ace_support.ace_constant {\ +color: #8EC65F\ +}\ +.ace-merbivore-soft .ace_constant.ace_numeric {\ +color: #7FC578\ +}\ +.ace-merbivore-soft .ace_invalid,\ +.ace-merbivore-soft .ace_invalid.ace_deprecated {\ +color: #FFFFFF;\ +background-color: #FE3838\ +}\ +.ace-merbivore-soft .ace_fold {\ +background-color: #FC803A;\ +border-color: #E6E1DC\ +}\ +.ace-merbivore-soft .ace_comment,\ +.ace-merbivore-soft .ace_meta {\ +font-style: italic;\ +color: #AC4BB8\ +}\ +.ace-merbivore-soft .ace_entity.ace_other.ace_attribute-name {\ +color: #EAF1A3\ +}\ +.ace-merbivore-soft .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWOQkpLyZfD09PwPAAfYAnaStpHRAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-mono_industrial.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-mono_industrial.js new file mode 100755 index 0000000..0ece030 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-mono_industrial.js @@ -0,0 +1,107 @@ +ace.define("ace/theme/mono_industrial",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-mono-industrial"; +exports.cssText = ".ace-mono-industrial .ace_gutter {\ +background: #1d2521;\ +color: #C5C9C9\ +}\ +.ace-mono-industrial .ace_print-margin {\ +width: 1px;\ +background: #555651\ +}\ +.ace-mono-industrial {\ +background-color: #222C28;\ +color: #FFFFFF\ +}\ +.ace-mono-industrial .ace_cursor {\ +color: #FFFFFF\ +}\ +.ace-mono-industrial .ace_marker-layer .ace_selection {\ +background: rgba(145, 153, 148, 0.40)\ +}\ +.ace-mono-industrial.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #222C28;\ +}\ +.ace-mono-industrial .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-mono-industrial .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgba(102, 108, 104, 0.50)\ +}\ +.ace-mono-industrial .ace_marker-layer .ace_active-line {\ +background: rgba(12, 13, 12, 0.25)\ +}\ +.ace-mono-industrial .ace_gutter-active-line {\ +background-color: rgba(12, 13, 12, 0.25)\ +}\ +.ace-mono-industrial .ace_marker-layer .ace_selected-word {\ +border: 1px solid rgba(145, 153, 148, 0.40)\ +}\ +.ace-mono-industrial .ace_invisible {\ +color: rgba(102, 108, 104, 0.50)\ +}\ +.ace-mono-industrial .ace_string {\ +background-color: #151C19;\ +color: #FFFFFF\ +}\ +.ace-mono-industrial .ace_keyword,\ +.ace-mono-industrial .ace_meta {\ +color: #A39E64\ +}\ +.ace-mono-industrial .ace_constant,\ +.ace-mono-industrial .ace_constant.ace_character,\ +.ace-mono-industrial .ace_constant.ace_character.ace_escape,\ +.ace-mono-industrial .ace_constant.ace_numeric,\ +.ace-mono-industrial .ace_constant.ace_other {\ +color: #E98800\ +}\ +.ace-mono-industrial .ace_entity.ace_name.ace_function,\ +.ace-mono-industrial .ace_keyword.ace_operator,\ +.ace-mono-industrial .ace_variable {\ +color: #A8B3AB\ +}\ +.ace-mono-industrial .ace_invalid {\ +color: #FFFFFF;\ +background-color: rgba(153, 0, 0, 0.68)\ +}\ +.ace-mono-industrial .ace_support.ace_constant {\ +color: #C87500\ +}\ +.ace-mono-industrial .ace_fold {\ +background-color: #A8B3AB;\ +border-color: #FFFFFF\ +}\ +.ace-mono-industrial .ace_support.ace_function {\ +color: #588E60\ +}\ +.ace-mono-industrial .ace_entity.ace_name,\ +.ace-mono-industrial .ace_support.ace_class,\ +.ace-mono-industrial .ace_support.ace_type {\ +color: #5778B6\ +}\ +.ace-mono-industrial .ace_storage {\ +color: #C23B00\ +}\ +.ace-mono-industrial .ace_variable.ace_language,\ +.ace-mono-industrial .ace_variable.ace_parameter {\ +color: #648BD2\ +}\ +.ace-mono-industrial .ace_comment {\ +color: #666C68;\ +background-color: #151C19\ +}\ +.ace-mono-industrial .ace_entity.ace_other.ace_attribute-name {\ +color: #909993\ +}\ +.ace-mono-industrial .ace_entity.ace_name.ace_tag {\ +color: #A65EFF\ +}\ +.ace-mono-industrial .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNQ1NbwZfALD/4PAAlTArlEC4r/AAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-monokai.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-monokai.js new file mode 100755 index 0000000..322c2fa --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-monokai.js @@ -0,0 +1,105 @@ +ace.define("ace/theme/monokai",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-monokai"; +exports.cssText = ".ace-monokai .ace_gutter {\ +background: #2F3129;\ +color: #8F908A\ +}\ +.ace-monokai .ace_print-margin {\ +width: 1px;\ +background: #555651\ +}\ +.ace-monokai {\ +background-color: #272822;\ +color: #F8F8F2\ +}\ +.ace-monokai .ace_cursor {\ +color: #F8F8F0\ +}\ +.ace-monokai .ace_marker-layer .ace_selection {\ +background: #49483E\ +}\ +.ace-monokai.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #272822;\ +}\ +.ace-monokai .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-monokai .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #49483E\ +}\ +.ace-monokai .ace_marker-layer .ace_active-line {\ +background: #202020\ +}\ +.ace-monokai .ace_gutter-active-line {\ +background-color: #272727\ +}\ +.ace-monokai .ace_marker-layer .ace_selected-word {\ +border: 1px solid #49483E\ +}\ +.ace-monokai .ace_invisible {\ +color: #52524d\ +}\ +.ace-monokai .ace_entity.ace_name.ace_tag,\ +.ace-monokai .ace_keyword,\ +.ace-monokai .ace_meta.ace_tag,\ +.ace-monokai .ace_storage {\ +color: #F92672\ +}\ +.ace-monokai .ace_punctuation,\ +.ace-monokai .ace_punctuation.ace_tag {\ +color: #fff\ +}\ +.ace-monokai .ace_constant.ace_character,\ +.ace-monokai .ace_constant.ace_language,\ +.ace-monokai .ace_constant.ace_numeric,\ +.ace-monokai .ace_constant.ace_other {\ +color: #AE81FF\ +}\ +.ace-monokai .ace_invalid {\ +color: #F8F8F0;\ +background-color: #F92672\ +}\ +.ace-monokai .ace_invalid.ace_deprecated {\ +color: #F8F8F0;\ +background-color: #AE81FF\ +}\ +.ace-monokai .ace_support.ace_constant,\ +.ace-monokai .ace_support.ace_function {\ +color: #66D9EF\ +}\ +.ace-monokai .ace_fold {\ +background-color: #A6E22E;\ +border-color: #F8F8F2\ +}\ +.ace-monokai .ace_storage.ace_type,\ +.ace-monokai .ace_support.ace_class,\ +.ace-monokai .ace_support.ace_type {\ +font-style: italic;\ +color: #66D9EF\ +}\ +.ace-monokai .ace_entity.ace_name.ace_function,\ +.ace-monokai .ace_entity.ace_other,\ +.ace-monokai .ace_entity.ace_other.ace_attribute-name,\ +.ace-monokai .ace_variable {\ +color: #A6E22E\ +}\ +.ace-monokai .ace_variable.ace_parameter {\ +font-style: italic;\ +color: #FD971F\ +}\ +.ace-monokai .ace_string {\ +color: #E6DB74\ +}\ +.ace-monokai .ace_comment {\ +color: #75715E\ +}\ +.ace-monokai .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWPQ0FD0ZXBzd/wPAAjVAoxeSgNeAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-pastel_on_dark.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-pastel_on_dark.js new file mode 100755 index 0000000..2631ae0 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-pastel_on_dark.js @@ -0,0 +1,108 @@ +ace.define("ace/theme/pastel_on_dark",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-pastel-on-dark"; +exports.cssText = ".ace-pastel-on-dark .ace_gutter {\ +background: #353030;\ +color: #8F938F\ +}\ +.ace-pastel-on-dark .ace_print-margin {\ +width: 1px;\ +background: #353030\ +}\ +.ace-pastel-on-dark {\ +background-color: #2C2828;\ +color: #8F938F\ +}\ +.ace-pastel-on-dark .ace_cursor {\ +color: #A7A7A7\ +}\ +.ace-pastel-on-dark .ace_marker-layer .ace_selection {\ +background: rgba(221, 240, 255, 0.20)\ +}\ +.ace-pastel-on-dark.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #2C2828;\ +}\ +.ace-pastel-on-dark .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-pastel-on-dark .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgba(255, 255, 255, 0.25)\ +}\ +.ace-pastel-on-dark .ace_marker-layer .ace_active-line {\ +background: rgba(255, 255, 255, 0.031)\ +}\ +.ace-pastel-on-dark .ace_gutter-active-line {\ +background-color: rgba(255, 255, 255, 0.031)\ +}\ +.ace-pastel-on-dark .ace_marker-layer .ace_selected-word {\ +border: 1px solid rgba(221, 240, 255, 0.20)\ +}\ +.ace-pastel-on-dark .ace_invisible {\ +color: rgba(255, 255, 255, 0.25)\ +}\ +.ace-pastel-on-dark .ace_keyword,\ +.ace-pastel-on-dark .ace_meta {\ +color: #757aD8\ +}\ +.ace-pastel-on-dark .ace_constant,\ +.ace-pastel-on-dark .ace_constant.ace_character,\ +.ace-pastel-on-dark .ace_constant.ace_character.ace_escape,\ +.ace-pastel-on-dark .ace_constant.ace_other {\ +color: #4FB7C5\ +}\ +.ace-pastel-on-dark .ace_keyword.ace_operator {\ +color: #797878\ +}\ +.ace-pastel-on-dark .ace_constant.ace_character {\ +color: #AFA472\ +}\ +.ace-pastel-on-dark .ace_constant.ace_language {\ +color: #DE8E30\ +}\ +.ace-pastel-on-dark .ace_constant.ace_numeric {\ +color: #CCCCCC\ +}\ +.ace-pastel-on-dark .ace_invalid,\ +.ace-pastel-on-dark .ace_invalid.ace_illegal {\ +color: #F8F8F8;\ +background-color: rgba(86, 45, 86, 0.75)\ +}\ +.ace-pastel-on-dark .ace_invalid.ace_deprecated {\ +text-decoration: underline;\ +font-style: italic;\ +color: #D2A8A1\ +}\ +.ace-pastel-on-dark .ace_fold {\ +background-color: #757aD8;\ +border-color: #8F938F\ +}\ +.ace-pastel-on-dark .ace_support.ace_function {\ +color: #AEB2F8\ +}\ +.ace-pastel-on-dark .ace_string {\ +color: #66A968\ +}\ +.ace-pastel-on-dark .ace_string.ace_regexp {\ +color: #E9C062\ +}\ +.ace-pastel-on-dark .ace_comment {\ +color: #A6C6FF\ +}\ +.ace-pastel-on-dark .ace_variable {\ +color: #BEBF55\ +}\ +.ace-pastel-on-dark .ace_variable.ace_language {\ +color: #C1C144\ +}\ +.ace-pastel-on-dark .ace_xml-pe {\ +color: #494949\ +}\ +.ace-pastel-on-dark .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYIiPj/8PAARgAh2NTMh8AAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-solarized_dark.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-solarized_dark.js new file mode 100755 index 0000000..d1acdb4 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-solarized_dark.js @@ -0,0 +1,88 @@ +ace.define("ace/theme/solarized_dark",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-solarized-dark"; +exports.cssText = ".ace-solarized-dark .ace_gutter {\ +background: #01313f;\ +color: #d0edf7\ +}\ +.ace-solarized-dark .ace_print-margin {\ +width: 1px;\ +background: #33555E\ +}\ +.ace-solarized-dark {\ +background-color: #002B36;\ +color: #93A1A1\ +}\ +.ace-solarized-dark .ace_entity.ace_other.ace_attribute-name,\ +.ace-solarized-dark .ace_storage {\ +color: #93A1A1\ +}\ +.ace-solarized-dark .ace_cursor,\ +.ace-solarized-dark .ace_string.ace_regexp {\ +color: #D30102\ +}\ +.ace-solarized-dark .ace_marker-layer .ace_active-line,\ +.ace-solarized-dark .ace_marker-layer .ace_selection {\ +background: rgba(255, 255, 255, 0.1)\ +}\ +.ace-solarized-dark.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #002B36;\ +}\ +.ace-solarized-dark .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-solarized-dark .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgba(147, 161, 161, 0.50)\ +}\ +.ace-solarized-dark .ace_gutter-active-line {\ +background-color: #0d3440\ +}\ +.ace-solarized-dark .ace_marker-layer .ace_selected-word {\ +border: 1px solid #073642\ +}\ +.ace-solarized-dark .ace_invisible {\ +color: rgba(147, 161, 161, 0.50)\ +}\ +.ace-solarized-dark .ace_keyword,\ +.ace-solarized-dark .ace_meta,\ +.ace-solarized-dark .ace_support.ace_class,\ +.ace-solarized-dark .ace_support.ace_type {\ +color: #859900\ +}\ +.ace-solarized-dark .ace_constant.ace_character,\ +.ace-solarized-dark .ace_constant.ace_other {\ +color: #CB4B16\ +}\ +.ace-solarized-dark .ace_constant.ace_language {\ +color: #B58900\ +}\ +.ace-solarized-dark .ace_constant.ace_numeric {\ +color: #D33682\ +}\ +.ace-solarized-dark .ace_fold {\ +background-color: #268BD2;\ +border-color: #93A1A1\ +}\ +.ace-solarized-dark .ace_entity.ace_name.ace_function,\ +.ace-solarized-dark .ace_entity.ace_name.ace_tag,\ +.ace-solarized-dark .ace_support.ace_function,\ +.ace-solarized-dark .ace_variable,\ +.ace-solarized-dark .ace_variable.ace_language {\ +color: #268BD2\ +}\ +.ace-solarized-dark .ace_string {\ +color: #2AA198\ +}\ +.ace-solarized-dark .ace_comment {\ +font-style: italic;\ +color: #657B83\ +}\ +.ace-solarized-dark .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNg0Db1ZVCxc/sPAAd4AlUHlLenAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-solarized_light.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-solarized_light.js new file mode 100755 index 0000000..f0c078a --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-solarized_light.js @@ -0,0 +1,91 @@ +ace.define("ace/theme/solarized_light",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = false; +exports.cssClass = "ace-solarized-light"; +exports.cssText = ".ace-solarized-light .ace_gutter {\ +background: #fbf1d3;\ +color: #333\ +}\ +.ace-solarized-light .ace_print-margin {\ +width: 1px;\ +background: #e8e8e8\ +}\ +.ace-solarized-light {\ +background-color: #FDF6E3;\ +color: #586E75\ +}\ +.ace-solarized-light .ace_cursor {\ +color: #000000\ +}\ +.ace-solarized-light .ace_marker-layer .ace_selection {\ +background: rgba(7, 54, 67, 0.09)\ +}\ +.ace-solarized-light.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #FDF6E3;\ +}\ +.ace-solarized-light .ace_marker-layer .ace_step {\ +background: rgb(255, 255, 0)\ +}\ +.ace-solarized-light .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgba(147, 161, 161, 0.50)\ +}\ +.ace-solarized-light .ace_marker-layer .ace_active-line {\ +background: #EEE8D5\ +}\ +.ace-solarized-light .ace_gutter-active-line {\ +background-color : #EDE5C1\ +}\ +.ace-solarized-light .ace_marker-layer .ace_selected-word {\ +border: 1px solid #073642\ +}\ +.ace-solarized-light .ace_invisible {\ +color: rgba(147, 161, 161, 0.50)\ +}\ +.ace-solarized-light .ace_keyword,\ +.ace-solarized-light .ace_meta,\ +.ace-solarized-light .ace_support.ace_class,\ +.ace-solarized-light .ace_support.ace_type {\ +color: #859900\ +}\ +.ace-solarized-light .ace_constant.ace_character,\ +.ace-solarized-light .ace_constant.ace_other {\ +color: #CB4B16\ +}\ +.ace-solarized-light .ace_constant.ace_language {\ +color: #B58900\ +}\ +.ace-solarized-light .ace_constant.ace_numeric {\ +color: #D33682\ +}\ +.ace-solarized-light .ace_fold {\ +background-color: #268BD2;\ +border-color: #586E75\ +}\ +.ace-solarized-light .ace_entity.ace_name.ace_function,\ +.ace-solarized-light .ace_entity.ace_name.ace_tag,\ +.ace-solarized-light .ace_support.ace_function,\ +.ace-solarized-light .ace_variable,\ +.ace-solarized-light .ace_variable.ace_language {\ +color: #268BD2\ +}\ +.ace-solarized-light .ace_storage {\ +color: #073642\ +}\ +.ace-solarized-light .ace_string {\ +color: #2AA198\ +}\ +.ace-solarized-light .ace_string.ace_regexp {\ +color: #D30102\ +}\ +.ace-solarized-light .ace_comment,\ +.ace-solarized-light .ace_entity.ace_other.ace_attribute-name {\ +color: #93A1A1\ +}\ +.ace-solarized-light .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHjy8NJ/AAjgA5fzQUmBAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-sqlserver.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-sqlserver.js new file mode 100755 index 0000000..91f34f6 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-sqlserver.js @@ -0,0 +1,138 @@ +ace.define("ace/theme/sqlserver",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = false; +exports.cssClass = "ace-sqlserver"; +exports.cssText = ".ace-sqlserver .ace_gutter {\ +background: #ebebeb;\ +color: #333;\ +overflow: hidden;\ +}\ +.ace-sqlserver .ace_print-margin {\ +width: 1px;\ +background: #e8e8e8;\ +}\ +.ace-sqlserver {\ +background-color: #FFFFFF;\ +color: black;\ +}\ +.ace-sqlserver .ace_identifier {\ +color: black;\ +}\ +.ace-sqlserver .ace_keyword {\ +color: #0000FF;\ +}\ +.ace-sqlserver .ace_numeric {\ +color: black;\ +}\ +.ace-sqlserver .ace_storage {\ +color: #11B7BE;\ +}\ +.ace-sqlserver .ace_keyword.ace_operator,\ +.ace-sqlserver .ace_lparen,\ +.ace-sqlserver .ace_rparen,\ +.ace-sqlserver .ace_punctuation {\ +color: #808080;\ +}\ +.ace-sqlserver .ace_set.ace_statement {\ +color: #0000FF;\ +text-decoration: underline;\ +}\ +.ace-sqlserver .ace_cursor {\ +color: black;\ +}\ +.ace-sqlserver .ace_invisible {\ +color: rgb(191, 191, 191);\ +}\ +.ace-sqlserver .ace_constant.ace_buildin {\ +color: rgb(88, 72, 246);\ +}\ +.ace-sqlserver .ace_constant.ace_language {\ +color: #979797;\ +}\ +.ace-sqlserver .ace_constant.ace_library {\ +color: rgb(6, 150, 14);\ +}\ +.ace-sqlserver .ace_invalid {\ +background-color: rgb(153, 0, 0);\ +color: white;\ +}\ +.ace-sqlserver .ace_support.ace_function {\ +color: #FF00FF;\ +}\ +.ace-sqlserver .ace_support.ace_constant {\ +color: rgb(6, 150, 14);\ +}\ +.ace-sqlserver .ace_class {\ +color: #008080;\ +}\ +.ace-sqlserver .ace_support.ace_other {\ +color: #6D79DE;\ +}\ +.ace-sqlserver .ace_variable.ace_parameter {\ +font-style: italic;\ +color: #FD971F;\ +}\ +.ace-sqlserver .ace_comment {\ +color: #008000;\ +}\ +.ace-sqlserver .ace_constant.ace_numeric {\ +color: black;\ +}\ +.ace-sqlserver .ace_variable {\ +color: rgb(49, 132, 149);\ +}\ +.ace-sqlserver .ace_xml-pe {\ +color: rgb(104, 104, 91);\ +}\ +.ace-sqlserver .ace_support.ace_storedprocedure {\ +color: #800000;\ +}\ +.ace-sqlserver .ace_heading {\ +color: rgb(12, 7, 255);\ +}\ +.ace-sqlserver .ace_list {\ +color: rgb(185, 6, 144);\ +}\ +.ace-sqlserver .ace_marker-layer .ace_selection {\ +background: rgb(181, 213, 255);\ +}\ +.ace-sqlserver .ace_marker-layer .ace_step {\ +background: rgb(252, 255, 0);\ +}\ +.ace-sqlserver .ace_marker-layer .ace_stack {\ +background: rgb(164, 229, 101);\ +}\ +.ace-sqlserver .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgb(192, 192, 192);\ +}\ +.ace-sqlserver .ace_marker-layer .ace_active-line {\ +background: rgba(0, 0, 0, 0.07);\ +}\ +.ace-sqlserver .ace_gutter-active-line {\ +background-color: #dcdcdc;\ +}\ +.ace-sqlserver .ace_marker-layer .ace_selected-word {\ +background: rgb(250, 250, 255);\ +border: 1px solid rgb(200, 200, 250);\ +}\ +.ace-sqlserver .ace_meta.ace_tag {\ +color: #0000FF;\ +}\ +.ace-sqlserver .ace_string.ace_regex {\ +color: #FF0000;\ +}\ +.ace-sqlserver .ace_string {\ +color: #FF0000;\ +}\ +.ace-sqlserver .ace_entity.ace_other.ace_attribute-name {\ +color: #994409;\ +}\ +.ace-sqlserver .ace_indent-guide {\ +background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\ +}\ +"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-terminal.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-terminal.js new file mode 100755 index 0000000..def9e69 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-terminal.js @@ -0,0 +1,114 @@ +ace.define("ace/theme/terminal",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-terminal-theme"; +exports.cssText = ".ace-terminal-theme .ace_gutter {\ +background: #1a0005;\ +color: steelblue\ +}\ +.ace-terminal-theme .ace_print-margin {\ +width: 1px;\ +background: #1a1a1a\ +}\ +.ace-terminal-theme {\ +background-color: black;\ +color: #DEDEDE\ +}\ +.ace-terminal-theme .ace_cursor {\ +color: #9F9F9F\ +}\ +.ace-terminal-theme .ace_marker-layer .ace_selection {\ +background: #424242\ +}\ +.ace-terminal-theme.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px black;\ +}\ +.ace-terminal-theme .ace_marker-layer .ace_step {\ +background: rgb(0, 0, 0)\ +}\ +.ace-terminal-theme .ace_marker-layer .ace_bracket {\ +background: #090;\ +}\ +.ace-terminal-theme .ace_marker-layer .ace_bracket-start {\ +background: #090;\ +}\ +.ace-terminal-theme .ace_marker-layer .ace_bracket-unmatched {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #900\ +}\ +.ace-terminal-theme .ace_marker-layer .ace_active-line {\ +background: #2A2A2A\ +}\ +.ace-terminal-theme .ace_gutter-active-line {\ +background-color: #2A112A\ +}\ +.ace-terminal-theme .ace_marker-layer .ace_selected-word {\ +border: 1px solid #424242\ +}\ +.ace-terminal-theme .ace_invisible {\ +color: #343434\ +}\ +.ace-terminal-theme .ace_keyword,\ +.ace-terminal-theme .ace_meta,\ +.ace-terminal-theme .ace_storage,\ +.ace-terminal-theme .ace_storage.ace_type,\ +.ace-terminal-theme .ace_support.ace_type {\ +color: tomato\ +}\ +.ace-terminal-theme .ace_keyword.ace_operator {\ +color: deeppink\ +}\ +.ace-terminal-theme .ace_constant.ace_character,\ +.ace-terminal-theme .ace_constant.ace_language,\ +.ace-terminal-theme .ace_constant.ace_numeric,\ +.ace-terminal-theme .ace_keyword.ace_other.ace_unit,\ +.ace-terminal-theme .ace_support.ace_constant,\ +.ace-terminal-theme .ace_variable.ace_parameter {\ +color: #E78C45\ +}\ +.ace-terminal-theme .ace_constant.ace_other {\ +color: gold\ +}\ +.ace-terminal-theme .ace_invalid {\ +color: yellow;\ +background-color: red\ +}\ +.ace-terminal-theme .ace_invalid.ace_deprecated {\ +color: #CED2CF;\ +background-color: #B798BF\ +}\ +.ace-terminal-theme .ace_fold {\ +background-color: #7AA6DA;\ +border-color: #DEDEDE\ +}\ +.ace-terminal-theme .ace_entity.ace_name.ace_function,\ +.ace-terminal-theme .ace_support.ace_function,\ +.ace-terminal-theme .ace_variable {\ +color: #7AA6DA\ +}\ +.ace-terminal-theme .ace_support.ace_class,\ +.ace-terminal-theme .ace_support.ace_type {\ +color: #E7C547\ +}\ +.ace-terminal-theme .ace_heading,\ +.ace-terminal-theme .ace_string {\ +color: #B9CA4A\ +}\ +.ace-terminal-theme .ace_entity.ace_name.ace_tag,\ +.ace-terminal-theme .ace_entity.ace_other.ace_attribute-name,\ +.ace-terminal-theme .ace_meta.ace_tag,\ +.ace-terminal-theme .ace_string.ace_regexp,\ +.ace-terminal-theme .ace_variable {\ +color: #D54E53\ +}\ +.ace-terminal-theme .ace_comment {\ +color: orangered\ +}\ +.ace-terminal-theme .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYLBWV/8PAAK4AYnhiq+xAAAAAElFTkSuQmCC) right repeat-y;\ +}\ +"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-textmate.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-textmate.js new file mode 100755 index 0000000..0033eda --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-textmate.js @@ -0,0 +1,129 @@ +ace.define("ace/theme/textmate",["require","exports","module","ace/lib/dom"], function(require, exports, module) { +"use strict"; + +exports.isDark = false; +exports.cssClass = "ace-tm"; +exports.cssText = ".ace-tm .ace_gutter {\ +background: #f0f0f0;\ +color: #333;\ +}\ +.ace-tm .ace_print-margin {\ +width: 1px;\ +background: #e8e8e8;\ +}\ +.ace-tm .ace_fold {\ +background-color: #6B72E6;\ +}\ +.ace-tm {\ +background-color: #FFFFFF;\ +color: black;\ +}\ +.ace-tm .ace_cursor {\ +color: black;\ +}\ +.ace-tm .ace_invisible {\ +color: rgb(191, 191, 191);\ +}\ +.ace-tm .ace_storage,\ +.ace-tm .ace_keyword {\ +color: blue;\ +}\ +.ace-tm .ace_constant {\ +color: rgb(197, 6, 11);\ +}\ +.ace-tm .ace_constant.ace_buildin {\ +color: rgb(88, 72, 246);\ +}\ +.ace-tm .ace_constant.ace_language {\ +color: rgb(88, 92, 246);\ +}\ +.ace-tm .ace_constant.ace_library {\ +color: rgb(6, 150, 14);\ +}\ +.ace-tm .ace_invalid {\ +background-color: rgba(255, 0, 0, 0.1);\ +color: red;\ +}\ +.ace-tm .ace_support.ace_function {\ +color: rgb(60, 76, 114);\ +}\ +.ace-tm .ace_support.ace_constant {\ +color: rgb(6, 150, 14);\ +}\ +.ace-tm .ace_support.ace_type,\ +.ace-tm .ace_support.ace_class {\ +color: rgb(109, 121, 222);\ +}\ +.ace-tm .ace_keyword.ace_operator {\ +color: rgb(104, 118, 135);\ +}\ +.ace-tm .ace_string {\ +color: rgb(3, 106, 7);\ +}\ +.ace-tm .ace_comment {\ +color: rgb(76, 136, 107);\ +}\ +.ace-tm .ace_comment.ace_doc {\ +color: rgb(0, 102, 255);\ +}\ +.ace-tm .ace_comment.ace_doc.ace_tag {\ +color: rgb(128, 159, 191);\ +}\ +.ace-tm .ace_constant.ace_numeric {\ +color: rgb(0, 0, 205);\ +}\ +.ace-tm .ace_variable {\ +color: rgb(49, 132, 149);\ +}\ +.ace-tm .ace_xml-pe {\ +color: rgb(104, 104, 91);\ +}\ +.ace-tm .ace_entity.ace_name.ace_function {\ +color: #0000A2;\ +}\ +.ace-tm .ace_heading {\ +color: rgb(12, 7, 255);\ +}\ +.ace-tm .ace_list {\ +color:rgb(185, 6, 144);\ +}\ +.ace-tm .ace_meta.ace_tag {\ +color:rgb(0, 22, 142);\ +}\ +.ace-tm .ace_string.ace_regex {\ +color: rgb(255, 0, 0)\ +}\ +.ace-tm .ace_marker-layer .ace_selection {\ +background: rgb(181, 213, 255);\ +}\ +.ace-tm.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px white;\ +}\ +.ace-tm .ace_marker-layer .ace_step {\ +background: rgb(252, 255, 0);\ +}\ +.ace-tm .ace_marker-layer .ace_stack {\ +background: rgb(164, 229, 101);\ +}\ +.ace-tm .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgb(192, 192, 192);\ +}\ +.ace-tm .ace_marker-layer .ace_active-line {\ +background: rgba(0, 0, 0, 0.07);\ +}\ +.ace-tm .ace_gutter-active-line {\ +background-color : #dcdcdc;\ +}\ +.ace-tm .ace_marker-layer .ace_selected-word {\ +background: rgb(250, 250, 255);\ +border: 1px solid rgb(200, 200, 250);\ +}\ +.ace-tm .ace_indent-guide {\ +background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\ +}\ +"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow.js new file mode 100755 index 0000000..4661be1 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow.js @@ -0,0 +1,108 @@ +ace.define("ace/theme/tomorrow",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = false; +exports.cssClass = "ace-tomorrow"; +exports.cssText = ".ace-tomorrow .ace_gutter {\ +background: #f6f6f6;\ +color: #4D4D4C\ +}\ +.ace-tomorrow .ace_print-margin {\ +width: 1px;\ +background: #f6f6f6\ +}\ +.ace-tomorrow {\ +background-color: #FFFFFF;\ +color: #4D4D4C\ +}\ +.ace-tomorrow .ace_cursor {\ +color: #AEAFAD\ +}\ +.ace-tomorrow .ace_marker-layer .ace_selection {\ +background: #D6D6D6\ +}\ +.ace-tomorrow.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #FFFFFF;\ +}\ +.ace-tomorrow .ace_marker-layer .ace_step {\ +background: rgb(255, 255, 0)\ +}\ +.ace-tomorrow .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #D1D1D1\ +}\ +.ace-tomorrow .ace_marker-layer .ace_active-line {\ +background: #EFEFEF\ +}\ +.ace-tomorrow .ace_gutter-active-line {\ +background-color : #dcdcdc\ +}\ +.ace-tomorrow .ace_marker-layer .ace_selected-word {\ +border: 1px solid #D6D6D6\ +}\ +.ace-tomorrow .ace_invisible {\ +color: #D1D1D1\ +}\ +.ace-tomorrow .ace_keyword,\ +.ace-tomorrow .ace_meta,\ +.ace-tomorrow .ace_storage,\ +.ace-tomorrow .ace_storage.ace_type,\ +.ace-tomorrow .ace_support.ace_type {\ +color: #8959A8\ +}\ +.ace-tomorrow .ace_keyword.ace_operator {\ +color: #3E999F\ +}\ +.ace-tomorrow .ace_constant.ace_character,\ +.ace-tomorrow .ace_constant.ace_language,\ +.ace-tomorrow .ace_constant.ace_numeric,\ +.ace-tomorrow .ace_keyword.ace_other.ace_unit,\ +.ace-tomorrow .ace_support.ace_constant,\ +.ace-tomorrow .ace_variable.ace_parameter {\ +color: #F5871F\ +}\ +.ace-tomorrow .ace_constant.ace_other {\ +color: #666969\ +}\ +.ace-tomorrow .ace_invalid {\ +color: #FFFFFF;\ +background-color: #C82829\ +}\ +.ace-tomorrow .ace_invalid.ace_deprecated {\ +color: #FFFFFF;\ +background-color: #8959A8\ +}\ +.ace-tomorrow .ace_fold {\ +background-color: #4271AE;\ +border-color: #4D4D4C\ +}\ +.ace-tomorrow .ace_entity.ace_name.ace_function,\ +.ace-tomorrow .ace_support.ace_function,\ +.ace-tomorrow .ace_variable {\ +color: #4271AE\ +}\ +.ace-tomorrow .ace_support.ace_class,\ +.ace-tomorrow .ace_support.ace_type {\ +color: #C99E00\ +}\ +.ace-tomorrow .ace_heading,\ +.ace-tomorrow .ace_markup.ace_heading,\ +.ace-tomorrow .ace_string {\ +color: #718C00\ +}\ +.ace-tomorrow .ace_entity.ace_name.ace_tag,\ +.ace-tomorrow .ace_entity.ace_other.ace_attribute-name,\ +.ace-tomorrow .ace_meta.ace_tag,\ +.ace-tomorrow .ace_string.ace_regexp,\ +.ace-tomorrow .ace_variable {\ +color: #C82829\ +}\ +.ace-tomorrow .ace_comment {\ +color: #8E908C\ +}\ +.ace-tomorrow .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bdu3f/BwAlfgctduB85QAAAABJRU5ErkJggg==) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow_night.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow_night.js new file mode 100755 index 0000000..53e1f39 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow_night.js @@ -0,0 +1,108 @@ +ace.define("ace/theme/tomorrow_night",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-tomorrow-night"; +exports.cssText = ".ace-tomorrow-night .ace_gutter {\ +background: #25282c;\ +color: #C5C8C6\ +}\ +.ace-tomorrow-night .ace_print-margin {\ +width: 1px;\ +background: #25282c\ +}\ +.ace-tomorrow-night {\ +background-color: #1D1F21;\ +color: #C5C8C6\ +}\ +.ace-tomorrow-night .ace_cursor {\ +color: #AEAFAD\ +}\ +.ace-tomorrow-night .ace_marker-layer .ace_selection {\ +background: #373B41\ +}\ +.ace-tomorrow-night.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #1D1F21;\ +}\ +.ace-tomorrow-night .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-tomorrow-night .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #4B4E55\ +}\ +.ace-tomorrow-night .ace_marker-layer .ace_active-line {\ +background: #282A2E\ +}\ +.ace-tomorrow-night .ace_gutter-active-line {\ +background-color: #282A2E\ +}\ +.ace-tomorrow-night .ace_marker-layer .ace_selected-word {\ +border: 1px solid #373B41\ +}\ +.ace-tomorrow-night .ace_invisible {\ +color: #4B4E55\ +}\ +.ace-tomorrow-night .ace_keyword,\ +.ace-tomorrow-night .ace_meta,\ +.ace-tomorrow-night .ace_storage,\ +.ace-tomorrow-night .ace_storage.ace_type,\ +.ace-tomorrow-night .ace_support.ace_type {\ +color: #B294BB\ +}\ +.ace-tomorrow-night .ace_keyword.ace_operator {\ +color: #8ABEB7\ +}\ +.ace-tomorrow-night .ace_constant.ace_character,\ +.ace-tomorrow-night .ace_constant.ace_language,\ +.ace-tomorrow-night .ace_constant.ace_numeric,\ +.ace-tomorrow-night .ace_keyword.ace_other.ace_unit,\ +.ace-tomorrow-night .ace_support.ace_constant,\ +.ace-tomorrow-night .ace_variable.ace_parameter {\ +color: #DE935F\ +}\ +.ace-tomorrow-night .ace_constant.ace_other {\ +color: #CED1CF\ +}\ +.ace-tomorrow-night .ace_invalid {\ +color: #CED2CF;\ +background-color: #DF5F5F\ +}\ +.ace-tomorrow-night .ace_invalid.ace_deprecated {\ +color: #CED2CF;\ +background-color: #B798BF\ +}\ +.ace-tomorrow-night .ace_fold {\ +background-color: #81A2BE;\ +border-color: #C5C8C6\ +}\ +.ace-tomorrow-night .ace_entity.ace_name.ace_function,\ +.ace-tomorrow-night .ace_support.ace_function,\ +.ace-tomorrow-night .ace_variable {\ +color: #81A2BE\ +}\ +.ace-tomorrow-night .ace_support.ace_class,\ +.ace-tomorrow-night .ace_support.ace_type {\ +color: #F0C674\ +}\ +.ace-tomorrow-night .ace_heading,\ +.ace-tomorrow-night .ace_markup.ace_heading,\ +.ace-tomorrow-night .ace_string {\ +color: #B5BD68\ +}\ +.ace-tomorrow-night .ace_entity.ace_name.ace_tag,\ +.ace-tomorrow-night .ace_entity.ace_other.ace_attribute-name,\ +.ace-tomorrow-night .ace_meta.ace_tag,\ +.ace-tomorrow-night .ace_string.ace_regexp,\ +.ace-tomorrow-night .ace_variable {\ +color: #CC6666\ +}\ +.ace-tomorrow-night .ace_comment {\ +color: #969896\ +}\ +.ace-tomorrow-night .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHB3d/8PAAOIAdULw8qMAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow_night_blue.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow_night_blue.js new file mode 100755 index 0000000..956e221 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow_night_blue.js @@ -0,0 +1,106 @@ +ace.define("ace/theme/tomorrow_night_blue",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-tomorrow-night-blue"; +exports.cssText = ".ace-tomorrow-night-blue .ace_gutter {\ +background: #00204b;\ +color: #7388b5\ +}\ +.ace-tomorrow-night-blue .ace_print-margin {\ +width: 1px;\ +background: #00204b\ +}\ +.ace-tomorrow-night-blue {\ +background-color: #002451;\ +color: #FFFFFF\ +}\ +.ace-tomorrow-night-blue .ace_constant.ace_other,\ +.ace-tomorrow-night-blue .ace_cursor {\ +color: #FFFFFF\ +}\ +.ace-tomorrow-night-blue .ace_marker-layer .ace_selection {\ +background: #003F8E\ +}\ +.ace-tomorrow-night-blue.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #002451;\ +}\ +.ace-tomorrow-night-blue .ace_marker-layer .ace_step {\ +background: rgb(127, 111, 19)\ +}\ +.ace-tomorrow-night-blue .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #404F7D\ +}\ +.ace-tomorrow-night-blue .ace_marker-layer .ace_active-line {\ +background: #00346E\ +}\ +.ace-tomorrow-night-blue .ace_gutter-active-line {\ +background-color: #022040\ +}\ +.ace-tomorrow-night-blue .ace_marker-layer .ace_selected-word {\ +border: 1px solid #003F8E\ +}\ +.ace-tomorrow-night-blue .ace_invisible {\ +color: #404F7D\ +}\ +.ace-tomorrow-night-blue .ace_keyword,\ +.ace-tomorrow-night-blue .ace_meta,\ +.ace-tomorrow-night-blue .ace_storage,\ +.ace-tomorrow-night-blue .ace_storage.ace_type,\ +.ace-tomorrow-night-blue .ace_support.ace_type {\ +color: #EBBBFF\ +}\ +.ace-tomorrow-night-blue .ace_keyword.ace_operator {\ +color: #99FFFF\ +}\ +.ace-tomorrow-night-blue .ace_constant.ace_character,\ +.ace-tomorrow-night-blue .ace_constant.ace_language,\ +.ace-tomorrow-night-blue .ace_constant.ace_numeric,\ +.ace-tomorrow-night-blue .ace_keyword.ace_other.ace_unit,\ +.ace-tomorrow-night-blue .ace_support.ace_constant,\ +.ace-tomorrow-night-blue .ace_variable.ace_parameter {\ +color: #FFC58F\ +}\ +.ace-tomorrow-night-blue .ace_invalid {\ +color: #FFFFFF;\ +background-color: #F99DA5\ +}\ +.ace-tomorrow-night-blue .ace_invalid.ace_deprecated {\ +color: #FFFFFF;\ +background-color: #EBBBFF\ +}\ +.ace-tomorrow-night-blue .ace_fold {\ +background-color: #BBDAFF;\ +border-color: #FFFFFF\ +}\ +.ace-tomorrow-night-blue .ace_entity.ace_name.ace_function,\ +.ace-tomorrow-night-blue .ace_support.ace_function,\ +.ace-tomorrow-night-blue .ace_variable {\ +color: #BBDAFF\ +}\ +.ace-tomorrow-night-blue .ace_support.ace_class,\ +.ace-tomorrow-night-blue .ace_support.ace_type {\ +color: #FFEEAD\ +}\ +.ace-tomorrow-night-blue .ace_heading,\ +.ace-tomorrow-night-blue .ace_markup.ace_heading,\ +.ace-tomorrow-night-blue .ace_string {\ +color: #D1F1A9\ +}\ +.ace-tomorrow-night-blue .ace_entity.ace_name.ace_tag,\ +.ace-tomorrow-night-blue .ace_entity.ace_other.ace_attribute-name,\ +.ace-tomorrow-night-blue .ace_meta.ace_tag,\ +.ace-tomorrow-night-blue .ace_string.ace_regexp,\ +.ace-tomorrow-night-blue .ace_variable {\ +color: #FF9DA4\ +}\ +.ace-tomorrow-night-blue .ace_comment {\ +color: #7285B7\ +}\ +.ace-tomorrow-night-blue .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYJDzqfwPAANXAeNsiA+ZAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow_night_bright.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow_night_bright.js new file mode 100755 index 0000000..8514a0d --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow_night_bright.js @@ -0,0 +1,121 @@ +ace.define("ace/theme/tomorrow_night_bright",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-tomorrow-night-bright"; +exports.cssText = ".ace-tomorrow-night-bright .ace_gutter {\ +background: #1a1a1a;\ +color: #DEDEDE\ +}\ +.ace-tomorrow-night-bright .ace_print-margin {\ +width: 1px;\ +background: #1a1a1a\ +}\ +.ace-tomorrow-night-bright {\ +background-color: #000000;\ +color: #DEDEDE\ +}\ +.ace-tomorrow-night-bright .ace_cursor {\ +color: #9F9F9F\ +}\ +.ace-tomorrow-night-bright .ace_marker-layer .ace_selection {\ +background: #424242\ +}\ +.ace-tomorrow-night-bright.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #000000;\ +}\ +.ace-tomorrow-night-bright .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-tomorrow-night-bright .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #888888\ +}\ +.ace-tomorrow-night-bright .ace_marker-layer .ace_highlight {\ +border: 1px solid rgb(110, 119, 0);\ +border-bottom: 0;\ +box-shadow: inset 0 -1px rgb(110, 119, 0);\ +margin: -1px 0 0 -1px;\ +background: rgba(255, 235, 0, 0.1)\ +}\ +.ace-tomorrow-night-bright .ace_marker-layer .ace_active-line {\ +background: #2A2A2A\ +}\ +.ace-tomorrow-night-bright .ace_gutter-active-line {\ +background-color: #2A2A2A\ +}\ +.ace-tomorrow-night-bright .ace_stack {\ +background-color: rgb(66, 90, 44)\ +}\ +.ace-tomorrow-night-bright .ace_marker-layer .ace_selected-word {\ +border: 1px solid #888888\ +}\ +.ace-tomorrow-night-bright .ace_invisible {\ +color: #343434\ +}\ +.ace-tomorrow-night-bright .ace_keyword,\ +.ace-tomorrow-night-bright .ace_meta,\ +.ace-tomorrow-night-bright .ace_storage,\ +.ace-tomorrow-night-bright .ace_storage.ace_type,\ +.ace-tomorrow-night-bright .ace_support.ace_type {\ +color: #C397D8\ +}\ +.ace-tomorrow-night-bright .ace_keyword.ace_operator {\ +color: #70C0B1\ +}\ +.ace-tomorrow-night-bright .ace_constant.ace_character,\ +.ace-tomorrow-night-bright .ace_constant.ace_language,\ +.ace-tomorrow-night-bright .ace_constant.ace_numeric,\ +.ace-tomorrow-night-bright .ace_keyword.ace_other.ace_unit,\ +.ace-tomorrow-night-bright .ace_support.ace_constant,\ +.ace-tomorrow-night-bright .ace_variable.ace_parameter {\ +color: #E78C45\ +}\ +.ace-tomorrow-night-bright .ace_constant.ace_other {\ +color: #EEEEEE\ +}\ +.ace-tomorrow-night-bright .ace_invalid {\ +color: #CED2CF;\ +background-color: #DF5F5F\ +}\ +.ace-tomorrow-night-bright .ace_invalid.ace_deprecated {\ +color: #CED2CF;\ +background-color: #B798BF\ +}\ +.ace-tomorrow-night-bright .ace_fold {\ +background-color: #7AA6DA;\ +border-color: #DEDEDE\ +}\ +.ace-tomorrow-night-bright .ace_entity.ace_name.ace_function,\ +.ace-tomorrow-night-bright .ace_support.ace_function,\ +.ace-tomorrow-night-bright .ace_variable {\ +color: #7AA6DA\ +}\ +.ace-tomorrow-night-bright .ace_support.ace_class,\ +.ace-tomorrow-night-bright .ace_support.ace_type {\ +color: #E7C547\ +}\ +.ace-tomorrow-night-bright .ace_heading,\ +.ace-tomorrow-night-bright .ace_markup.ace_heading,\ +.ace-tomorrow-night-bright .ace_string {\ +color: #B9CA4A\ +}\ +.ace-tomorrow-night-bright .ace_entity.ace_name.ace_tag,\ +.ace-tomorrow-night-bright .ace_entity.ace_other.ace_attribute-name,\ +.ace-tomorrow-night-bright .ace_meta.ace_tag,\ +.ace-tomorrow-night-bright .ace_string.ace_regexp,\ +.ace-tomorrow-night-bright .ace_variable {\ +color: #D54E53\ +}\ +.ace-tomorrow-night-bright .ace_comment {\ +color: #969896\ +}\ +.ace-tomorrow-night-bright .ace_c9searchresults.ace_keyword {\ +color: #C2C280\ +}\ +.ace-tomorrow-night-bright .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYFBXV/8PAAJoAXX4kT2EAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow_night_eighties.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow_night_eighties.js new file mode 100755 index 0000000..3665e3f --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-tomorrow_night_eighties.js @@ -0,0 +1,108 @@ +ace.define("ace/theme/tomorrow_night_eighties",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-tomorrow-night-eighties"; +exports.cssText = ".ace-tomorrow-night-eighties .ace_gutter {\ +background: #272727;\ +color: #CCC\ +}\ +.ace-tomorrow-night-eighties .ace_print-margin {\ +width: 1px;\ +background: #272727\ +}\ +.ace-tomorrow-night-eighties {\ +background-color: #2D2D2D;\ +color: #CCCCCC\ +}\ +.ace-tomorrow-night-eighties .ace_constant.ace_other,\ +.ace-tomorrow-night-eighties .ace_cursor {\ +color: #CCCCCC\ +}\ +.ace-tomorrow-night-eighties .ace_marker-layer .ace_selection {\ +background: #515151\ +}\ +.ace-tomorrow-night-eighties.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #2D2D2D;\ +}\ +.ace-tomorrow-night-eighties .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-tomorrow-night-eighties .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #6A6A6A\ +}\ +.ace-tomorrow-night-bright .ace_stack {\ +background: rgb(66, 90, 44)\ +}\ +.ace-tomorrow-night-eighties .ace_marker-layer .ace_active-line {\ +background: #393939\ +}\ +.ace-tomorrow-night-eighties .ace_gutter-active-line {\ +background-color: #393939\ +}\ +.ace-tomorrow-night-eighties .ace_marker-layer .ace_selected-word {\ +border: 1px solid #515151\ +}\ +.ace-tomorrow-night-eighties .ace_invisible {\ +color: #6A6A6A\ +}\ +.ace-tomorrow-night-eighties .ace_keyword,\ +.ace-tomorrow-night-eighties .ace_meta,\ +.ace-tomorrow-night-eighties .ace_storage,\ +.ace-tomorrow-night-eighties .ace_storage.ace_type,\ +.ace-tomorrow-night-eighties .ace_support.ace_type {\ +color: #CC99CC\ +}\ +.ace-tomorrow-night-eighties .ace_keyword.ace_operator {\ +color: #66CCCC\ +}\ +.ace-tomorrow-night-eighties .ace_constant.ace_character,\ +.ace-tomorrow-night-eighties .ace_constant.ace_language,\ +.ace-tomorrow-night-eighties .ace_constant.ace_numeric,\ +.ace-tomorrow-night-eighties .ace_keyword.ace_other.ace_unit,\ +.ace-tomorrow-night-eighties .ace_support.ace_constant,\ +.ace-tomorrow-night-eighties .ace_variable.ace_parameter {\ +color: #F99157\ +}\ +.ace-tomorrow-night-eighties .ace_invalid {\ +color: #CDCDCD;\ +background-color: #F2777A\ +}\ +.ace-tomorrow-night-eighties .ace_invalid.ace_deprecated {\ +color: #CDCDCD;\ +background-color: #CC99CC\ +}\ +.ace-tomorrow-night-eighties .ace_fold {\ +background-color: #6699CC;\ +border-color: #CCCCCC\ +}\ +.ace-tomorrow-night-eighties .ace_entity.ace_name.ace_function,\ +.ace-tomorrow-night-eighties .ace_support.ace_function,\ +.ace-tomorrow-night-eighties .ace_variable {\ +color: #6699CC\ +}\ +.ace-tomorrow-night-eighties .ace_support.ace_class,\ +.ace-tomorrow-night-eighties .ace_support.ace_type {\ +color: #FFCC66\ +}\ +.ace-tomorrow-night-eighties .ace_heading,\ +.ace-tomorrow-night-eighties .ace_markup.ace_heading,\ +.ace-tomorrow-night-eighties .ace_string {\ +color: #99CC99\ +}\ +.ace-tomorrow-night-eighties .ace_comment {\ +color: #999999\ +}\ +.ace-tomorrow-night-eighties .ace_entity.ace_name.ace_tag,\ +.ace-tomorrow-night-eighties .ace_entity.ace_other.ace_attribute-name,\ +.ace-tomorrow-night-eighties .ace_meta.ace_tag,\ +.ace-tomorrow-night-eighties .ace_variable {\ +color: #F2777A\ +}\ +.ace-tomorrow-night-eighties .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWPQ09NrYAgMjP4PAAtGAwchHMyAAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-twilight.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-twilight.js new file mode 100755 index 0000000..48ec030 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-twilight.js @@ -0,0 +1,109 @@ +ace.define("ace/theme/twilight",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-twilight"; +exports.cssText = ".ace-twilight .ace_gutter {\ +background: #232323;\ +color: #E2E2E2\ +}\ +.ace-twilight .ace_print-margin {\ +width: 1px;\ +background: #232323\ +}\ +.ace-twilight {\ +background-color: #141414;\ +color: #F8F8F8\ +}\ +.ace-twilight .ace_cursor {\ +color: #A7A7A7\ +}\ +.ace-twilight .ace_marker-layer .ace_selection {\ +background: rgba(221, 240, 255, 0.20)\ +}\ +.ace-twilight.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #141414;\ +}\ +.ace-twilight .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-twilight .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgba(255, 255, 255, 0.25)\ +}\ +.ace-twilight .ace_marker-layer .ace_active-line {\ +background: rgba(255, 255, 255, 0.031)\ +}\ +.ace-twilight .ace_gutter-active-line {\ +background-color: rgba(255, 255, 255, 0.031)\ +}\ +.ace-twilight .ace_marker-layer .ace_selected-word {\ +border: 1px solid rgba(221, 240, 255, 0.20)\ +}\ +.ace-twilight .ace_invisible {\ +color: rgba(255, 255, 255, 0.25)\ +}\ +.ace-twilight .ace_keyword,\ +.ace-twilight .ace_meta {\ +color: #CDA869\ +}\ +.ace-twilight .ace_constant,\ +.ace-twilight .ace_constant.ace_character,\ +.ace-twilight .ace_constant.ace_character.ace_escape,\ +.ace-twilight .ace_constant.ace_other,\ +.ace-twilight .ace_heading,\ +.ace-twilight .ace_markup.ace_heading,\ +.ace-twilight .ace_support.ace_constant {\ +color: #CF6A4C\ +}\ +.ace-twilight .ace_invalid.ace_illegal {\ +color: #F8F8F8;\ +background-color: rgba(86, 45, 86, 0.75)\ +}\ +.ace-twilight .ace_invalid.ace_deprecated {\ +text-decoration: underline;\ +font-style: italic;\ +color: #D2A8A1\ +}\ +.ace-twilight .ace_support {\ +color: #9B859D\ +}\ +.ace-twilight .ace_fold {\ +background-color: #AC885B;\ +border-color: #F8F8F8\ +}\ +.ace-twilight .ace_support.ace_function {\ +color: #DAD085\ +}\ +.ace-twilight .ace_list,\ +.ace-twilight .ace_markup.ace_list,\ +.ace-twilight .ace_storage {\ +color: #F9EE98\ +}\ +.ace-twilight .ace_entity.ace_name.ace_function,\ +.ace-twilight .ace_meta.ace_tag,\ +.ace-twilight .ace_variable {\ +color: #AC885B\ +}\ +.ace-twilight .ace_string {\ +color: #8F9D6A\ +}\ +.ace-twilight .ace_string.ace_regexp {\ +color: #E9C062\ +}\ +.ace-twilight .ace_comment {\ +font-style: italic;\ +color: #5F5A60\ +}\ +.ace-twilight .ace_variable {\ +color: #7587A6\ +}\ +.ace-twilight .ace_xml-pe {\ +color: #494949\ +}\ +.ace-twilight .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWMQERFpYLC1tf0PAAgOAnPnhxyiAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-vibrant_ink.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-vibrant_ink.js new file mode 100755 index 0000000..db926c7 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-vibrant_ink.js @@ -0,0 +1,94 @@ +ace.define("ace/theme/vibrant_ink",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = true; +exports.cssClass = "ace-vibrant-ink"; +exports.cssText = ".ace-vibrant-ink .ace_gutter {\ +background: #1a1a1a;\ +color: #BEBEBE\ +}\ +.ace-vibrant-ink .ace_print-margin {\ +width: 1px;\ +background: #1a1a1a\ +}\ +.ace-vibrant-ink {\ +background-color: #0F0F0F;\ +color: #FFFFFF\ +}\ +.ace-vibrant-ink .ace_cursor {\ +color: #FFFFFF\ +}\ +.ace-vibrant-ink .ace_marker-layer .ace_selection {\ +background: #6699CC\ +}\ +.ace-vibrant-ink.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #0F0F0F;\ +}\ +.ace-vibrant-ink .ace_marker-layer .ace_step {\ +background: rgb(102, 82, 0)\ +}\ +.ace-vibrant-ink .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #404040\ +}\ +.ace-vibrant-ink .ace_marker-layer .ace_active-line {\ +background: #333333\ +}\ +.ace-vibrant-ink .ace_gutter-active-line {\ +background-color: #333333\ +}\ +.ace-vibrant-ink .ace_marker-layer .ace_selected-word {\ +border: 1px solid #6699CC\ +}\ +.ace-vibrant-ink .ace_invisible {\ +color: #404040\ +}\ +.ace-vibrant-ink .ace_keyword,\ +.ace-vibrant-ink .ace_meta {\ +color: #FF6600\ +}\ +.ace-vibrant-ink .ace_constant,\ +.ace-vibrant-ink .ace_constant.ace_character,\ +.ace-vibrant-ink .ace_constant.ace_character.ace_escape,\ +.ace-vibrant-ink .ace_constant.ace_other {\ +color: #339999\ +}\ +.ace-vibrant-ink .ace_constant.ace_numeric {\ +color: #99CC99\ +}\ +.ace-vibrant-ink .ace_invalid,\ +.ace-vibrant-ink .ace_invalid.ace_deprecated {\ +color: #CCFF33;\ +background-color: #000000\ +}\ +.ace-vibrant-ink .ace_fold {\ +background-color: #FFCC00;\ +border-color: #FFFFFF\ +}\ +.ace-vibrant-ink .ace_entity.ace_name.ace_function,\ +.ace-vibrant-ink .ace_support.ace_function,\ +.ace-vibrant-ink .ace_variable {\ +color: #FFCC00\ +}\ +.ace-vibrant-ink .ace_variable.ace_parameter {\ +font-style: italic\ +}\ +.ace-vibrant-ink .ace_string {\ +color: #66FF00\ +}\ +.ace-vibrant-ink .ace_string.ace_regexp {\ +color: #44B4CC\ +}\ +.ace-vibrant-ink .ace_comment {\ +color: #9933CC\ +}\ +.ace-vibrant-ink .ace_entity.ace_other.ace_attribute-name {\ +font-style: italic;\ +color: #99CC99\ +}\ +.ace-vibrant-ink .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYNDTc/oPAALPAZ7hxlbYAAAAAElFTkSuQmCC) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-xcode.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-xcode.js new file mode 100755 index 0000000..3604a17 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/theme-xcode.js @@ -0,0 +1,88 @@ +ace.define("ace/theme/xcode",["require","exports","module","ace/lib/dom"], function(require, exports, module) { + +exports.isDark = false; +exports.cssClass = "ace-xcode"; +exports.cssText = "\ +.ace-xcode .ace_gutter {\ +background: #e8e8e8;\ +color: #333\ +}\ +.ace-xcode .ace_print-margin {\ +width: 1px;\ +background: #e8e8e8\ +}\ +.ace-xcode {\ +background-color: #FFFFFF;\ +color: #000000\ +}\ +.ace-xcode .ace_cursor {\ +color: #000000\ +}\ +.ace-xcode .ace_marker-layer .ace_selection {\ +background: #B5D5FF\ +}\ +.ace-xcode.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px #FFFFFF;\ +}\ +.ace-xcode .ace_marker-layer .ace_step {\ +background: rgb(198, 219, 174)\ +}\ +.ace-xcode .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid #BFBFBF\ +}\ +.ace-xcode .ace_marker-layer .ace_active-line {\ +background: rgba(0, 0, 0, 0.071)\ +}\ +.ace-xcode .ace_gutter-active-line {\ +background-color: rgba(0, 0, 0, 0.071)\ +}\ +.ace-xcode .ace_marker-layer .ace_selected-word {\ +border: 1px solid #B5D5FF\ +}\ +.ace-xcode .ace_constant.ace_language,\ +.ace-xcode .ace_keyword,\ +.ace-xcode .ace_meta,\ +.ace-xcode .ace_variable.ace_language {\ +color: #C800A4\ +}\ +.ace-xcode .ace_invisible {\ +color: #BFBFBF\ +}\ +.ace-xcode .ace_constant.ace_character,\ +.ace-xcode .ace_constant.ace_other {\ +color: #275A5E\ +}\ +.ace-xcode .ace_constant.ace_numeric {\ +color: #3A00DC\ +}\ +.ace-xcode .ace_entity.ace_other.ace_attribute-name,\ +.ace-xcode .ace_support.ace_constant,\ +.ace-xcode .ace_support.ace_function {\ +color: #450084\ +}\ +.ace-xcode .ace_fold {\ +background-color: #C800A4;\ +border-color: #000000\ +}\ +.ace-xcode .ace_entity.ace_name.ace_tag,\ +.ace-xcode .ace_support.ace_class,\ +.ace-xcode .ace_support.ace_type {\ +color: #790EAD\ +}\ +.ace-xcode .ace_storage {\ +color: #C900A4\ +}\ +.ace-xcode .ace_string {\ +color: #DF0002\ +}\ +.ace-xcode .ace_comment {\ +color: #008E00\ +}\ +.ace-xcode .ace_indent-guide {\ +background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==) right repeat-y\ +}"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/modules/backend/formwidgets/codeeditor/assets/vendor/ace/worker-css.js b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/worker-css.js new file mode 100755 index 0000000..28774f7 --- /dev/null +++ b/modules/backend/formwidgets/codeeditor/assets/vendor/ace/worker-css.js @@ -0,0 +1,8762 @@ +"no use strict"; +;(function(window) { +if (typeof window.window != "undefined" && window.document) + return; +if (window.require && window.define) + return; + +if (!window.console) { + window.console = function() { + var msgs = Array.prototype.slice.call(arguments, 0); + postMessage({type: "log", data: msgs}); + }; + window.console.error = + window.console.warn = + window.console.log = + window.console.trace = window.console; +} +window.window = window; +window.ace = window; + +window.onerror = function(message, file, line, col, err) { + postMessage({type: "error", data: { + message: message, + data: err.data, + file: file, + line: line, + col: col, + stack: err.stack + }}); +}; + +window.normalizeModule = function(parentId, moduleName) { + // normalize plugin requires + if (moduleName.indexOf("!") !== -1) { + var chunks = moduleName.split("!"); + return window.normalizeModule(parentId, chunks[0]) + "!" + window.normalizeModule(parentId, chunks[1]); + } + // normalize relative requires + if (moduleName.charAt(0) == ".") { + var base = parentId.split("/").slice(0, -1).join("/"); + moduleName = (base ? base + "/" : "") + moduleName; + + while (moduleName.indexOf(".") !== -1 && previous != moduleName) { + var previous = moduleName; + moduleName = moduleName.replace(/^\.\//, "").replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, ""); + } + } + + return moduleName; +}; + +window.require = function require(parentId, id) { + if (!id) { + id = parentId; + parentId = null; + } + if (!id.charAt) + throw new Error("worker.js require() accepts only (parentId, id) as arguments"); + + id = window.normalizeModule(parentId, id); + + var module = window.require.modules[id]; + if (module) { + if (!module.initialized) { + module.initialized = true; + module.exports = module.factory().exports; + } + return module.exports; + } + + if (!window.require.tlns) + return console.log("unable to load " + id); + + var path = resolveModuleId(id, window.require.tlns); + if (path.slice(-3) != ".js") path += ".js"; + + window.require.id = id; + window.require.modules[id] = {}; // prevent infinite loop on broken modules + importScripts(path); + return window.require(parentId, id); +}; +function resolveModuleId(id, paths) { + var testPath = id, tail = ""; + while (testPath) { + var alias = paths[testPath]; + if (typeof alias == "string") { + return alias + tail; + } else if (alias) { + return alias.location.replace(/\/*$/, "/") + (tail || alias.main || alias.name); + } else if (alias === false) { + return ""; + } + var i = testPath.lastIndexOf("/"); + if (i === -1) break; + tail = testPath.substr(i) + tail; + testPath = testPath.slice(0, i); + } + return id; +} +window.require.modules = {}; +window.require.tlns = {}; + +window.define = function(id, deps, factory) { + if (arguments.length == 2) { + factory = deps; + if (typeof id != "string") { + deps = id; + id = window.require.id; + } + } else if (arguments.length == 1) { + factory = id; + deps = []; + id = window.require.id; + } + + if (typeof factory != "function") { + window.require.modules[id] = { + exports: factory, + initialized: true + }; + return; + } + + if (!deps.length) + // If there is no dependencies, we inject "require", "exports" and + // "module" as dependencies, to provide CommonJS compatibility. + deps = ["require", "exports", "module"]; + + var req = function(childId) { + return window.require(id, childId); + }; + + window.require.modules[id] = { + exports: {}, + factory: function() { + var module = this; + var returnExports = factory.apply(this, deps.map(function(dep) { + switch (dep) { + // Because "require", "exports" and "module" aren't actual + // dependencies, we must handle them seperately. + case "require": return req; + case "exports": return module.exports; + case "module": return module; + // But for all other dependencies, we can just go ahead and + // require them. + default: return req(dep); + } + })); + if (returnExports) + module.exports = returnExports; + return module; + } + }; +}; +window.define.amd = {}; +require.tlns = {}; +window.initBaseUrls = function initBaseUrls(topLevelNamespaces) { + for (var i in topLevelNamespaces) + require.tlns[i] = topLevelNamespaces[i]; +}; + +window.initSender = function initSender() { + + var EventEmitter = window.require("ace/lib/event_emitter").EventEmitter; + var oop = window.require("ace/lib/oop"); + + var Sender = function() {}; + + (function() { + + oop.implement(this, EventEmitter); + + this.callback = function(data, callbackId) { + postMessage({ + type: "call", + id: callbackId, + data: data + }); + }; + + this.emit = function(name, data) { + postMessage({ + type: "event", + name: name, + data: data + }); + }; + + }).call(Sender.prototype); + + return new Sender(); +}; + +var main = window.main = null; +var sender = window.sender = null; + +window.onmessage = function(e) { + var msg = e.data; + if (msg.event && sender) { + sender._signal(msg.event, msg.data); + } + else if (msg.command) { + if (main[msg.command]) + main[msg.command].apply(main, msg.args); + else if (window[msg.command]) + window[msg.command].apply(window, msg.args); + else + throw new Error("Unknown command:" + msg.command); + } + else if (msg.init) { + window.initBaseUrls(msg.tlns); + require("ace/lib/es5-shim"); + sender = window.sender = window.initSender(); + var clazz = require(msg.module)[msg.classname]; + main = window.main = new clazz(sender); + } +}; +})(this); + +ace.define("ace/lib/oop",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.inherits = function(ctor, superCtor) { + ctor.super_ = superCtor; + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); +}; + +exports.mixin = function(obj, mixin) { + for (var key in mixin) { + obj[key] = mixin[key]; + } + return obj; +}; + +exports.implement = function(proto, mixin) { + exports.mixin(proto, mixin); +}; + +}); + +ace.define("ace/lib/lang",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.last = function(a) { + return a[a.length - 1]; +}; + +exports.stringReverse = function(string) { + return string.split("").reverse().join(""); +}; + +exports.stringRepeat = function (string, count) { + var result = ''; + while (count > 0) { + if (count & 1) + result += string; + + if (count >>= 1) + string += string; + } + return result; +}; + +var trimBeginRegexp = /^\s\s*/; +var trimEndRegexp = /\s\s*$/; + +exports.stringTrimLeft = function (string) { + return string.replace(trimBeginRegexp, ''); +}; + +exports.stringTrimRight = function (string) { + return string.replace(trimEndRegexp, ''); +}; + +exports.copyObject = function(obj) { + var copy = {}; + for (var key in obj) { + copy[key] = obj[key]; + } + return copy; +}; + +exports.copyArray = function(array){ + var copy = []; + for (var i=0, l=array.length; i [" + this.end.row + "/" + this.end.column + "]"); + }; + + this.contains = function(row, column) { + return this.compare(row, column) == 0; + }; + this.compareRange = function(range) { + var cmp, + end = range.end, + start = range.start; + + cmp = this.compare(end.row, end.column); + if (cmp == 1) { + cmp = this.compare(start.row, start.column); + if (cmp == 1) { + return 2; + } else if (cmp == 0) { + return 1; + } else { + return 0; + } + } else if (cmp == -1) { + return -2; + } else { + cmp = this.compare(start.row, start.column); + if (cmp == -1) { + return -1; + } else if (cmp == 1) { + return 42; + } else { + return 0; + } + } + }; + this.comparePoint = function(p) { + return this.compare(p.row, p.column); + }; + this.containsRange = function(range) { + return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0; + }; + this.intersects = function(range) { + var cmp = this.compareRange(range); + return (cmp == -1 || cmp == 0 || cmp == 1); + }; + this.isEnd = function(row, column) { + return this.end.row == row && this.end.column == column; + }; + this.isStart = function(row, column) { + return this.start.row == row && this.start.column == column; + }; + this.setStart = function(row, column) { + if (typeof row == "object") { + this.start.column = row.column; + this.start.row = row.row; + } else { + this.start.row = row; + this.start.column = column; + } + }; + this.setEnd = function(row, column) { + if (typeof row == "object") { + this.end.column = row.column; + this.end.row = row.row; + } else { + this.end.row = row; + this.end.column = column; + } + }; + this.inside = function(row, column) { + if (this.compare(row, column) == 0) { + if (this.isEnd(row, column) || this.isStart(row, column)) { + return false; + } else { + return true; + } + } + return false; + }; + this.insideStart = function(row, column) { + if (this.compare(row, column) == 0) { + if (this.isEnd(row, column)) { + return false; + } else { + return true; + } + } + return false; + }; + this.insideEnd = function(row, column) { + if (this.compare(row, column) == 0) { + if (this.isStart(row, column)) { + return false; + } else { + return true; + } + } + return false; + }; + this.compare = function(row, column) { + if (!this.isMultiLine()) { + if (row === this.start.row) { + return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0); + } + } + + if (row < this.start.row) + return -1; + + if (row > this.end.row) + return 1; + + if (this.start.row === row) + return column >= this.start.column ? 0 : -1; + + if (this.end.row === row) + return column <= this.end.column ? 0 : 1; + + return 0; + }; + this.compareStart = function(row, column) { + if (this.start.row == row && this.start.column == column) { + return -1; + } else { + return this.compare(row, column); + } + }; + this.compareEnd = function(row, column) { + if (this.end.row == row && this.end.column == column) { + return 1; + } else { + return this.compare(row, column); + } + }; + this.compareInside = function(row, column) { + if (this.end.row == row && this.end.column == column) { + return 1; + } else if (this.start.row == row && this.start.column == column) { + return -1; + } else { + return this.compare(row, column); + } + }; + this.clipRows = function(firstRow, lastRow) { + if (this.end.row > lastRow) + var end = {row: lastRow + 1, column: 0}; + else if (this.end.row < firstRow) + var end = {row: firstRow, column: 0}; + + if (this.start.row > lastRow) + var start = {row: lastRow + 1, column: 0}; + else if (this.start.row < firstRow) + var start = {row: firstRow, column: 0}; + + return Range.fromPoints(start || this.start, end || this.end); + }; + this.extend = function(row, column) { + var cmp = this.compare(row, column); + + if (cmp == 0) + return this; + else if (cmp == -1) + var start = {row: row, column: column}; + else + var end = {row: row, column: column}; + + return Range.fromPoints(start || this.start, end || this.end); + }; + + this.isEmpty = function() { + return (this.start.row === this.end.row && this.start.column === this.end.column); + }; + this.isMultiLine = function() { + return (this.start.row !== this.end.row); + }; + this.clone = function() { + return Range.fromPoints(this.start, this.end); + }; + this.collapseRows = function() { + if (this.end.column == 0) + return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0) + else + return new Range(this.start.row, 0, this.end.row, 0) + }; + this.toScreenRange = function(session) { + var screenPosStart = session.documentToScreenPosition(this.start); + var screenPosEnd = session.documentToScreenPosition(this.end); + + return new Range( + screenPosStart.row, screenPosStart.column, + screenPosEnd.row, screenPosEnd.column + ); + }; + this.moveBy = function(row, column) { + this.start.row += row; + this.start.column += column; + this.end.row += row; + this.end.column += column; + }; + +}).call(Range.prototype); +Range.fromPoints = function(start, end) { + return new Range(start.row, start.column, end.row, end.column); +}; +Range.comparePoints = comparePoints; + +Range.comparePoints = function(p1, p2) { + return p1.row - p2.row || p1.column - p2.column; +}; + + +exports.Range = Range; +}); + +ace.define("ace/apply_delta",["require","exports","module"], function(require, exports, module) { +"use strict"; + +function throwDeltaError(delta, errorText){ + console.log("Invalid Delta:", delta); + throw "Invalid Delta: " + errorText; +} + +function positionInDocument(docLines, position) { + return position.row >= 0 && position.row < docLines.length && + position.column >= 0 && position.column <= docLines[position.row].length; +} + +function validateDelta(docLines, delta) { + if (delta.action != "insert" && delta.action != "remove") + throwDeltaError(delta, "delta.action must be 'insert' or 'remove'"); + if (!(delta.lines instanceof Array)) + throwDeltaError(delta, "delta.lines must be an Array"); + if (!delta.start || !delta.end) + throwDeltaError(delta, "delta.start/end must be an present"); + var start = delta.start; + if (!positionInDocument(docLines, delta.start)) + throwDeltaError(delta, "delta.start must be contained in document"); + var end = delta.end; + if (delta.action == "remove" && !positionInDocument(docLines, end)) + throwDeltaError(delta, "delta.end must contained in document for 'remove' actions"); + var numRangeRows = end.row - start.row; + var numRangeLastLineChars = (end.column - (numRangeRows == 0 ? start.column : 0)); + if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars) + throwDeltaError(delta, "delta.range must match delta lines"); +} + +exports.applyDelta = function(docLines, delta, doNotValidate) { + + var row = delta.start.row; + var startColumn = delta.start.column; + var line = docLines[row] || ""; + switch (delta.action) { + case "insert": + var lines = delta.lines; + if (lines.length === 1) { + docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); + } else { + var args = [row, 1].concat(delta.lines); + docLines.splice.apply(docLines, args); + docLines[row] = line.substring(0, startColumn) + docLines[row]; + docLines[row + delta.lines.length - 1] += line.substring(startColumn); + } + break; + case "remove": + var endColumn = delta.end.column; + var endRow = delta.end.row; + if (row === endRow) { + docLines[row] = line.substring(0, startColumn) + line.substring(endColumn); + } else { + docLines.splice( + row, endRow - row + 1, + line.substring(0, startColumn) + docLines[endRow].substring(endColumn) + ); + } + break; + } +} +}); + +ace.define("ace/lib/event_emitter",["require","exports","module"], function(require, exports, module) { +"use strict"; + +var EventEmitter = {}; +var stopPropagation = function() { this.propagationStopped = true; }; +var preventDefault = function() { this.defaultPrevented = true; }; + +EventEmitter._emit = +EventEmitter._dispatchEvent = function(eventName, e) { + this._eventRegistry || (this._eventRegistry = {}); + this._defaultHandlers || (this._defaultHandlers = {}); + + var listeners = this._eventRegistry[eventName] || []; + var defaultHandler = this._defaultHandlers[eventName]; + if (!listeners.length && !defaultHandler) + return; + + if (typeof e != "object" || !e) + e = {}; + + if (!e.type) + e.type = eventName; + if (!e.stopPropagation) + e.stopPropagation = stopPropagation; + if (!e.preventDefault) + e.preventDefault = preventDefault; + + listeners = listeners.slice(); + for (var i=0; i this.row) + return; + + var point = $getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight); + this.setPosition(point.row, point.column, true); + }; + + function $pointsInOrder(point1, point2, equalPointsInOrder) { + var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column; + return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter); + } + + function $getTransformedPoint(delta, point, moveIfEqual) { + var deltaIsInsert = delta.action == "insert"; + var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.end.row - delta.start.row); + var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.end.column - delta.start.column); + var deltaStart = delta.start; + var deltaEnd = deltaIsInsert ? deltaStart : delta.end; // Collapse insert range. + if ($pointsInOrder(point, deltaStart, moveIfEqual)) { + return { + row: point.row, + column: point.column + }; + } + if ($pointsInOrder(deltaEnd, point, !moveIfEqual)) { + return { + row: point.row + deltaRowShift, + column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0) + }; + } + + return { + row: deltaStart.row, + column: deltaStart.column + }; + } + this.setPosition = function(row, column, noClip) { + var pos; + if (noClip) { + pos = { + row: row, + column: column + }; + } else { + pos = this.$clipPositionToDocument(row, column); + } + + if (this.row == pos.row && this.column == pos.column) + return; + + var old = { + row: this.row, + column: this.column + }; + + this.row = pos.row; + this.column = pos.column; + this._signal("change", { + old: old, + value: pos + }); + }; + this.detach = function() { + this.document.removeEventListener("change", this.$onChange); + }; + this.attach = function(doc) { + this.document = doc || this.document; + this.document.on("change", this.$onChange); + }; + this.$clipPositionToDocument = function(row, column) { + var pos = {}; + + if (row >= this.document.getLength()) { + pos.row = Math.max(0, this.document.getLength() - 1); + pos.column = this.document.getLine(pos.row).length; + } + else if (row < 0) { + pos.row = 0; + pos.column = 0; + } + else { + pos.row = row; + pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column)); + } + + if (column < 0) + pos.column = 0; + + return pos; + }; + +}).call(Anchor.prototype); + +}); + +ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var applyDelta = require("./apply_delta").applyDelta; +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var Range = require("./range").Range; +var Anchor = require("./anchor").Anchor; + +var Document = function(textOrLines) { + this.$lines = [""]; + if (textOrLines.length === 0) { + this.$lines = [""]; + } else if (Array.isArray(textOrLines)) { + this.insertMergedLines({row: 0, column: 0}, textOrLines); + } else { + this.insert({row: 0, column:0}, textOrLines); + } +}; + +(function() { + + oop.implement(this, EventEmitter); + this.setValue = function(text) { + var len = this.getLength() - 1; + this.remove(new Range(0, 0, len, this.getLine(len).length)); + this.insert({row: 0, column: 0}, text); + }; + this.getValue = function() { + return this.getAllLines().join(this.getNewLineCharacter()); + }; + this.createAnchor = function(row, column) { + return new Anchor(this, row, column); + }; + if ("aaa".split(/a/).length === 0) { + this.$split = function(text) { + return text.replace(/\r\n|\r/g, "\n").split("\n"); + }; + } else { + this.$split = function(text) { + return text.split(/\r\n|\r|\n/); + }; + } + + + this.$detectNewLine = function(text) { + var match = text.match(/^.*?(\r\n|\r|\n)/m); + this.$autoNewLine = match ? match[1] : "\n"; + this._signal("changeNewLineMode"); + }; + this.getNewLineCharacter = function() { + switch (this.$newLineMode) { + case "windows": + return "\r\n"; + case "unix": + return "\n"; + default: + return this.$autoNewLine || "\n"; + } + }; + + this.$autoNewLine = ""; + this.$newLineMode = "auto"; + this.setNewLineMode = function(newLineMode) { + if (this.$newLineMode === newLineMode) + return; + + this.$newLineMode = newLineMode; + this._signal("changeNewLineMode"); + }; + this.getNewLineMode = function() { + return this.$newLineMode; + }; + this.isNewLine = function(text) { + return (text == "\r\n" || text == "\r" || text == "\n"); + }; + this.getLine = function(row) { + return this.$lines[row] || ""; + }; + this.getLines = function(firstRow, lastRow) { + return this.$lines.slice(firstRow, lastRow + 1); + }; + this.getAllLines = function() { + return this.getLines(0, this.getLength()); + }; + this.getLength = function() { + return this.$lines.length; + }; + this.getTextRange = function(range) { + return this.getLinesForRange(range).join(this.getNewLineCharacter()); + }; + this.getLinesForRange = function(range) { + var lines; + if (range.start.row === range.end.row) { + lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)]; + } else { + lines = this.getLines(range.start.row, range.end.row); + lines[0] = (lines[0] || "").substring(range.start.column); + var l = lines.length - 1; + if (range.end.row - range.start.row == l) + lines[l] = lines[l].substring(0, range.end.column); + } + return lines; + }; + this.insertLines = function(row, lines) { + console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."); + return this.insertFullLines(row, lines); + }; + this.removeLines = function(firstRow, lastRow) { + console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."); + return this.removeFullLines(firstRow, lastRow); + }; + this.insertNewLine = function(position) { + console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\'\', \'\']) instead."); + return this.insertMergedLines(position, ["", ""]); + }; + this.insert = function(position, text) { + if (this.getLength() <= 1) + this.$detectNewLine(text); + + return this.insertMergedLines(position, this.$split(text)); + }; + this.insertInLine = function(position, text) { + var start = this.clippedPos(position.row, position.column); + var end = this.pos(position.row, position.column + text.length); + + this.applyDelta({ + start: start, + end: end, + action: "insert", + lines: [text] + }, true); + + return this.clonePos(end); + }; + + this.clippedPos = function(row, column) { + var length = this.getLength(); + if (row === undefined) { + row = length; + } else if (row < 0) { + row = 0; + } else if (row >= length) { + row = length - 1; + column = undefined; + } + var line = this.getLine(row); + if (column == undefined) + column = line.length; + column = Math.min(Math.max(column, 0), line.length); + return {row: row, column: column}; + }; + + this.clonePos = function(pos) { + return {row: pos.row, column: pos.column}; + }; + + this.pos = function(row, column) { + return {row: row, column: column}; + }; + + this.$clipPosition = function(position) { + var length = this.getLength(); + if (position.row >= length) { + position.row = Math.max(0, length - 1); + position.column = this.getLine(length - 1).length; + } else { + position.row = Math.max(0, position.row); + position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length); + } + return position; + }; + this.insertFullLines = function(row, lines) { + row = Math.min(Math.max(row, 0), this.getLength()); + var column = 0; + if (row < this.getLength()) { + lines = lines.concat([""]); + column = 0; + } else { + lines = [""].concat(lines); + row--; + column = this.$lines[row].length; + } + this.insertMergedLines({row: row, column: column}, lines); + }; + this.insertMergedLines = function(position, lines) { + var start = this.clippedPos(position.row, position.column); + var end = { + row: start.row + lines.length - 1, + column: (lines.length == 1 ? start.column : 0) + lines[lines.length - 1].length + }; + + this.applyDelta({ + start: start, + end: end, + action: "insert", + lines: lines + }); + + return this.clonePos(end); + }; + this.remove = function(range) { + var start = this.clippedPos(range.start.row, range.start.column); + var end = this.clippedPos(range.end.row, range.end.column); + this.applyDelta({ + start: start, + end: end, + action: "remove", + lines: this.getLinesForRange({start: start, end: end}) + }); + return this.clonePos(start); + }; + this.removeInLine = function(row, startColumn, endColumn) { + var start = this.clippedPos(row, startColumn); + var end = this.clippedPos(row, endColumn); + + this.applyDelta({ + start: start, + end: end, + action: "remove", + lines: this.getLinesForRange({start: start, end: end}) + }, true); + + return this.clonePos(start); + }; + this.removeFullLines = function(firstRow, lastRow) { + firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1); + lastRow = Math.min(Math.max(0, lastRow ), this.getLength() - 1); + var deleteFirstNewLine = lastRow == this.getLength() - 1 && firstRow > 0; + var deleteLastNewLine = lastRow < this.getLength() - 1; + var startRow = ( deleteFirstNewLine ? firstRow - 1 : firstRow ); + var startCol = ( deleteFirstNewLine ? this.getLine(startRow).length : 0 ); + var endRow = ( deleteLastNewLine ? lastRow + 1 : lastRow ); + var endCol = ( deleteLastNewLine ? 0 : this.getLine(endRow).length ); + var range = new Range(startRow, startCol, endRow, endCol); + var deletedLines = this.$lines.slice(firstRow, lastRow + 1); + + this.applyDelta({ + start: range.start, + end: range.end, + action: "remove", + lines: this.getLinesForRange(range) + }); + return deletedLines; + }; + this.removeNewLine = function(row) { + if (row < this.getLength() - 1 && row >= 0) { + this.applyDelta({ + start: this.pos(row, this.getLine(row).length), + end: this.pos(row + 1, 0), + action: "remove", + lines: ["", ""] + }); + } + }; + this.replace = function(range, text) { + if (!(range instanceof Range)) + range = Range.fromPoints(range.start, range.end); + if (text.length === 0 && range.isEmpty()) + return range.start; + if (text == this.getTextRange(range)) + return range.end; + + this.remove(range); + var end; + if (text) { + end = this.insert(range.start, text); + } + else { + end = range.start; + } + + return end; + }; + this.applyDeltas = function(deltas) { + for (var i=0; i=0; i--) { + this.revertDelta(deltas[i]); + } + }; + this.applyDelta = function(delta, doNotValidate) { + var isInsert = delta.action == "insert"; + if (isInsert ? delta.lines.length <= 1 && !delta.lines[0] + : !Range.comparePoints(delta.start, delta.end)) { + return; + } + + if (isInsert && delta.lines.length > 20000) + this.$splitAndapplyLargeDelta(delta, 20000); + applyDelta(this.$lines, delta, doNotValidate); + this._signal("change", delta); + }; + + this.$splitAndapplyLargeDelta = function(delta, MAX) { + var lines = delta.lines; + var l = lines.length; + var row = delta.start.row; + var column = delta.start.column; + var from = 0, to = 0; + do { + from = to; + to += MAX - 1; + var chunk = lines.slice(from, to); + if (to > l) { + delta.lines = chunk; + delta.start.row = row + from; + delta.start.column = column; + break; + } + chunk.push(""); + this.applyDelta({ + start: this.pos(row + from, column), + end: this.pos(row + to, column = 0), + action: delta.action, + lines: chunk + }, true); + } while(true); + }; + this.revertDelta = function(delta) { + this.applyDelta({ + start: this.clonePos(delta.start), + end: this.clonePos(delta.end), + action: (delta.action == "insert" ? "remove" : "insert"), + lines: delta.lines.slice() + }); + }; + this.indexToPosition = function(index, startRow) { + var lines = this.$lines || this.getAllLines(); + var newlineLength = this.getNewLineCharacter().length; + for (var i = startRow || 0, l = lines.length; i < l; i++) { + index -= lines[i].length + newlineLength; + if (index < 0) + return {row: i, column: index + lines[i].length + newlineLength}; + } + return {row: l-1, column: lines[l-1].length}; + }; + this.positionToIndex = function(pos, startRow) { + var lines = this.$lines || this.getAllLines(); + var newlineLength = this.getNewLineCharacter().length; + var index = 0; + var row = Math.min(pos.row, lines.length); + for (var i = startRow || 0; i < row; ++i) + index += lines[i].length + newlineLength; + + return index + pos.column; + }; + +}).call(Document.prototype); + +exports.Document = Document; +}); + +ace.define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"], function(require, exports, module) { +"use strict"; + +var Range = require("../range").Range; +var Document = require("../document").Document; +var lang = require("../lib/lang"); + +var Mirror = exports.Mirror = function(sender) { + this.sender = sender; + var doc = this.doc = new Document(""); + + var deferredUpdate = this.deferredUpdate = lang.delayedCall(this.onUpdate.bind(this)); + + var _self = this; + sender.on("change", function(e) { + var data = e.data; + if (data[0].start) { + doc.applyDeltas(data); + } else { + for (var i = 0; i < data.length; i += 2) { + if (Array.isArray(data[i+1])) { + var d = {action: "insert", start: data[i], lines: data[i+1]}; + } else { + var d = {action: "remove", start: data[i], end: data[i+1]}; + } + doc.applyDelta(d, true); + } + } + if (_self.$timeout) + return deferredUpdate.schedule(_self.$timeout); + _self.onUpdate(); + }); +}; + +(function() { + + this.$timeout = 500; + + this.setTimeout = function(timeout) { + this.$timeout = timeout; + }; + + this.setValue = function(value) { + this.doc.setValue(value); + this.deferredUpdate.schedule(this.$timeout); + }; + + this.getValue = function(callbackId) { + this.sender.callback(this.doc.getValue(), callbackId); + }; + + this.onUpdate = function() { + }; + + this.isPending = function() { + return this.deferredUpdate.isPending(); + }; + +}).call(Mirror.prototype); + +}); + +ace.define("ace/mode/css/csslint",["require","exports","module"], function(require, exports, module) { +var parserlib = {}; +(function(){ +function EventTarget(){ + this._listeners = {}; +} + +EventTarget.prototype = { + constructor: EventTarget, + addListener: function(type, listener){ + if (!this._listeners[type]){ + this._listeners[type] = []; + } + + this._listeners[type].push(listener); + }, + fire: function(event){ + if (typeof event == "string"){ + event = { type: event }; + } + if (typeof event.target != "undefined"){ + event.target = this; + } + + if (typeof event.type == "undefined"){ + throw new Error("Event object missing 'type' property."); + } + + if (this._listeners[event.type]){ + var listeners = this._listeners[event.type].concat(); + for (var i=0, len=listeners.length; i < len; i++){ + listeners[i].call(this, event); + } + } + }, + removeListener: function(type, listener){ + if (this._listeners[type]){ + var listeners = this._listeners[type]; + for (var i=0, len=listeners.length; i < len; i++){ + if (listeners[i] === listener){ + listeners.splice(i, 1); + break; + } + } + + + } + } +}; +function StringReader(text){ + this._input = text.replace(/\n\r?/g, "\n"); + this._line = 1; + this._col = 1; + this._cursor = 0; +} + +StringReader.prototype = { + constructor: StringReader, + getCol: function(){ + return this._col; + }, + getLine: function(){ + return this._line ; + }, + eof: function(){ + return (this._cursor == this._input.length); + }, + peek: function(count){ + var c = null; + count = (typeof count == "undefined" ? 1 : count); + if (this._cursor < this._input.length){ + c = this._input.charAt(this._cursor + count - 1); + } + + return c; + }, + read: function(){ + var c = null; + if (this._cursor < this._input.length){ + if (this._input.charAt(this._cursor) == "\n"){ + this._line++; + this._col=1; + } else { + this._col++; + } + c = this._input.charAt(this._cursor++); + } + + return c; + }, + mark: function(){ + this._bookmark = { + cursor: this._cursor, + line: this._line, + col: this._col + }; + }, + + reset: function(){ + if (this._bookmark){ + this._cursor = this._bookmark.cursor; + this._line = this._bookmark.line; + this._col = this._bookmark.col; + delete this._bookmark; + } + }, + readTo: function(pattern){ + + var buffer = "", + c; + while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){ + c = this.read(); + if (c){ + buffer += c; + } else { + throw new Error("Expected \"" + pattern + "\" at line " + this._line + ", col " + this._col + "."); + } + } + + return buffer; + + }, + readWhile: function(filter){ + + var buffer = "", + c = this.read(); + + while(c !== null && filter(c)){ + buffer += c; + c = this.read(); + } + + return buffer; + + }, + readMatch: function(matcher){ + + var source = this._input.substring(this._cursor), + value = null; + if (typeof matcher == "string"){ + if (source.indexOf(matcher) === 0){ + value = this.readCount(matcher.length); + } + } else if (matcher instanceof RegExp){ + if (matcher.test(source)){ + value = this.readCount(RegExp.lastMatch.length); + } + } + + return value; + }, + readCount: function(count){ + var buffer = ""; + + while(count--){ + buffer += this.read(); + } + + return buffer; + } + +}; +function SyntaxError(message, line, col){ + this.col = col; + this.line = line; + this.message = message; + +} +SyntaxError.prototype = new Error(); +function SyntaxUnit(text, line, col, type){ + this.col = col; + this.line = line; + this.text = text; + this.type = type; +} +SyntaxUnit.fromToken = function(token){ + return new SyntaxUnit(token.value, token.startLine, token.startCol); +}; + +SyntaxUnit.prototype = { + constructor: SyntaxUnit, + valueOf: function(){ + return this.text; + }, + toString: function(){ + return this.text; + } + +}; +function TokenStreamBase(input, tokenData){ + this._reader = input ? new StringReader(input.toString()) : null; + this._token = null; + this._tokenData = tokenData; + this._lt = []; + this._ltIndex = 0; + + this._ltIndexCache = []; +} +TokenStreamBase.createTokenData = function(tokens){ + + var nameMap = [], + typeMap = {}, + tokenData = tokens.concat([]), + i = 0, + len = tokenData.length+1; + + tokenData.UNKNOWN = -1; + tokenData.unshift({name:"EOF"}); + + for (; i < len; i++){ + nameMap.push(tokenData[i].name); + tokenData[tokenData[i].name] = i; + if (tokenData[i].text){ + typeMap[tokenData[i].text] = i; + } + } + + tokenData.name = function(tt){ + return nameMap[tt]; + }; + + tokenData.type = function(c){ + return typeMap[c]; + }; + + return tokenData; +}; + +TokenStreamBase.prototype = { + constructor: TokenStreamBase, + match: function(tokenTypes, channel){ + if (!(tokenTypes instanceof Array)){ + tokenTypes = [tokenTypes]; + } + + var tt = this.get(channel), + i = 0, + len = tokenTypes.length; + + while(i < len){ + if (tt == tokenTypes[i++]){ + return true; + } + } + this.unget(); + return false; + }, + mustMatch: function(tokenTypes, channel){ + + var token; + if (!(tokenTypes instanceof Array)){ + tokenTypes = [tokenTypes]; + } + + if (!this.match.apply(this, arguments)){ + token = this.LT(1); + throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name + + " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + } + }, + advance: function(tokenTypes, channel){ + + while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){ + this.get(); + } + + return this.LA(0); + }, + get: function(channel){ + + var tokenInfo = this._tokenData, + reader = this._reader, + value, + i =0, + len = tokenInfo.length, + found = false, + token, + info; + if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){ + + i++; + this._token = this._lt[this._ltIndex++]; + info = tokenInfo[this._token.type]; + while((info.channel !== undefined && channel !== info.channel) && + this._ltIndex < this._lt.length){ + this._token = this._lt[this._ltIndex++]; + info = tokenInfo[this._token.type]; + i++; + } + if ((info.channel === undefined || channel === info.channel) && + this._ltIndex <= this._lt.length){ + this._ltIndexCache.push(i); + return this._token.type; + } + } + token = this._getToken(); + if (token.type > -1 && !tokenInfo[token.type].hide){ + token.channel = tokenInfo[token.type].channel; + this._token = token; + this._lt.push(token); + this._ltIndexCache.push(this._lt.length - this._ltIndex + i); + if (this._lt.length > 5){ + this._lt.shift(); + } + if (this._ltIndexCache.length > 5){ + this._ltIndexCache.shift(); + } + this._ltIndex = this._lt.length; + } + info = tokenInfo[token.type]; + if (info && + (info.hide || + (info.channel !== undefined && channel !== info.channel))){ + return this.get(channel); + } else { + return token.type; + } + }, + LA: function(index){ + var total = index, + tt; + if (index > 0){ + if (index > 5){ + throw new Error("Too much lookahead."); + } + while(total){ + tt = this.get(); + total--; + } + while(total < index){ + this.unget(); + total++; + } + } else if (index < 0){ + + if(this._lt[this._ltIndex+index]){ + tt = this._lt[this._ltIndex+index].type; + } else { + throw new Error("Too much lookbehind."); + } + + } else { + tt = this._token.type; + } + + return tt; + + }, + LT: function(index){ + this.LA(index); + return this._lt[this._ltIndex+index-1]; + }, + peek: function(){ + return this.LA(1); + }, + token: function(){ + return this._token; + }, + tokenName: function(tokenType){ + if (tokenType < 0 || tokenType > this._tokenData.length){ + return "UNKNOWN_TOKEN"; + } else { + return this._tokenData[tokenType].name; + } + }, + tokenType: function(tokenName){ + return this._tokenData[tokenName] || -1; + }, + unget: function(){ + if (this._ltIndexCache.length){ + this._ltIndex -= this._ltIndexCache.pop();//--; + this._token = this._lt[this._ltIndex - 1]; + } else { + throw new Error("Too much lookahead."); + } + } + +}; + + +parserlib.util = { +StringReader: StringReader, +SyntaxError : SyntaxError, +SyntaxUnit : SyntaxUnit, +EventTarget : EventTarget, +TokenStreamBase : TokenStreamBase +}; +})(); +(function(){ +var EventTarget = parserlib.util.EventTarget, +TokenStreamBase = parserlib.util.TokenStreamBase, +StringReader = parserlib.util.StringReader, +SyntaxError = parserlib.util.SyntaxError, +SyntaxUnit = parserlib.util.SyntaxUnit; + +var Colors = { + aliceblue :"#f0f8ff", + antiquewhite :"#faebd7", + aqua :"#00ffff", + aquamarine :"#7fffd4", + azure :"#f0ffff", + beige :"#f5f5dc", + bisque :"#ffe4c4", + black :"#000000", + blanchedalmond :"#ffebcd", + blue :"#0000ff", + blueviolet :"#8a2be2", + brown :"#a52a2a", + burlywood :"#deb887", + cadetblue :"#5f9ea0", + chartreuse :"#7fff00", + chocolate :"#d2691e", + coral :"#ff7f50", + cornflowerblue :"#6495ed", + cornsilk :"#fff8dc", + crimson :"#dc143c", + cyan :"#00ffff", + darkblue :"#00008b", + darkcyan :"#008b8b", + darkgoldenrod :"#b8860b", + darkgray :"#a9a9a9", + darkgrey :"#a9a9a9", + darkgreen :"#006400", + darkkhaki :"#bdb76b", + darkmagenta :"#8b008b", + darkolivegreen :"#556b2f", + darkorange :"#ff8c00", + darkorchid :"#9932cc", + darkred :"#8b0000", + darksalmon :"#e9967a", + darkseagreen :"#8fbc8f", + darkslateblue :"#483d8b", + darkslategray :"#2f4f4f", + darkslategrey :"#2f4f4f", + darkturquoise :"#00ced1", + darkviolet :"#9400d3", + deeppink :"#ff1493", + deepskyblue :"#00bfff", + dimgray :"#696969", + dimgrey :"#696969", + dodgerblue :"#1e90ff", + firebrick :"#b22222", + floralwhite :"#fffaf0", + forestgreen :"#228b22", + fuchsia :"#ff00ff", + gainsboro :"#dcdcdc", + ghostwhite :"#f8f8ff", + gold :"#ffd700", + goldenrod :"#daa520", + gray :"#808080", + grey :"#808080", + green :"#008000", + greenyellow :"#adff2f", + honeydew :"#f0fff0", + hotpink :"#ff69b4", + indianred :"#cd5c5c", + indigo :"#4b0082", + ivory :"#fffff0", + khaki :"#f0e68c", + lavender :"#e6e6fa", + lavenderblush :"#fff0f5", + lawngreen :"#7cfc00", + lemonchiffon :"#fffacd", + lightblue :"#add8e6", + lightcoral :"#f08080", + lightcyan :"#e0ffff", + lightgoldenrodyellow :"#fafad2", + lightgray :"#d3d3d3", + lightgrey :"#d3d3d3", + lightgreen :"#90ee90", + lightpink :"#ffb6c1", + lightsalmon :"#ffa07a", + lightseagreen :"#20b2aa", + lightskyblue :"#87cefa", + lightslategray :"#778899", + lightslategrey :"#778899", + lightsteelblue :"#b0c4de", + lightyellow :"#ffffe0", + lime :"#00ff00", + limegreen :"#32cd32", + linen :"#faf0e6", + magenta :"#ff00ff", + maroon :"#800000", + mediumaquamarine:"#66cdaa", + mediumblue :"#0000cd", + mediumorchid :"#ba55d3", + mediumpurple :"#9370d8", + mediumseagreen :"#3cb371", + mediumslateblue :"#7b68ee", + mediumspringgreen :"#00fa9a", + mediumturquoise :"#48d1cc", + mediumvioletred :"#c71585", + midnightblue :"#191970", + mintcream :"#f5fffa", + mistyrose :"#ffe4e1", + moccasin :"#ffe4b5", + navajowhite :"#ffdead", + navy :"#000080", + oldlace :"#fdf5e6", + olive :"#808000", + olivedrab :"#6b8e23", + orange :"#ffa500", + orangered :"#ff4500", + orchid :"#da70d6", + palegoldenrod :"#eee8aa", + palegreen :"#98fb98", + paleturquoise :"#afeeee", + palevioletred :"#d87093", + papayawhip :"#ffefd5", + peachpuff :"#ffdab9", + peru :"#cd853f", + pink :"#ffc0cb", + plum :"#dda0dd", + powderblue :"#b0e0e6", + purple :"#800080", + red :"#ff0000", + rosybrown :"#bc8f8f", + royalblue :"#4169e1", + saddlebrown :"#8b4513", + salmon :"#fa8072", + sandybrown :"#f4a460", + seagreen :"#2e8b57", + seashell :"#fff5ee", + sienna :"#a0522d", + silver :"#c0c0c0", + skyblue :"#87ceeb", + slateblue :"#6a5acd", + slategray :"#708090", + slategrey :"#708090", + snow :"#fffafa", + springgreen :"#00ff7f", + steelblue :"#4682b4", + tan :"#d2b48c", + teal :"#008080", + thistle :"#d8bfd8", + tomato :"#ff6347", + turquoise :"#40e0d0", + violet :"#ee82ee", + wheat :"#f5deb3", + white :"#ffffff", + whitesmoke :"#f5f5f5", + yellow :"#ffff00", + yellowgreen :"#9acd32", + activeBorder :"Active window border.", + activecaption :"Active window caption.", + appworkspace :"Background color of multiple document interface.", + background :"Desktop background.", + buttonface :"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.", + buttonhighlight :"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", + buttonshadow :"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", + buttontext :"Text on push buttons.", + captiontext :"Text in caption, size box, and scrollbar arrow box.", + graytext :"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.", + greytext :"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.", + highlight :"Item(s) selected in a control.", + highlighttext :"Text of item(s) selected in a control.", + inactiveborder :"Inactive window border.", + inactivecaption :"Inactive window caption.", + inactivecaptiontext :"Color of text in an inactive caption.", + infobackground :"Background color for tooltip controls.", + infotext :"Text color for tooltip controls.", + menu :"Menu background.", + menutext :"Text in menus.", + scrollbar :"Scroll bar gray area.", + threeddarkshadow :"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedface :"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedhighlight :"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedlightshadow :"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedshadow :"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + window :"Window background.", + windowframe :"Window frame.", + windowtext :"Text in windows." +}; +function Combinator(text, line, col){ + + SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE); + this.type = "unknown"; + if (/^\s+$/.test(text)){ + this.type = "descendant"; + } else if (text == ">"){ + this.type = "child"; + } else if (text == "+"){ + this.type = "adjacent-sibling"; + } else if (text == "~"){ + this.type = "sibling"; + } + +} + +Combinator.prototype = new SyntaxUnit(); +Combinator.prototype.constructor = Combinator; +function MediaFeature(name, value){ + + SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE); + this.name = name; + this.value = value; +} + +MediaFeature.prototype = new SyntaxUnit(); +MediaFeature.prototype.constructor = MediaFeature; +function MediaQuery(modifier, mediaType, features, line, col){ + + SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType : "") + (mediaType && features.length > 0 ? " and " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE); + this.modifier = modifier; + this.mediaType = mediaType; + this.features = features; + +} + +MediaQuery.prototype = new SyntaxUnit(); +MediaQuery.prototype.constructor = MediaQuery; +function Parser(options){ + EventTarget.call(this); + + + this.options = options || {}; + + this._tokenStream = null; +} +Parser.DEFAULT_TYPE = 0; +Parser.COMBINATOR_TYPE = 1; +Parser.MEDIA_FEATURE_TYPE = 2; +Parser.MEDIA_QUERY_TYPE = 3; +Parser.PROPERTY_NAME_TYPE = 4; +Parser.PROPERTY_VALUE_TYPE = 5; +Parser.PROPERTY_VALUE_PART_TYPE = 6; +Parser.SELECTOR_TYPE = 7; +Parser.SELECTOR_PART_TYPE = 8; +Parser.SELECTOR_SUB_PART_TYPE = 9; + +Parser.prototype = function(){ + + var proto = new EventTarget(), //new prototype + prop, + additions = { + constructor: Parser, + DEFAULT_TYPE : 0, + COMBINATOR_TYPE : 1, + MEDIA_FEATURE_TYPE : 2, + MEDIA_QUERY_TYPE : 3, + PROPERTY_NAME_TYPE : 4, + PROPERTY_VALUE_TYPE : 5, + PROPERTY_VALUE_PART_TYPE : 6, + SELECTOR_TYPE : 7, + SELECTOR_PART_TYPE : 8, + SELECTOR_SUB_PART_TYPE : 9, + + _stylesheet: function(){ + + var tokenStream = this._tokenStream, + charset = null, + count, + token, + tt; + + this.fire("startstylesheet"); + this._charset(); + + this._skipCruft(); + while (tokenStream.peek() == Tokens.IMPORT_SYM){ + this._import(); + this._skipCruft(); + } + while (tokenStream.peek() == Tokens.NAMESPACE_SYM){ + this._namespace(); + this._skipCruft(); + } + tt = tokenStream.peek(); + while(tt > Tokens.EOF){ + + try { + + switch(tt){ + case Tokens.MEDIA_SYM: + this._media(); + this._skipCruft(); + break; + case Tokens.PAGE_SYM: + this._page(); + this._skipCruft(); + break; + case Tokens.FONT_FACE_SYM: + this._font_face(); + this._skipCruft(); + break; + case Tokens.KEYFRAMES_SYM: + this._keyframes(); + this._skipCruft(); + break; + case Tokens.VIEWPORT_SYM: + this._viewport(); + this._skipCruft(); + break; + case Tokens.UNKNOWN_SYM: //unknown @ rule + tokenStream.get(); + if (!this.options.strict){ + this.fire({ + type: "error", + error: null, + message: "Unknown @ rule: " + tokenStream.LT(0).value + ".", + line: tokenStream.LT(0).startLine, + col: tokenStream.LT(0).startCol + }); + count=0; + while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){ + count++; //keep track of nesting depth + } + + while(count){ + tokenStream.advance([Tokens.RBRACE]); + count--; + } + + } else { + throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol); + } + break; + case Tokens.S: + this._readWhitespace(); + break; + default: + if(!this._ruleset()){ + switch(tt){ + case Tokens.CHARSET_SYM: + token = tokenStream.LT(1); + this._charset(false); + throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol); + case Tokens.IMPORT_SYM: + token = tokenStream.LT(1); + this._import(false); + throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol); + case Tokens.NAMESPACE_SYM: + token = tokenStream.LT(1); + this._namespace(false); + throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol); + default: + tokenStream.get(); //get the last token + this._unexpectedToken(tokenStream.token()); + } + + } + } + } catch(ex) { + if (ex instanceof SyntaxError && !this.options.strict){ + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + } else { + throw ex; + } + } + + tt = tokenStream.peek(); + } + + if (tt != Tokens.EOF){ + this._unexpectedToken(tokenStream.token()); + } + + this.fire("endstylesheet"); + }, + + _charset: function(emit){ + var tokenStream = this._tokenStream, + charset, + token, + line, + col; + + if (tokenStream.match(Tokens.CHARSET_SYM)){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.STRING); + + token = tokenStream.token(); + charset = token.value; + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.SEMICOLON); + + if (emit !== false){ + this.fire({ + type: "charset", + charset:charset, + line: line, + col: col + }); + } + } + }, + + _import: function(emit){ + + var tokenStream = this._tokenStream, + tt, + uri, + importToken, + mediaList = []; + tokenStream.mustMatch(Tokens.IMPORT_SYM); + importToken = tokenStream.token(); + this._readWhitespace(); + + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); + uri = tokenStream.token().value.replace(/^(?:url\()?["']?([^"']+?)["']?\)?$/, "$1"); + + this._readWhitespace(); + + mediaList = this._media_query_list(); + tokenStream.mustMatch(Tokens.SEMICOLON); + this._readWhitespace(); + + if (emit !== false){ + this.fire({ + type: "import", + uri: uri, + media: mediaList, + line: importToken.startLine, + col: importToken.startCol + }); + } + + }, + + _namespace: function(emit){ + + var tokenStream = this._tokenStream, + line, + col, + prefix, + uri; + tokenStream.mustMatch(Tokens.NAMESPACE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + this._readWhitespace(); + if (tokenStream.match(Tokens.IDENT)){ + prefix = tokenStream.token().value; + this._readWhitespace(); + } + + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); + uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1"); + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.SEMICOLON); + this._readWhitespace(); + + if (emit !== false){ + this.fire({ + type: "namespace", + prefix: prefix, + uri: uri, + line: line, + col: col + }); + } + + }, + + _media: function(){ + var tokenStream = this._tokenStream, + line, + col, + mediaList;// = []; + tokenStream.mustMatch(Tokens.MEDIA_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + mediaList = this._media_query_list(); + + tokenStream.mustMatch(Tokens.LBRACE); + this._readWhitespace(); + + this.fire({ + type: "startmedia", + media: mediaList, + line: line, + col: col + }); + + while(true) { + if (tokenStream.peek() == Tokens.PAGE_SYM){ + this._page(); + } else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){ + this._font_face(); + } else if (tokenStream.peek() == Tokens.VIEWPORT_SYM){ + this._viewport(); + } else if (!this._ruleset()){ + break; + } + } + + tokenStream.mustMatch(Tokens.RBRACE); + this._readWhitespace(); + + this.fire({ + type: "endmedia", + media: mediaList, + line: line, + col: col + }); + }, + _media_query_list: function(){ + var tokenStream = this._tokenStream, + mediaList = []; + + + this._readWhitespace(); + + if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){ + mediaList.push(this._media_query()); + } + + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + mediaList.push(this._media_query()); + } + + return mediaList; + }, + _media_query: function(){ + var tokenStream = this._tokenStream, + type = null, + ident = null, + token = null, + expressions = []; + + if (tokenStream.match(Tokens.IDENT)){ + ident = tokenStream.token().value.toLowerCase(); + if (ident != "only" && ident != "not"){ + tokenStream.unget(); + ident = null; + } else { + token = tokenStream.token(); + } + } + + this._readWhitespace(); + + if (tokenStream.peek() == Tokens.IDENT){ + type = this._media_type(); + if (token === null){ + token = tokenStream.token(); + } + } else if (tokenStream.peek() == Tokens.LPAREN){ + if (token === null){ + token = tokenStream.LT(1); + } + expressions.push(this._media_expression()); + } + + if (type === null && expressions.length === 0){ + return null; + } else { + this._readWhitespace(); + while (tokenStream.match(Tokens.IDENT)){ + if (tokenStream.token().value.toLowerCase() != "and"){ + this._unexpectedToken(tokenStream.token()); + } + + this._readWhitespace(); + expressions.push(this._media_expression()); + } + } + + return new MediaQuery(ident, type, expressions, token.startLine, token.startCol); + }, + _media_type: function(){ + return this._media_feature(); + }, + _media_expression: function(){ + var tokenStream = this._tokenStream, + feature = null, + token, + expression = null; + + tokenStream.mustMatch(Tokens.LPAREN); + + feature = this._media_feature(); + this._readWhitespace(); + + if (tokenStream.match(Tokens.COLON)){ + this._readWhitespace(); + token = tokenStream.LT(1); + expression = this._expression(); + } + + tokenStream.mustMatch(Tokens.RPAREN); + this._readWhitespace(); + + return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null)); + }, + _media_feature: function(){ + var tokenStream = this._tokenStream; + + tokenStream.mustMatch(Tokens.IDENT); + + return SyntaxUnit.fromToken(tokenStream.token()); + }, + _page: function(){ + var tokenStream = this._tokenStream, + line, + col, + identifier = null, + pseudoPage = null; + tokenStream.mustMatch(Tokens.PAGE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + if (tokenStream.match(Tokens.IDENT)){ + identifier = tokenStream.token().value; + if (identifier.toLowerCase() === "auto"){ + this._unexpectedToken(tokenStream.token()); + } + } + if (tokenStream.peek() == Tokens.COLON){ + pseudoPage = this._pseudo_page(); + } + + this._readWhitespace(); + + this.fire({ + type: "startpage", + id: identifier, + pseudo: pseudoPage, + line: line, + col: col + }); + + this._readDeclarations(true, true); + + this.fire({ + type: "endpage", + id: identifier, + pseudo: pseudoPage, + line: line, + col: col + }); + + }, + _margin: function(){ + var tokenStream = this._tokenStream, + line, + col, + marginSym = this._margin_sym(); + + if (marginSym){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this.fire({ + type: "startpagemargin", + margin: marginSym, + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endpagemargin", + margin: marginSym, + line: line, + col: col + }); + return true; + } else { + return false; + } + }, + _margin_sym: function(){ + + var tokenStream = this._tokenStream; + + if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM, + Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM, + Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM, + Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM, + Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM, + Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM, + Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM])) + { + return SyntaxUnit.fromToken(tokenStream.token()); + } else { + return null; + } + + }, + + _pseudo_page: function(){ + + var tokenStream = this._tokenStream; + + tokenStream.mustMatch(Tokens.COLON); + tokenStream.mustMatch(Tokens.IDENT); + + return tokenStream.token().value; + }, + + _font_face: function(){ + var tokenStream = this._tokenStream, + line, + col; + tokenStream.mustMatch(Tokens.FONT_FACE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + this.fire({ + type: "startfontface", + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endfontface", + line: line, + col: col + }); + }, + + _viewport: function(){ + var tokenStream = this._tokenStream, + line, + col; + + tokenStream.mustMatch(Tokens.VIEWPORT_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + this.fire({ + type: "startviewport", + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endviewport", + line: line, + col: col + }); + + }, + + _operator: function(inFunction){ + + var tokenStream = this._tokenStream, + token = null; + + if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) || + (inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))){ + token = tokenStream.token(); + this._readWhitespace(); + } + return token ? PropertyValuePart.fromToken(token) : null; + + }, + + _combinator: function(){ + + var tokenStream = this._tokenStream, + value = null, + token; + + if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){ + token = tokenStream.token(); + value = new Combinator(token.value, token.startLine, token.startCol); + this._readWhitespace(); + } + + return value; + }, + + _unary_operator: function(){ + + var tokenStream = this._tokenStream; + + if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){ + return tokenStream.token().value; + } else { + return null; + } + }, + + _property: function(){ + + var tokenStream = this._tokenStream, + value = null, + hack = null, + tokenValue, + token, + line, + col; + if (tokenStream.peek() == Tokens.STAR && this.options.starHack){ + tokenStream.get(); + token = tokenStream.token(); + hack = token.value; + line = token.startLine; + col = token.startCol; + } + + if(tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + tokenValue = token.value; + if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){ + hack = "_"; + tokenValue = tokenValue.substring(1); + } + + value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol)); + this._readWhitespace(); + } + + return value; + }, + _ruleset: function(){ + + var tokenStream = this._tokenStream, + tt, + selectors; + try { + selectors = this._selectors_group(); + } catch (ex){ + if (ex instanceof SyntaxError && !this.options.strict){ + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + tt = tokenStream.advance([Tokens.RBRACE]); + if (tt == Tokens.RBRACE){ + } else { + throw ex; + } + + } else { + throw ex; + } + return true; + } + if (selectors){ + + this.fire({ + type: "startrule", + selectors: selectors, + line: selectors[0].line, + col: selectors[0].col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endrule", + selectors: selectors, + line: selectors[0].line, + col: selectors[0].col + }); + + } + + return selectors; + + }, + _selectors_group: function(){ + var tokenStream = this._tokenStream, + selectors = [], + selector; + + selector = this._selector(); + if (selector !== null){ + + selectors.push(selector); + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + selector = this._selector(); + if (selector !== null){ + selectors.push(selector); + } else { + this._unexpectedToken(tokenStream.LT(1)); + } + } + } + + return selectors.length ? selectors : null; + }, + _selector: function(){ + + var tokenStream = this._tokenStream, + selector = [], + nextSelector = null, + combinator = null, + ws = null; + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null){ + return null; + } + + selector.push(nextSelector); + + do { + combinator = this._combinator(); + + if (combinator !== null){ + selector.push(combinator); + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null){ + this._unexpectedToken(tokenStream.LT(1)); + } else { + selector.push(nextSelector); + } + } else { + if (this._readWhitespace()){ + ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol); + combinator = this._combinator(); + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null){ + if (combinator !== null){ + this._unexpectedToken(tokenStream.LT(1)); + } + } else { + + if (combinator !== null){ + selector.push(combinator); + } else { + selector.push(ws); + } + + selector.push(nextSelector); + } + } else { + break; + } + + } + } while(true); + + return new Selector(selector, selector[0].line, selector[0].col); + }, + _simple_selector_sequence: function(){ + + var tokenStream = this._tokenStream, + elementName = null, + modifiers = [], + selectorText= "", + components = [ + function(){ + return tokenStream.match(Tokens.HASH) ? + new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : + null; + }, + this._class, + this._attrib, + this._pseudo, + this._negation + ], + i = 0, + len = components.length, + component = null, + found = false, + line, + col; + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + + elementName = this._type_selector(); + if (!elementName){ + elementName = this._universal(); + } + + if (elementName !== null){ + selectorText += elementName; + } + + while(true){ + if (tokenStream.peek() === Tokens.S){ + break; + } + while(i < len && component === null){ + component = components[i++].call(this); + } + + if (component === null){ + if (selectorText === ""){ + return null; + } else { + break; + } + } else { + i = 0; + modifiers.push(component); + selectorText += component.toString(); + component = null; + } + } + + + return selectorText !== "" ? + new SelectorPart(elementName, modifiers, selectorText, line, col) : + null; + }, + _type_selector: function(){ + + var tokenStream = this._tokenStream, + ns = this._namespace_prefix(), + elementName = this._element_name(); + + if (!elementName){ + if (ns){ + tokenStream.unget(); + if (ns.length > 1){ + tokenStream.unget(); + } + } + + return null; + } else { + if (ns){ + elementName.text = ns + elementName.text; + elementName.col -= ns.length; + } + return elementName; + } + }, + _class: function(){ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.DOT)){ + tokenStream.mustMatch(Tokens.IDENT); + token = tokenStream.token(); + return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1); + } else { + return null; + } + + }, + _element_name: function(){ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol); + + } else { + return null; + } + }, + _namespace_prefix: function(){ + var tokenStream = this._tokenStream, + value = ""; + if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){ + + if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){ + value += tokenStream.token().value; + } + + tokenStream.mustMatch(Tokens.PIPE); + value += "|"; + + } + + return value.length ? value : null; + }, + _universal: function(){ + var tokenStream = this._tokenStream, + value = "", + ns; + + ns = this._namespace_prefix(); + if(ns){ + value += ns; + } + + if(tokenStream.match(Tokens.STAR)){ + value += "*"; + } + + return value.length ? value : null; + + }, + _attrib: function(){ + + var tokenStream = this._tokenStream, + value = null, + ns, + token; + + if (tokenStream.match(Tokens.LBRACKET)){ + token = tokenStream.token(); + value = token.value; + value += this._readWhitespace(); + + ns = this._namespace_prefix(); + + if (ns){ + value += ns; + } + + tokenStream.mustMatch(Tokens.IDENT); + value += tokenStream.token().value; + value += this._readWhitespace(); + + if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH, + Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){ + + value += tokenStream.token().value; + value += this._readWhitespace(); + + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); + value += tokenStream.token().value; + value += this._readWhitespace(); + } + + tokenStream.mustMatch(Tokens.RBRACKET); + + return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol); + } else { + return null; + } + }, + _pseudo: function(){ + + var tokenStream = this._tokenStream, + pseudo = null, + colons = ":", + line, + col; + + if (tokenStream.match(Tokens.COLON)){ + + if (tokenStream.match(Tokens.COLON)){ + colons += ":"; + } + + if (tokenStream.match(Tokens.IDENT)){ + pseudo = tokenStream.token().value; + line = tokenStream.token().startLine; + col = tokenStream.token().startCol - colons.length; + } else if (tokenStream.peek() == Tokens.FUNCTION){ + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol - colons.length; + pseudo = this._functional_pseudo(); + } + + if (pseudo){ + pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col); + } + } + + return pseudo; + }, + _functional_pseudo: function(){ + + var tokenStream = this._tokenStream, + value = null; + + if(tokenStream.match(Tokens.FUNCTION)){ + value = tokenStream.token().value; + value += this._readWhitespace(); + value += this._expression(); + tokenStream.mustMatch(Tokens.RPAREN); + value += ")"; + } + + return value; + }, + _expression: function(){ + + var tokenStream = this._tokenStream, + value = ""; + + while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION, + Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH, + Tokens.FREQ, Tokens.ANGLE, Tokens.TIME, + Tokens.RESOLUTION, Tokens.SLASH])){ + + value += tokenStream.token().value; + value += this._readWhitespace(); + } + + return value.length ? value : null; + + }, + _negation: function(){ + + var tokenStream = this._tokenStream, + line, + col, + value = "", + arg, + subpart = null; + + if (tokenStream.match(Tokens.NOT)){ + value = tokenStream.token().value; + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + value += this._readWhitespace(); + arg = this._negation_arg(); + value += arg; + value += this._readWhitespace(); + tokenStream.match(Tokens.RPAREN); + value += tokenStream.token().value; + + subpart = new SelectorSubPart(value, "not", line, col); + subpart.args.push(arg); + } + + return subpart; + }, + _negation_arg: function(){ + + var tokenStream = this._tokenStream, + args = [ + this._type_selector, + this._universal, + function(){ + return tokenStream.match(Tokens.HASH) ? + new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : + null; + }, + this._class, + this._attrib, + this._pseudo + ], + arg = null, + i = 0, + len = args.length, + elementName, + line, + col, + part; + + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + + while(i < len && arg === null){ + + arg = args[i].call(this); + i++; + } + if (arg === null){ + this._unexpectedToken(tokenStream.LT(1)); + } + if (arg.type == "elementName"){ + part = new SelectorPart(arg, [], arg.toString(), line, col); + } else { + part = new SelectorPart(null, [arg], arg.toString(), line, col); + } + + return part; + }, + + _declaration: function(){ + + var tokenStream = this._tokenStream, + property = null, + expr = null, + prio = null, + error = null, + invalid = null, + propertyName= ""; + + property = this._property(); + if (property !== null){ + + tokenStream.mustMatch(Tokens.COLON); + this._readWhitespace(); + + expr = this._expr(); + if (!expr || expr.length === 0){ + this._unexpectedToken(tokenStream.LT(1)); + } + + prio = this._prio(); + propertyName = property.toString(); + if (this.options.starHack && property.hack == "*" || + this.options.underscoreHack && property.hack == "_") { + + propertyName = property.text; + } + + try { + this._validateProperty(propertyName, expr); + } catch (ex) { + invalid = ex; + } + + this.fire({ + type: "property", + property: property, + value: expr, + important: prio, + line: property.line, + col: property.col, + invalid: invalid + }); + + return true; + } else { + return false; + } + }, + + _prio: function(){ + + var tokenStream = this._tokenStream, + result = tokenStream.match(Tokens.IMPORTANT_SYM); + + this._readWhitespace(); + return result; + }, + + _expr: function(inFunction){ + + var tokenStream = this._tokenStream, + values = [], + value = null, + operator = null; + + value = this._term(inFunction); + if (value !== null){ + + values.push(value); + + do { + operator = this._operator(inFunction); + if (operator){ + values.push(operator); + } /*else { + values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); + valueParts = []; + }*/ + + value = this._term(inFunction); + + if (value === null){ + break; + } else { + values.push(value); + } + } while(true); + } + + return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null; + }, + + _term: function(inFunction){ + + var tokenStream = this._tokenStream, + unary = null, + value = null, + endChar = null, + token, + line, + col; + unary = this._unary_operator(); + if (unary !== null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){ + + value = this._ie_function(); + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + } else if (inFunction && tokenStream.match([Tokens.LPAREN, Tokens.LBRACE, Tokens.LBRACKET])){ + + token = tokenStream.token(); + endChar = token.endChar; + value = token.value + this._expr(inFunction).text; + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + tokenStream.mustMatch(Tokens.type(endChar)); + value += endChar; + this._readWhitespace(); + } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH, + Tokens.ANGLE, Tokens.TIME, + Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){ + + value = tokenStream.token().value; + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + this._readWhitespace(); + } else { + token = this._hexcolor(); + if (token === null){ + if (unary === null){ + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + } + if (value === null){ + if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){ + value = this._ie_function(); + } else { + value = this._function(); + } + } + + } else { + value = token.value; + if (unary === null){ + line = token.startLine; + col = token.startCol; + } + } + + } + + return value !== null ? + new PropertyValuePart(unary !== null ? unary + value : value, line, col) : + null; + + }, + + _function: function(){ + + var tokenStream = this._tokenStream, + functionText = null, + expr = null, + lt; + + if (tokenStream.match(Tokens.FUNCTION)){ + functionText = tokenStream.token().value; + this._readWhitespace(); + expr = this._expr(true); + functionText += expr; + if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){ + do { + + if (this._readWhitespace()){ + functionText += tokenStream.token().value; + } + if (tokenStream.LA(0) == Tokens.COMMA){ + functionText += tokenStream.token().value; + } + + tokenStream.match(Tokens.IDENT); + functionText += tokenStream.token().value; + + tokenStream.match(Tokens.EQUALS); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ + tokenStream.get(); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + } + } while(tokenStream.match([Tokens.COMMA, Tokens.S])); + } + + tokenStream.match(Tokens.RPAREN); + functionText += ")"; + this._readWhitespace(); + } + + return functionText; + }, + + _ie_function: function(){ + + var tokenStream = this._tokenStream, + functionText = null, + expr = null, + lt; + if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){ + functionText = tokenStream.token().value; + + do { + + if (this._readWhitespace()){ + functionText += tokenStream.token().value; + } + if (tokenStream.LA(0) == Tokens.COMMA){ + functionText += tokenStream.token().value; + } + + tokenStream.match(Tokens.IDENT); + functionText += tokenStream.token().value; + + tokenStream.match(Tokens.EQUALS); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ + tokenStream.get(); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + } + } while(tokenStream.match([Tokens.COMMA, Tokens.S])); + + tokenStream.match(Tokens.RPAREN); + functionText += ")"; + this._readWhitespace(); + } + + return functionText; + }, + + _hexcolor: function(){ + + var tokenStream = this._tokenStream, + token = null, + color; + + if(tokenStream.match(Tokens.HASH)){ + + token = tokenStream.token(); + color = token.value; + if (!/#[a-f0-9]{3,6}/i.test(color)){ + throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + } + this._readWhitespace(); + } + + return token; + }, + + _keyframes: function(){ + var tokenStream = this._tokenStream, + token, + tt, + name, + prefix = ""; + + tokenStream.mustMatch(Tokens.KEYFRAMES_SYM); + token = tokenStream.token(); + if (/^@\-([^\-]+)\-/.test(token.value)) { + prefix = RegExp.$1; + } + + this._readWhitespace(); + name = this._keyframe_name(); + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.LBRACE); + + this.fire({ + type: "startkeyframes", + name: name, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); + + this._readWhitespace(); + tt = tokenStream.peek(); + while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) { + this._keyframe_rule(); + this._readWhitespace(); + tt = tokenStream.peek(); + } + + this.fire({ + type: "endkeyframes", + name: name, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.RBRACE); + + }, + + _keyframe_name: function(){ + var tokenStream = this._tokenStream, + token; + + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); + return SyntaxUnit.fromToken(tokenStream.token()); + }, + + _keyframe_rule: function(){ + var tokenStream = this._tokenStream, + token, + keyList = this._key_list(); + + this.fire({ + type: "startkeyframerule", + keys: keyList, + line: keyList[0].line, + col: keyList[0].col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endkeyframerule", + keys: keyList, + line: keyList[0].line, + col: keyList[0].col + }); + + }, + + _key_list: function(){ + var tokenStream = this._tokenStream, + token, + key, + keyList = []; + keyList.push(this._key()); + + this._readWhitespace(); + + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + keyList.push(this._key()); + this._readWhitespace(); + } + + return keyList; + }, + + _key: function(){ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.PERCENTAGE)){ + return SyntaxUnit.fromToken(tokenStream.token()); + } else if (tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + + if (/from|to/i.test(token.value)){ + return SyntaxUnit.fromToken(token); + } + + tokenStream.unget(); + } + this._unexpectedToken(tokenStream.LT(1)); + }, + _skipCruft: function(){ + while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){ + } + }, + _readDeclarations: function(checkStart, readMargins){ + var tokenStream = this._tokenStream, + tt; + + + this._readWhitespace(); + + if (checkStart){ + tokenStream.mustMatch(Tokens.LBRACE); + } + + this._readWhitespace(); + + try { + + while(true){ + + if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){ + } else if (this._declaration()){ + if (!tokenStream.match(Tokens.SEMICOLON)){ + break; + } + } else { + break; + } + this._readWhitespace(); + } + + tokenStream.mustMatch(Tokens.RBRACE); + this._readWhitespace(); + + } catch (ex) { + if (ex instanceof SyntaxError && !this.options.strict){ + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]); + if (tt == Tokens.SEMICOLON){ + this._readDeclarations(false, readMargins); + } else if (tt != Tokens.RBRACE){ + throw ex; + } + + } else { + throw ex; + } + } + + }, + _readWhitespace: function(){ + + var tokenStream = this._tokenStream, + ws = ""; + + while(tokenStream.match(Tokens.S)){ + ws += tokenStream.token().value; + } + + return ws; + }, + _unexpectedToken: function(token){ + throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + }, + _verifyEnd: function(){ + if (this._tokenStream.LA(1) != Tokens.EOF){ + this._unexpectedToken(this._tokenStream.LT(1)); + } + }, + _validateProperty: function(property, value){ + Validation.validate(property, value); + }, + + parse: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + this._stylesheet(); + }, + + parseStyleSheet: function(input){ + return this.parse(input); + }, + + parseMediaQuery: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + var result = this._media_query(); + this._verifyEnd(); + return result; + }, + parsePropertyValue: function(input){ + + this._tokenStream = new TokenStream(input, Tokens); + this._readWhitespace(); + + var result = this._expr(); + this._readWhitespace(); + this._verifyEnd(); + return result; + }, + parseRule: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + this._readWhitespace(); + + var result = this._ruleset(); + this._readWhitespace(); + this._verifyEnd(); + return result; + }, + parseSelector: function(input){ + + this._tokenStream = new TokenStream(input, Tokens); + this._readWhitespace(); + + var result = this._selector(); + this._readWhitespace(); + this._verifyEnd(); + return result; + }, + parseStyleAttribute: function(input){ + input += "}"; // for error recovery in _readDeclarations() + this._tokenStream = new TokenStream(input, Tokens); + this._readDeclarations(); + } + }; + for (prop in additions){ + if (additions.hasOwnProperty(prop)){ + proto[prop] = additions[prop]; + } + } + + return proto; +}(); +var Properties = { + "align-items" : "flex-start | flex-end | center | baseline | stretch", + "align-content" : "flex-start | flex-end | center | space-between | space-around | stretch", + "align-self" : "auto | flex-start | flex-end | center | baseline | stretch", + "-webkit-align-items" : "flex-start | flex-end | center | baseline | stretch", + "-webkit-align-content" : "flex-start | flex-end | center | space-between | space-around | stretch", + "-webkit-align-self" : "auto | flex-start | flex-end | center | baseline | stretch", + "alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | | ", + "alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical", + "animation" : 1, + "animation-delay" : { multi: "
    " + ].join(""); + })(); + + function paletteTemplate (p, color, className, opts) { + var html = []; + for (var i = 0; i < p.length; i++) { + var current = p[i]; + if(current) { + var tiny = tinycolor(current); + var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light"; + c += (tinycolor.equals(color, current)) ? " sp-thumb-active" : ""; + var formattedString = tiny.toString(opts.preferredFormat || "rgb"); + var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter(); + html.push(''); + } else { + var cls = 'sp-clear-display'; + html.push($('
    ') + .append($('') + .attr('title', opts.noColorSelectedText) + ) + .html() + ); + } + } + return "
    " + html.join('') + "
    "; + } + + function hideAll() { + for (var i = 0; i < spectrums.length; i++) { + if (spectrums[i]) { + spectrums[i].hide(); + } + } + } + + function instanceOptions(o, callbackContext) { + var opts = $.extend({}, defaultOpts, o); + opts.callbacks = { + 'move': bind(opts.move, callbackContext), + 'change': bind(opts.change, callbackContext), + 'show': bind(opts.show, callbackContext), + 'hide': bind(opts.hide, callbackContext), + 'beforeShow': bind(opts.beforeShow, callbackContext) + }; + + return opts; + } + + function spectrum(element, o) { + + var opts = instanceOptions(o, element), + flat = opts.flat, + showSelectionPalette = opts.showSelectionPalette, + localStorageKey = opts.localStorageKey, + theme = opts.theme, + callbacks = opts.callbacks, + resize = throttle(reflow, 10), + visible = false, + isDragging = false, + dragWidth = 0, + dragHeight = 0, + dragHelperHeight = 0, + slideHeight = 0, + slideWidth = 0, + alphaWidth = 0, + alphaSlideHelperWidth = 0, + slideHelperHeight = 0, + currentHue = 0, + currentSaturation = 0, + currentValue = 0, + currentAlpha = 1, + palette = [], + paletteArray = [], + paletteLookup = {}, + selectionPalette = opts.selectionPalette.slice(0), + maxSelectionSize = opts.maxSelectionSize, + draggingClass = "sp-dragging", + shiftMovementDirection = null; + + var doc = element.ownerDocument, + body = doc.body, + boundElement = $(element), + disabled = false, + container = $(markup, doc).addClass(theme), + pickerContainer = container.find(".sp-picker-container"), + dragger = container.find(".sp-color"), + dragHelper = container.find(".sp-dragger"), + slider = container.find(".sp-hue"), + slideHelper = container.find(".sp-slider"), + alphaSliderInner = container.find(".sp-alpha-inner"), + alphaSlider = container.find(".sp-alpha"), + alphaSlideHelper = container.find(".sp-alpha-handle"), + textInput = container.find(".sp-input"), + paletteContainer = container.find(".sp-palette"), + initialColorContainer = container.find(".sp-initial"), + cancelButton = container.find(".sp-cancel"), + clearButton = container.find(".sp-clear"), + chooseButton = container.find(".sp-choose"), + toggleButton = container.find(".sp-palette-toggle"), + isInput = boundElement.is("input"), + isInputTypeColor = isInput && boundElement.attr("type") === "color" && inputTypeColorSupport(), + shouldReplace = isInput && !flat, + replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className).addClass(opts.replacerClassName) : $([]), + offsetElement = (shouldReplace) ? replacer : boundElement, + previewElement = replacer.find(".sp-preview-inner"), + initialColor = opts.color || (isInput && boundElement.val()), + colorOnShow = false, + currentPreferredFormat = opts.preferredFormat, + clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange, + isEmpty = !initialColor, + allowEmpty = opts.allowEmpty && !isInputTypeColor; + + function applyOptions() { + + if (opts.showPaletteOnly) { + opts.showPalette = true; + } + + toggleButton.text(opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText); + + if (opts.palette) { + palette = opts.palette.slice(0); + paletteArray = $.isArray(palette[0]) ? palette : [palette]; + paletteLookup = {}; + for (var i = 0; i < paletteArray.length; i++) { + for (var j = 0; j < paletteArray[i].length; j++) { + var rgb = tinycolor(paletteArray[i][j]).toRgbString(); + paletteLookup[rgb] = true; + } + } + } + + container.toggleClass("sp-flat", flat); + container.toggleClass("sp-input-disabled", !opts.showInput); + container.toggleClass("sp-alpha-enabled", opts.showAlpha); + container.toggleClass("sp-clear-enabled", allowEmpty); + container.toggleClass("sp-buttons-disabled", !opts.showButtons); + container.toggleClass("sp-palette-buttons-disabled", !opts.togglePaletteOnly); + container.toggleClass("sp-palette-disabled", !opts.showPalette); + container.toggleClass("sp-palette-only", opts.showPaletteOnly); + container.toggleClass("sp-initial-disabled", !opts.showInitial); + container.addClass(opts.className).addClass(opts.containerClassName); + + reflow(); + } + + function initialize() { + + if (IE) { + container.find("*:not(input)").attr("unselectable", "on"); + } + + applyOptions(); + + if (shouldReplace) { + boundElement.after(replacer).hide(); + } + + if (!allowEmpty) { + clearButton.hide(); + } + + if (flat) { + boundElement.after(container).hide(); + } + else { + + var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo); + if (appendTo.length !== 1) { + appendTo = $("body"); + } + + appendTo.append(container); + } + + updateSelectionPaletteFromStorage(); + + offsetElement.on("click.spectrum touchstart.spectrum", function (e) { + if (!disabled) { + toggle(); + } + + e.stopPropagation(); + + if (!$(e.target).is("input")) { + e.preventDefault(); + } + }); + + if(boundElement.is(":disabled") || (opts.disabled === true)) { + disable(); + } + + // Prevent clicks from bubbling up to document. This would cause it to be hidden. + container.click(stopPropagation); + + // Handle user typed input + textInput.change(setFromTextInput); + textInput.on("paste", function () { + setTimeout(setFromTextInput, 1); + }); + textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } }); + + cancelButton.text(opts.cancelText); + cancelButton.on("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + revert(); + hide(); + }); + + clearButton.attr("title", opts.clearText); + clearButton.on("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + isEmpty = true; + move(); + + if(flat) { + //for the flat style, this is a change event + updateOriginalInput(true); + } + }); + + chooseButton.text(opts.chooseText); + chooseButton.on("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + + if (IE && textInput.is(":focus")) { + textInput.trigger('change'); + } + + if (isValid()) { + updateOriginalInput(true); + hide(); + } + }); + + toggleButton.text(opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText); + toggleButton.on("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + + opts.showPaletteOnly = !opts.showPaletteOnly; + + // To make sure the Picker area is drawn on the right, next to the + // Palette area (and not below the palette), first move the Palette + // to the left to make space for the picker, plus 5px extra. + // The 'applyOptions' function puts the whole container back into place + // and takes care of the button-text and the sp-palette-only CSS class. + if (!opts.showPaletteOnly && !flat) { + container.css('left', '-=' + (pickerContainer.outerWidth(true) + 5)); + } + applyOptions(); + }); + + draggable(alphaSlider, function (dragX, dragY, e) { + currentAlpha = (dragX / alphaWidth); + isEmpty = false; + if (e.shiftKey) { + currentAlpha = Math.round(currentAlpha * 10) / 10; + } + + move(); + }, dragStart, dragStop); + + draggable(slider, function (dragX, dragY) { + currentHue = parseFloat(dragY / slideHeight); + isEmpty = false; + if (!opts.showAlpha) { + currentAlpha = 1; + } + move(); + }, dragStart, dragStop); + + draggable(dragger, function (dragX, dragY, e) { + + // shift+drag should snap the movement to either the x or y axis. + if (!e.shiftKey) { + shiftMovementDirection = null; + } + else if (!shiftMovementDirection) { + var oldDragX = currentSaturation * dragWidth; + var oldDragY = dragHeight - (currentValue * dragHeight); + var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY); + + shiftMovementDirection = furtherFromX ? "x" : "y"; + } + + var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x"; + var setValue = !shiftMovementDirection || shiftMovementDirection === "y"; + + if (setSaturation) { + currentSaturation = parseFloat(dragX / dragWidth); + } + if (setValue) { + currentValue = parseFloat((dragHeight - dragY) / dragHeight); + } + + isEmpty = false; + if (!opts.showAlpha) { + currentAlpha = 1; + } + + move(); + + }, dragStart, dragStop); + + if (!!initialColor) { + set(initialColor); + + // In case color was black - update the preview UI and set the format + // since the set function will not run (default color is black). + updateUI(); + currentPreferredFormat = opts.preferredFormat || tinycolor(initialColor).format; + + addColorToSelectionPalette(initialColor); + } + else { + updateUI(); + } + + if (flat) { + show(); + } + + function paletteElementClick(e) { + if (e.data && e.data.ignore) { + set($(e.target).closest(".sp-thumb-el").data("color")); + move(); + } + else { + set($(e.target).closest(".sp-thumb-el").data("color")); + move(); + + // If the picker is going to close immediately, a palette selection + // is a change. Otherwise, it's a move only. + if (opts.hideAfterPaletteSelect) { + updateOriginalInput(true); + hide(); + } else { + updateOriginalInput(); + } + } + + return false; + } + + var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum"; + paletteContainer.on(paletteEvent, ".sp-thumb-el", paletteElementClick); + initialColorContainer.on(paletteEvent, ".sp-thumb-el:nth-child(1)", { ignore: true }, paletteElementClick); + } + + function updateSelectionPaletteFromStorage() { + + if (localStorageKey && window.localStorage) { + + // Migrate old palettes over to new format. May want to remove this eventually. + try { + var oldPalette = window.localStorage[localStorageKey].split(",#"); + if (oldPalette.length > 1) { + delete window.localStorage[localStorageKey]; + $.each(oldPalette, function(i, c) { + addColorToSelectionPalette(c); + }); + } + } + catch(e) { } + + try { + selectionPalette = window.localStorage[localStorageKey].split(";"); + } + catch (e) { } + } + } + + function addColorToSelectionPalette(color) { + if (showSelectionPalette) { + var rgb = tinycolor(color).toRgbString(); + if (!paletteLookup[rgb] && $.inArray(rgb, selectionPalette) === -1) { + selectionPalette.push(rgb); + while(selectionPalette.length > maxSelectionSize) { + selectionPalette.shift(); + } + } + + if (localStorageKey && window.localStorage) { + try { + window.localStorage[localStorageKey] = selectionPalette.join(";"); + } + catch(e) { } + } + } + } + + function getUniqueSelectionPalette() { + var unique = []; + if (opts.showPalette) { + for (var i = 0; i < selectionPalette.length; i++) { + var rgb = tinycolor(selectionPalette[i]).toRgbString(); + + if (!paletteLookup[rgb]) { + unique.push(selectionPalette[i]); + } + } + } + + return unique.reverse().slice(0, opts.maxSelectionSize); + } + + function drawPalette() { + + var currentColor = get(); + + var html = $.map(paletteArray, function (palette, i) { + return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i, opts); + }); + + updateSelectionPaletteFromStorage(); + + if (selectionPalette) { + html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection", opts)); + } + + paletteContainer.html(html.join("")); + } + + function drawInitial() { + if (opts.showInitial) { + var initial = colorOnShow; + var current = get(); + initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial", opts)); + } + } + + function dragStart() { + if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) { + reflow(); + } + isDragging = true; + container.addClass(draggingClass); + shiftMovementDirection = null; + boundElement.trigger('dragstart.spectrum', [ get() ]); + } + + function dragStop() { + isDragging = false; + container.removeClass(draggingClass); + boundElement.trigger('dragstop.spectrum', [ get() ]); + } + + function setFromTextInput() { + + var value = textInput.val(); + + if ((value === null || value === "") && allowEmpty) { + set(null); + move(); + updateOriginalInput(); + } + else { + var tiny = tinycolor(value); + if (tiny.isValid()) { + set(tiny); + move(); + updateOriginalInput(); + } + else { + textInput.addClass("sp-validation-error"); + } + } + } + + function toggle() { + if (visible) { + hide(); + } + else { + show(); + } + } + + function show() { + var event = $.Event('beforeShow.spectrum'); + + if (visible) { + reflow(); + return; + } + + boundElement.trigger(event, [ get() ]); + + if (callbacks.beforeShow(get()) === false || event.isDefaultPrevented()) { + return; + } + + hideAll(); + visible = true; + + $(doc).on("keydown.spectrum", onkeydown); + $(doc).on("click.spectrum", clickout); + $(window).on("resize.spectrum", resize); + replacer.addClass("sp-active"); + container.removeClass("sp-hidden"); + + reflow(); + updateUI(); + + colorOnShow = get(); + + drawInitial(); + callbacks.show(colorOnShow); + boundElement.trigger('show.spectrum', [ colorOnShow ]); + } + + function onkeydown(e) { + // Close on ESC + if (e.keyCode === 27) { + hide(); + } + } + + function clickout(e) { + // Return on right click. + if (e.button == 2) { return; } + + // If a drag event was happening during the mouseup, don't hide + // on click. + if (isDragging) { return; } + + if (clickoutFiresChange) { + updateOriginalInput(true); + } + else { + revert(); + } + hide(); + } + + function hide() { + // Return if hiding is unnecessary + if (!visible || flat) { return; } + visible = false; + + $(doc).off("keydown.spectrum", onkeydown); + $(doc).off("click.spectrum", clickout); + $(window).off("resize.spectrum", resize); + + replacer.removeClass("sp-active"); + container.addClass("sp-hidden"); + + callbacks.hide(get()); + boundElement.trigger('hide.spectrum', [ get() ]); + } + + function revert() { + set(colorOnShow, true); + updateOriginalInput(true); + } + + function set(color, ignoreFormatChange) { + if (tinycolor.equals(color, get())) { + // Update UI just in case a validation error needs + // to be cleared. + updateUI(); + return; + } + + var newColor, newHsv; + if (!color && allowEmpty) { + isEmpty = true; + } else { + isEmpty = false; + newColor = tinycolor(color); + newHsv = newColor.toHsv(); + + currentHue = (newHsv.h % 360) / 360; + currentSaturation = newHsv.s; + currentValue = newHsv.v; + currentAlpha = newHsv.a; + } + updateUI(); + + if (newColor && newColor.isValid() && !ignoreFormatChange) { + currentPreferredFormat = opts.preferredFormat || newColor.getFormat(); + } + } + + function get(opts) { + opts = opts || { }; + + if (allowEmpty && isEmpty) { + return null; + } + + return tinycolor.fromRatio({ + h: currentHue, + s: currentSaturation, + v: currentValue, + a: Math.round(currentAlpha * 1000) / 1000 + }, { format: opts.format || currentPreferredFormat }); + } + + function isValid() { + return !textInput.hasClass("sp-validation-error"); + } + + function move() { + updateUI(); + + callbacks.move(get()); + boundElement.trigger('move.spectrum', [ get() ]); + } + + function updateUI() { + + textInput.removeClass("sp-validation-error"); + + updateHelperLocations(); + + // Update dragger background color (gradients take care of saturation and value). + var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 }); + dragger.css("background-color", flatColor.toHexString()); + + // Get a format that alpha will be included in (hex and names ignore alpha) + var format = currentPreferredFormat; + if (currentAlpha < 1 && !(currentAlpha === 0 && format === "name")) { + if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") { + format = "rgb"; + } + } + + var realColor = get({ format: format }), + displayColor = ''; + + //reset background info for preview element + previewElement.removeClass("sp-clear-display"); + previewElement.css('background-color', 'transparent'); + + if (!realColor && allowEmpty) { + // Update the replaced elements background with icon indicating no color selection + previewElement.addClass("sp-clear-display"); + } + else { + var realHex = realColor.toHexString(), + realRgb = realColor.toRgbString(); + + // Update the replaced elements background color (with actual selected color) + if (rgbaSupport || realColor.alpha === 1) { + previewElement.css("background-color", realRgb); + } + else { + previewElement.css("background-color", "transparent"); + previewElement.css("filter", realColor.toFilter()); + } + + if (opts.showAlpha) { + var rgb = realColor.toRgb(); + rgb.a = 0; + var realAlpha = tinycolor(rgb).toRgbString(); + var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")"; + + if (IE) { + alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex)); + } + else { + alphaSliderInner.css("background", "-webkit-" + gradient); + alphaSliderInner.css("background", "-moz-" + gradient); + alphaSliderInner.css("background", "-ms-" + gradient); + // Use current syntax gradient on unprefixed property. + alphaSliderInner.css("background", + "linear-gradient(to right, " + realAlpha + ", " + realHex + ")"); + } + } + + displayColor = realColor.toString(format); + } + + // Update the text entry input as it changes happen + if (opts.showInput) { + textInput.val(displayColor); + } + + if (opts.showPalette) { + drawPalette(); + } + + drawInitial(); + } + + function updateHelperLocations() { + var s = currentSaturation; + var v = currentValue; + + if(allowEmpty && isEmpty) { + //if selected color is empty, hide the helpers + alphaSlideHelper.hide(); + slideHelper.hide(); + dragHelper.hide(); + } + else { + //make sure helpers are visible + alphaSlideHelper.show(); + slideHelper.show(); + dragHelper.show(); + + // Where to show the little circle in that displays your current selected color + var dragX = s * dragWidth; + var dragY = dragHeight - (v * dragHeight); + dragX = Math.max( + -dragHelperHeight, + Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight) + ); + dragY = Math.max( + -dragHelperHeight, + Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight) + ); + dragHelper.css({ + "top": dragY + "px", + "left": dragX + "px" + }); + + var alphaX = currentAlpha * alphaWidth; + alphaSlideHelper.css({ + "left": (alphaX - (alphaSlideHelperWidth / 2)) + "px" + }); + + // Where to show the bar that displays your current selected hue + var slideY = (currentHue) * slideHeight; + slideHelper.css({ + "top": (slideY - slideHelperHeight) + "px" + }); + } + } + + function updateOriginalInput(fireCallback) { + var color = get(), + displayColor = '', + hasChanged = !tinycolor.equals(color, colorOnShow); + + if (color) { + displayColor = color.toString(currentPreferredFormat); + // Update the selection palette with the current color + addColorToSelectionPalette(color); + } + + if (isInput) { + boundElement.val(displayColor); + } + + if (fireCallback && hasChanged) { + callbacks.change(color); + boundElement.trigger('change', [ color ]); + } + } + + function reflow() { + if (!visible) { + return; // Calculations would be useless and wouldn't be reliable anyways + } + dragWidth = dragger.width(); + dragHeight = dragger.height(); + dragHelperHeight = dragHelper.height(); + slideWidth = slider.width(); + slideHeight = slider.height(); + slideHelperHeight = slideHelper.height(); + alphaWidth = alphaSlider.width(); + alphaSlideHelperWidth = alphaSlideHelper.width(); + + if (!flat) { + container.css("position", "absolute"); + if (opts.offset) { + container.offset(opts.offset); + } else { + container.offset(getOffset(container, offsetElement)); + } + } + + updateHelperLocations(); + + if (opts.showPalette) { + drawPalette(); + } + + boundElement.trigger('reflow.spectrum'); + } + + function destroy() { + boundElement.show(); + offsetElement.off("click.spectrum touchstart.spectrum"); + container.remove(); + replacer.remove(); + spectrums[spect.id] = null; + } + + function option(optionName, optionValue) { + if (optionName === undefined) { + return $.extend({}, opts); + } + if (optionValue === undefined) { + return opts[optionName]; + } + + opts[optionName] = optionValue; + + if (optionName === "preferredFormat") { + currentPreferredFormat = opts.preferredFormat; + } + applyOptions(); + } + + function enable() { + disabled = false; + boundElement.attr("disabled", false); + offsetElement.removeClass("sp-disabled"); + } + + function disable() { + hide(); + disabled = true; + boundElement.attr("disabled", true); + offsetElement.addClass("sp-disabled"); + } + + function setOffset(coord) { + opts.offset = coord; + reflow(); + } + + initialize(); + + var spect = { + show: show, + hide: hide, + toggle: toggle, + reflow: reflow, + option: option, + enable: enable, + disable: disable, + offset: setOffset, + set: function (c) { + set(c); + updateOriginalInput(); + }, + get: get, + destroy: destroy, + container: container + }; + + spect.id = spectrums.push(spect) - 1; + + return spect; + } + + /** + * checkOffset - get the offset below/above and left/right element depending on screen position + * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js + */ + function getOffset(picker, input) { + var extraY = 0; + var dpWidth = picker.outerWidth(); + var dpHeight = picker.outerHeight(); + var inputHeight = input.outerHeight(); + var doc = picker[0].ownerDocument; + var docElem = doc.documentElement; + var viewWidth = docElem.clientWidth + $(doc).scrollLeft(); + var viewHeight = docElem.clientHeight + $(doc).scrollTop(); + var offset = input.offset(); + var offsetLeft = offset.left; + var offsetTop = offset.top; + + offsetTop += inputHeight; + + offsetLeft -= + Math.min(offsetLeft, (offsetLeft + dpWidth > viewWidth && viewWidth > dpWidth) ? + Math.abs(offsetLeft + dpWidth - viewWidth) : 0); + + offsetTop -= + Math.min(offsetTop, ((offsetTop + dpHeight > viewHeight && viewHeight > dpHeight) ? + Math.abs(dpHeight + inputHeight - extraY) : extraY)); + + return { + top: offsetTop, + bottom: offset.bottom, + left: offsetLeft, + right: offset.right, + width: offset.width, + height: offset.height + }; + } + + /** + * noop - do nothing + */ + function noop() { + + } + + /** + * stopPropagation - makes the code only doing this a little easier to read in line + */ + function stopPropagation(e) { + e.stopPropagation(); + } + + /** + * Create a function bound to a given object + * Thanks to underscore.js + */ + function bind(func, obj) { + var slice = Array.prototype.slice; + var args = slice.call(arguments, 2); + return function () { + return func.apply(obj, args.concat(slice.call(arguments))); + }; + } + + /** + * Lightweight drag helper. Handles containment within the element, so that + * when dragging, the x is within [0,element.width] and y is within [0,element.height] + */ + function draggable(element, onmove, onstart, onstop) { + onmove = onmove || function () { }; + onstart = onstart || function () { }; + onstop = onstop || function () { }; + var doc = document; + var dragging = false; + var offset = {}; + var maxHeight = 0; + var maxWidth = 0; + var hasTouch = ('ontouchstart' in window); + + var duringDragEvents = {}; + duringDragEvents["selectstart"] = prevent; + duringDragEvents["dragstart"] = prevent; + duringDragEvents["touchmove mousemove"] = move; + duringDragEvents["touchend mouseup"] = stop; + + function prevent(e) { + if (e.stopPropagation) { + e.stopPropagation(); + } + if (e.preventDefault) { + e.preventDefault(); + } + e.returnValue = false; + } + + function move(e) { + if (dragging) { + // Mouseup happened outside of window + if (IE && doc.documentMode < 9 && !e.button) { + return stop(); + } + + var t0 = e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[0]; + var pageX = t0 && t0.pageX || e.pageX; + var pageY = t0 && t0.pageY || e.pageY; + + var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); + var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); + + if (hasTouch) { + // Stop scrolling in iOS + prevent(e); + } + + onmove.apply(element, [dragX, dragY, e]); + } + } + + function start(e) { + var rightclick = (e.which) ? (e.which == 3) : (e.button == 2); + + if (!rightclick && !dragging) { + if (onstart.apply(element, arguments) !== false) { + dragging = true; + maxHeight = $(element).height(); + maxWidth = $(element).width(); + offset = $(element).offset(); + + $(doc).on(duringDragEvents); + $(doc.body).addClass("sp-dragging"); + + move(e); + + prevent(e); + } + } + } + + function stop() { + if (dragging) { + $(doc).off(duringDragEvents); + $(doc.body).removeClass("sp-dragging"); + + // Wait a tick before notifying observers to allow the click event + // to fire in Chrome. + setTimeout(function() { + onstop.apply(element, arguments); + }, 0); + } + dragging = false; + } + + $(element).on("touchstart mousedown", start); + } + + function throttle(func, wait, debounce) { + var timeout; + return function () { + var context = this, args = arguments; + var throttler = function () { + timeout = null; + func.apply(context, args); + }; + if (debounce) clearTimeout(timeout); + if (debounce || !timeout) timeout = setTimeout(throttler, wait); + }; + } + + function inputTypeColorSupport() { + return $.fn.spectrum.inputTypeColorSupport(); + } + + /** + * Define a jQuery plugin + */ + var dataID = "spectrum.id"; + $.fn.spectrum = function (opts, extra) { + + if (typeof opts == "string") { + + var returnValue = this; + var args = Array.prototype.slice.call( arguments, 1 ); + + this.each(function () { + var spect = spectrums[$(this).data(dataID)]; + if (spect) { + var method = spect[opts]; + if (!method) { + throw new Error( "Spectrum: no such method: '" + opts + "'" ); + } + + if (opts == "get") { + returnValue = spect.get(); + } + else if (opts == "container") { + returnValue = spect.container; + } + else if (opts == "option") { + returnValue = spect.option.apply(spect, args); + } + else if (opts == "destroy") { + spect.destroy(); + $(this).removeData(dataID); + } + else { + method.apply(spect, args); + } + } + }); + + return returnValue; + } + + // Initializing a new instance of spectrum + return this.spectrum("destroy").each(function () { + var options = $.extend({}, $(this).data(), opts); + var spect = spectrum(this, options); + $(this).data(dataID, spect.id); + }); + }; + + $.fn.spectrum.load = true; + $.fn.spectrum.loadOpts = {}; + $.fn.spectrum.draggable = draggable; + $.fn.spectrum.defaults = defaultOpts; + $.fn.spectrum.inputTypeColorSupport = function inputTypeColorSupport() { + if (typeof inputTypeColorSupport._cachedResult === "undefined") { + var colorInput = $("")[0]; // if color element is supported, value will default to not null + inputTypeColorSupport._cachedResult = colorInput.type === "color" && colorInput.value !== ""; + } + return inputTypeColorSupport._cachedResult; + }; + + $.spectrum = { }; + $.spectrum.localization = { }; + $.spectrum.palettes = { }; + + $.fn.spectrum.processNativeColorInputs = function () { + var colorInputs = $("input[type=color]"); + if (colorInputs.length && !inputTypeColorSupport()) { + colorInputs.spectrum({ + preferredFormat: "hex6" + }); + } + }; + + // TinyColor v1.1.2 + // https://github.com/bgrins/TinyColor + // Brian Grinstead, MIT License + + (function() { + + var trimLeft = /^[\s,#]+/, + trimRight = /\s+$/, + tinyCounter = 0, + math = Math, + mathRound = math.round, + mathMin = math.min, + mathMax = math.max, + mathRandom = math.random; + + var tinycolor = function(color, opts) { + + color = (color) ? color : ''; + opts = opts || { }; + + // If input is already a tinycolor, return itself + if (color instanceof tinycolor) { + return color; + } + // If we are called as a function, call using new instead + if (!(this instanceof tinycolor)) { + return new tinycolor(color, opts); + } + + var rgb = inputToRGB(color); + this._originalInput = color, + this._r = rgb.r, + this._g = rgb.g, + this._b = rgb.b, + this._a = rgb.a, + this._roundA = mathRound(1000 * this._a) / 1000, + this._format = opts.format || rgb.format; + this._gradientType = opts.gradientType; + + // Don't let the range of [0,255] come back in [0,1]. + // Potentially lose a little bit of precision here, but will fix issues where + // .5 gets interpreted as half of the total, instead of half of 1 + // If it was supposed to be 128, this was already taken care of by `inputToRgb` + if (this._r < 1) { this._r = mathRound(this._r); } + if (this._g < 1) { this._g = mathRound(this._g); } + if (this._b < 1) { this._b = mathRound(this._b); } + + this._ok = rgb.ok; + this._tc_id = tinyCounter++; + }; + + tinycolor.prototype = { + isDark: function() { + return this.getBrightness() < 128; + }, + isLight: function() { + return !this.isDark(); + }, + isValid: function() { + return this._ok; + }, + getOriginalInput: function() { + return this._originalInput; + }, + getFormat: function() { + return this._format; + }, + getAlpha: function() { + return this._a; + }, + getBrightness: function() { + var rgb = this.toRgb(); + return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000; + }, + setAlpha: function(value) { + this._a = boundAlpha(value); + this._roundA = mathRound(1000 * this._a) / 1000; + return this; + }, + toHsv: function() { + var hsv = rgbToHsv(this._r, this._g, this._b); + return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a }; + }, + toHsvString: function() { + var hsv = rgbToHsv(this._r, this._g, this._b); + var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); + return (this._a == 1) ? + "hsv(" + h + ", " + s + "%, " + v + "%)" : + "hsva(" + h + ", " + s + "%, " + v + "%, "+ this._roundA + ")"; + }, + toHsl: function() { + var hsl = rgbToHsl(this._r, this._g, this._b); + return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a }; + }, + toHslString: function() { + var hsl = rgbToHsl(this._r, this._g, this._b); + var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); + return (this._a == 1) ? + "hsl(" + h + ", " + s + "%, " + l + "%)" : + "hsla(" + h + ", " + s + "%, " + l + "%, "+ this._roundA + ")"; + }, + toHex: function(allow3Char) { + return rgbToHex(this._r, this._g, this._b, allow3Char); + }, + toHexString: function(allow3Char) { + return '#' + this.toHex(allow3Char); + }, + toHex8: function() { + return rgbaToHex(this._r, this._g, this._b, this._a); + }, + toHex8String: function() { + return '#' + this.toHex8(); + }, + toRgb: function() { + return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a }; + }, + toRgbString: function() { + return (this._a == 1) ? + "rgb(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ")" : + "rgba(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ", " + this._roundA + ")"; + }, + toPercentageRgb: function() { + return { r: mathRound(bound01(this._r, 255) * 100) + "%", g: mathRound(bound01(this._g, 255) * 100) + "%", b: mathRound(bound01(this._b, 255) * 100) + "%", a: this._a }; + }, + toPercentageRgbString: function() { + return (this._a == 1) ? + "rgb(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%)" : + "rgba(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%, " + this._roundA + ")"; + }, + toName: function() { + if (this._a === 0) { + return "transparent"; + } + + if (this._a < 1) { + return false; + } + + return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false; + }, + toFilter: function(secondColor) { + var hex8String = '#' + rgbaToHex(this._r, this._g, this._b, this._a); + var secondHex8String = hex8String; + var gradientType = this._gradientType ? "GradientType = 1, " : ""; + + if (secondColor) { + var s = tinycolor(secondColor); + secondHex8String = s.toHex8String(); + } + + return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")"; + }, + toString: function(format) { + var formatSet = !!format; + format = format || this._format; + + var formattedString = false; + var hasAlpha = this._a < 1 && this._a >= 0; + var needsAlphaFormat = !formatSet && hasAlpha && (format === "hex" || format === "hex6" || format === "hex3" || format === "name"); + + if (needsAlphaFormat) { + // Special case for "transparent", all other non-alpha formats + // will return rgba when there is transparency. + if (format === "name" && this._a === 0) { + return this.toName(); + } + return this.toRgbString(); + } + if (format === "rgb") { + formattedString = this.toRgbString(); + } + if (format === "prgb") { + formattedString = this.toPercentageRgbString(); + } + if (format === "hex" || format === "hex6") { + formattedString = this.toHexString(); + } + if (format === "hex3") { + formattedString = this.toHexString(true); + } + if (format === "hex8") { + formattedString = this.toHex8String(); + } + if (format === "name") { + formattedString = this.toName(); + } + if (format === "hsl") { + formattedString = this.toHslString(); + } + if (format === "hsv") { + formattedString = this.toHsvString(); + } + + return formattedString || this.toHexString(); + }, + + _applyModification: function(fn, args) { + var color = fn.apply(null, [this].concat([].slice.call(args))); + this._r = color._r; + this._g = color._g; + this._b = color._b; + this.setAlpha(color._a); + return this; + }, + lighten: function() { + return this._applyModification(lighten, arguments); + }, + brighten: function() { + return this._applyModification(brighten, arguments); + }, + darken: function() { + return this._applyModification(darken, arguments); + }, + desaturate: function() { + return this._applyModification(desaturate, arguments); + }, + saturate: function() { + return this._applyModification(saturate, arguments); + }, + greyscale: function() { + return this._applyModification(greyscale, arguments); + }, + spin: function() { + return this._applyModification(spin, arguments); + }, + + _applyCombination: function(fn, args) { + return fn.apply(null, [this].concat([].slice.call(args))); + }, + analogous: function() { + return this._applyCombination(analogous, arguments); + }, + complement: function() { + return this._applyCombination(complement, arguments); + }, + monochromatic: function() { + return this._applyCombination(monochromatic, arguments); + }, + splitcomplement: function() { + return this._applyCombination(splitcomplement, arguments); + }, + triad: function() { + return this._applyCombination(triad, arguments); + }, + tetrad: function() { + return this._applyCombination(tetrad, arguments); + } + }; + + // If input is an object, force 1 into "1.0" to handle ratios properly + // String input requires "1.0" as input, so 1 will be treated as 1 + tinycolor.fromRatio = function(color, opts) { + if (typeof color == "object") { + var newColor = {}; + for (var i in color) { + if (color.hasOwnProperty(i)) { + if (i === "a") { + newColor[i] = color[i]; + } + else { + newColor[i] = convertToPercentage(color[i]); + } + } + } + color = newColor; + } + + return tinycolor(color, opts); + }; + + // Given a string or object, convert that input to RGB + // Possible string inputs: + // + // "red" + // "#f00" or "f00" + // "#ff0000" or "ff0000" + // "#ff000000" or "ff000000" + // "rgb 255 0 0" or "rgb (255, 0, 0)" + // "rgb 1.0 0 0" or "rgb (1, 0, 0)" + // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" + // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" + // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" + // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" + // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" + // + function inputToRGB(color) { + + var rgb = { r: 0, g: 0, b: 0 }; + var a = 1; + var ok = false; + var format = false; + + if (typeof color == "string") { + color = stringInputToObject(color); + } + + if (typeof color == "object") { + if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { + rgb = rgbToRgb(color.r, color.g, color.b); + ok = true; + format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; + } + else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { + color.s = convertToPercentage(color.s); + color.v = convertToPercentage(color.v); + rgb = hsvToRgb(color.h, color.s, color.v); + ok = true; + format = "hsv"; + } + else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { + color.s = convertToPercentage(color.s); + color.l = convertToPercentage(color.l); + rgb = hslToRgb(color.h, color.s, color.l); + ok = true; + format = "hsl"; + } + + if (color.hasOwnProperty("a")) { + a = color.a; + } + } + + a = boundAlpha(a); + + return { + ok: ok, + format: color.format || format, + r: mathMin(255, mathMax(rgb.r, 0)), + g: mathMin(255, mathMax(rgb.g, 0)), + b: mathMin(255, mathMax(rgb.b, 0)), + a: a + }; + } + + + // Conversion Functions + // -------------------- + + // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: + // + + // `rgbToRgb` + // Handle bounds / percentage checking to conform to CSS color spec + // + // *Assumes:* r, g, b in [0, 255] or [0, 1] + // *Returns:* { r, g, b } in [0, 255] + function rgbToRgb(r, g, b){ + return { + r: bound01(r, 255) * 255, + g: bound01(g, 255) * 255, + b: bound01(b, 255) * 255 + }; + } + + // `rgbToHsl` + // Converts an RGB color value to HSL. + // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] + // *Returns:* { h, s, l } in [0,1] + function rgbToHsl(r, g, b) { + + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + + var max = mathMax(r, g, b), min = mathMin(r, g, b); + var h, s, l = (max + min) / 2; + + if(max == min) { + h = s = 0; // achromatic + } + else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch(max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + + h /= 6; + } + + return { h: h, s: s, l: l }; + } + + // `hslToRgb` + // Converts an HSL color value to RGB. + // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] + // *Returns:* { r, g, b } in the set [0, 255] + function hslToRgb(h, s, l) { + var r, g, b; + + h = bound01(h, 360); + s = bound01(s, 100); + l = bound01(l, 100); + + function hue2rgb(p, q, t) { + if(t < 0) t += 1; + if(t > 1) t -= 1; + if(t < 1/6) return p + (q - p) * 6 * t; + if(t < 1/2) return q; + if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; + return p; + } + + if(s === 0) { + r = g = b = l; // achromatic + } + else { + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1/3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1/3); + } + + return { r: r * 255, g: g * 255, b: b * 255 }; + } + + // `rgbToHsv` + // Converts an RGB color value to HSV + // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] + // *Returns:* { h, s, v } in [0,1] + function rgbToHsv(r, g, b) { + + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + + var max = mathMax(r, g, b), min = mathMin(r, g, b); + var h, s, v = max; + + var d = max - min; + s = max === 0 ? 0 : d / max; + + if(max == min) { + h = 0; // achromatic + } + else { + switch(max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + return { h: h, s: s, v: v }; + } + + // `hsvToRgb` + // Converts an HSV color value to RGB. + // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] + // *Returns:* { r, g, b } in the set [0, 255] + function hsvToRgb(h, s, v) { + + h = bound01(h, 360) * 6; + s = bound01(s, 100); + v = bound01(v, 100); + + var i = math.floor(h), + f = h - i, + p = v * (1 - s), + q = v * (1 - f * s), + t = v * (1 - (1 - f) * s), + mod = i % 6, + r = [v, q, p, p, t, v][mod], + g = [t, v, v, q, p, p][mod], + b = [p, p, t, v, v, q][mod]; + + return { r: r * 255, g: g * 255, b: b * 255 }; + } + + // `rgbToHex` + // Converts an RGB color to hex + // Assumes r, g, and b are contained in the set [0, 255] + // Returns a 3 or 6 character hex + function rgbToHex(r, g, b, allow3Char) { + + var hex = [ + pad2(mathRound(r).toString(16)), + pad2(mathRound(g).toString(16)), + pad2(mathRound(b).toString(16)) + ]; + + // Return a 3 character hex if possible + if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { + return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); + } + + return hex.join(""); + } + // `rgbaToHex` + // Converts an RGBA color plus alpha transparency to hex + // Assumes r, g, b and a are contained in the set [0, 255] + // Returns an 8 character hex + function rgbaToHex(r, g, b, a) { + + var hex = [ + pad2(convertDecimalToHex(a)), + pad2(mathRound(r).toString(16)), + pad2(mathRound(g).toString(16)), + pad2(mathRound(b).toString(16)) + ]; + + return hex.join(""); + } + + // `equals` + // Can be called with any tinycolor input + tinycolor.equals = function (color1, color2) { + if (!color1 || !color2) { return false; } + return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); + }; + tinycolor.random = function() { + return tinycolor.fromRatio({ + r: mathRandom(), + g: mathRandom(), + b: mathRandom() + }); + }; + + + // Modification Functions + // ---------------------- + // Thanks to less.js for some of the basics here + // + + function desaturate(color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.s -= amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); + } + + function saturate(color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.s += amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); + } + + function greyscale(color) { + return tinycolor(color).desaturate(100); + } + + function lighten (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.l += amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); + } + + function brighten(color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var rgb = tinycolor(color).toRgb(); + rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * - (amount / 100)))); + rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * - (amount / 100)))); + rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * - (amount / 100)))); + return tinycolor(rgb); + } + + function darken (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.l -= amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); + } + + // Spin takes a positive or negative amount within [-360, 360] indicating the change of hue. + // Values outside of this range will be wrapped into this range. + function spin(color, amount) { + var hsl = tinycolor(color).toHsl(); + var hue = (mathRound(hsl.h) + amount) % 360; + hsl.h = hue < 0 ? 360 + hue : hue; + return tinycolor(hsl); + } + + // Combination Functions + // --------------------- + // Thanks to jQuery xColor for some of the ideas behind these + // + + function complement(color) { + var hsl = tinycolor(color).toHsl(); + hsl.h = (hsl.h + 180) % 360; + return tinycolor(hsl); + } + + function triad(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) + ]; + } + + function tetrad(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) + ]; + } + + function splitcomplement(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), + tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) + ]; + } + + function analogous(color, results, slices) { + results = results || 6; + slices = slices || 30; + + var hsl = tinycolor(color).toHsl(); + var part = 360 / slices; + var ret = [tinycolor(color)]; + + for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { + hsl.h = (hsl.h + part) % 360; + ret.push(tinycolor(hsl)); + } + return ret; + } + + function monochromatic(color, results) { + results = results || 6; + var hsv = tinycolor(color).toHsv(); + var h = hsv.h, s = hsv.s, v = hsv.v; + var ret = []; + var modification = 1 / results; + + while (results--) { + ret.push(tinycolor({ h: h, s: s, v: v})); + v = (v + modification) % 1; + } + + return ret; + } + + // Utility Functions + // --------------------- + + tinycolor.mix = function(color1, color2, amount) { + amount = (amount === 0) ? 0 : (amount || 50); + + var rgb1 = tinycolor(color1).toRgb(); + var rgb2 = tinycolor(color2).toRgb(); + + var p = amount / 100; + var w = p * 2 - 1; + var a = rgb2.a - rgb1.a; + + var w1; + + if (w * a == -1) { + w1 = w; + } else { + w1 = (w + a) / (1 + w * a); + } + + w1 = (w1 + 1) / 2; + + var w2 = 1 - w1; + + var rgba = { + r: rgb2.r * w1 + rgb1.r * w2, + g: rgb2.g * w1 + rgb1.g * w2, + b: rgb2.b * w1 + rgb1.b * w2, + a: rgb2.a * p + rgb1.a * (1 - p) + }; + + return tinycolor(rgba); + }; + + + // Readability Functions + // --------------------- + // + + // `readability` + // Analyze the 2 colors and returns an object with the following properties: + // `brightness`: difference in brightness between the two colors + // `color`: difference in color/hue between the two colors + tinycolor.readability = function(color1, color2) { + var c1 = tinycolor(color1); + var c2 = tinycolor(color2); + var rgb1 = c1.toRgb(); + var rgb2 = c2.toRgb(); + var brightnessA = c1.getBrightness(); + var brightnessB = c2.getBrightness(); + var colorDiff = ( + Math.max(rgb1.r, rgb2.r) - Math.min(rgb1.r, rgb2.r) + + Math.max(rgb1.g, rgb2.g) - Math.min(rgb1.g, rgb2.g) + + Math.max(rgb1.b, rgb2.b) - Math.min(rgb1.b, rgb2.b) + ); + + return { + brightness: Math.abs(brightnessA - brightnessB), + color: colorDiff + }; + }; + + // `readable` + // http://www.w3.org/TR/AERT#color-contrast + // Ensure that foreground and background color combinations provide sufficient contrast. + // *Example* + // tinycolor.isReadable("#000", "#111") => false + tinycolor.isReadable = function(color1, color2) { + var readability = tinycolor.readability(color1, color2); + return readability.brightness > 125 && readability.color > 500; + }; + + // `mostReadable` + // Given a base color and a list of possible foreground or background + // colors for that base, returns the most readable color. + // *Example* + // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" + tinycolor.mostReadable = function(baseColor, colorList) { + var bestColor = null; + var bestScore = 0; + var bestIsReadable = false; + for (var i=0; i < colorList.length; i++) { + + // We normalize both around the "acceptable" breaking point, + // but rank brightness constrast higher than hue. + + var readability = tinycolor.readability(baseColor, colorList[i]); + var readable = readability.brightness > 125 && readability.color > 500; + var score = 3 * (readability.brightness / 125) + (readability.color / 500); + + if ((readable && ! bestIsReadable) || + (readable && bestIsReadable && score > bestScore) || + ((! readable) && (! bestIsReadable) && score > bestScore)) { + bestIsReadable = readable; + bestScore = score; + bestColor = tinycolor(colorList[i]); + } + } + return bestColor; + }; + + + // Big List of Colors + // ------------------ + // + var names = tinycolor.names = { + aliceblue: "f0f8ff", + antiquewhite: "faebd7", + aqua: "0ff", + aquamarine: "7fffd4", + azure: "f0ffff", + beige: "f5f5dc", + bisque: "ffe4c4", + black: "000", + blanchedalmond: "ffebcd", + blue: "00f", + blueviolet: "8a2be2", + brown: "a52a2a", + burlywood: "deb887", + burntsienna: "ea7e5d", + cadetblue: "5f9ea0", + chartreuse: "7fff00", + chocolate: "d2691e", + coral: "ff7f50", + cornflowerblue: "6495ed", + cornsilk: "fff8dc", + crimson: "dc143c", + cyan: "0ff", + darkblue: "00008b", + darkcyan: "008b8b", + darkgoldenrod: "b8860b", + darkgray: "a9a9a9", + darkgreen: "006400", + darkgrey: "a9a9a9", + darkkhaki: "bdb76b", + darkmagenta: "8b008b", + darkolivegreen: "556b2f", + darkorange: "ff8c00", + darkorchid: "9932cc", + darkred: "8b0000", + darksalmon: "e9967a", + darkseagreen: "8fbc8f", + darkslateblue: "483d8b", + darkslategray: "2f4f4f", + darkslategrey: "2f4f4f", + darkturquoise: "00ced1", + darkviolet: "9400d3", + deeppink: "ff1493", + deepskyblue: "00bfff", + dimgray: "696969", + dimgrey: "696969", + dodgerblue: "1e90ff", + firebrick: "b22222", + floralwhite: "fffaf0", + forestgreen: "228b22", + fuchsia: "f0f", + gainsboro: "dcdcdc", + ghostwhite: "f8f8ff", + gold: "ffd700", + goldenrod: "daa520", + gray: "808080", + green: "008000", + greenyellow: "adff2f", + grey: "808080", + honeydew: "f0fff0", + hotpink: "ff69b4", + indianred: "cd5c5c", + indigo: "4b0082", + ivory: "fffff0", + khaki: "f0e68c", + lavender: "e6e6fa", + lavenderblush: "fff0f5", + lawngreen: "7cfc00", + lemonchiffon: "fffacd", + lightblue: "add8e6", + lightcoral: "f08080", + lightcyan: "e0ffff", + lightgoldenrodyellow: "fafad2", + lightgray: "d3d3d3", + lightgreen: "90ee90", + lightgrey: "d3d3d3", + lightpink: "ffb6c1", + lightsalmon: "ffa07a", + lightseagreen: "20b2aa", + lightskyblue: "87cefa", + lightslategray: "789", + lightslategrey: "789", + lightsteelblue: "b0c4de", + lightyellow: "ffffe0", + lime: "0f0", + limegreen: "32cd32", + linen: "faf0e6", + magenta: "f0f", + maroon: "800000", + mediumaquamarine: "66cdaa", + mediumblue: "0000cd", + mediumorchid: "ba55d3", + mediumpurple: "9370db", + mediumseagreen: "3cb371", + mediumslateblue: "7b68ee", + mediumspringgreen: "00fa9a", + mediumturquoise: "48d1cc", + mediumvioletred: "c71585", + midnightblue: "191970", + mintcream: "f5fffa", + mistyrose: "ffe4e1", + moccasin: "ffe4b5", + navajowhite: "ffdead", + navy: "000080", + oldlace: "fdf5e6", + olive: "808000", + olivedrab: "6b8e23", + orange: "ffa500", + orangered: "ff4500", + orchid: "da70d6", + palegoldenrod: "eee8aa", + palegreen: "98fb98", + paleturquoise: "afeeee", + palevioletred: "db7093", + papayawhip: "ffefd5", + peachpuff: "ffdab9", + peru: "cd853f", + pink: "ffc0cb", + plum: "dda0dd", + powderblue: "b0e0e6", + purple: "800080", + rebeccapurple: "663399", + red: "f00", + rosybrown: "bc8f8f", + royalblue: "4169e1", + saddlebrown: "8b4513", + salmon: "fa8072", + sandybrown: "f4a460", + seagreen: "2e8b57", + seashell: "fff5ee", + sienna: "a0522d", + silver: "c0c0c0", + skyblue: "87ceeb", + slateblue: "6a5acd", + slategray: "708090", + slategrey: "708090", + snow: "fffafa", + springgreen: "00ff7f", + steelblue: "4682b4", + tan: "d2b48c", + teal: "008080", + thistle: "d8bfd8", + tomato: "ff6347", + turquoise: "40e0d0", + violet: "ee82ee", + wheat: "f5deb3", + white: "fff", + whitesmoke: "f5f5f5", + yellow: "ff0", + yellowgreen: "9acd32" + }; + + // Make it easy to access colors via `hexNames[hex]` + var hexNames = tinycolor.hexNames = flip(names); + + + // Utilities + // --------- + + // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` + function flip(o) { + var flipped = { }; + for (var i in o) { + if (o.hasOwnProperty(i)) { + flipped[o[i]] = i; + } + } + return flipped; + } + + // Return a valid alpha value [0,1] with all invalid values being set to 1 + function boundAlpha(a) { + a = parseFloat(a); + + if (isNaN(a) || a < 0 || a > 1) { + a = 1; + } + + return a; + } + + // Take input from [0, n] and return it as [0, 1] + function bound01(n, max) { + if (isOnePointZero(n)) { n = "100%"; } + + var processPercent = isPercentage(n); + n = mathMin(max, mathMax(0, parseFloat(n))); + + // Automatically convert percentage into number + if (processPercent) { + n = parseInt(n * max, 10) / 100; + } + + // Handle floating point rounding errors + if ((math.abs(n - max) < 0.000001)) { + return 1; + } + + // Convert into [0, 1] range if it isn't already + return (n % max) / parseFloat(max); + } + + // Force a number between 0 and 1 + function clamp01(val) { + return mathMin(1, mathMax(0, val)); + } + + // Parse a base-16 hex value into a base-10 integer + function parseIntFromHex(val) { + return parseInt(val, 16); + } + + // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 + // + function isOnePointZero(n) { + return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; + } + + // Check to see if string passed in is a percentage + function isPercentage(n) { + return typeof n === "string" && n.indexOf('%') != -1; + } + + // Force a hex value to have 2 characters + function pad2(c) { + return c.length == 1 ? '0' + c : '' + c; + } + + // Replace a decimal with it's percentage value + function convertToPercentage(n) { + if (n <= 1) { + n = (n * 100) + "%"; + } + + return n; + } + + // Converts a decimal to a hex value + function convertDecimalToHex(d) { + return Math.round(parseFloat(d) * 255).toString(16); + } + // Converts a hex value to a decimal + function convertHexToDecimal(h) { + return (parseIntFromHex(h) / 255); + } + + var matchers = (function() { + + // + var CSS_INTEGER = "[-\\+]?\\d+%?"; + + // + var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; + + // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. + var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; + + // Actual matching. + // Parentheses and commas are optional, but not required. + // Whitespace can take the place of commas or opening paren + var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + + return { + rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), + rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), + hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), + hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), + hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), + hsva: new RegExp("hsva" + PERMISSIVE_MATCH4), + hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, + hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, + hex8: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ + }; + })(); + + // `stringInputToObject` + // Permissive string parsing. Take in a number of formats, and output an object + // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` + function stringInputToObject(color) { + + color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); + var named = false; + if (names[color]) { + color = names[color]; + named = true; + } + else if (color == 'transparent') { + return { r: 0, g: 0, b: 0, a: 0, format: "name" }; + } + + // Try to match string input using regular expressions. + // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] + // Just return an object and let the conversion functions handle that. + // This way the result will be the same whether the tinycolor is initialized with string or object. + var match; + if ((match = matchers.rgb.exec(color))) { + return { r: match[1], g: match[2], b: match[3] }; + } + if ((match = matchers.rgba.exec(color))) { + return { r: match[1], g: match[2], b: match[3], a: match[4] }; + } + if ((match = matchers.hsl.exec(color))) { + return { h: match[1], s: match[2], l: match[3] }; + } + if ((match = matchers.hsla.exec(color))) { + return { h: match[1], s: match[2], l: match[3], a: match[4] }; + } + if ((match = matchers.hsv.exec(color))) { + return { h: match[1], s: match[2], v: match[3] }; + } + if ((match = matchers.hsva.exec(color))) { + return { h: match[1], s: match[2], v: match[3], a: match[4] }; + } + if ((match = matchers.hex8.exec(color))) { + return { + a: convertHexToDecimal(match[1]), + r: parseIntFromHex(match[2]), + g: parseIntFromHex(match[3]), + b: parseIntFromHex(match[4]), + format: named ? "name" : "hex8" + }; + } + if ((match = matchers.hex6.exec(color))) { + return { + r: parseIntFromHex(match[1]), + g: parseIntFromHex(match[2]), + b: parseIntFromHex(match[3]), + format: named ? "name" : "hex" + }; + } + if ((match = matchers.hex3.exec(color))) { + return { + r: parseIntFromHex(match[1] + '' + match[1]), + g: parseIntFromHex(match[2] + '' + match[2]), + b: parseIntFromHex(match[3] + '' + match[3]), + format: named ? "name" : "hex" + }; + } + + return false; + } + + window.tinycolor = tinycolor; + })(); + + $(function () { + if ($.fn.spectrum.load) { + $.fn.spectrum.processNativeColorInputs(); + } + }); + +}); diff --git a/modules/backend/formwidgets/colorpicker/partials/_colorpicker.htm b/modules/backend/formwidgets/colorpicker/partials/_colorpicker.htm new file mode 100644 index 0000000..d482114 --- /dev/null +++ b/modules/backend/formwidgets/colorpicker/partials/_colorpicker.htm @@ -0,0 +1,42 @@ +previewMode): ?> +
    + +
    data-show-alpha="" + data-allow-empty="" + data-data-locker="#getId('input') ?>" + data-disabled="true" + formField->getAttributes() ?>> + +
      + + $color): ?> +
    • + +
    • + + + +
    • + +
    • +
    + + +
    + + diff --git a/modules/backend/formwidgets/datatable/partials/_datatable.htm b/modules/backend/formwidgets/datatable/partials/_datatable.htm new file mode 100644 index 0000000..cb73e48 --- /dev/null +++ b/modules/backend/formwidgets/datatable/partials/_datatable.htm @@ -0,0 +1,8 @@ +
    + + render() ?> + +
    + diff --git a/modules/backend/formwidgets/datepicker/partials/_datepicker.htm b/modules/backend/formwidgets/datepicker/partials/_datepicker.htm new file mode 100644 index 0000000..5efcea5 --- /dev/null +++ b/modules/backend/formwidgets/datepicker/partials/_datepicker.htm @@ -0,0 +1,49 @@ +previewMode): ?> +
    $format, + 'formatAlias' => $formatAlias, + 'defaultValue' => $value + ]) ?>
    + + +
    data-format="" + data-min-date="" + data-max-date="" + data-mode="" + data-year-range="" + data-first-day="" + data-show-week-number="" + data-ignore-timezone + > + + + makePartial('picker_date') ?> + +
    +
    + makePartial('picker_date') ?> +
    +
    + makePartial('picker_time') ?> +
    +
    + + makePartial('picker_time') ?> + + + + + +
    + + diff --git a/modules/backend/formwidgets/datepicker/partials/_picker_date.htm b/modules/backend/formwidgets/datepicker/partials/_picker_date.htm new file mode 100644 index 0000000..261f37b --- /dev/null +++ b/modules/backend/formwidgets/datepicker/partials/_picker_date.htm @@ -0,0 +1,11 @@ + +
    + + getAttributes() ?> + data-datepicker /> +
    diff --git a/modules/backend/formwidgets/datepicker/partials/_picker_time.htm b/modules/backend/formwidgets/datepicker/partials/_picker_time.htm new file mode 100644 index 0000000..0e5c579 --- /dev/null +++ b/modules/backend/formwidgets/datepicker/partials/_picker_time.htm @@ -0,0 +1,11 @@ + +
    + + getAttributes() ?> + data-timepicker /> +
    diff --git a/modules/backend/formwidgets/fileupload/assets/css/fileupload.css b/modules/backend/formwidgets/fileupload/assets/css/fileupload.css new file mode 100644 index 0000000..b3d4ba1 --- /dev/null +++ b/modules/backend/formwidgets/fileupload/assets/css/fileupload.css @@ -0,0 +1,157 @@ +.field-fileupload .upload-object {-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;position:relative;outline:none;overflow:hidden;display:inline-block;vertical-align:top} +.field-fileupload .upload-object img {width:100%;height:100%} +.field-fileupload .upload-object .icon-container {display:table;opacity:.6} +.field-fileupload .upload-object .icon-container i {color:#95a5a6;display:inline-block} +.field-fileupload .upload-object .icon-container div {display:table-cell;text-align:center;vertical-align:middle} +.field-fileupload .upload-object .icon-container.image >div.icon-wrapper {display:none} +.field-fileupload .upload-object h4 {font-size:13px;color:#2A3E51;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:150%;margin:15px 0 5px 0;padding-right:0;-webkit-transition:padding 0.1s;transition:padding 0.1s;position:relative} +.field-fileupload .upload-object h4 a {position:absolute;right:0;top:0;display:none;font-weight:400} +.field-fileupload .upload-object p.size {font-size:12px;color:#95a5a6} +.field-fileupload .upload-object p.size strong {font-weight:400} +.field-fileupload .upload-object .meta .drag-handle {position:absolute;bottom:0;right:0;cursor:move;display:block} +.field-fileupload .upload-object .info h4 a, +.field-fileupload .upload-object .meta a.upload-remove-button, +.field-fileupload .upload-object .meta a.drag-handle {color:#2b3e50;display:none;font-size:13px;text-decoration:none} +.field-fileupload .upload-object .icon-container {position:relative} +.field-fileupload .upload-object .icon-container:after {background-image:url('../../../../../system/assets/ui/images/loader-transparent.svg');position:absolute;content:' ';width:40px;height:40px;left:50%;top:50%;margin-top:-20px;margin-left:-20px;display:block;background-size:40px 40px;background-position:50% 50%;-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite} +.field-fileupload .upload-object.is-success .icon-container {opacity:1} +.field-fileupload .upload-object.is-success .icon-container:after {opacity:0;-webkit-transition:opacity 0.3s ease;transition:opacity 0.3s ease} +.field-fileupload .upload-object.is-error .icon-container:after {content:"";background:none;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f071";-webkit-animation:none;animation:none;font-size:40px;color:#ab2a1c;margin-top:-20px;margin-left:-20px;text-shadow:2px 2px 0 #fff} +.field-fileupload .upload-object.is-loading .icon-container {opacity:.6} +.field-fileupload .upload-object.is-loading .icon-container:after {opacity:1;-webkit-transition:opacity 0.3s ease;transition:opacity 0.3s ease} +.field-fileupload .upload-object.is-success {cursor:pointer} +.field-fileupload .upload-object.is-success .progress-bar {opacity:0;-webkit-transition:opacity 0.3s ease;transition:opacity 0.3s ease} +.field-fileupload .upload-object.is-success:hover h4 a, +.field-fileupload .upload-object.is-success:hover .meta .upload-remove-button, +.field-fileupload .upload-object.is-success:hover .meta .drag-handle {display:block} +.field-fileupload .upload-object.is-error {cursor:pointer} +.field-fileupload .upload-object.is-error .icon-container {opacity:1} +.field-fileupload .upload-object.is-error .icon-container >img, +.field-fileupload .upload-object.is-error .icon-container >i {opacity:.5} +.field-fileupload .upload-object.is-error .info h4 {color:#ab2a1c} +.field-fileupload .upload-object.is-error .info h4 a {display:none} +.field-fileupload .upload-object.is-error .meta {display:none} +.field-fileupload.is-sortable {position:relative} +.field-fileupload.is-sortable .upload-placeholder {position:relative;border:1px dotted #e0e0e0 !important} +.field-fileupload.is-sortable .upload-object.dragged {position:absolute;opacity:0.5;filter:alpha(opacity=50);z-index:2000} +.field-fileupload.is-sortable .upload-object.dragged .uploader-toolbar {display:none} +.field-fileupload.is-preview .upload-button, +.field-fileupload.is-preview .upload-remove-button, +.field-fileupload.is-preview .meta a.drag-handle {display:none !important} +@media (max-width:1024px) {.field-fileupload .upload-object.is-success h4 a,.field-fileupload .upload-object.is-success .meta .upload-remove-button,.field-fileupload .upload-object.is-success .meta .drag-handle {display:block !important }} +.fileupload-config-form .fileupload-url-button {padding-left:0} +.fileupload-config-form .fileupload-url-button >i {color:#666} +.fileupload-config-form .file-upload-modal-image-header {background-color:#FEFEFE;background-image:-webkit-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb),-webkit-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb);background-image:-moz-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb),-moz-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb);background-image:-o-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb),-o-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb);background-image:-ms-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb),-ms-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb);background-image:linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb),linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb);-webkit-background-size:20px 20px;-moz-background-size:20px 20px;background-size:20px 20px;background-position:0 0,10px 10px} +.fileupload-config-form .file-upload-modal-image-header, +.fileupload-config-form .file-upload-modal-image-header img {border-top-right-radius:2px;border-top-left-radius:2px} +.fileupload-config-form .file-upload-modal-image-header .close {position:absolute;top:20px;right:20px;background:#BDC3C7;opacity:.7;height:24px;width:22px} +.fileupload-config-form .file-upload-modal-image-header .close:hover, +.fileupload-config-form .file-upload-modal-image-header .close:focus {opacity:.9} +.fileupload-config-form .file-upload-modal-image-header + .modal-body {padding-top:20px} +.field-fileupload.style-image-multi .upload-button, +.field-fileupload.style-image-multi .upload-object {margin:0 10px 10px 0} +.field-fileupload.style-image-multi .upload-button {display:block;border:2px dashed #BDC3C7;background-clip:content-box;background-color:#F9F9F9;position:relative;outline:none;float:left;width:76px;height:76px} +.field-fileupload.style-image-multi .upload-button .upload-button-icon {position:absolute;width:22px;height:22px;top:50%;left:50%;margin-top:-11px;margin-left:-11px} +.field-fileupload.style-image-multi .upload-button .upload-button-icon:before {text-align:center;display:block;font-size:22px;height:22px;width:22px;line-height:22px;color:#BDC3C7} +.field-fileupload.style-image-multi .upload-button .upload-button-icon.large-icon {width:34px;height:34px;top:50%;left:50%;margin-top:-17px;margin-left:-17px} +.field-fileupload.style-image-multi .upload-button .upload-button-icon.large-icon:before {font-size:34px;height:24px;width:24px;line-height:24px} +.field-fileupload.style-image-multi .upload-button:hover {border:2px dashed #1F99DC} +.field-fileupload.style-image-multi .upload-button:hover .upload-button-icon:before {color:#1F99DC} +.field-fileupload.style-image-multi .upload-button:focus {border:2px dashed #1F99DC} +.field-fileupload.style-image-multi .upload-button:focus .upload-button-icon:before {color:#1F99DC} +.field-fileupload.style-image-multi .upload-files-container {margin-left:90px} +.field-fileupload.style-image-multi .upload-object {background:#fff;border:1px solid #ecf0f1;width:260px} +.field-fileupload.style-image-multi .upload-object .progress-bar {display:block;width:100%;overflow:hidden;height:5px;background-color:#f5f5f5;border-radius:3px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);position:absolute;bottom:10px;left:0} +.field-fileupload.style-image-multi .upload-object .progress-bar .upload-progress {float:left;width:0%;height:100%;line-height:5px;color:#fff;background-color:#5fb6f5;-webkit-box-shadow:none;box-shadow:none;-webkit-transition:width 0.6s ease;transition:width 0.6s ease} +.field-fileupload.style-image-multi .upload-object .icon-container {border-right:1px solid #f6f8f9;float:left;display:inline-block;overflow:hidden;width:75px;height:75px} +.field-fileupload.style-image-multi .upload-object .icon-container i {font-size:35px} +.field-fileupload.style-image-multi .upload-object .icon-container.image img {border-bottom-left-radius:3px;border-top-left-radius:3px;width:auto} +.field-fileupload.style-image-multi .upload-object .info {margin-left:90px} +.field-fileupload.style-image-multi .upload-object .info h4 {padding-right:15px} +.field-fileupload.style-image-multi .upload-object .info h4 a {right:15px} +.field-fileupload.style-image-multi .upload-object .meta {position:absolute;bottom:0;left:0;right:0;margin:0 15px 0 90px} +.field-fileupload.style-image-multi .upload-object .meta a.drag-handle {bottom:15px} +.field-fileupload.style-image-multi .upload-object.upload-placeholder {height:75px;background-color:transparent} +.field-fileupload.style-image-multi .upload-object.upload-placeholder:after {opacity:0} +.field-fileupload.style-image-multi .upload-object:hover {background:#4da7e8 !important} +.field-fileupload.style-image-multi .upload-object:hover i, +.field-fileupload.style-image-multi .upload-object:hover p.size {color:#ecf0f1} +.field-fileupload.style-image-multi .upload-object:hover h4 {color:white} +.field-fileupload.style-image-multi .upload-object:hover .icon-container {border-right-color:#4da7e8 !important} +.field-fileupload.style-image-multi .upload-object:hover h4 {padding-right:35px} +.field-fileupload.style-image-multi.is-preview .upload-files-container {margin-left:0} +.form-sidebar .field-fileupload.style-image-multi .upload-files-container {margin-left:0} +.form-sidebar .field-fileupload.style-image-multi .upload-button {width:100%} +@media (max-width:1280px) {.field-fileupload.style-image-multi .upload-object {width:230px }} +@media (max-width:1024px) {.field-fileupload.style-image-multi .upload-button {width:100% }.field-fileupload.style-image-multi .upload-files-container {margin-left:0 }.field-fileupload.style-image-multi .upload-object {margin-right:0;display:block;width:auto }} +.field-fileupload.style-image-single.is-populated .upload-button {display:none} +.field-fileupload.style-image-single .upload-button {display:block;border:2px dashed #BDC3C7;background-clip:content-box;background-color:#F9F9F9;position:relative;outline:none;min-height:100px;min-width:100px} +.field-fileupload.style-image-single .upload-button .upload-button-icon {position:absolute;width:22px;height:22px;top:50%;left:50%;margin-top:-11px;margin-left:-11px} +.field-fileupload.style-image-single .upload-button .upload-button-icon:before {text-align:center;display:block;font-size:22px;height:22px;width:22px;line-height:22px;color:#BDC3C7} +.field-fileupload.style-image-single .upload-button .upload-button-icon.large-icon {width:34px;height:34px;top:50%;left:50%;margin-top:-17px;margin-left:-17px} +.field-fileupload.style-image-single .upload-button .upload-button-icon.large-icon:before {font-size:34px;height:24px;width:24px;line-height:24px} +.field-fileupload.style-image-single .upload-button:hover {border:2px dashed #1F99DC} +.field-fileupload.style-image-single .upload-button:hover .upload-button-icon:before {color:#1F99DC} +.field-fileupload.style-image-single .upload-button:focus {border:2px dashed #1F99DC} +.field-fileupload.style-image-single .upload-button:focus .upload-button-icon:before {color:#1F99DC} +.field-fileupload.style-image-single .upload-object {padding-bottom:66px} +.field-fileupload.style-image-single .upload-object .icon-container {border:1px solid #f6f8f9;background:rgba(255,255,255,0.5)} +.field-fileupload.style-image-single .upload-object .icon-container.image img {-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;display:block;max-width:100%;height:auto;min-height:100px;min-width:100px} +.field-fileupload.style-image-single .upload-object .progress-bar {display:block;width:100%;overflow:hidden;height:5px;background-color:#f5f5f5;border-radius:3px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);position:absolute;bottom:10px;left:0} +.field-fileupload.style-image-single .upload-object .progress-bar .upload-progress {float:left;width:0%;height:100%;line-height:5px;color:#fff;background-color:#5fb6f5;-webkit-box-shadow:none;box-shadow:none;-webkit-transition:width 0.6s ease;transition:width 0.6s ease} +.field-fileupload.style-image-single .upload-object .info {position:absolute;left:0;right:0;bottom:0;height:66px} +.field-fileupload.style-image-single .upload-object .meta {position:absolute;bottom:65px;left:0;right:0;margin:0 15px} +.field-fileupload.style-image-single .upload-object:hover h4 {padding-right:20px} +@media (max-width:1024px) {.field-fileupload.style-image-single .upload-object h4 {padding-right:20px !important }} +.field-fileupload.style-file-multi .upload-button {margin-bottom:10px} +.field-fileupload.style-file-multi .upload-files-container {border:1px solid #eee;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;border-bottom:none;display:none} +.field-fileupload.style-file-multi.is-populated .upload-files-container {display:block} +.field-fileupload.style-file-multi .upload-object {display:block;width:100%;border-bottom:1px solid #eee;padding-left:10px} +.field-fileupload.style-file-multi .upload-object:nth-child(even) {background-color:#f5f5f5} +.field-fileupload.style-file-multi .upload-object .icon-container {position:absolute;top:0;left:10px;width:15px;padding:11px 7px} +.field-fileupload.style-file-multi .upload-object .icon-container i {line-height:150%;font-size:15px} +.field-fileupload.style-file-multi .upload-object .icon-container img {display:none} +.field-fileupload.style-file-multi .upload-object .info {margin-left:35px;margin-right:15%} +.field-fileupload.style-file-multi .upload-object .info h4, +.field-fileupload.style-file-multi .upload-object .info p {margin:0;padding:11px 0;font-size:12px;font-weight:normal;line-height:150%;color:#666} +.field-fileupload.style-file-multi .upload-object .info h4 {padding-right:15px} +.field-fileupload.style-file-multi .upload-object .info h4 a {padding:10px 0;right:15px} +.field-fileupload.style-file-multi .upload-object .info p.size {position:absolute;top:0;right:0;width:15%;display:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} +.field-fileupload.style-file-multi .upload-object .progress-bar {display:block;width:100%;overflow:hidden;height:5px;background-color:#f5f5f5;border-radius:3px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);position:absolute;top:18px;left:0} +.field-fileupload.style-file-multi .upload-object .progress-bar .upload-progress {float:left;width:0%;height:100%;line-height:5px;color:#fff;background-color:#5fb6f5;-webkit-box-shadow:none;box-shadow:none;-webkit-transition:width 0.6s ease;transition:width 0.6s ease} +.field-fileupload.style-file-multi .upload-object .meta {position:absolute;top:0;right:0;margin-right:15px;width:15%} +.field-fileupload.style-file-multi .upload-object .meta a.drag-handle {top:-2px;bottom:auto;line-height:150%;padding:10px 0} +.field-fileupload.style-file-multi .upload-object .icon-container:after {width:20px;height:20px;margin-top:-10px;margin-left:-10px;background-size:20px 20px} +.field-fileupload.style-file-multi .upload-object.is-error .icon-container:after {font-size:20px} +.field-fileupload.style-file-multi .upload-object.is-success .info p.size {display:block} +.field-fileupload.style-file-multi .upload-object.upload-placeholder {height:35px;background-color:transparent} +.field-fileupload.style-file-multi .upload-object.upload-placeholder:after {opacity:0} +.field-fileupload.style-file-multi .upload-object:hover {background:#4da7e8 !important} +.field-fileupload.style-file-multi .upload-object:hover i, +.field-fileupload.style-file-multi .upload-object:hover p.size {color:#ecf0f1} +.field-fileupload.style-file-multi .upload-object:hover h4 {color:white} +.field-fileupload.style-file-multi .upload-object:hover .icon-container {border-right-color:#4da7e8 !important} +.field-fileupload.style-file-multi .upload-object:hover h4 {padding-right:35px} +@media (max-width:1199px) {.field-fileupload.style-file-multi .info {margin-right:20% !important }.field-fileupload.style-file-multi .info p.size {width:20% !important }.field-fileupload.style-file-multi .meta {width:20% !important }} +@media (max-width:991px) {.field-fileupload.style-file-multi .upload-object h4 {padding-right:35px !important }.field-fileupload.style-file-multi .info {margin-right:25% !important }.field-fileupload.style-file-multi .info p.size {width:25% !important;padding-right:35px !important }.field-fileupload.style-file-multi .meta {width:25% !important }} +.field-fileupload.style-file-single {background-color:#fff;border:1px solid #d1d6d9;overflow:hidden;position:relative;padding-right:30px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 rgba(209,214,217,0.25),0 1px 0 rgba(255,255,255,.5);box-shadow:inset 0 1px 0 rgba(209,214,217,0.25),0 1px 0 rgba(255,255,255,.5)} +.field-fileupload.style-file-single .upload-button {position:absolute;top:50%;margin-top:-44px;height:88px;background:transparent;right:-2px;color:#595959} +.field-fileupload.style-file-single .upload-button i {font-size:14px} +.field-fileupload.style-file-single .upload-button:hover {color:#333} +.field-fileupload.style-file-single .upload-empty-message {padding:8px 0 8px 11px;font-size:14px} +.field-fileupload.style-file-single.is-populated .upload-empty-message {display:none} +.field-fileupload.style-file-single .upload-object {display:block;width:100%;padding:7px 0 9px 0} +.field-fileupload.style-file-single .upload-object .icon-container {position:absolute;top:0;left:0;width:15px;padding:0 5px;margin:8px 0 0 7px;text-align:center} +.field-fileupload.style-file-single .upload-object .icon-container i {line-height:150%;font-size:15px} +.field-fileupload.style-file-single .upload-object .icon-container img {display:none} +.field-fileupload.style-file-single .upload-object .info {margin-left:34px;margin-right:15%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} +.field-fileupload.style-file-single .upload-object .info h4, +.field-fileupload.style-file-single .upload-object .info p {display:inline;margin:0;padding:0;font-size:13px;line-height:150%;color:#666} +.field-fileupload.style-file-single .upload-object .info p.size {font-weight:normal} +.field-fileupload.style-file-single .upload-object .info p.size:before {content:" - "} +.field-fileupload.style-file-single .upload-object .progress-bar {display:block;width:100%;overflow:hidden;height:5px;background-color:#f5f5f5;border-radius:3px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);position:absolute;top:50%;margin-top:-2px;right:5px} +.field-fileupload.style-file-single .upload-object .progress-bar .upload-progress {float:left;width:0%;height:100%;line-height:5px;color:#fff;background-color:#5fb6f5;-webkit-box-shadow:none;box-shadow:none;-webkit-transition:width 0.6s ease;transition:width 0.6s ease} +.field-fileupload.style-file-single .upload-object .meta {position:absolute;top:50%;margin-top:-44px;height:88px;right:0;width:15%} +.field-fileupload.style-file-single .upload-object .meta .upload-remove-button {position:absolute;top:50%;right:0;height:20px;margin-top:-10px;margin-right:10px;z-index:100} +.field-fileupload.style-file-single .upload-object .icon-container:after {width:20px;height:20px;margin-top:-10px;margin-left:-10px;background-size:20px 20px} +.field-fileupload.style-file-single .upload-object.is-error .icon-container:after {font-size:20px} \ No newline at end of file diff --git a/modules/backend/formwidgets/fileupload/assets/js/fileupload.js b/modules/backend/formwidgets/fileupload/assets/js/fileupload.js new file mode 100644 index 0000000..2ad476d --- /dev/null +++ b/modules/backend/formwidgets/fileupload/assets/js/fileupload.js @@ -0,0 +1,511 @@ +/* + * File upload form field control + * + * Data attributes: + * - data-control="fileupload" - enables the file upload plugin + * - data-template - a Dropzone.js template to use for each item + * - data-error-template - a popover template used to show an error + * - data-sort-handler - AJAX handler for sorting postbacks + * - data-config-handler - AJAX handler for configuration popup + * + * JavaScript API: + * $('div').fileUploader() + * + * Dependancies: + * - Dropzone.js + */ ++function ($) { "use strict"; + + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + // FILEUPLOAD CLASS DEFINITION + // ============================ + + var FileUpload = function (element, options) { + this.$el = $(element) + this.options = options || {} + + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + this.init() + } + + FileUpload.prototype = Object.create(BaseProto) + FileUpload.prototype.constructor = FileUpload + + FileUpload.prototype.init = function () { + if (this.options.isMulti === null) { + this.options.isMulti = this.$el.hasClass('is-multi') + } + + if (this.options.isPreview === null) { + this.options.isPreview = this.$el.hasClass('is-preview') + } + + if (this.options.isSortable === null) { + this.options.isSortable = this.$el.hasClass('is-sortable') + } + + this.$el.one('dispose-control', this.proxy(this.dispose)) + this.$uploadButton = $('.upload-button', this.$el) + this.$filesContainer = $('.upload-files-container', this.$el) + this.uploaderOptions = {} + + this.$el.on('click', '.upload-object.is-success', this.proxy(this.onClickSuccessObject)) + this.$el.on('click', '.upload-object.is-error', this.proxy(this.onClickErrorObject)) + + // Stop here for preview mode + if (this.options.isPreview) + return + + this.$el.on('click', '.upload-remove-button', this.proxy(this.onRemoveObject)) + + this.bindUploader() + + if (this.options.isSortable) { + this.bindSortable() + } + + } + + FileUpload.prototype.dispose = function () { + + this.$el.off('click', '.upload-object.is-success', this.proxy(this.onClickSuccessObject)) + this.$el.off('click', '.upload-object.is-error', this.proxy(this.onClickErrorObject)) + this.$el.off('click', '.upload-remove-button', this.proxy(this.onRemoveObject)) + + this.$el.off('dispose-control', this.proxy(this.dispose)) + this.$el.removeData('oc.fileUpload') + + this.$el = null + this.$uploadButton = null + this.$filesContainer = null + this.uploaderOptions = null + + // In some cases options could contain callbacks, + // so it's better to clean them up too. + this.options = null + + BaseProto.dispose.call(this) + } + + // + // Uploading + // + + FileUpload.prototype.bindUploader = function () { + this.uploaderOptions = { + url: this.options.url, + paramName: this.options.paramName, + clickable: this.$uploadButton.get(0), + previewsContainer: this.$filesContainer.get(0), + maxFilesize: this.options.maxFilesize, + timeout: 0, + headers: {} + } + + if (!this.options.isMulti) { + this.uploaderOptions.maxFiles = 1 + } else if (this.options.maxFiles) { + this.uploaderOptions.maxFiles = this.options.maxFiles + } else { + this.uploaderOptions.maxFiles = null + } + + if (this.options.fileTypes) { + this.uploaderOptions.acceptedFiles = this.options.fileTypes + } + + if (this.options.template) { + this.uploaderOptions.previewTemplate = $(this.options.template).html() + } + + this.uploaderOptions.thumbnailWidth = this.options.thumbnailWidth + ? this.options.thumbnailWidth : null + + this.uploaderOptions.thumbnailHeight = this.options.thumbnailHeight + ? this.options.thumbnailHeight : null + + this.uploaderOptions.resize = this.onResizeFileInfo + + /* + * Add CSRF token to headers + */ + var token = $('meta[name="csrf-token"]').attr('content') + if (token) { + this.uploaderOptions.headers['X-CSRF-TOKEN'] = token + } + + this.dropzone = new Dropzone(this.$el.get(0), this.uploaderOptions) + + this.dropzone.on('addedfile', this.proxy(this.onUploadAddedFile)) + this.dropzone.on('sending', this.proxy(this.onUploadSending)) + this.dropzone.on('success', this.proxy(this.onUploadSuccess)) + this.dropzone.on('error', this.proxy(this.onUploadError)) + this.dropzone.on('maxfilesreached', this.proxy(this.removeEventListeners)) + this.dropzone.on('removedfile', this.proxy(this.setupEventListeners)) + this.loadAlreadyUploadedFiles() + } + + FileUpload.prototype.removeEventListeners = function () { + this.dropzone.removeEventListeners() + } + + FileUpload.prototype.setupEventListeners = function () { + if (this.dropzone.files.length < this.dropzone.options.maxFiles) { + this.dropzone.setupEventListeners() + } + } + + FileUpload.prototype.loadAlreadyUploadedFiles = function () { + var self = this + + this.$el.find('.server-file').each(function () { + var file = $(this).data() + + self.dropzone.files.push(file) + self.dropzone.emit('addedfile', file) + self.dropzone.emit('success', file, file) + + $(this).remove() + }) + + self.dropzone._updateMaxFilesReachedClass() + } + + FileUpload.prototype.onResizeFileInfo = function (file) { + var info, + targetWidth, + targetHeight + + if (!this.options.thumbnailWidth && !this.options.thumbnailHeight) { + targetWidth = targetHeight = 100 + } + else if (this.options.thumbnailWidth) { + targetWidth = this.options.thumbnailWidth + targetHeight = this.options.thumbnailWidth * file.height / file.width + } + else if (this.options.thumbnailHeight) { + targetWidth = this.options.thumbnailHeight * file.height / file.width + targetHeight = this.options.thumbnailHeight + } + + // drawImage(image, srcX, srcY, srcWidth, srcHeight, trgX, trgY, trgWidth, trgHeight) takes an image, clips it to + // the rectangle (srcX, srcY, srcWidth, srcHeight), scales it to dimensions (trgWidth, trgHeight), and draws it + // on the canvas at coordinates (trgX, trgY). + info = { + srcX: 0, + srcY: 0, + srcWidth: file.width, + srcHeight: file.height, + trgX: 0, + trgY: 0, + trgWidth: targetWidth, + trgHeight: targetHeight + } + + return info + } + + FileUpload.prototype.onUploadAddedFile = function(file) { + var $object = $(file.previewElement).data('dzFileObject', file), + filesize = this.getFilesize(file) + + // Change filesize format to match October\Rain\Filesystem\Filesystem::sizeToString() format + $(file.previewElement).find('[data-dz-size]').html('' + filesize.size + ' ' + filesize.units) + + // Remove any exisiting objects for single variety + if (!this.options.isMulti) { + this.removeFileFromElement($object.siblings()) + } + + this.evalIsPopulated() + } + + FileUpload.prototype.onUploadSending = function (file, xhr, formData) { + this.addExtraFormData(formData) + xhr.setRequestHeader('X-OCTOBER-REQUEST-HANDLER', this.options.uploadHandler) + } + + FileUpload.prototype.onUploadSuccess = function (file, response) { + var $preview = $(file.previewElement), + $img = $('.image img', $preview) + + $preview.addClass('is-success') + + if (response.id) { + $preview.data('id', response.id) + $preview.data('path', response.path) + $('.upload-remove-button', $preview).data('request-data', { file_id: response.id }) + $img.attr('src', response.thumb) + } + + this.triggerChange(); + } + + FileUpload.prototype.onUploadError = function (file, error) { + var $preview = $(file.previewElement) + $preview.addClass('is-error') + } + + /* + * Trigger change event (Compatibility with october.form.js) + */ + FileUpload.prototype.triggerChange = function () { + this.$el.closest('[data-field-name]').trigger('change.oc.formwidget') + } + + FileUpload.prototype.addExtraFormData = function (formData) { + if (this.options.extraData) { + $.each(this.options.extraData, function (name, value) { + formData.append(name, value) + }) + } + + var $form = this.$el.closest('form') + if ($form.length > 0) { + $.each($form.serializeArray(), function (index, field) { + formData.append(field.name, field.value) + }) + } + } + + FileUpload.prototype.removeFileFromElement = function ($element) { + var self = this + + $element.each(function () { + var $el = $(this), + obj = $el.data('dzFileObject') + + if (obj) { + self.dropzone.removeFile(obj) + } + else { + $el.remove() + } + }) + } + + // + // Sorting + // + + FileUpload.prototype.bindSortable = function () { + var + self = this, + placeholderEl = $('
    ').css({ + width: this.options.imageWidth, + height: this.options.imageHeight + }) + + this.$filesContainer.sortable({ + itemSelector: 'div.upload-object.is-success', + nested: false, + tolerance: -100, + placeholder: placeholderEl, + handle: '.drag-handle', + onDrop: function ($item, container, _super) { + _super($item, container) + self.onSortAttachments() + }, + distance: 10 + }) + } + + FileUpload.prototype.onSortAttachments = function () { + if (this.options.sortHandler) { + /* + * Build an object of ID:ORDER + */ + var orderData = {} + + this.$el.find('.upload-object.is-success') + .each(function (index) { + var id = $(this).data('id') + orderData[id] = index + 1 + }) + + this.$el.request(this.options.sortHandler, { + data: { sortOrder: orderData } + }) + } + } + + // + // User interaction + // + + FileUpload.prototype.onRemoveObject = function (ev) { + var self = this, + $object = $(ev.target).closest('.upload-object') + + $(ev.target) + .closest('.upload-remove-button') + .one('ajaxPromise', function () { + $object.addClass('is-loading') + }) + .one('ajaxDone', function () { + self.removeFileFromElement($object) + self.evalIsPopulated() + self.triggerChange() + }) + .request() + + ev.stopPropagation() + } + + FileUpload.prototype.onClickSuccessObject = function(ev) { + if ($(ev.target).closest('.meta').length) return + + var $target = $(ev.target).closest('.upload-object') + + if (!this.options.configHandler) { + window.open($target.data('path')) + return + } + + $target.popup({ + handler: this.options.configHandler, + extraData: { file_id: $target.data('id') } + }) + + $target.one('popupComplete', function (event, element, modal) { + + modal.one('ajaxDone', 'button[type=submit]', function (e, context, data) { + if (data.displayName) { + $('[data-dz-name]', $target).text(data.displayName) + } + }) + }) + } + + FileUpload.prototype.onClickErrorObject = function (ev) { + var + self = this, + $target = $(ev.target).closest('.upload-object'), + errorMsg = $('[data-dz-errormessage]', $target).text(), + $template = $(this.options.errorTemplate) + + // Remove any exisiting objects for single variety + if (!this.options.isMulti) { + this.removeFileFromElement($target.siblings()) + } + + $target.ocPopover({ + content: Mustache.render($template.html(), { errorMsg: errorMsg }), + modal: true, + highlightModalTarget: true, + placement: 'top', + fallbackPlacement: 'left', + containerClass: 'popover-danger' + }) + + var $container = $target.data('oc.popover').$container + $container.one('click', '[data-remove-file]', function () { + $target.data('oc.popover').hide() + self.removeFileFromElement($target) + self.evalIsPopulated() + }) + } + + // + // Helpers + // + + FileUpload.prototype.evalIsPopulated = function () { + var isPopulated = !!$('.upload-object', this.$filesContainer).length + this.$el.toggleClass('is-populated', isPopulated) + + // Reset maxFiles counter + if (!isPopulated) { + this.dropzone.removeAllFiles() + } + } + + /* + * Replicates the formatting of October\Rain\Filesystem\Filesystem::sizeToString(). This method will return + * an object with the file size amount and the unit used as `size` and `units` respectively. + */ + FileUpload.prototype.getFilesize = function (file) { + var formatter = new Intl.NumberFormat('en', { + style: 'decimal', + minimumFractionDigits: 2, + maximumFractionDigits: 2 + }), + size = 0, + units = 'bytes' + + if (file.size >= 1073741824) { + size = formatter.format(file.size / 1073741824) + units = 'GB' + } else if (file.size >= 1048576) { + size = formatter.format(file.size / 1048576) + units = 'MB' + } else if (file.size >= 1024) { + size = formatter.format(file.size / 1024) + units = 'KB' + } else if (file.size > 1) { + size = file.size + units = 'bytes' + } else if (file.size == 1) { + size = 1 + units = 'byte' + } + + return { + size: size, + units: units + } + } + + FileUpload.DEFAULTS = { + url: window.location, + uploadHandler: null, + configHandler: null, + sortHandler: null, + extraData: {}, + paramName: 'file_data', + fileTypes: null, + maxFilesize: 256, + template: null, + errorTemplate: null, + isMulti: null, + isPreview: null, + isSortable: null, + thumbnailWidth: 120, + thumbnailHeight: 120 + } + + // FILEUPLOAD PLUGIN DEFINITION + // ============================ + + var old = $.fn.fileUploader + + $.fn.fileUploader = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('oc.fileUpload') + var options = $.extend({}, FileUpload.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.fileUpload', (data = new FileUpload(this, options))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.fileUploader.Constructor = FileUpload + + // FILEUPLOAD NO CONFLICT + // ================= + + $.fn.fileUploader.noConflict = function () { + $.fn.fileUpload = old + return this + } + + // FILEUPLOAD DATA-API + // =============== + $(document).render(function () { + $('[data-control="fileupload"]').fileUploader() + }) + +}(window.jQuery); diff --git a/modules/backend/formwidgets/fileupload/assets/less/fileupload.base.less b/modules/backend/formwidgets/fileupload/assets/less/fileupload.base.less new file mode 100644 index 0000000..d8804ca --- /dev/null +++ b/modules/backend/formwidgets/fileupload/assets/less/fileupload.base.less @@ -0,0 +1,413 @@ +.uploader-object-active() { + background: @fileupload-object-active-bg !important; + + i, p.size { + color: #ecf0f1; + } + + h4 { + color: white; + } + + .icon-container { + border-right-color: @fileupload-object-active-bg !important; + } +} + +.uploader-progress-bar() { + display: block; + width: 100%; + overflow: hidden; + height: @fileupload-progress-bar-height; + background-color: @fileupload-progress-bar-bg; + border-radius: @border-radius-base; + .box-shadow(inset 0 1px 2px rgba(0,0,0,.1)); + + .upload-progress { + float: left; + width: 0%; + height: 100%; + line-height: @fileupload-progress-bar-height; + color: @fileupload-progress-bar-color; + background-color: #5fb6f5; + .box-shadow(none); + .transition(width .6s ease); + } +} + +.uploader-block-button() { + display: block; + border: 2px dashed #BDC3C7; + background-clip: content-box; + background-color: #F9F9F9; + position: relative; + outline: none; + + .upload-button-icon { + position: absolute; + width: 22px; + height: 22px; + top: 50%; + left: 50%; + margin-top: -11px; + margin-left: -11px; + + &:before { + text-align: center; + display: block; + font-size: 22px; + height: 22px; + width: 22px; + line-height: 22px; + color: #BDC3C7; + } + + &.large-icon { + width: 34px; + height: 34px; + top: 50%; + left: 50%; + margin-top: -17px; + margin-left: -17px; + + &:before { + font-size: 34px; + height: 24px; + width: 24px; + line-height: 24px; + } + } + } + + &:hover { + border: 2px dashed #1F99DC; + + .upload-button-icon:before { + color: #1F99DC; + } + } + + &:focus { + border: 2px dashed #1F99DC; + + .upload-button-icon:before { + color: #1F99DC; + } + } +} + +.uploader-small-loader() { + width: 20px; + height: 20px; + margin-top: -10px; + margin-left: -10px; + background-size: 20px 20px; +} + +.uploader-vertical-align() { + position: absolute; + top: 50%; + margin-top: -44px; + height: 88px; +} + +// +// Shared +// + +.field-fileupload { + + // + // Uploaded item + // + + .upload-object { + + .border-radius(3px); + position: relative; + outline: none; + overflow: hidden; + display: inline-block; + vertical-align: top; + + img { + width: 100%; + height: 100%; + } + + .icon-container { + display: table; + opacity: .6; + + i { + color: #95a5a6; + display: inline-block; + } + + div { + display: table-cell; + text-align: center; + vertical-align: middle; + } + } + + .icon-container.image { + > div.icon-wrapper { + display: none; + } + } + + h4 { + font-size: 13px; + color: #2A3E51; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + line-height: 150%; + margin: 15px 0 5px 0; + padding-right: 0; + .transition(padding 0.1s); + + position: relative; + + a { + position: absolute; + right: 0; + top: 0; + display: none; + font-weight: 400; + } + } + + p.size { + font-size: 12px; + color: #95a5a6; + strong { font-weight: 400; } + } + + .meta { + .drag-handle { + position: absolute; + bottom: 0; + right: 0; + cursor: move; + display: block; + } + } + + .info h4 a, + .meta a.upload-remove-button, + .meta a.drag-handle { + color: #2b3e50; + display: none; + font-size: 13px; + text-decoration: none; + } + + } + + // + // Loading State + // + + .upload-object { + .icon-container { + position: relative; + } + + .icon-container:after { + background-image: url('../../../../../system/assets/ui/images/loader-transparent.svg'); + position: absolute; + content: ' '; + width: 40px; + height: 40px; + left: 50%; + top: 50%; + margin-top: -20px; + margin-left: -20px; + display: block; + background-size: 40px 40px; + background-position: 50% 50%; + .animation(spin 1s linear infinite); + } + + &.is-success { + .icon-container { + opacity: 1; + } + .icon-container:after { + opacity: 0; + .transition(opacity .3s ease); + } + } + + // Replaces the loader with an error symbol + &.is-error { + .icon-container:after { + content: ""; + background: none; + .icon(@exclamation-triangle); + .animation(none); + font-size: 40px; + color: #ab2a1c; + margin-top: -20px; + margin-left: -20px; + text-shadow: 2px 2px 0 #fff; + } + } + + &.is-loading { + .icon-container { + opacity: .6; + } + .icon-container:after { + opacity: 1; + .transition(opacity .3s ease); + } + } + } + + // + // Success state + // + + .upload-object.is-success { + cursor: pointer; + + .progress-bar { + opacity: 0; + .transition(opacity .3s ease); + } + + &:hover { + h4 a, + .meta .upload-remove-button, + .meta .drag-handle { display: block; } + } + } + + // + // Error State + // + + .upload-object.is-error { + cursor: pointer; + + .icon-container { + opacity: 1; + > img, > i { + opacity: .5; + } + } + + .info h4 { + color: #ab2a1c; + a { + display: none; + } + } + + .meta { + display: none; + } + } + + // + // Sortable + // + + &.is-sortable { + position: relative; + + .upload-placeholder { + position: relative; + border: 1px dotted #e0e0e0 !important; + } + + .upload-object.dragged { + position: absolute; + .opacity(.5); + z-index: 2000; + .uploader-toolbar { + display: none; + } + } + } + + // + // Preview mode + // + + &.is-preview { + .upload-button, + .upload-remove-button, + .meta a.drag-handle { + display: none !important; + } + } +} + +// +// Media +// + +@media (max-width: 1024px) { + .field-fileupload { + .upload-object.is-success { + h4 a, + .meta .upload-remove-button, + .meta .drag-handle { display: block !important; } + } + } +} + +// +// Config form +// + +.fileupload-config-form { + .fileupload-url-button{ + padding-left: 0; + > i { + color: #666; + } + } + + .file-upload-modal-image-header { + // Photoshop transparent background + // Based on: http://lea.verou.me/css3patterns/#checkerboard + background-color: #FEFEFE; + background-image: -webkit-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB), -webkit-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB); + background-image: -moz-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB), -moz-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB); + background-image: -o-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB), -o-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB); + background-image: -ms-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB), -ms-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB); + background-image: linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB), linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB); + -webkit-background-size: 20px 20px; + -moz-background-size: 20px 20px; + background-size: 20px 20px; + background-position: 0 0, 10px 10px; + + + &, img { + .border-top-radius(2px); + } + + .close { + position: absolute; + top: 20px; + right: 20px; + background: #BDC3C7; + opacity: .7; + height: 24px; + width: 22px; + + &:hover, &:focus { + opacity: .9; + } + } + } + + .file-upload-modal-image-header + .modal-body { + padding-top: @padding-standard; + } +} diff --git a/modules/backend/formwidgets/fileupload/assets/less/fileupload.filemulti.less b/modules/backend/formwidgets/fileupload/assets/less/fileupload.filemulti.less new file mode 100644 index 0000000..5fa0106 --- /dev/null +++ b/modules/backend/formwidgets/fileupload/assets/less/fileupload.filemulti.less @@ -0,0 +1,176 @@ +// +// Multi File +// + +.field-fileupload.style-file-multi { + .upload-button { + margin-bottom: 10px; + } + + .upload-files-container { + border: 1px solid @fileupload-list-border-color; + .border-radius(3px); + border-bottom: none; + display: none; + } + + &.is-populated .upload-files-container { + display: block; + } + + .upload-object { + display: block; + width: 100%; + border-bottom: 1px solid @fileupload-list-border-color; + padding-left: 10px; + + &:nth-child(even) { + background-color: @fileupload-list-accent-bg; + } + + .icon-container { + position: absolute; + top: 0; + left: 10px; + width: 15px; + padding: 11px 7px; + + i { + line-height: 150%; + font-size: 15px; + } + + img { display: none; } + } + + .info { + margin-left: 35px; + margin-right: 15%; + + h4, p { + margin: 0; + padding: 11px 0; + font-size: 12px; + font-weight: normal; + line-height: 150%; + color: #666666; + } + + h4 { + padding-right: 15px; + + a { + padding: 10px 0; + right: 15px; + } + } + + p.size { + position: absolute; + top: 0; + right: 0; + width: 15%; + display: none; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + + .progress-bar { + .uploader-progress-bar(); + position: absolute; + top: 18px; + left: 0; + } + + .meta { + position: absolute; + top: 0; + right: 0; + margin-right: 15px; + width: 15%; + + a.drag-handle { + top: -2px; + bottom: auto; + line-height: 150%; + padding: 10px 0; + } + } + + .icon-container:after { + .uploader-small-loader(); + } + + &.is-error .icon-container:after { + font-size: 20px; + } + + // + // Success + // + + &.is-success { + .info p.size { display: block; } + } + + // + // Sorting + // + + &.upload-placeholder { + height: 35px; + background-color: transparent; + &:after { opacity: 0; } + } + + // + // Hover + // + + &:hover { + .uploader-object-active(); + h4 { padding-right: 35px; } + } + } +} + +// +// Media +// + +@media (max-width: @screen-md-max) { + .field-fileupload.style-file-multi { + .info { + margin-right: 20% !important; + p.size { + width: 20% !important; + } + } + + .meta { + width: 20% !important; + } + } +} + +@media (max-width: @screen-sm-max) { + .field-fileupload.style-file-multi { + .upload-object { + h4 { padding-right: 35px !important; } + } + + .info { + margin-right: 25% !important; + p.size { + width: 25% !important; + padding-right: 35px !important; + } + } + + .meta { + width: 25% !important; + } + } +} \ No newline at end of file diff --git a/modules/backend/formwidgets/fileupload/assets/less/fileupload.filesingle.less b/modules/backend/formwidgets/fileupload/assets/less/fileupload.filesingle.less new file mode 100644 index 0000000..e6305be --- /dev/null +++ b/modules/backend/formwidgets/fileupload/assets/less/fileupload.filesingle.less @@ -0,0 +1,119 @@ +// +// Single File +// + +.field-fileupload.style-file-single { + background-color: @color-form-field-bg; + border: 1px solid @color-form-field-border; + overflow: hidden; + position: relative; + padding-right: 30px; + border-radius: 3px; + .box-shadow(@input-box-shadow); + + .upload-button { + .uploader-vertical-align(); + background: transparent; + right: -2px; + + color: lighten(@color-form-field-recordfinder-btn, 15%); + + i { + font-size: 14px; + } + + &:hover { + color: @color-form-field-recordfinder-btn; + } + } + + .upload-empty-message { + padding: 8px 0 8px 11px; + font-size: 14px; + } + + &.is-populated { + .upload-empty-message { + display: none; + } + } + + .upload-object { + display: block; + width: 100%; + padding: 7px 0 9px 0; + + .icon-container { + position: absolute; + top: 0; + left: 0; + width: 15px; + padding: 0 5px; + margin: 8px 0 0 7px; + text-align: center; + + i { + line-height: 150%; + font-size: 15px; + } + + img { display: none; } + } + + .info { + margin-left: 34px; + margin-right: 15%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + h4, p { + display: inline; + margin: 0; + padding: 0; + font-size: 13px; + line-height: 150%; + color: #666666; + } + + p.size { + font-weight: normal; + &:before { + content: " - "; + } + } + } + + .progress-bar { + .uploader-progress-bar(); + position: absolute; + top: 50%; + margin-top: -2px; + right: 5px; + } + + .meta { + .uploader-vertical-align(); + right: 0; + width: 15%; + .upload-remove-button { + position: absolute; + top: 50%; + right: 0; + height: 20px; + margin-top: -10px; + margin-right: 10px; + z-index: 100; + } + } + + .icon-container:after { + .uploader-small-loader(); + } + + &.is-error .icon-container:after { + font-size: 20px; + } + } + +} \ No newline at end of file diff --git a/modules/backend/formwidgets/fileupload/assets/less/fileupload.imagemulti.less b/modules/backend/formwidgets/fileupload/assets/less/fileupload.imagemulti.less new file mode 100644 index 0000000..79c2eb3 --- /dev/null +++ b/modules/backend/formwidgets/fileupload/assets/less/fileupload.imagemulti.less @@ -0,0 +1,134 @@ +// +// Multi Image +// + +.field-fileupload.style-image-multi { + .upload-button, + .upload-object { + margin: 0 10px 10px 0; + } + + .upload-button { + .uploader-block-button(); + float: left; + width: 76px; + height: 76px; + } + + .upload-files-container { + margin-left: 90px; + } + + .upload-object { + background: #fff; + border: 1px solid #ecf0f1; + width: 260px; + + .progress-bar { + .uploader-progress-bar(); + position: absolute; + bottom: 10px; + left: 0; + } + + .icon-container { + border-right: 1px solid #f6f8f9; + float: left; + display: inline-block; + overflow: hidden; + width: 75px; + height: 75px; + + i { + font-size: 35px; + } + + &.image img { + .border-left-radius(3px); + width: auto; + } + } + + .info { + margin-left: 90px; + + h4 { + padding-right: 15px; + a { + right: 15px; + } + } + } + + .meta { + position: absolute; + bottom: 0; + left: 0; + right: 0; + margin: 0 15px 0 90px; + + a.drag-handle { + bottom: 15px; + } + } + + &.upload-placeholder { + height: 75px; + background-color: transparent; + &:after { opacity: 0; } + } + + &:hover { + .uploader-object-active(); + h4 { padding-right: 35px; } + } + } + + &.is-preview { + .upload-files-container { + margin-left: 0; + } + } +} + +// +// On Sidebar +// + +.form-sidebar .field-fileupload.style-image-multi .upload-files-container { + margin-left: 0px; +} + +.form-sidebar .field-fileupload.style-image-multi .upload-button { + width: 100%; +} + +// +// Media +// + +@media (max-width: 1280px) { + .field-fileupload.style-image-multi { + .upload-object { + width: 230px; + } + } +} + +@media (max-width: 1024px) { + .field-fileupload.style-image-multi { + .upload-button { + width: 100%; + } + + .upload-files-container { + margin-left: 0; + } + + .upload-object { + margin-right: 0; + display: block; + width: auto; + } + } +} \ No newline at end of file diff --git a/modules/backend/formwidgets/fileupload/assets/less/fileupload.imagesingle.less b/modules/backend/formwidgets/fileupload/assets/less/fileupload.imagesingle.less new file mode 100644 index 0000000..a0b4982 --- /dev/null +++ b/modules/backend/formwidgets/fileupload/assets/less/fileupload.imagesingle.less @@ -0,0 +1,78 @@ +// +// Single Image +// + +.field-fileupload.style-image-single { + &.is-populated { + .upload-button { + display: none; + } + } + + .upload-button { + .uploader-block-button(); + min-height: 100px; + min-width: 100px; + } + + .upload-object { + padding-bottom: 66px; + + .icon-container { + border: 1px solid #f6f8f9; + background: rgba(255,255,255,.5); + + &.image img { + .border-radius(3px); + .img-responsive(); + + // This is needed when the image is very large and + // being processed by dropzone on the client-side + // the image has no height or width. + min-height: 100px; + min-width: 100px; + } + } + + .progress-bar { + .uploader-progress-bar(); + position: absolute; + bottom: 10px; + left: 0; + } + + .info { + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 66px; + } + + .meta { + position: absolute; + bottom: 65px; + left: 0; + right: 0; + margin: 0 15px; + } + + &:hover { + h4 { padding-right: 20px; } + } + } + +} + + +// +// Media +// + +@media (max-width: 1024px) { + .field-fileupload.style-image-single { + .upload-object { + h4 { padding-right: 20px !important; } + } + } +} \ No newline at end of file diff --git a/modules/backend/formwidgets/fileupload/assets/less/fileupload.less b/modules/backend/formwidgets/fileupload/assets/less/fileupload.less new file mode 100644 index 0000000..3415f98 --- /dev/null +++ b/modules/backend/formwidgets/fileupload/assets/less/fileupload.less @@ -0,0 +1,15 @@ +@import "../../../../assets/less/core/boot.less"; + +@fileupload-progress-bar-height: 5px; +@fileupload-progress-bar-color: #fff; +@fileupload-progress-bar-bg: #f5f5f5; +@fileupload-inactive-icon: #808b93; +@fileupload-object-active-bg: #4da7e8; +@fileupload-list-accent-bg: #f5f5f5; +@fileupload-list-border-color: #eeeeee; + +@import "fileupload.base.less"; +@import "fileupload.imagemulti.less"; +@import "fileupload.imagesingle.less"; +@import "fileupload.filemulti.less"; +@import "fileupload.filesingle.less"; diff --git a/modules/backend/formwidgets/fileupload/partials/_config_form.htm b/modules/backend/formwidgets/fileupload/partials/_config_form.htm new file mode 100644 index 0000000..91302a4 --- /dev/null +++ b/modules/backend/formwidgets/fileupload/partials/_config_form.htm @@ -0,0 +1,47 @@ +
    + + + + + + +
    + + +
    + + + + + + +
    diff --git a/modules/backend/formwidgets/fileupload/partials/_file_multi.htm b/modules/backend/formwidgets/fileupload/partials/_file_multi.htm new file mode 100644 index 0000000..46a7b89 --- /dev/null +++ b/modules/backend/formwidgets/fileupload/partials/_file_multi.htm @@ -0,0 +1,61 @@ +
    data-config-handler="getEventHandler('onLoadAttachmentConfig') ?>" + data-file-types="" + data-max-files="" + formField->getAttributes() ?> +> + + + + + +
    + +
    + +
    +
    + + + diff --git a/modules/backend/formwidgets/fileupload/partials/_file_single.htm b/modules/backend/formwidgets/fileupload/partials/_file_single.htm new file mode 100644 index 0000000..b38e083 --- /dev/null +++ b/modules/backend/formwidgets/fileupload/partials/_file_single.htm @@ -0,0 +1,76 @@ +
    data-config-handler="getEventHandler('onLoadAttachmentConfig') ?>" + data-file-types="" + formField->getAttributes() ?> +> + + + + + +
    + +
    +
    + +
    +
    +

    + title ?: $singleFile->file_name) ?> +

    +

    sizeToString()) ?>

    +
    +
    + +
    +
    + +
    + + +
    + +
    + +
    + + + diff --git a/modules/backend/formwidgets/fileupload/partials/_fileupload.htm b/modules/backend/formwidgets/fileupload/partials/_fileupload.htm new file mode 100644 index 0000000..84cc65a --- /dev/null +++ b/modules/backend/formwidgets/fileupload/partials/_fileupload.htm @@ -0,0 +1,39 @@ +previewMode && !$fileList->count()): ?> + + + + + + + makePartial('image_single') ?> + + + + makePartial('image_multi') ?> + + + + makePartial('file_single') ?> + + + + makePartial('file_multi') ?> + + + + + + + + \ No newline at end of file diff --git a/modules/backend/formwidgets/fileupload/partials/_image_multi.htm b/modules/backend/formwidgets/fileupload/partials/_image_multi.htm new file mode 100644 index 0000000..28792c6 --- /dev/null +++ b/modules/backend/formwidgets/fileupload/partials/_image_multi.htm @@ -0,0 +1,60 @@ +
    data-config-handler="getEventHandler('onLoadAttachmentConfig') ?>" + data-file-types="" + data-max-files="" + formField->getAttributes() ?> +> + + + + + + + +
    + +
    + +
    +
    + + + diff --git a/modules/backend/formwidgets/fileupload/partials/_image_single.htm b/modules/backend/formwidgets/fileupload/partials/_image_single.htm new file mode 100644 index 0000000..a9cba6b --- /dev/null +++ b/modules/backend/formwidgets/fileupload/partials/_image_single.htm @@ -0,0 +1,74 @@ +
    data-config-handler="getEventHandler('onLoadAttachmentConfig') ?>" + data-file-types="" + formField->getAttributes() ?> +> + + + + + + + +
    + +
    +
    + +
    +
    +

    + title ?: $singleFile->file_name) ?> + +

    +

    sizeToString()) ?>

    +
    +
    +
    + +
    + +
    + + + diff --git a/modules/backend/formwidgets/markdowneditor/assets/css/markdowneditor.css b/modules/backend/formwidgets/markdowneditor/assets/css/markdowneditor.css new file mode 100644 index 0000000..c2f36b0 --- /dev/null +++ b/modules/backend/formwidgets/markdowneditor/assets/css/markdowneditor.css @@ -0,0 +1,77 @@ +.field-markdowneditor {width:100%;position:relative;border:1px solid #d1d6d9;background:#fff;-webkit-transition:border-color ease-in-out 0.15s,box-shadow ease-in-out 0.15s;transition:border-color ease-in-out 0.15s,box-shadow ease-in-out 0.15s;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px} +.field-markdowneditor textarea {opacity:0;filter:alpha(opacity=0)} +.field-markdowneditor .editor-toolbar {border-top-right-radius:5px;border-top-left-radius:5px} +.field-markdowneditor.editor-focus {border:1px solid #d1d6d9} +.field-markdowneditor.size-tiny .editor-write {min-height:50px} +.field-markdowneditor.size-tiny .editor-preview {height:50px} +.field-markdowneditor.size-tiny.stretch {min-height:90px} +.field-markdowneditor.size-small .editor-write {min-height:100px} +.field-markdowneditor.size-small .editor-preview {height:100px} +.field-markdowneditor.size-small.stretch {min-height:140px} +.field-markdowneditor.size-large .editor-write {min-height:200px} +.field-markdowneditor.size-large .editor-preview {height:200px} +.field-markdowneditor.size-large.stretch {min-height:240px} +.field-markdowneditor.size-huge .editor-write {min-height:250px} +.field-markdowneditor.size-huge .editor-preview {height:250px} +.field-markdowneditor.size-huge.stretch {min-height:290px} +.field-markdowneditor.size-giant .editor-write {min-height:350px} +.field-markdowneditor.size-giant .editor-preview {height:350px} +.field-markdowneditor.size-giant.stretch {min-height:390px} +.field-markdowneditor .editor-write {position:relative} +.field-markdowneditor .editor-preview {padding:15px;overflow:auto} +.field-markdowneditor .editor-preview-loader {display:block;width:20px;height:20px;position:absolute;right:10px;top:10px;margin-top:40px;background-image:url('../../../../../system/assets/ui/images/loader-transparent.svg');background-size:20px 20px;background-position:50% 50%;-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite} +.field-markdowneditor.mode-tab .editor-preview {display:none} +.field-markdowneditor.mode-tab.is-preview .editor-write {display:none} +.field-markdowneditor.mode-tab.is-preview .editor-preview {display:block} +.field-markdowneditor.mode-split {overflow:hidden} +.field-markdowneditor.mode-split .editor-preview {float:right;width:50%} +.field-markdowneditor.mode-split .editor-write {float:left;width:50%} +.field-markdowneditor.mode-split .editor-write .editor-code {border-right:2px solid #808C8D} +.field-markdowneditor.stretch, +.field-markdowneditor.stretch .editor-toolbar {border-radius:0 !important} +.field-markdowneditor.stretch .editor-toolbar {height:auto} +.field-markdowneditor.stretch .editor-write {float:none;height:calc(100% - 40px);position:relative;min-height:0} +.field-markdowneditor.stretch .editor-preview {float:none;height:auto;position:absolute;left:0;right:0;top:0;bottom:0;margin-top:40px} +.field-markdowneditor.stretch.mode-split .editor-preview {left:auto} +.field-markdowneditor.stretch.mode-split .editor-write {right:auto} +.field-markdowneditor.is-fullscreen {z-index:600;position:fixed !important;top:0;left:0;width:100%} +.field-markdowneditor.is-fullscreen, +.field-markdowneditor.is-fullscreen .editor-toolbar {border-radius:0 !important;border:none} +.field-markdowneditor.disabled .ace_scroller {cursor:not-allowed} +.field-markdowneditor.disabled .control-toolbar.editor-toolbar .toolbar-item .btn {cursor:not-allowed;color:#bdbdbd} +.field-markdowneditor.disabled .control-toolbar.editor-toolbar .toolbar-item .btn:hover {background-color:transparent;color:#bdbdbd} +.field-markdowneditor.disabled .control-toolbar.editor-toolbar .toolbar-item .btn.oc-autumn-button {color:#bdbdbd !important} +.field-markdowneditor .editor-preview {color:#515c5d;font-family:"Helvetica",sans-serif;line-height:180%} +.field-markdowneditor .editor-preview h1, +.field-markdowneditor .editor-preview h2, +.field-markdowneditor .editor-preview h3, +.field-markdowneditor .editor-preview h4, +.field-markdowneditor .editor-preview h5, +.field-markdowneditor .editor-preview h6 {margin-top:20px;font-weight:bold} +.field-markdowneditor .editor-preview h1:first-child, +.field-markdowneditor .editor-preview h2:first-child, +.field-markdowneditor .editor-preview h3:first-child, +.field-markdowneditor .editor-preview h4:first-child, +.field-markdowneditor .editor-preview h5:first-child, +.field-markdowneditor .editor-preview h6:first-child {margin-top:0} +.field-markdowneditor .editor-preview *:last-child {margin-bottom:0} +.field-markdowneditor .editor-preview h1 {font-size:30px} +.field-markdowneditor .editor-preview h2 {font-size:26px} +.field-markdowneditor .editor-preview h3 {font-size:24px} +.field-markdowneditor .editor-preview h4 {font-size:22px} +.field-markdowneditor .editor-preview h5 {font-size:20px} +.field-markdowneditor .editor-preview h6 {font-size:18px} +.field-markdowneditor .editor-preview p, +.field-markdowneditor .editor-preview ol, +.field-markdowneditor .editor-preview ul {font-size:14px} +.field-markdowneditor .editor-preview h1, +.field-markdowneditor .editor-preview h2, +.field-markdowneditor .editor-preview h3, +.field-markdowneditor .editor-preview h4, +.field-markdowneditor .editor-preview h5, +.field-markdowneditor .editor-preview h6, +.field-markdowneditor .editor-preview p, +.field-markdowneditor .editor-preview ol, +.field-markdowneditor .editor-preview ul {margin-bottom:15px} +.field-markdowneditor .editor-preview pre.prettyprint {border-width:0;padding:13px 16px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;line-height:130%} +.field-markdowneditor .editor-preview img {display:block;max-width:100%;height:auto} \ No newline at end of file diff --git a/modules/backend/formwidgets/markdowneditor/assets/js/markdowneditor.js b/modules/backend/formwidgets/markdowneditor/assets/js/markdowneditor.js new file mode 100644 index 0000000..881cab6 --- /dev/null +++ b/modules/backend/formwidgets/markdowneditor/assets/js/markdowneditor.js @@ -0,0 +1,867 @@ ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var MarkdownEditor = function (element, options) { + this.$el = $(element) + this.options = options || {} + this.$textarea = $('textarea:first', this.$el) + this.$toolbar = $('.editor-toolbar:first', this.$el) + this.$write = $('.editor-write:first', this.$el) + this.$preview = $('.editor-preview:first', this.$el) + this.$code = null + this.editor = null + this.$form = null + this.$buttons = null + this.$fixedButtons = null + this.$indicator = null + this.editorPadding = 15 + this.updatesPaused = false + + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + this.init() + } + + MarkdownEditor.prototype = Object.create(BaseProto) + MarkdownEditor.prototype.constructor = MarkdownEditor + + MarkdownEditor.prototype.init = function() { + this.$el.one('dispose-control', this.proxy(this.dispose)) + + /* + * Control must have an identifier + */ + if (!this.$el.attr('id')) { + this.$el.attr('id', 'element-' + Math.random().toString(36).substring(7)) + } + + this.$form = this.$el.closest('form') + + this.createCodeContainer() + this.createToolbar() + this.createIndicator() + this.setViewMode(this.options.viewMode) + + this.$toolbar.on('click', '.btn, .md-dropdown-button', this.proxy(this.onClickToolbarButton)) + this.$form.on('oc.beforeRequest', this.proxy(this.onBeforeRequest)) + this.editor.on('change', this.proxy(this.onEditorChange)) + this.editor.getSession().on('changeScrollTop', this.proxy(this.onEditorScrollTop)) + + $('[data-control="tooltip"]', this.$toolbar).tooltip() + $('[data-toggle="dropdown"]', this.$toolbar).dropdown() + } + + MarkdownEditor.prototype.dispose = function() { + this.$el.off('dispose-control', this.proxy(this.dispose)) + + this.$toolbar.off('click', '.btn, .md-dropdown-button', this.proxy(this.onClickToolbarButton)) + this.$form.off('oc.beforeRequest', this.proxy(this.onBeforeRequest)) + this.editor.off('change', this.proxy(this.onEditorChange)) + $(window).off('resize', this.proxy(this.updateFullscreen)) + + this.$el.removeData('oc.markdownEditor') + + this.$el = null + this.$textarea = null + this.$toolbar = null + this.$write = null + this.$preview = null + this.$code = null + this.editor = null + this.$form = null + this.$buttons = null + this.$fixedButtons = null + this.$indicator = null + this.editorPadding = null + this.updatesPaused = null + + this.isSplitMode = null + this.isPreview = null + this.isFullscreen = null + this.dataTrackInputTimer = null + + this.options = null + + BaseProto.dispose.call(this) + } + + // + // Events + // + + MarkdownEditor.prototype.onClickToolbarButton = function(ev) { + if (this.options.disabled) { + return; + } + + var $target = $(ev.target), + $button = $target.is('a') ? $target : $target.closest('.btn'), + action = $button.data('button-action'), + template = $button.data('button-template') + + $button.blur() + + this.pauseUpdates() + + if (template) { + this[action](template) + } + else { + this[action]() + } + + this.resumeUpdates() + this.handleChange() + } + + MarkdownEditor.prototype.onEditorScrollTop = function(scroll) { + if (!this.isSplitMode) return + + var canvasHeight = this.$preview.height(), + editorHeight, + previewHeight, + scrollRatio + + if (canvasHeight != this.$el.data('markdowneditor-canvas-height')) { + + editorHeight = + (this.editor.getSession().getScreenLength() * + this.editor.renderer.lineHeight) - + canvasHeight + + previewHeight = this.$preview.get(0).scrollHeight - canvasHeight + + scrollRatio = previewHeight / editorHeight + + this.$el.data('markdowneditor-canvas-height', canvasHeight) + this.$el.data('markdowneditor-scroll-ratio', scrollRatio) + } + else { + scrollRatio = this.$el.data('markdowneditor-scroll-ratio') + } + + scroll += this.editorPadding + this.$preview.scrollTop(scroll * scrollRatio) + } + + MarkdownEditor.prototype.onEditorChange = function() { + var html = this.editor.getSession().getValue() + + this.$form.trigger('change') + + this.$textarea.trigger('changeContent.oc.markdowneditor', [this, html]) + + this.handleChange() + } + + MarkdownEditor.prototype.onBeforeRequest = function() { + this.$textarea.val(this.editor.getSession().getValue()) + } + + MarkdownEditor.prototype.onResize = function() { + this.editor.resize() + } + + MarkdownEditor.prototype.onBlur = function() { + this.$el.removeClass('editor-focus') + } + + MarkdownEditor.prototype.onFocus = function() { + this.$el.addClass('editor-focus') + } + + // + // Toolbar + // + + MarkdownEditor.prototype.createToolbar = function() { + var self = this, + $button, + $buttons = $('
    '), + $fixedButtons = $('
    ') + + $.each($.oc.markdownEditorButtons, function(code, button) { + $button = self.makeToolbarButton(code, button) + + if (button.fixed) { + $fixedButtons.append($button) + } + else { + $buttons.append($button) + } + + if (button.dropdown) { + $button.attr('data-toggle', 'dropdown') + self.createToolbarDropdown(button, $button) + } + }) + + $buttons.wrapInner('
    ') + this.$toolbar.append($buttons) + this.$toolbar.append($fixedButtons) + + this.$fixedButtons = $fixedButtons + this.$buttons = $buttons + } + + MarkdownEditor.prototype.createToolbarDropdown = function(button, $el) { + if (this.options.disabled) { + return; + } + + var $dropdown = $('';return c;},callback:function(cmd,val){this.video.align(val);},refresh:function($btn){this.video.refreshAlign($btn);},refreshOnShow:function($btn,$dropdown){this.video.refreshAlignOnShow($btn,$dropdown);}}) +$.FE.DefineIcon('videoRemove',{NAME:'trash'}) +$.FE.RegisterCommand('videoRemove',{title:'Remove',callback:function(){this.video.remove();}}) +$.FE.DefineIcon('videoSize',{NAME:'arrows-alt'}) +$.FE.RegisterCommand('videoSize',{undo:false,focus:false,title:'Change Size',callback:function(){this.video.showSizePopup();}});$.FE.DefineIcon('videoBack',{NAME:'arrow-left'});$.FE.RegisterCommand('videoBack',{title:'Back',undo:false,focus:false,back:true,callback:function(){this.video.back();},refresh:function($btn){var $current_video=this.video.get();if(!$current_video&&!this.opts.toolbarInline){$btn.addClass('fr-hidden');$btn.next('.fr-separator').addClass('fr-hidden');} +else{$btn.removeClass('fr-hidden');$btn.next('.fr-separator').removeClass('fr-hidden');}}});$.FE.RegisterCommand('videoSetSize',{undo:true,focus:false,callback:function(){this.video.setSize();}})}));(function(factory){if(typeof define==='function'&&define.amd){define(['jquery'],factory);}else if(typeof module==='object'&&module.exports){module.exports=function(root,jQuery){if(jQuery===undefined){if(typeof window!=='undefined'){jQuery=require('jquery');} +else{jQuery=require('jquery')(root);}} +factory(jQuery);return jQuery;};}else{factory(jQuery);}}(function($){'use strict';$.extend($.FE.POPUP_TEMPLATES,{'audio.insert':'[_BUTTONS_][_BY_URL_LAYER_][_EMBED_LAYER_]','audio.edit':'[_BUTTONS_]','audio.size':'[_BUTTONS_][_SIZE_LAYER_]'}) +$.extend($.FE.DEFAULTS,{audioInsertButtons:['audioBack','|','audioByURL','audioEmbed'],audioEditButtons:['audioDisplay','audioAlign','audioSize','audioRemove'],audioResize:true,audioSizeButtons:['audioBack','|'],audioSplitHTML:false,audioTextNear:true,audioDefaultAlign:'center',audioDefaultDisplay:'block',audioMove:true});$.FE.VIDEO_PROVIDERS=[];$.FE.VIDEO_EMBED_REGEX=/^\W*((<\/iframe>)|())\W*$/i;$.FE.PLUGINS.audio=function(editor){var $overlay;var $handler;var $audio_resizer;var $current_audio;function _refreshInsertPopup(){var $popup=editor.popups.get('audio.insert');var $url_input=$popup.find('.fr-audio-by-url-layer input');$url_input.val('').trigger('change');var $embed_area=$popup.find('.fr-audio-embed-layer textarea');$embed_area.val('').trigger('change');} +function showInsertPopup(){var $btn=editor.$tb.find('.fr-command[data-cmd="insertAudio"]');var $popup=editor.popups.get('audio.insert');if(!$popup)$popup=_initInsertPopup();if(!$popup.hasClass('fr-active')){editor.popups.refresh('audio.insert');editor.popups.setContainer('audio.insert',editor.$tb);var left=$btn.offset().left+$btn.outerWidth()/2;var top=$btn.offset().top+(editor.opts.toolbarBottom?10:$btn.outerHeight()-10);editor.popups.show('audio.insert',left,top,$btn.outerHeight());}} +function _showEditPopup(){var $popup=editor.popups.get('audio.edit');if(!$popup)$popup=_initEditPopup();editor.popups.setContainer('audio.edit',$(editor.opts.scrollableContainer));editor.popups.refresh('audio.edit');var $audio_obj=$current_audio.find('iframe, embed, audio');var left=$audio_obj.offset().left+$audio_obj.outerWidth()/2;var top=$audio_obj.offset().top+$audio_obj.outerHeight();editor.popups.show('audio.edit',left,top,$audio_obj.outerHeight());} +function _initInsertPopup(delayed){if(delayed){editor.popups.onRefresh('audio.insert',_refreshInsertPopup);return true;} +var audio_buttons='';if(editor.opts.audioInsertButtons.length>1){audio_buttons='
    '+editor.button.buildList(editor.opts.audioInsertButtons)+'
    ';} +var by_url_layer='';if(editor.opts.audioInsertButtons.indexOf('audioByURL')>=0){by_url_layer='
    '} +var embed_layer='';if(editor.opts.audioInsertButtons.indexOf('audioEmbed')>=0){embed_layer='
    '} +var template={buttons:audio_buttons,by_url_layer:by_url_layer,embed_layer:embed_layer} +var $popup=editor.popups.create('audio.insert',template);return $popup;} +function showLayer(name){var $popup=editor.popups.get('audio.insert');var left;var top;if(!$current_audio&&!editor.opts.toolbarInline){var $btn=editor.$tb.find('.fr-command[data-cmd="insertAudio"]');left=$btn.offset().left+$btn.outerWidth()/2;top=$btn.offset().top+(editor.opts.toolbarBottom?10:$btn.outerHeight()-10);} +if(editor.opts.toolbarInline){top=$popup.offset().top-editor.helpers.getPX($popup.css('margin-top'));if($popup.hasClass('fr-above')){top+=$popup.outerHeight();}} +$popup.find('.fr-layer').removeClass('fr-active');$popup.find('.fr-'+name+'-layer').addClass('fr-active');editor.popups.show('audio.insert',left,top,0);} +function refreshByURLButton($btn){var $popup=editor.popups.get('audio.insert');if($popup.find('.fr-audio-by-url-layer').hasClass('fr-active')){$btn.addClass('fr-active');}} +function refreshEmbedButton($btn){var $popup=editor.popups.get('audio.insert');if($popup.find('.fr-audio-embed-layer').hasClass('fr-active')){$btn.addClass('fr-active');}} +function insert(embedded_code){editor.events.focus(true);editor.selection.restore();editor.html.insert(''+embedded_code+'',false,editor.opts.audioSplitHTML);editor.popups.hide('audio.insert');var $audio=editor.$el.find('.fr-jiv');$audio.removeClass('fr-jiv');$audio.toggleClass('fr-draggable',editor.opts.audioMove);editor.events.trigger('audio.inserted',[$audio]);} +function insertByURL(link){if(typeof link=='undefined'){var $popup=editor.popups.get('audio.insert');link=$popup.find('.fr-audio-by-url-layer input[type="text"]').val()||'';} +var audio=null;if(editor.helpers.isURL(link)){for(var i=0;i<$.FE.VIDEO_PROVIDERS.length;i++){var vp=$.FE.VIDEO_PROVIDERS[i];if(vp.test_regex.test(link)){audio=link.replace(vp.url_regex,vp.url_text);audio=vp.html.replace(/\{url\}/,audio);break;}}} +if(audio){insert(audio);} +else{editor.events.trigger('audio.linkError',[link]);}} +function insertEmbed(code){if(typeof code=='undefined'){var $popup=editor.popups.get('audio.insert');code=$popup.find('.fr-audio-embed-layer textarea').val()||'';} +if(code.length===0||!$.FE.VIDEO_EMBED_REGEX.test(code)){editor.events.trigger('audio.codeError',[code]);} +else{insert(code);}} +function _handlerMousedown(e){if(!editor.core.sameInstance($audio_resizer))return true;e.preventDefault();e.stopPropagation();var c_x=e.pageX||(e.originalEvent.touches?e.originalEvent.touches[0].pageX:null);var c_y=e.pageY||(e.originalEvent.touches?e.originalEvent.touches[0].pageY:null);if(!c_x||!c_y){return false;} +if(!editor.undo.canDo())editor.undo.saveStep();$handler=$(this);$handler.data('start-x',c_x);$handler.data('start-y',c_y);$overlay.show();editor.popups.hideAll();_unmarkExit();} +function _handlerMousemove(e){if(!editor.core.sameInstance($audio_resizer))return true;if($handler){e.preventDefault() +var c_x=e.pageX||(e.originalEvent.touches?e.originalEvent.touches[0].pageX:null);var c_y=e.pageY||(e.originalEvent.touches?e.originalEvent.touches[0].pageY:null);if(!c_x||!c_y){return false;} +var s_x=$handler.data('start-x');var s_y=$handler.data('start-y');$handler.data('start-x',c_x);$handler.data('start-y',c_y);var diff_x=c_x-s_x;var diff_y=c_y-s_y;var $audio_obj=$current_audio.find('iframe, embed, audio');var width=$audio_obj.width();var height=$audio_obj.height();if($handler.hasClass('fr-hnw')||$handler.hasClass('fr-hsw')){diff_x=0-diff_x;} +if($handler.hasClass('fr-hnw')||$handler.hasClass('fr-hne')){diff_y=0-diff_y;} +$audio_obj.css('width',width+diff_x);$audio_obj.css('height',height+diff_y);$audio_obj.removeAttr('width');$audio_obj.removeAttr('height');_repositionResizer();}} +function _handlerMouseup(e){if(!editor.core.sameInstance($audio_resizer))return true;if($handler&&$current_audio){if(e)e.stopPropagation();$handler=null;$overlay.hide();_repositionResizer();_showEditPopup();editor.undo.saveStep();}} +function _getHandler(pos){return'
    ';} +function _initResizer(){var doc;if(!editor.shared.$audio_resizer){editor.shared.$audio_resizer=$('
    ');$audio_resizer=editor.shared.$audio_resizer;editor.events.$on($audio_resizer,'mousedown',function(e){e.stopPropagation();},true);if(editor.opts.audioResize){$audio_resizer.append(_getHandler('nw')+_getHandler('ne')+_getHandler('sw')+_getHandler('se'));editor.shared.$audio_overlay=$('
    ');$overlay=editor.shared.$audio_overlay;doc=$audio_resizer.get(0).ownerDocument;$(doc).find('body').append($overlay);}}else{$audio_resizer=editor.shared.$audio_resizer;$overlay=editor.shared.$audio_overlay;editor.events.on('destroy',function(){$audio_resizer.removeClass('fr-active').appendTo($('body'));},true);} +editor.events.on('shared.destroy',function(){$audio_resizer.html('').removeData().remove();$audio_resizer=null;if(editor.opts.audioResize){$overlay.remove();$overlay=null;}},true);if(!editor.helpers.isMobile()){editor.events.$on($(editor.o_win),'resize.audio',function(){_exitEdit(true);});} +if(editor.opts.audioResize){doc=$audio_resizer.get(0).ownerDocument;editor.events.$on($audio_resizer,editor._mousedown,'.fr-handler',_handlerMousedown);editor.events.$on($(doc),editor._mousemove,_handlerMousemove);editor.events.$on($(doc.defaultView||doc.parentWindow),editor._mouseup,_handlerMouseup);editor.events.$on($overlay,'mouseleave',_handlerMouseup);}} +function _repositionResizer(){if(!$audio_resizer)_initResizer();(editor.$wp||$(editor.opts.scrollableContainer)).append($audio_resizer);$audio_resizer.data('instance',editor);var $audio_obj=$current_audio.find('iframe, embed, audio');$audio_resizer.css('top',(editor.opts.iframe?$audio_obj.offset().top-1:$audio_obj.offset().top-editor.$wp.offset().top-1)+editor.$wp.scrollTop()).css('left',(editor.opts.iframe?$audio_obj.offset().left-1:$audio_obj.offset().left-editor.$wp.offset().left-1)+editor.$wp.scrollLeft()).css('width',$audio_obj.outerWidth()).css('height',$audio_obj.height()).addClass('fr-active')} +var touchScroll;function _edit(e){if(e&&e.type=='touchend'&&touchScroll){return true;} +e.preventDefault();e.stopPropagation();if(editor.edit.isDisabled()){return false;} +for(var i=0;i<$.FE.INSTANCES.length;i++){if($.FE.INSTANCES[i]!=editor){$.FE.INSTANCES[i].events.trigger('audio.hideResizer');}} +editor.toolbar.disable();if(editor.helpers.isMobile()){editor.events.disableBlur();editor.$el.blur();editor.events.enableBlur();} +$current_audio=$(this);$(this).addClass('fr-active');if(editor.opts.iframe){editor.size.syncIframe();} +_repositionResizer();_showEditPopup();editor.selection.clear();editor.button.bulkRefresh();editor.events.trigger('image.hideResizer');} +function _exitEdit(force_exit){if($current_audio&&(_canExit()||force_exit===true)){$audio_resizer.removeClass('fr-active');editor.toolbar.enable();$current_audio.removeClass('fr-active');$current_audio=null;_unmarkExit();}} +editor.shared.audio_exit_flag=false;function _markExit(){editor.shared.audio_exit_flag=true;} +function _unmarkExit(){editor.shared.audio_exit_flag=false;} +function _canExit(){return editor.shared.audio_exit_flag;} +function _initEvents(){editor.events.on('mousedown window.mousedown',_markExit);editor.events.on('window.touchmove',_unmarkExit);editor.events.on('mouseup window.mouseup',_exitEdit);editor.events.on('commands.mousedown',function($btn){if($btn.parents('.fr-toolbar').length>0){_exitEdit();}});editor.events.on('blur audio.hideResizer commands.undo commands.redo element.dropped',function(){_exitEdit(true);});} +function _initEditPopup(){var audio_buttons='';if(editor.opts.audioEditButtons.length>=1){audio_buttons+='
    ';audio_buttons+=editor.button.buildList(editor.opts.audioEditButtons);audio_buttons+='
    ';} +var template={buttons:audio_buttons} +var $popup=editor.popups.create('audio.edit',template);editor.events.$on(editor.$wp,'scroll.audio-edit',function(){if($current_audio&&editor.popups.isVisible('audio.edit')){_showEditPopup();}});return $popup;} +function _refreshSizePopup(){if($current_audio){var $popup=editor.popups.get('audio.size');var $audio_obj=$current_audio.find('iframe, embed, audio') +$popup.find('input[name="width"]').val($audio_obj.get(0).style.width||$audio_obj.attr('width')).trigger('change');$popup.find('input[name="height"]').val($audio_obj.get(0).style.height||$audio_obj.attr('height')).trigger('change');}} +function showSizePopup(){var $popup=editor.popups.get('audio.size');if(!$popup)$popup=_initSizePopup();editor.popups.refresh('audio.size');editor.popups.setContainer('audio.size',$(editor.opts.scrollableContainer));var $audio_obj=$current_audio.find('iframe, embed, audio') +var left=$audio_obj.offset().left+$audio_obj.width()/2;var top=$audio_obj.offset().top+$audio_obj.height();editor.popups.show('audio.size',left,top,$audio_obj.height());} +function _initSizePopup(delayed){if(delayed){editor.popups.onRefresh('audio.size',_refreshSizePopup);return true;} +var audio_buttons='';audio_buttons='
    '+editor.button.buildList(editor.opts.audioSizeButtons)+'
    ';var size_layer='';size_layer='
    ';var template={buttons:audio_buttons,size_layer:size_layer} +var $popup=editor.popups.create('audio.size',template);editor.events.$on(editor.$wp,'scroll',function(){if($current_audio&&editor.popups.isVisible('audio.size')){showSizePopup();}});return $popup;} +function align(val){$current_audio.removeClass('fr-fvr fr-fvl');if(val=='left'){$current_audio.addClass('fr-fvl');} +else if(val=='right'){$current_audio.addClass('fr-fvr');} +_repositionResizer();_showEditPopup();} +function refreshAlign($btn){if(!$current_audio)return false;if($current_audio.hasClass('fr-fvl')){$btn.find('> *:first').replaceWith(editor.icon.create('align-left'));} +else if($current_audio.hasClass('fr-fvr')){$btn.find('> *:first').replaceWith(editor.icon.create('align-right'));} +else{$btn.find('> *:first').replaceWith(editor.icon.create('align-justify'));}} +function refreshAlignOnShow($btn,$dropdown){var alignment='justify';if($current_audio.hasClass('fr-fvl')){alignment='left';} +else if($current_audio.hasClass('fr-fvr')){alignment='right';} +$dropdown.find('.fr-command[data-param1="'+alignment+'"]').addClass('fr-active');} +function display(val){$current_audio.removeClass('fr-dvi fr-dvb');if(val=='inline'){$current_audio.addClass('fr-dvi');} +else if(val=='block'){$current_audio.addClass('fr-dvb');} +_repositionResizer();_showEditPopup();} +function refreshDisplayOnShow($btn,$dropdown){var d='block';if($current_audio.hasClass('fr-dvi')){d='inline';} +$dropdown.find('.fr-command[data-param1="'+d+'"]').addClass('fr-active');} +function remove(){if($current_audio){if(editor.events.trigger('audio.beforeRemove',[$current_audio])!==false){var $audio=$current_audio;editor.popups.hideAll();_exitEdit(true);editor.selection.setBefore($audio.get(0))||editor.selection.setAfter($audio.get(0));$audio.remove();editor.selection.restore();editor.html.fillEmptyBlocks();editor.events.trigger('audio.removed',[$audio]);}}} +function _convertStyleToClasses($audio){if(!$audio.hasClass('fr-dvi')&&!$audio.hasClass('fr-dvb')){var flt=$audio.css('float');$audio.css('float','none');if($audio.css('display')=='block'){$audio.css('float',flt);if(parseInt($audio.css('margin-left'),10)===0&&($audio.attr('style')||'').indexOf('margin-right: auto')>=0){$audio.addClass('fr-fvl');} +else if(parseInt($audio.css('margin-right'),10)===0&&($audio.attr('style')||'').indexOf('margin-left: auto')>=0){$audio.addClass('fr-fvr');} +$audio.addClass('fr-dvb');} +else{$audio.css('float',flt);if($audio.css('float')=='left'){$audio.addClass('fr-fvl');} +else if($audio.css('float')=='right'){$audio.addClass('fr-fvr');} +$audio.addClass('fr-dvi');} +$audio.css('margin','');$audio.css('float','');$audio.css('display','');$audio.css('z-index','');$audio.css('position','');$audio.css('overflow','');$audio.css('vertical-align','');} +if(!editor.opts.audioTextNear){$audio.removeClass('fr-dvi').addClass('fr-dvb');}} +function _refreshAudioList(){editor.$el.find('audio').filter(function(){return $(this).parents('span.fr-video').length===0;}).wrap('');editor.$el.find('embed, iframe').filter(function(){if(editor.browser.safari&&this.getAttribute('src')){this.setAttribute('src',this.src);} +if($(this).parents('span.fr-video').length>0)return false;var link=$(this).attr('src');for(var i=0;i<$.FE.VIDEO_PROVIDERS.length;i++){var vp=$.FE.VIDEO_PROVIDERS[i];if(vp.test_regex.test(link)){return true;}} +return false;}).map(function(){return $(this).parents('object').length===0?this:$(this).parents('object').get(0);}).wrap('');var audios=editor.$el.find('span.fr-video');for(var i=0;i'+this.icon.create('align-'+val)+'';}} +c+='';return c;},callback:function(cmd,val){this.audio.align(val);},refresh:function($btn){this.audio.refreshAlign($btn);},refreshOnShow:function($btn,$dropdown){this.audio.refreshAlignOnShow($btn,$dropdown);}}) +$.FE.DefineIcon('audioRemove',{NAME:'trash'}) +$.FE.RegisterCommand('audioRemove',{title:'Remove',callback:function(){this.audio.remove();}}) +$.FE.DefineIcon('audioSize',{NAME:'arrows-alt'}) +$.FE.RegisterCommand('audioSize',{undo:false,focus:false,title:'Change Size',callback:function(){this.audio.showSizePopup();}});$.FE.DefineIcon('audioBack',{NAME:'arrow-left'});$.FE.RegisterCommand('audioBack',{title:'Back',undo:false,focus:false,back:true,callback:function(){this.audio.back();},refresh:function($btn){var $current_audio=this.audio.get();if(!$current_audio&&!this.opts.toolbarInline){$btn.addClass('fr-hidden');$btn.next('.fr-separator').addClass('fr-hidden');} +else{$btn.removeClass('fr-hidden');$btn.next('.fr-separator').removeClass('fr-hidden');}}});$.FE.RegisterCommand('audioSetSize',{undo:true,focus:false,callback:function(){this.audio.setSize();}})}));!function(n){"function"==typeof define&&define.amd?define(["jquery"],n):"object"==typeof module&&module.exports?module.exports=function(e,t){return t===undefined&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t)}:n(window.jQuery)}(function(a){a.FE.PLUGINS.quote=function(r){function o(e){for(;e.parentNode&&e.parentNode!=r.el;)e=e.parentNode;return e}return{apply:function(e){r.selection.save(),r.html.wrap(!0,!0,!0,!0),r.selection.restore(),"increase"==e?function(){var e,t=r.selection.blocks();for(e=0;e");for(n.insertBefore(t[0]),e=0;e'+this.language.translate(t[n])+(r?''+r+"":"")+""}return e+=""},callback:function(e,t){this.quote.apply(t)},plugin:"quote"}),a.FE.DefineIcon("quote",{NAME:"quote-left"})});!function(n){"function"==typeof define&&define.amd?define(["jquery"],n):"object"==typeof module&&module.exports?module.exports=function(e,t){return t===undefined&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t)}:n(window.jQuery)}(function(f){f.extend(f.FE.DEFAULTS,{fontSize:["8","9","10","11","12","14","18","24","30","36","48","60","72","96"],fontSizeSelection:!1,fontSizeDefaultSelection:"12",fontSizeUnit:"px"}),f.FE.PLUGINS.fontSize=function(r){return{apply:function(e){r.format.applyStyle("font-size",e)},refreshOnShow:function(e,t){var n=f(r.selection.element()).css("font-size");"pt"===r.opts.fontSizeUnit&&(n=Math.round(72*parseFloat(n,10)/96)+"pt"),t.find(".fr-command.fr-active").removeClass("fr-active").attr("aria-selected",!1),t.find('.fr-command[data-param1="'+n+'"]').addClass("fr-active").attr("aria-selected",!0);var o=t.find(".fr-dropdown-list"),i=t.find(".fr-active").parent();i.length?o.parent().scrollTop(i.offset().top-o.offset().top-(o.parent().outerHeight()/2-i.outerHeight()/2)):o.parent().scrollTop(0)},refresh:function(e){if(r.opts.fontSizeSelection){var t=r.helpers.getPX(f(r.selection.element()).css("font-size"));"pt"===r.opts.fontSizeUnit&&(t=Math.round(72*parseFloat(t,10)/96)+"pt"),e.find("> span").text(t)}}}},f.FE.RegisterCommand("fontSize",{type:"dropdown",title:"Font Size",displaySelection:function(e){return e.opts.fontSizeSelection},displaySelectionWidth:30,defaultSelection:function(e){return e.opts.fontSizeDefaultSelection},html:function(){for(var e='"},callback:function(e,t){this.fontSize.apply(t)},refresh:function(e){this.fontSize.refresh(e)},refreshOnShow:function(e,t){this.fontSize.refreshOnShow(e,t)},plugin:"fontSize"}),f.FE.DefineIcon("fontSize",{NAME:"text-height"})});!function(n){"function"==typeof define&&define.amd?define(["jquery"],n):"object"==typeof module&&module.exports?module.exports=function(e,t){return t===undefined&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t)}:n(window.jQuery)}(function(l){l.extend(l.FE.DEFAULTS,{fontFamily:{"Arial,Helvetica,sans-serif":"Arial","Georgia,serif":"Georgia","Impact,Charcoal,sans-serif":"Impact","Tahoma,Geneva,sans-serif":"Tahoma","Times New Roman,Times,serif,-webkit-standard":"Times New Roman","Verdana,Geneva,sans-serif":"Verdana"},fontFamilySelection:!1,fontFamilyDefaultSelection:"Font Family"}),l.FE.PLUGINS.fontFamily=function(o){function i(e){var t=e.replace(/(sans-serif|serif|monospace|cursive|fantasy)/gi,"").replace(/"|'| /g,"").split(",");return l.grep(t,function(e){return 0 span").text(o.opts.fontFamily[f()]||t[0]||o.language.translate(o.opts.fontFamilyDefaultSelection))}}}},l.FE.RegisterCommand("fontFamily",{type:"dropdown",displaySelection:function(e){return e.opts.fontFamilySelection},defaultSelection:function(e){return e.opts.fontFamilyDefaultSelection},displaySelectionWidth:120,html:function(){var e='"},title:"Font Family",callback:function(e,t){this.fontFamily.apply(t)},refresh:function(e){this.fontFamily.refresh(e)},refreshOnShow:function(e,t){this.fontFamily.refreshOnShow(e,t)},plugin:"fontFamily"}),l.FE.DefineIcon("fontFamily",{NAME:"font"})});!function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&module.exports?module.exports=function(e,o){return o===undefined&&(o="undefined"!=typeof window?require("jquery"):require("jquery")(e)),t(o)}:t(window.jQuery)}(function(g){g.extend(g.FE.POPUP_TEMPLATES,{emoticons:"[_BUTTONS_][_EMOTICONS_]"}),g.extend(g.FE.DEFAULTS,{emoticonsStep:8,emoticonsSet:[{code:"1f600",desc:"Grinning face"},{code:"1f601",desc:"Grinning face with smiling eyes"},{code:"1f602",desc:"Face with tears of joy"},{code:"1f603",desc:"Smiling face with open mouth"},{code:"1f604",desc:"Smiling face with open mouth and smiling eyes"},{code:"1f605",desc:"Smiling face with open mouth and cold sweat"},{code:"1f606",desc:"Smiling face with open mouth and tightly-closed eyes"},{code:"1f607",desc:"Smiling face with halo"},{code:"1f608",desc:"Smiling face with horns"},{code:"1f609",desc:"Winking face"},{code:"1f60a",desc:"Smiling face with smiling eyes"},{code:"1f60b",desc:"Face savoring delicious food"},{code:"1f60c",desc:"Relieved face"},{code:"1f60d",desc:"Smiling face with heart-shaped eyes"},{code:"1f60e",desc:"Smiling face with sunglasses"},{code:"1f60f",desc:"Smirking face"},{code:"1f610",desc:"Neutral face"},{code:"1f611",desc:"Expressionless face"},{code:"1f612",desc:"Unamused face"},{code:"1f613",desc:"Face with cold sweat"},{code:"1f614",desc:"Pensive face"},{code:"1f615",desc:"Confused face"},{code:"1f616",desc:"Confounded face"},{code:"1f617",desc:"Kissing face"},{code:"1f618",desc:"Face throwing a kiss"},{code:"1f619",desc:"Kissing face with smiling eyes"},{code:"1f61a",desc:"Kissing face with closed eyes"},{code:"1f61b",desc:"Face with stuck out tongue"},{code:"1f61c",desc:"Face with stuck out tongue and winking eye"},{code:"1f61d",desc:"Face with stuck out tongue and tightly-closed eyes"},{code:"1f61e",desc:"Disappointed face"},{code:"1f61f",desc:"Worried face"},{code:"1f620",desc:"Angry face"},{code:"1f621",desc:"Pouting face"},{code:"1f622",desc:"Crying face"},{code:"1f623",desc:"Persevering face"},{code:"1f624",desc:"Face with look of triumph"},{code:"1f625",desc:"Disappointed but relieved face"},{code:"1f626",desc:"Frowning face with open mouth"},{code:"1f627",desc:"Anguished face"},{code:"1f628",desc:"Fearful face"},{code:"1f629",desc:"Weary face"},{code:"1f62a",desc:"Sleepy face"},{code:"1f62b",desc:"Tired face"},{code:"1f62c",desc:"Grimacing face"},{code:"1f62d",desc:"Loudly crying face"},{code:"1f62e",desc:"Face with open mouth"},{code:"1f62f",desc:"Hushed face"},{code:"1f630",desc:"Face with open mouth and cold sweat"},{code:"1f631",desc:"Face screaming in fear"},{code:"1f632",desc:"Astonished face"},{code:"1f633",desc:"Flushed face"},{code:"1f634",desc:"Sleeping face"},{code:"1f635",desc:"Dizzy face"},{code:"1f636",desc:"Face without mouth"},{code:"1f637",desc:"Face with medical mask"}],emoticonsButtons:["emoticonsBack","|"],emoticonsUseImage:!0}),g.FE.PLUGINS.emoticons=function(E){function n(){if(!E.selection.isCollapsed())return!1;var e=E.selection.element(),o=E.selection.endElement();if(e&&E.node.hasClass(e,"fr-emoticon"))return e;if(o&&E.node.hasClass(o,"fr-emoticon"))return o;var t=E.selection.ranges(0),s=t.startContainer;if(s.nodeType==Node.ELEMENT_NODE&&0=g.FE.KEYCODE.ARROW_LEFT&&e.which<=g.FE.KEYCODE.ARROW_DOWN)){var s=n();E.node.hasClass(s,"fr-emoticon-img")&&(g(s).append(g.FE.MARKERS),E.selection.restore())}})},insert:function(e,o){var t=n(),s=E.selection.ranges(0);t?(0===s.startOffset&&E.selection.element()===t?g(t).before(g.FE.MARKERS+g.FE.INVISIBLE_SPACE):0"+(o?" ":e)+" "+g.FE.MARKERS,!0)):E.html.insert('"+(o?" ":e)+" ",!0)},showEmoticonsPopup:function(){var e=E.$tb.find('.fr-command[data-cmd="emoticons"]'),o=E.popups.get("emoticons");if(o||(o=function(){var e="";E.opts.toolbarInline&&0'+E.button.buildList(E.opts.emoticonsButtons)+"
    ");var h,o={buttons:e,emoticons:function(){for(var e='
    ',o=0;o"),e+=''+(E.opts.emoticonsUseImage?'':"&#x"+E.opts.emoticonsSet[o].code+";")+''+E.language.translate(E.opts.emoticonsSet[o].desc)+"   ";return E.opts.emoticonsUseImage&&(e+='

    Emoji free by Emoji One

    '),e+="
    "}()},t=E.popups.create("emoticons",o);return E.tooltip.bind(t,".fr-emoticon"),h=t,E.events.on("popup.tab",function(e){var o=g(e.currentTarget);if(!E.popups.isVisible("emoticons")||!o.is("span, a"))return!0;var t,s,n,c=e.which;if(g.FE.KEYCODE.TAB==c){if(o.is("span.fr-emoticon")&&e.shiftKey||o.is("a")&&!e.shiftKey){var i=h.find(".fr-buttons");t=!E.accessibility.focusToolbar(i,!!e.shiftKey)}if(!1!==t){var a=h.find("span.fr-emoticon:focus:first, span.fr-emoticon:visible:first, a");o.is("span.fr-emoticon")&&(a=a.not("span.fr-emoticon:not(:focus)")),s=a.index(o),s=e.shiftKey?((s-1)%a.length+a.length)%a.length:(s+1)%a.length,n=a.get(s),E.events.disableBlur(),n.focus(),t=!1}}else if(g.FE.KEYCODE.ARROW_UP==c||g.FE.KEYCODE.ARROW_DOWN==c||g.FE.KEYCODE.ARROW_LEFT==c||g.FE.KEYCODE.ARROW_RIGHT==c){if(o.is("span.fr-emoticon")){var f=o.parent().find("span.fr-emoticon");s=f.index(o);var d=E.opts.emoticonsStep,r=Math.floor(f.length/d),l=s%d,m=Math.floor(s/d),u=m*d+l,p=r*d;g.FE.KEYCODE.ARROW_UP==c?u=((u-d)%p+p)%p:g.FE.KEYCODE.ARROW_DOWN==c?u=(u+d)%p:g.FE.KEYCODE.ARROW_LEFT==c?u=((u-1)%p+p)%p:g.FE.KEYCODE.ARROW_RIGHT==c&&(u=(u+1)%p),n=g(f.get(u)),E.events.disableBlur(),n.focus(),t=!1}}else g.FE.KEYCODE.ENTER==c&&(o.is("a")?o[0].click():E.button.exec(o),t=!1);return!1===t&&(e.preventDefault(),e.stopPropagation()),t},!0),t}()),!o.hasClass("fr-active")){E.popups.refresh("emoticons"),E.popups.setContainer("emoticons",E.$tb);var t=e.offset().left+e.outerWidth()/2,s=e.offset().top+(E.opts.toolbarBottom?10:e.outerHeight()-10);E.popups.show("emoticons",t,s,e.outerHeight())}},hideEmoticonsPopup:function(){E.popups.hide("emoticons")},back:function(){E.popups.hide("emoticons"),E.toolbar.showInline()}}},g.FE.DefineIcon("emoticons",{NAME:"smile-o",FA5NAME:"smile"}),g.FE.RegisterCommand("emoticons",{title:"Emoticons",undo:!1,focus:!0,refreshOnCallback:!1,popup:!0,callback:function(){this.popups.isVisible("emoticons")?(this.$el.find(".fr-marker").length&&(this.events.disableBlur(),this.selection.restore()),this.popups.hide("emoticons")):this.emoticons.showEmoticonsPopup()},plugin:"emoticons"}),g.FE.RegisterCommand("insertEmoticon",{callback:function(e,o){this.emoticons.insert("&#x"+o+";",this.opts.emoticonsUseImage?"https://cdnjs.cloudflare.com/ajax/libs/emojione/2.0.1/assets/svg/"+o+".svg":null),this.emoticons.hideEmoticonsPopup()}}),g.FE.DefineIcon("emoticonsBack",{NAME:"arrow-left"}),g.FE.RegisterCommand("emoticonsBack",{title:"Back",undo:!1,focus:!1,back:!0,refreshAfterCallback:!1,callback:function(){this.emoticons.back()}})});!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof module&&module.exports?module.exports=function(o,r){return r===undefined&&(r="undefined"!=typeof window?require("jquery"):require("jquery")(o)),e(r)}:e(window.jQuery)}(function(C){C.extend(C.FE.POPUP_TEMPLATES,{"colors.picker":"[_BUTTONS_][_TEXT_COLORS_][_BACKGROUND_COLORS_][_CUSTOM_COLOR_]"}),C.extend(C.FE.DEFAULTS,{colorsText:["#61BD6D","#1ABC9C","#54ACD2","#2C82C9","#9365B8","#475577","#CCCCCC","#41A85F","#00A885","#3D8EB9","#2969B0","#553982","#28324E","#000000","#F7DA64","#FBA026","#EB6B56","#E25041","#A38F84","#EFEFEF","#FFFFFF","#FAC51C","#F37934","#D14841","#B8312F","#7C706B","#D1D5D8","REMOVE"],colorsBackground:["#61BD6D","#1ABC9C","#54ACD2","#2C82C9","#9365B8","#475577","#CCCCCC","#41A85F","#00A885","#3D8EB9","#2969B0","#553982","#28324E","#000000","#F7DA64","#FBA026","#EB6B56","#E25041","#A38F84","#EFEFEF","#FFFFFF","#FAC51C","#F37934","#D14841","#B8312F","#7C706B","#D1D5D8","REMOVE"],colorsStep:7,colorsHEXInput:!0,colorsDefaultTab:"text",colorsButtons:["colorsBack","|","-"]});var c=["text","background"];C.FE.PLUGINS.colors=function(E){function r(){E.popups.hide("colors.picker")}function s(o){for(var r="text"==o?E.opts.colorsText:E.opts.colorsBackground,e='
    ',t=0;t"),"REMOVE"!=r[t]?e+=''+E.language.translate("Color")+" "+r[t]+"   ":e+=''+E.icon.create("remove")+''+E.language.translate("Clear Formatting")+"";return e+"
    "}function l(o){var r=E.popups.get("colors.picker"),e=r.find(".fr-"+o+"-color .fr-active-item").attr("data-param1"),t=r.find(".fr-color-hex-layer input"),a=r.find('.fr-colors-tab[data-param1="'+o+'"]');t.length&&a.hasClass("fr-selected-tab")&&t.val(e).trigger("change")}function t(o){"REMOVE"!=o?E.format.applyStyle("background-color",E.helpers.HEXtoRGB(o)):E.format.removeStyle("background-color"),r()}function a(o){"REMOVE"!=o?E.format.applyStyle("color",E.helpers.HEXtoRGB(o)):E.format.removeStyle("color"),r()}return{showColorsPopup:function(){var o=E.$tb.find('.fr-command[data-cmd="color"]'),r=E.popups.get("colors.picker");if(r||(r=function(){var o,r='
    ';E.opts.toolbarInline&&0',o+=''+E.language.translate("Text")+"",(o+=''+E.language.translate("Background")+"")+"
    ");var e="";E.opts.colorsHEXInput&&(e='
    ");var b,t={buttons:r,text_colors:s("text"),background_colors:s("background"),custom_color:e},a=E.popups.create("colors.picker",t);return b=a,E.events.on("popup.tab",function(o){var r=C(o.currentTarget);if(!E.popups.isVisible("colors.picker")||!r.is("span"))return!0;var e=o.which,t=!0;if(C.FE.KEYCODE.TAB==e){var a=b.find(".fr-buttons");t=!E.accessibility.focusToolbar(a,!!o.shiftKey)}else if(C.FE.KEYCODE.ARROW_UP==e||C.FE.KEYCODE.ARROW_DOWN==e||C.FE.KEYCODE.ARROW_LEFT==e||C.FE.KEYCODE.ARROW_RIGHT==e){if(r.is("span.fr-select-color")){var s=r.parent().find("span.fr-select-color"),l=s.index(r),c=E.opts.colorsStep,n=Math.floor(s.length/c),i=l%c,p=Math.floor(l/c),u=p*c+i,d=n*c;C.FE.KEYCODE.ARROW_UP==e?u=((u-c)%d+d)%d:C.FE.KEYCODE.ARROW_DOWN==e?u=(u+c)%d:C.FE.KEYCODE.ARROW_LEFT==e?u=((u-1)%d+d)%d:C.FE.KEYCODE.ARROW_RIGHT==e&&(u=(u+1)%d);var f=C(s.get(u));E.events.disableBlur(),f.focus(),t=!1}}else C.FE.KEYCODE.ENTER==e&&(E.button.exec(r),t=!1);return!1===t&&(o.preventDefault(),o.stopPropagation()),t},!0),a}()),!r.hasClass("fr-active"))if(E.popups.setContainer("colors.picker",E.$tb),c.map(function(o){!function(o){var r,e=E.popups.get("colors.picker"),t=C(E.selection.element());r="background"==o?"background-color":"color";var a=e.find(".fr-"+o+"-color .fr-select-color");for(a.find(".fr-selected-color").remove(),a.removeClass("fr-active-item"),a.not('[data-param1="REMOVE"]').attr("aria-selected",!1);t.get(0)!=E.el;){if("transparent"!=t.css(r)&&"rgba(0, 0, 0, 0)"!=t.css(r)){var s=e.find(".fr-"+o+'-color .fr-select-color[data-param1="'+E.helpers.RGBToHex(t.css(r))+'"]');s.append(''),s.addClass("fr-active-item").attr("aria-selected",!0);break}t=t.parent()}l(o)}(o)}),o.is(":visible")){var e=o.offset().left+o.outerWidth()/2,t=o.offset().top+(E.opts.toolbarBottom?10:o.outerHeight()-10);E.popups.show("colors.picker",e,t,o.outerHeight())}else E.position.forSelection(r),E.popups.show("colors.picker")},hideColorsPopup:r,changeSet:function(o,r){o.hasClass("fr-selected-tab")||(o.siblings().removeClass("fr-selected-tab").attr("aria-pressed",!1),o.addClass("fr-selected-tab").attr("aria-pressed",!0),o.parents(".fr-popup").find(".fr-color-set").removeClass("fr-selected-set"),o.parents(".fr-popup").find(".fr-color-set.fr-"+r+"-color").addClass("fr-selected-set"),l(r)),E.accessibility.focusPopup(o.parents(".fr-popup"))},background:t,customColor:function(){var o=E.popups.get("colors.picker"),r=o.find(".fr-color-hex-layer input");if(r.length){var e=r.val();"background"==o.find(".fr-selected-tab").attr("data-param1")?t(e):a(e)}},text:a,back:function(){E.popups.hide("colors.picker"),E.toolbar.showInline()}}},C.FE.DefineIcon("colors",{NAME:"tint"}),C.FE.RegisterCommand("color",{title:"Colors",undo:!1,focus:!0,refreshOnCallback:!1,popup:!0,callback:function(){this.popups.isVisible("colors.picker")?(this.$el.find(".fr-marker").length&&(this.events.disableBlur(),this.selection.restore()),this.popups.hide("colors.picker")):this.colors.showColorsPopup()},plugin:"colors"}),C.FE.RegisterCommand("textColor",{undo:!0,callback:function(o,r){this.colors.text(r)}}),C.FE.RegisterCommand("backgroundColor",{undo:!0,callback:function(o,r){this.colors.background(r)}}),C.FE.RegisterCommand("colorChangeSet",{undo:!1,focus:!1,callback:function(o,r){var e=this.popups.get("colors.picker").find('.fr-command[data-cmd="'+o+'"][data-param1="'+r+'"]');this.colors.changeSet(e,r)}}),C.FE.DefineIcon("colorsBack",{NAME:"arrow-left"}),C.FE.RegisterCommand("colorsBack",{title:"Back",undo:!1,focus:!1,back:!0,refreshAfterCallback:!1,callback:function(){this.colors.back()}}),C.FE.RegisterCommand("customColor",{title:"OK",undo:!0,callback:function(){this.colors.customColor()}}),C.FE.DefineIcon("remove",{NAME:"eraser"})});!function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&module.exports?module.exports=function(e,n){return n===undefined&&(n="undefined"!=typeof window?require("jquery"):require("jquery")(e)),t(n)}:t(window.jQuery)}(function(f){f.FE.URLRegEx="(^| |\\u00A0)("+f.FE.LinkRegEx+"|([a-z0-9+-_.]{1,}@[a-z0-9+-_.]{1,}\\.[a-z0-9+-_]{1,}))$",f.FE.PLUGINS.url=function(i){var l=null;function n(e,n,t){for(var r="";t.length&&"."==t[t.length-1];)r+=".",t=t.substring(0,t.length-1);var o=t;if(i.opts.linkConvertEmailAddress)i.helpers.isEmail(o)&&!/^mailto:.*/i.test(o)&&(o="mailto:"+o);else if(i.helpers.isEmail(o))return n+t;return/^((http|https|ftp|ftps|mailto|tel|sms|notes|data)\:)/i.test(o)||(o="//"+o),(n||"")+"'+t.replace(/&/g,"&").replace(/&/g,"&").replace(//g,">")+""+r}function a(){return new RegExp(f.FE.URLRegEx,"gi")}function s(e){return i.opts.linkAlwaysNoFollow&&(l="nofollow"),i.opts.linkAlwaysBlank&&(i.opts.linkNoOpener&&(l?l+=" noopener":l="noopener"),i.opts.linkNoReferrer&&(l?l+=" noreferrer":l="noreferrer")),e.replace(a(),n)}function p(e){var n=e.split(" ");return n[n.length-1]}function t(){var n=i.selection.ranges(0),t=n.startContainer;if(!t||t.nodeType!==Node.TEXT_NODE||n.startOffset!==(t.textContent||"").length)return!1;if(function e(n){return!!n&&("A"===n.tagName||!(!n.parentNode||n.parentNode==i.el)&&e(n.parentNode))}(t))return!1;if(a().test(p(t.textContent))){f(t).before(s(t.textContent));var r=f(t.parentNode).find("a[data-fr-linked]");r.removeAttr("data-fr-linked"),t.parentNode.removeChild(t),i.events.trigger("url.linked",[r.get(0)])}else if(t.textContent.split(" ").length<=2&&t.previousSibling&&"A"===t.previousSibling.tagName){var o=t.previousSibling.innerText+t.textContent;a().test(p(o))&&(f(t.previousSibling).replaceWith(s(o)),t.parentNode.removeChild(t))}}return{_init:function(){i.events.on("keypress",function(e){!i.selection.isCollapsed()||"."!=e.key&&")"!=e.key&&"("!=e.key||t()},!0),i.events.on("keydown",function(e){var n=e.which;!i.selection.isCollapsed()||n!=f.FE.KEYCODE.ENTER&&n!=f.FE.KEYCODE.SPACE||t()},!0),i.events.on("paste.beforeCleanup",function(e){if(i.helpers.isURL(e)){var n=null;return i.opts.linkAlwaysBlank&&(i.opts.linkNoOpener&&(n?n+=" noopener":n="noopener"),i.opts.linkNoReferrer&&(n?n+=" noreferrer":n="noreferrer")),"'+e+""}})}}}});!function(n){"function"==typeof define&&define.amd?define(["jquery"],n):"object"==typeof module&&module.exports?module.exports=function(e,t){return t===undefined&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t)}:n(window.jQuery)}(function(v){v.extend(v.FE.DEFAULTS,{lineBreakerTags:["table","hr","form","dl","span.fr-video",".fr-embedly"],lineBreakerOffset:15,lineBreakerHorizontalOffset:10}),v.FE.PLUGINS.lineBreaker=function(d){var g,t,a;function s(e,t){var n,r,a,o,i,s,f,l;if(null==e)i=(o=t.parent()).offset().top,n=(f=t.offset().top)-Math.min((f-i)/2,d.opts.lineBreakerOffset),a=o.outerWidth(),r=o.offset().left;else if(null==t)(s=(o=e.parent()).offset().top+o.outerHeight())<(l=e.offset().top+e.outerHeight())&&(s=(o=v(o).parent()).offset().top+o.outerHeight()),n=l+Math.min(Math.abs(s-l)/2,d.opts.lineBreakerOffset),a=o.outerWidth(),r=o.offset().left;else{o=e.parent();var p=e.offset().top+e.height(),u=t.offset().top;if(ud.$box.offset().left&&e"+v.FE.MARKERS+"
    "):r.before(v.FE.MARKERS+"
    "):a&&"TD"!=n.parent().get(0).tagName&&0===n.parents(a).length?n.after("<"+a+">"+v.FE.MARKERS+"
    "):n.after(v.FE.MARKERS+"
    "),t.selection.restore()}return{_init:function(){if(!d.$wp)return!1;d.shared.$line_breaker||(d.shared.$line_breaker=v('
    ')),g=d.shared.$line_breaker,d.events.on("shared.destroy",function(){g.html("").removeData().remove(),g=null},!0),d.events.on("destroy",function(){g.removeData("instance").removeClass("fr-visible").appendTo("body:first"),clearTimeout(a)},!0),d.events.$on(g,"mousemove",function(e){e.stopPropagation()},!0),d.events.bindClick(g,"a",c),t=!1,d.events.$on(d.$win,"mousemove",e),d.events.$on(v(d.win),"scroll",r),d.events.on("popups.show.table.edit",r),d.events.on("commands.after",r),d.events.$on(v(d.win),"mousedown",p),d.events.$on(v(d.win),"mouseup",u)}}}});!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&module.exports?module.exports=function(e,r){return r===undefined&&(r="undefined"!=typeof window?require("jquery"):require("jquery")(e)),a(r)}:a(window.jQuery)}(function(c){c.extend(c.FE.DEFAULTS,{entities:""'¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿŒœŠšŸƒˆ˜ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρςστυφχψωϑϒϖ   ‌‍‎‏–—‘’‚“”„†‡•…‰′″‹›‾⁄€ℑ℘ℜ™ℵ←↑→↓↔↵⇐⇑⇒⇓⇔∀∂∃∅∇∈∉∋∏∑−∗√∝∞∠∧∨∩∪∫∴∼≅≈≠≡≤≥⊂⊃⊄⊆⊇⊕⊗⊥⋅⌈⌉⌊⌋⟨⟩◊♠♣♥♦"}),c.FE.PLUGINS.entities=function(t){var n,u;function i(e){var r=e.textContent;if(r.match(n)){for(var a="",i=0;i").html(t.opts.entities).text(),r=t.opts.entities.split(";");u={},n="";for(var a=0;a
    ')),p=v.FE.$draggable_helper,f.events.on("shared.destroy",function(){p.html("").removeData().remove(),p=null},!0)),i=e.originalEvent.pageY'),p.removeClass("fr-visible");else if(!1===f.markers.insertAtPoint(e.originalEvent))return!1;if(t.removeClass("fr-dragging"),!1===(t=f.events.chainTrigger("element.beforeDrop",t)))return!1;var a=t;if(t.parent().is("A")&&1==t.parent().get(0).childNodes.length&&(a=t.parent()),f.core.isEmpty())f.events.focus();else f.$el.find(".fr-marker").replaceWith(v.FE.MARKERS),f.selection.restore();if(n==f||f.undo.canDo()||f.undo.saveStep(),f.core.isEmpty())f.$el.html(a);else{var o=f.markers.insert();0===a.find(o).length?v(o).replaceWith(a):0===t.find(o).length&&v(o).replaceWith(t),t.after(v.FE.MARKERS),f.selection.restore()}return f.popups.hideAll(),f.selection.save(),f.$el.find(f.html.emptyBlockTagsQuery()).not("TD, TH, LI, .fr-inner").not(f.opts.htmlAllowedEmptyTags.join(",")).remove(),f.html.wrap(),f.html.fillEmptyBlocks(),f.selection.restore(),f.undo.saveStep(),f.opts.iframe&&f.size.syncIframe(),n!=f&&(n.popups.hideAll(),n.$el.find(n.html.emptyBlockTagsQuery()).not("TD, TH, LI, .fr-inner").remove(),n.html.wrap(),n.html.fillEmptyBlocks(),n.undo.saveStep(),n.events.trigger("element.dropped"),n.opts.iframe&&n.size.syncIframe()),f.events.trigger("element.dropped",[a]),!1}p&&p.removeClass("fr-visible"),f.undo.canDo()||f.undo.saveStep(),setTimeout(function(){f.undo.saveStep()},0)}function o(e){if(e&&"DIV"==e.tagName&&f.node.hasClass(e,"fr-drag-helper"))e.parentNode.removeChild(e);else if(e&&e.nodeType==Node.ELEMENT_NODE)for(var t=e.querySelectorAll("div.fr-drag-helper"),n=0;nn&&(n=e.line_indent_level)),{mode:t,parent:e,last_text:e?e.last_text:"",last_word:e?e.last_word:"",declaration_statement:!1,declaration_assignment:!1,multiline_frame:!1,if_block:!1,else_block:!1,do_block:!1,do_while:!1,in_case_statement:!1,in_case:!1,case_body:!1,indentation_level:n,line_indent_level:e?e.line_indent_level:n,start_line_index:_.get_line_number(),ternary_depth:0}}for(p={TK_START_EXPR:function(){O();var e=L.Expression;if("["===a.text){if("TK_WORD"===o||")"===c.last_text)return"TK_RESERVED"===o&&F(c.last_text,s.line_starters)&&(_.space_before_token=!0),v(e),R(),b(),void(d.space_in_paren&&(_.space_before_token=!0));e=L.ArrayLiteral,S(c.mode)&&("["!==c.last_text&&(","!==c.last_text||"]"!==l&&"}"!==l)||d.keep_array_indentation||K())}else"TK_RESERVED"===o&&"for"===c.last_text?e=L.ForInitializer:"TK_RESERVED"===o&&F(c.last_text,["if","while"])&&(e=L.Conditional);";"===c.last_text||"TK_START_BLOCK"===o?K():"TK_END_EXPR"===o||"TK_START_EXPR"===o||"TK_END_BLOCK"===o||"."===c.last_text?w(a.wanted_newline):"TK_RESERVED"===o&&"("===a.text||"TK_WORD"===o||"TK_OPERATOR"===o?"TK_RESERVED"===o&&("function"===c.last_word||"typeof"===c.last_word)||"*"===c.last_text&&"function"===l?d.space_after_anon_function&&(_.space_before_token=!0):"TK_RESERVED"!==o||!F(c.last_text,s.line_starters)&&"catch"!==c.last_text||d.space_before_conditional&&(_.space_before_token=!0):_.space_before_token=!0;"("===a.text&&"TK_RESERVED"===o&&"await"===c.last_word&&(_.space_before_token=!0);"("===a.text&&("TK_EQUALS"!==o&&"TK_OPERATOR"!==o||y()||w());v(e),R(),d.space_in_paren&&(_.space_before_token=!0);b()},TK_END_EXPR:function(){for(;c.mode===L.Statement;)k();c.multiline_frame&&w("]"===a.text&&S(c.mode)&&!d.keep_array_indentation);d.space_in_paren&&("TK_START_EXPR"!==o||d.space_in_empty_paren?_.space_before_token=!0:(_.trim(),_.space_before_token=!1));"]"===a.text&&d.keep_array_indentation?(R(),k()):(k(),R());_.remove_redundant_indentation(u),c.do_while&&u.mode===L.Conditional&&(u.mode=L.Expression,c.do_block=!1,c.do_while=!1)},TK_START_BLOCK:function(){var e=D(1),t=D(2);t&&(":"===t.text&&F(e.type,["TK_STRING","TK_WORD","TK_RESERVED"])||F(e.text,["get","set"])&&F(t.type,["TK_WORD","TK_RESERVED"]))?F(l,["class","interface"])?v(L.BlockStatement):v(L.ObjectLiteral):v(L.BlockStatement);var n=!e.comments_before.length&&"}"===e.text&&"function"===c.last_word&&"TK_END_EXPR"===o;"expand"===d.brace_style||"none"===d.brace_style&&a.wanted_newline?"TK_OPERATOR"!==o&&(n||"TK_EQUALS"===o||"TK_RESERVED"===o&&N(c.last_text)&&"else"!==c.last_text)?_.space_before_token=!0:K(!1,!0):"TK_OPERATOR"!==o&&"TK_START_EXPR"!==o?"TK_START_BLOCK"===o?K():_.space_before_token=!0:S(u.mode)&&","===c.last_text&&("}"===l?_.space_before_token=!0:K());R(),b()},TK_END_BLOCK:function(){for(;c.mode===L.Statement;)k();var e="TK_START_BLOCK"===o;"expand"===d.brace_style?e||K():e||(S(c.mode)&&d.keep_array_indentation?(d.keep_array_indentation=!1,K(),d.keep_array_indentation=!0):K());k(),R()},TK_WORD:C,TK_RESERVED:C,TK_SEMICOLON:function(){O()&&(_.space_before_token=!1);for(;c.mode===L.Statement&&!c.if_block&&!c.do_block;)k();R()},TK_STRING:function(){O()?_.space_before_token=!0:"TK_RESERVED"===o||"TK_WORD"===o?_.space_before_token=!0:"TK_COMMA"===o||"TK_START_EXPR"===o||"TK_EQUALS"===o||"TK_OPERATOR"===o?y()||w():K();R()},TK_EQUALS:function(){O();c.declaration_statement&&(c.declaration_assignment=!0);_.space_before_token=!0,R(),_.space_before_token=!0},TK_OPERATOR:function(){O();if("TK_RESERVED"===o&&N(c.last_text))return _.space_before_token=!0,void R();if("*"===a.text&&"TK_DOT"===o)return void R();if(":"===a.text&&c.in_case)return c.case_body=!0,b(),R(),K(),void(c.in_case=!1);if("::"===a.text)return void R();"TK_OPERATOR"===o&&w();var e=!0,t=!0;F(a.text,["--","++","!","~"])||F(a.text,["-","+"])&&(F(o,["TK_START_BLOCK","TK_START_EXPR","TK_EQUALS","TK_OPERATOR"])||F(c.last_text,s.line_starters)||","===c.last_text)?(t=e=!1,!a.wanted_newline||"--"!==a.text&&"++"!==a.text||K(!1,!0),";"===c.last_text&&A(c.mode)&&(e=!0),"TK_RESERVED"===o?e=!0:"TK_END_EXPR"===o?e=!("]"===c.last_text&&("--"===a.text||"++"===a.text)):"TK_OPERATOR"===o&&(e=F(a.text,["--","-","++","+"])&&F(c.last_text,["--","-","++","+"]),F(a.text,["+","-"])&&F(c.last_text,["--","++"])&&(t=!0)),c.mode!==L.BlockStatement&&c.mode!==L.Statement||"{"!==c.last_text&&";"!==c.last_text||K()):":"===a.text?0===c.ternary_depth?e=!1:c.ternary_depth-=1:"?"===a.text?c.ternary_depth+=1:"*"===a.text&&"TK_RESERVED"===o&&"function"===c.last_text&&(t=e=!1);_.space_before_token=_.space_before_token||e,R(),_.space_before_token=t},TK_COMMA:function(){if(c.declaration_statement)return A(c.parent.mode)&&(c.declaration_assignment=!1),R(),void(c.declaration_assignment?K(c.declaration_assignment=!1,!0):(_.space_before_token=!0,d.comma_first&&w()));R(),c.mode===L.ObjectLiteral||c.mode===L.Statement&&c.parent.mode===L.ObjectLiteral?(c.mode===L.Statement&&k(),K()):(_.space_before_token=!0,d.comma_first&&w())},TK_BLOCK_COMMENT:function(){if(_.raw)return _.add_raw_token(a),void(a.directives&&"end"===a.directives.preserve&&(d.test_output_raw||(_.raw=!1)));if(a.directives)return K(!1,!0),R(),"start"===a.directives.preserve&&(_.raw=!0),void K(!1,!0);if(!X.newline.test(a.text)&&!a.wanted_newline)return _.space_before_token=!0,R(),void(_.space_before_token=!0);var e,t=function(e){e=e.replace(/\x0d/g,"");var t=[],n=e.indexOf("\n");for(;-1!==n;)t.push(e.substring(0,n)),e=e.substring(n+1),n=e.indexOf("\n");e.length&&t.push(e);return t}(a.text),n=!1,i=!1,r=a.whitespace_before,s=r.length;K(!1,!0),1s?R(t[e].substring(s)):_.add_token(t[e]);K(!1,!0)},TK_COMMENT:function(){a.wanted_newline?K(!1,!0):_.trim(!0);_.space_before_token=!0,R(),K(!1,!0)},TK_DOT:function(){O();"TK_RESERVED"===o&&N(c.last_text)?_.space_before_token=!0:w(")"===c.last_text&&d.break_chained_methods);R()},TK_UNKNOWN:function(){R(),"\n"===a.text[a.text.length-1]&&K()},TK_EOF:function(){for(;c.mode===L.Statement;)k()}},d={},(e=e||{}).braces_on_own_line!==undefined&&(d.brace_style=e.braces_on_own_line?"expand":"collapse"),d.brace_style=e.brace_style?e.brace_style:d.brace_style?d.brace_style:"collapse","expand-strict"===d.brace_style&&(d.brace_style="expand"),d.indent_size=e.indent_size?parseInt(e.indent_size,10):4,d.indent_char=e.indent_char?e.indent_char:" ",d.eol=e.eol?e.eol:"\n",d.preserve_newlines=e.preserve_newlines===undefined||e.preserve_newlines,d.break_chained_methods=e.break_chained_methods!==undefined&&e.break_chained_methods,d.max_preserve_newlines=e.max_preserve_newlines===undefined?0:parseInt(e.max_preserve_newlines,10),d.space_in_paren=e.space_in_paren!==undefined&&e.space_in_paren,d.space_in_empty_paren=e.space_in_empty_paren!==undefined&&e.space_in_empty_paren,d.jslint_happy=e.jslint_happy!==undefined&&e.jslint_happy,d.space_after_anon_function=e.space_after_anon_function!==undefined&&e.space_after_anon_function,d.keep_array_indentation=e.keep_array_indentation!==undefined&&e.keep_array_indentation,d.space_before_conditional=e.space_before_conditional===undefined||e.space_before_conditional,d.unescape_strings=e.unescape_strings!==undefined&&e.unescape_strings,d.wrap_line_length=e.wrap_line_length===undefined?0:parseInt(e.wrap_line_length,10),d.e4x=e.e4x!==undefined&&e.e4x,d.end_with_newline=e.end_with_newline!==undefined&&e.end_with_newline,d.comma_first=e.comma_first!==undefined&&e.comma_first,d.test_output_raw=e.test_output_raw!==undefined&&e.test_output_raw,d.jslint_happy&&(d.space_after_anon_function=!0),e.indent_with_tabs&&(d.indent_char="\t",d.indent_size=1),d.eol=d.eol.replace(/\\r/,"\r").replace(/\\n/,"\n"),h="";0d.max_preserve_newlines&&(t=d.max_preserve_newlines),d.preserve_newlines&&1=d.wrap_line_length&&K(!1,!0)}}function K(e,t){if(!t&&";"!==c.last_text&&","!==c.last_text&&"="!==c.last_text&&"TK_OPERATOR"!==o)for(;c.mode===L.Statement&&!c.if_block&&!c.do_block;)k();_.add_new_line(e)&&(c.multiline_frame=!0)}function m(){_.just_added_newline()&&(d.keep_array_indentation&&S(c.mode)&&a.wanted_newline?(_.current_line.push(a.whitespace_before),_.space_before_token=!1):_.set_indent(c.indentation_level)&&(c.line_indent_level=c.indentation_level))}function R(e){_.raw?_.add_raw_token(a):(d.comma_first&&"TK_COMMA"===o&&_.just_added_newline()&&","===_.previous_line.last()&&(_.previous_line.pop(),m(),_.add_token(","),_.space_before_token=!0),e=e||a.text,m(),_.add_token(e))}function b(){c.indentation_level+=1}function v(e){c?(t.push(c),u=c):u=E(null,e),c=E(u,e)}function S(e){return e===L.ArrayLiteral}function A(e){return F(e,[L.Expression,L.ForInitializer,L.Conditional])}function k(){0=f.length?null:f[t]}function C(){("TK_RESERVED"===a.type&&c.mode!==L.ObjectLiteral&&F(a.text,["set","get"])&&(a.type="TK_WORD"),"TK_RESERVED"===a.type&&c.mode===L.ObjectLiteral)&&(":"==D(1).text&&(a.type="TK_WORD"));if(O()||!a.wanted_newline||A(c.mode)||"TK_OPERATOR"===o&&"--"!==c.last_text&&"++"!==c.last_text||"TK_EQUALS"===o||!d.preserve_newlines&&"TK_RESERVED"===o&&F(c.last_text,["var","let","const","set","get"])||K(),c.do_block&&!c.do_while){if("TK_RESERVED"===a.type&&"while"===a.text)return _.space_before_token=!0,R(),_.space_before_token=!0,void(c.do_while=!0);K(),c.do_block=!1}if(c.if_block)if(c.else_block||"TK_RESERVED"!==a.type||"else"!==a.text){for(;c.mode===L.Statement;)k();c.if_block=!1,c.else_block=!1}else c.else_block=!0;if("TK_RESERVED"===a.type&&("case"===a.text||"default"===a.text&&c.in_case_statement))return K(),(c.case_body||d.jslint_happy)&&(0c.parent.indentation_level)&&(c.indentation_level-=1),c.case_body=!1),R(),c.in_case=!0,void(c.in_case_statement=!0);if("TK_RESERVED"===a.type&&"function"===a.text&&((F(c.last_text,["}",";"])||_.just_added_newline()&&!F(c.last_text,["[","{",":","=",","]))&&(_.just_added_blankline()||a.comments_before.length||(K(),K(!0))),"TK_RESERVED"===o||"TK_WORD"===o?"TK_RESERVED"===o&&F(c.last_text,["get","set","new","return","export","async"])?_.space_before_token=!0:"TK_RESERVED"===o&&"default"===c.last_text&&"export"===l?_.space_before_token=!0:K():"TK_OPERATOR"===o||"="===c.last_text?_.space_before_token=!0:(c.multiline_frame||!A(c.mode)&&!S(c.mode))&&K()),"TK_COMMA"!==o&&"TK_START_EXPR"!==o&&"TK_EQUALS"!==o&&"TK_OPERATOR"!==o||y()||w(),"TK_RESERVED"===a.type&&F(a.text,["function","get","set"]))return R(),void(c.last_word=a.text);(n="NONE","TK_END_BLOCK"===o?"TK_RESERVED"===a.type&&F(a.text,["else","catch","finally"])?"expand"===d.brace_style||"end-expand"===d.brace_style||"none"===d.brace_style&&a.wanted_newline?n="NEWLINE":(n="SPACE",_.space_before_token=!0):n="NEWLINE":"TK_SEMICOLON"===o&&c.mode===L.BlockStatement?n="NEWLINE":"TK_SEMICOLON"===o&&A(c.mode)?n="SPACE":"TK_STRING"===o?n="NEWLINE":"TK_RESERVED"===o||"TK_WORD"===o||"*"===c.last_text&&"function"===l?n="SPACE":"TK_START_BLOCK"===o?n="NEWLINE":"TK_END_EXPR"===o&&(_.space_before_token=!0,n="NEWLINE"),"TK_RESERVED"===a.type&&F(a.text,s.line_starters)&&")"!==c.last_text&&(n="else"===c.last_text||"export"===c.last_text?"SPACE":"NEWLINE"),"TK_RESERVED"===a.type&&F(a.text,["else","catch","finally"]))?"TK_END_BLOCK"!==o||"expand"===d.brace_style||"end-expand"===d.brace_style||"none"===d.brace_style&&a.wanted_newline?K():(_.trim(!0),"}"!==_.current_line.last()&&K(),_.space_before_token=!0):"NEWLINE"===n?"TK_RESERVED"===o&&N(c.last_text)?_.space_before_token=!0:"TK_END_EXPR"!==o?"TK_START_EXPR"===o&&"TK_RESERVED"===a.type&&F(a.text,["var","let","const"])||":"===c.last_text||("TK_RESERVED"===a.type&&"if"===a.text&&"else"===c.last_text?_.space_before_token=!0:K()):"TK_RESERVED"===a.type&&F(a.text,s.line_starters)&&")"!==c.last_text&&K():c.multiline_frame&&S(c.mode)&&","===c.last_text&&"}"===l?K():"SPACE"===n&&(_.space_before_token=!0);R(),c.last_word=a.text,"TK_RESERVED"===a.type&&"do"===a.text&&(c.do_block=!0),"TK_RESERVED"===a.type&&"if"===a.text&&(c.if_block=!0)}o="TK_START_BLOCK",l="",(_=new I(h,T)).raw=d.test_output_raw,t=[],v(L.BlockStatement),this.beautify=function(){var e,t;for(s=new V(i,d,h),f=s.tokenize(),r=0;e=D();){for(var n=0;n=this.indent_cache.length;)this.indent_cache.push(this.indent_cache[this.indent_cache.length-1]+this.indent_string);return this.current_line.set_indent(e),!0}return this.current_line.set_indent(0),!1},this.add_raw_token=function(e){for(var t=0;t < >= <= >> << >>> >>>= >>= <<= && &= | || ! ~ , : ? ^ ^= |= :: =>".split(" ");this.line_starters="continue,try,throw,return,var,let,const,if,switch,case,default,for,while,break,function,import,export".split(",");var D,C,L,I,V,P,j=this.line_starters.concat(["do","in","else","get","set","new","catch","finally","typeof","yield","async","await"]),B=/([\s\S]*?)((?:\*\/)|$)/g,M=/([^\n\r\u2028\u2029]*)/g,U=/\/\* beautify( \w+[:]\w+)+ \*\//g,W=/ (\w+)[:](\w+)/g,z=/([\s\S]*?)((?:\/\*\sbeautify\signore:end\s\*\/)|$)/g,G=/((<\?php|<\?=)[\s\S]*?\?>)|(<%[\s\S]*?%>)/g;function _(){var e,t,n=[];if(D=0,C="",P<=V)return["","TK_EOF"];t=I.length?I[I.length-1]:new Q("TK_START_BLOCK","{");var i=v.charAt(V);for(V+=1;F(i,A);){if(X.newline.test(i)?"\n"===i&&"\r"===v.charAt(V-2)||(D+=1,n=[]):n.push(i),P<=V)return["","TK_EOF"];i=v.charAt(V),V+=1}if(n.length&&(C=n.join("")),k.test(i)){var r=!0,s=!0,_=k;for("0"===i&&V/))&&("TK_RESERVED"===t.type&&F(t.text,["return","case","throw","else","do","typeof","yield"])||"TK_END_EXPR"===t.type&&")"===t.text&&t.parent&&"TK_RESERVED"===t.parent.type&&F(t.parent.text,["if","while","for"])||F(t.type,["TK_COMMENT","TK_START_EXPR","TK_START_BLOCK","TK_END_BLOCK","TK_OPERATOR","TK_EQUALS","TK_EOF","TK_SEMICOLON","TK_COMMA"]))){var h=i,c=!1,u=!1;if(e=i,"/"===h)for(var p=!1;V/g,f=v.slice(V-1),T=d.exec(f);if(T&&0===T.index){for(var E=T[2],g=0;T;){var x=!!T[1],w=T[2],K=!!T[T.length-1]||"![CDATA["===w.slice(0,8);if(w!==E||K||(x?--g:++g),g<=0)break;T=d.exec(f)}var m=T?T.index+T[0].length:f.length;return f=f.slice(0,m),V+=m-1,[f=f.replace(X.lineBreak,"\n"),"TK_STRING"]}}else for(;V=this.wrap_line_length?(this.print_newline(!1,e),this.print_indentation(e)):(this.line_char_count++,e.push(" "))},this.get_content=function(){for(var e="",t=[];"<"!=this.input.charAt(this.pos);){if(this.pos>=this.input.length)return t.length?t.join(""):["","TK_EOF"];if(this.traverse_whitespace())this.space_or_wrap(t);else{if(g){var n=this.input.substr(this.pos,3);if("{{#"==n||"{{/"==n)break;if("{{!"==n)return[this.get_tag(),"TK_TAG_HANDLEBARS_COMMENT"];if("{{"==this.input.substr(this.pos,2)&&"{{else}}"==this.get_tag(!0))break}e=this.input.charAt(this.pos),this.pos++,this.line_char_count++,t.push(e)}}return t.length?t.join(""):""},this.get_contents_to=function(e){if(this.pos==this.input.length)return["","TK_EOF"];var t="",n=new RegExp("","igm");n.lastIndex=this.pos;var i=n.exec(this.input),r=i?i.index:this.input.length;return this.pos=this.input.length)return e&&(this.pos=o,this.line_char_count=l),r.length?r.join(""):["","TK_EOF"];if(i=this.input.charAt(this.pos),this.pos++,this.Utils.in_array(i,this.Utils.whitespace))_=!0;else{if("'"!=i&&'"'!=i||(i+=this.get_unformatted(i),_=!0),"="==i&&(_=!1),r.length&&"="!=r[r.length-1]&&">"!=i&&_){if(this.space_or_wrap(r),_=!1,!a&&"force"==x&&"/"!=i){this.print_newline(!0,r),this.print_indentation(r);for(var h=0;h"!=i);var u,p,d=r.join("");u=-1!=d.indexOf(" ")?d.indexOf(" "):"{"==d[0]?d.indexOf("}"):d.indexOf(">"),p="<"!=d[0]&&g?"#"==d[2]?3:2:1;var f=d.substring(p,u).toLowerCase();return"/"==d.charAt(d.length-2)||this.Utils.in_array(f,this.Utils.single_token)?e||(this.tag_type="SINGLE"):g&&"{"==d[0]&&"else"==f?e||(this.indent_to_tag("if"),this.tag_type="HANDLEBARS_ELSE",this.indent_content=!0,this.traverse_whitespace()):this.is_unformatted(f,E)?(s=this.get_unformatted("",d),r.push(s),this.pos,this.tag_type="SINGLE"):"script"==f&&(-1==d.search("type")||-1",i=!0):0===t.indexOf("",i=!0):0===t.indexOf("",i=!0):0===t.indexOf("\x3c!--")?(n="--\x3e",i=!0):0===t.indexOf("{{!")?(n="}}",i=!0):0===t.indexOf("",i=!0):0===t.indexOf("<%")&&(n="%>",i=!0)),r=this.input.charAt(this.pos),this.pos++;return t},this.get_unformatted=function(e,t){if(t&&-1!=t.toLowerCase().indexOf(e))return"";var n="",i="",r=0,s=!0;do{if(this.pos>=this.input.length)return i;if(n=this.input.charAt(this.pos),this.pos++,this.Utils.in_array(n,this.Utils.whitespace)){if(!s){this.line_char_count--;continue}if("\n"==n||"\r"==n){i+="\n",this.line_char_count=0;continue}}i+=n,this.line_char_count++,s=!0,g&&"{"==n&&i.length&&"{"==i[i.length-2]&&(r=(i+=this.get_unformatted("}}")).length)}while(-1==i.toLowerCase().indexOf(e,r));return i},this.get_token=function(){var e;if("TK_TAG_SCRIPT"==this.last_token||"TK_TAG_STYLE"==this.last_token){var t=this.last_token.substr(7);return"string"!=typeof(e=this.get_contents_to(t))?e:[e,"TK_"+t]}return"CONTENT"==this.current_mode?"string"!=typeof(e=this.get_content())?e:[e,"TK_CONTENT"]:"TAG"==this.current_mode?"string"!=typeof(e=this.get_tag())?e:[e,"TK_TAG_"+this.tag_type]:void 0},this.get_full_indent=function(e){return(e=this.indent_level+e||0)<1?"":new Array(e+1).join(this.indent_string)},this.is_unformatted=function(e,t){if(!this.Utils.in_array(e,t))return!1;if("a"!=e.toLowerCase()||!this.Utils.in_array("a",t))return!0;var n=(this.get_tag(!0)||"").match(/^\s*<\s*\/?([a-z]*)\s*[^>]*>\s*$/);return!(n&&!this.Utils.in_array(n,t))},this.printer=function(e,t,n,i,r){this.input=e||"",this.output=[],this.indent_character=t,this.indent_string="",this.indent_size=n,this.brace_style=r,this.indent_level=0,this.wrap_line_length=i;for(var s=this.line_char_count=0;s1){$.oc.alert($.oc.lang.get('mediamanager.invalid_file_single_insert')) +return} +var link,text=editor.selection.text(),textIsEmpty=$.trim(text)==='' +for(var i=0,len=items.length;i'+text+'');var $file=editor.$el.find('#fr-inserted-file');$file.removeAttr('id');editor.undo.saveStep() +this.hide()}})} +function onInsertImage(){var $currentImage=editor.image.get(),selection=editor.selection.get(),range=editor.selection.ranges(0);new $.oc.mediaManager.popup({alias:'ocmediamanager',cropAndInsertButton:true,onInsert:function(items){editor.selection.clear();selection.addRange(range);if(!items.length){$.oc.alert($.oc.lang.get('mediamanager.invalid_image_empty_insert')) +return} +var imagesInserted=0 +for(var i=0,len=items.length;i1){$.oc.alert($.oc.lang.get('mediamanager.invalid_file_single_insert')) +return} +var item=items[0] +if(item.documentType!=='video'){$.oc.alert($.oc.lang.get('mediamanager.invalid_video_invalid_insert','The file "'+item.title+'" is not a video.')) +return} +var $richEditorNode=editor.$el.closest('[data-control="richeditor"]') +$richEditorNode.richEditor('insertVideo',item.publicUrl,item.title) +this.hide()}})} +function onInsertAudio(){new $.oc.mediaManager.popup({alias:'ocmediamanager',cropAndInsertButton:false,onInsert:function(items){if(!items.length){$.oc.alert($.oc.lang.get('mediamanager.invalid_audio_empty_insert')) +return} +if(items.length>1){$.oc.alert($.oc.lang.get('mediamanager.invalid_file_single_insert')) +return} +var item=items[0] +if(item.documentType!=='audio'){$.oc.alert($.oc.lang.get('mediamanager.invalid_audio_invalid_insert','The file "'+item.title+'" is not an audio file.')) +return} +var $richEditorNode=editor.$el.closest('[data-control="richeditor"]') +$richEditorNode.richEditor('insertAudio',item.publicUrl,item.title) +this.hide()}})} +function _insertVideoFallback(link){var $richEditorNode=editor.$el.closest('[data-control="richeditor"]') +var title=link.substring(link.lastIndexOf('/')+1) +$richEditorNode.richEditor('insertVideo',link,title) +editor.popups.hide('video.insert')} +function _insertAudioFallback(link){var $richEditorNode=editor.$el.closest('[data-control="richeditor"]') +var title=link.substring(link.lastIndexOf('/')+1) +$richEditorNode.richEditor('insertAudio',link,title) +editor.popups.hide('audio.insert')} +function _init(){editor.events.on('destroy',_destroy,true) +editor.events.on('video.linkError',_insertVideoFallback) +editor.events.on('audio.linkError',_insertAudioFallback)} +function _destroy(){} +return{_init:_init,insertFile:onInsertFile,insertImage:onInsertImage,insertVideo:onInsertVideo,insertAudio:onInsertAudio}} +if(!$.FE.PLUGINS.link||!$.FE.PLUGINS.file||!$.FE.PLUGINS.image||!$.FE.PLUGINS.video){throw new Error('Media manager plugin requires link, file, image and video plugin.');} +$.FE.DEFAULTS.imageInsertButtons.push('mmImageManager');$.FE.RegisterCommand('mmImageManager',{title:'Browse',undo:false,focus:false,callback:function(){this.mediaManager.insertImage();},plugin:'mediaManager'}) +$.FE.DefineIcon('mmImageManager',{NAME:'folder'});$.FE.DEFAULTS.fileInsertButtons.push('mmFileManager');$.FE.RegisterCommand('mmFileManager',{title:'Browse',undo:false,focus:false,callback:function(){this.mediaManager.insertFile();},plugin:'mediaManager'}) +$.FE.DefineIcon('mmFileManager',{NAME:'folder'});$.FE.DEFAULTS.videoInsertButtons.push('mmVideoManager');$.FE.RegisterCommand('mmVideoManager',{title:'Browse',undo:false,focus:false,callback:function(){this.mediaManager.insertVideo();},plugin:'mediaManager'}) +$.FE.DefineIcon('mmVideoManager',{NAME:'folder'});$.FE.DEFAULTS.audioInsertButtons.push('mmAudioManager');$.FE.RegisterCommand('mmAudioManager',{title:'Browse',undo:false,focus:false,callback:function(){this.mediaManager.insertAudio();},plugin:'mediaManager'}) +$.FE.DefineIcon('mmAudioManager',{NAME:'folder'});})(jQuery);var richeditorPageLinksPlugin +function richeditorPageLinksSelectPage($form){richeditorPageLinksPlugin.setLinkValueFromPopup($form)} +$.FroalaEditor.DEFAULTS=$.extend($.FroalaEditor.DEFAULTS,{pageLinksHandler:'onLoadPageLinksForm'});$.FroalaEditor.DEFAULTS.key='JA6B2B5A1qB1F1F4D3I1A15A11D3E6B5dVh1VCQWa1EOQFe1NCb1==';(function($){$.FroalaEditor.PLUGINS.pageLinks=function(editor){function setLinkValueFromPopup($form){var $select=$('select[name=pagelink]',$form) +var link={text:$('option:selected',$select).text().trim(),href:$select.val()} +setTimeout(function(){editor.popups.show('link.insert') +setLinkValue(link)},300)} +function setLinkValue(link){var $popup=editor.popups.get('link.insert');var text_inputs=$popup.find('input.fr-link-attr[type="text"]');var check_inputs=$popup.find('input.fr-link-attr[type="checkbox"]');var $input;var i;for(i=0;i').append($el.clone()).remove().html() +editor.events.focus(true) +editor.selection.restore() +editor.html.insert(html) +editor.html.cleanEmptyTags() +$('figure',editor.$el).each(function(){var $this=$(this),$parent=$this.parent('p'),$next=$this.next('p') +if(!!$parent.length){$this.insertAfter($parent)} +if(!!$next.length&&$.trim($next.text()).length==0){$next.remove()}}) +editor.undo.saveStep()} +function _makeUiBlockElement(){var $node=$('
     
    ') +$node.get(0).contentEditable=false +return $node} +function insertVideo(url,text){var $node=_makeUiBlockElement() +$node.attr('data-video',url) +$node.attr('data-label',text) +insertElement($node)} +function insertAudio(url,text){var $node=_makeUiBlockElement() +$node.attr('data-audio',url) +$node.attr('data-label',text) +insertElement($node)} +function _initUiBlocks(){$('[data-video], [data-audio]',editor.$el).each(function(){$(this).addClass('fr-draggable').attr({'data-ui-block':'true','draggable':'true','tabindex':'0'}).html(' ') +this.contentEditable=false})} +function _handleUiBlocksKeydown(ev){if(ev.key==='ArrowDown'||ev.key==='ArrowUp'||ev.key==='Backspace'||ev.key==='Delete'){var $block=$(editor.selection.element()) +if($block.is('br')){$block=$block.parent()} +if(!!$block.length){switch(ev.key){case'ArrowUp':_handleUiBlockCaretIn($block.prev()) +break +case'ArrowDown':_handleUiBlockCaretIn($block.next()) +break +case'Delete':_handleUiBlockCaretClearEmpty($block.next(),$block) +break +case'Backspace':_handleUiBlockCaretClearEmpty($block.prev(),$block) +break}}}} +function _handleUiBlockCaretClearEmpty($block,$p){if($block.attr('data-ui-block')!==undefined&&$.trim($p.text()).length==0){$p.remove() +_handleUiBlockCaretIn($block) +editor.undo.saveStep()}} +function _handleUiBlockCaretIn($block){if($block.attr('data-ui-block')!==undefined){$block.focus() +editor.selection.clear() +return true} +return false} +function _uiBlockKeyDown(ev,block){if(ev.key==='ArrowDown'||ev.key==='ArrowUp'||ev.key==='Enter'||ev.key==='Backspace'||ev.key==='Delete'){switch(ev.key){case'ArrowDown':_focusUiBlockOrText($(block).next(),true) +break +case'ArrowUp':_focusUiBlockOrText($(block).prev(),false) +break +case'Enter':var $paragraph=$('


    ') +$paragraph.insertAfter(block) +editor.selection.setAfter(block) +editor.selection.restore() +editor.undo.saveStep() +break +case'Backspace':case'Delete':var $nextFocus=$(block).next(),gotoStart=true +if($nextFocus.length==0){$nextFocus=$(block).prev() +gotoStart=false} +_focusUiBlockOrText($nextFocus,gotoStart) +$(block).remove() +editor.undo.saveStep() +break} +ev.preventDefault()}} +function _focusUiBlockOrText($block,gotoStart){if(!!$block.length){if(!_handleUiBlockCaretIn($block)){if(gotoStart){editor.selection.setAtStart($block.get(0)) +editor.selection.restore()} +else{editor.selection.setAtEnd($block.get(0)) +editor.selection.restore()}}}} +function _onKeydown(ev){_handleUiBlocksKeydown(ev) +if(ev.isDefaultPrevented()){return false}} +function _onFigureKeydown(ev){if(ev.target&&$(ev.target).attr('data-ui-block')!==undefined){_uiBlockKeyDown(ev,ev.target)} +if(ev.isDefaultPrevented()){return false}} +function _onSync(html){var $domTree=$('
    '+html+'
    ') +$domTree.find('[data-video], [data-audio]').each(function(){$(this).removeAttr('contenteditable data-ui-block tabindex draggable').removeClass('fr-draggable fr-dragging')}) +return $domTree.html()} +function _init(){editor.events.on('initialized',_initUiBlocks) +editor.events.on('html.set',_initUiBlocks) +editor.events.on('html.get',_onSync) +editor.events.on('keydown',_onKeydown) +editor.events.on('destroy',_destroy,true) +editor.$el.on('keydown','figure',_onFigureKeydown)} +function _destroy(){editor.$el.off('keydown','figure',_onFigureKeydown)} +return{_init:_init,insert:insertElement,insertVideo:insertVideo,insertAudio:insertAudio}}})(jQuery);+function($){"use strict";var Base=$.oc.foundation.base,BaseProto=Base.prototype +var RichEditor=function(element,options){this.options=options +this.$el=$(element) +this.$textarea=this.$el.find('>textarea:first') +this.$form=this.$el.closest('form') +this.editor=null +$.oc.foundation.controlUtils.markDisposable(element) +Base.call(this) +this.init()} +RichEditor.prototype=Object.create(BaseProto) +RichEditor.prototype.constructor=RichEditor +RichEditor.DEFAULTS={linksHandler:null,uploadHandler:null,stylesheet:null,fullpage:false,editorLang:'en',useMediaManager:false,toolbarButtons:null,allowEmptyTags:null,allowTags:null,noWrapTags:null,removeTags:null,lineBreakerTags:null,imageStyles:null,linkStyles:null,paragraphStyles:null,paragraphFormat:null,tableStyles:null,tableCellStyles:null,aceVendorPath:'/',readOnly:false} +RichEditor.prototype.init=function(){var self=this;this.$el.one('dispose-control',this.proxy(this.dispose)) +if(!this.$textarea.attr('id')){this.$textarea.attr('id','element-'+Math.random().toString(36).substring(7))} +this.initFroala()} +RichEditor.prototype.initFroala=function(){var froalaOptions={editorClass:'control-richeditor',language:this.options.editorLang,fullPage:this.options.fullpage,pageLinksHandler:this.options.linksHandler,uploadHandler:this.options.uploadHandler,aceEditorVendorPath:this.options.aceVendorPath,toolbarSticky:false} +if(this.options.toolbarButtons){froalaOptions.toolbarButtons=this.options.toolbarButtons.split(',')} +else{froalaOptions.toolbarButtons=$.oc.richEditorButtons} +froalaOptions.imageStyles=this.options.imageStyles?this.options.imageStyles:{'oc-img-rounded':'Rounded','oc-img-bordered':'Bordered'} +froalaOptions.linkStyles=this.options.linkStyles?this.options.linkStyles:{'oc-link-green':'Green','oc-link-strong':'Thick'} +froalaOptions.paragraphStyles=this.options.paragraphStyles?this.options.paragraphStyles:{'oc-text-gray':'Gray','oc-text-bordered':'Bordered','oc-text-spaced':'Spaced','oc-text-uppercase':'Uppercase'} +froalaOptions.paragraphFormat=this.options.paragraphFormat?this.options.paragraphFormat:{'N':'Normal','H1':'Heading 1','H2':'Heading 2','H3':'Heading 3','H4':'Heading 4','PRE':'Code'} +froalaOptions.tableStyles=this.options.tableStyles?this.options.tableStyles:{'oc-dashed-borders':'Dashed Borders','oc-alternate-rows':'Alternate Rows'} +froalaOptions.tableCellStyles=this.options.tableCellStyles?this.options.tableCellStyles:{'oc-cell-highlighted':'Highlighted','oc-cell-thick-border':'Thick'} +froalaOptions.toolbarButtonsMD=froalaOptions.toolbarButtons +froalaOptions.toolbarButtonsSM=froalaOptions.toolbarButtons +froalaOptions.toolbarButtonsXS=froalaOptions.toolbarButtons +if(this.options.allowEmptyTags){froalaOptions.htmlAllowedEmptyTags=[];this.options.allowEmptyTags.split(/[\s,]+/).forEach(function(selector){var tag=selector.split('.',2) +if(froalaOptions.htmlAllowedEmptyTags.indexOf(tag[0])===-1){froalaOptions.htmlAllowedEmptyTags.push(selector)}})}else{froalaOptions.htmlAllowedEmptyTags=['textarea','a','iframe','object','video','style','script','.fa','.fr-emoticon','.fr-inner','path','line','hr','i']} +froalaOptions.htmlAllowedTags=this.options.allowTags?this.options.allowTags.split(/[\s,]+/):['a','abbr','address','area','article','aside','audio','b','bdi','bdo','blockquote','br','button','canvas','caption','cite','code','col','colgroup','datalist','dd','del','details','dfn','dialog','div','dl','dt','em','embed','fieldset','figcaption','figure','footer','form','h1','h2','h3','h4','h5','h6','header','hgroup','hr','i','iframe','img','input','ins','kbd','keygen','label','legend','li','link','main','map','mark','menu','menuitem','meter','nav','noscript','object','ol','optgroup','option','output','p','param','pre','progress','queue','rp','rt','ruby','s','samp','script','style','section','select','small','source','span','strike','strong','sub','summary','sup','table','tbody','td','textarea','tfoot','th','thead','time','title','tr','track','u','ul','var','video','wbr'] +froalaOptions.htmlDoNotWrapTags=this.options.noWrapTags?this.options.noWrapTags.split(/[\s,]+/):['figure','script','style'] +froalaOptions.htmlRemoveTags=this.options.removeTags?this.options.removeTags.split(/[\s,]+/):['script','style','base'] +froalaOptions.lineBreakerTags=this.options.lineBreakerTags?this.options.lineBreakerTags.split(/[\s,]+/):['figure, table, hr, iframe, form, dl'] +froalaOptions.shortcutsEnabled=['show','bold','italic','underline','indent','outdent','undo','redo'] +froalaOptions.requestHeaders={'X-CSRF-TOKEN':$('meta[name="csrf-token"]').attr('content'),'X-Requested-With':'XMLHttpRequest'} +var $form=this.$el.closest('form') +var formData={};if($form.length>0){$.each($form.serializeArray(),function(index,field){formData[field.name]=field.value;})} +froalaOptions.imageUploadURL=froalaOptions.fileUploadURL=window.location +froalaOptions.imageUploadParam=froalaOptions.fileUploadParam='file_data' +froalaOptions.imageUploadParams=froalaOptions.fileUploadParams=$.extend(formData,{_handler:froalaOptions.uploadHandler,}) +var placeholder=this.$textarea.attr('placeholder') +froalaOptions.placeholderText=placeholder?placeholder:'' +froalaOptions.height=this.$el.hasClass('stretch')?Infinity:$('.height-indicator',this.$el).height() +if(!this.options.useMediaManager){delete $.FroalaEditor.PLUGINS.mediaManager} +$.FroalaEditor.ICON_TEMPLATES={font_awesome:'',text:'[NAME]',image:'[ALT]'} +this.$textarea.on('froalaEditor.initialized',this.proxy(this.build)) +this.$textarea.on('froalaEditor.contentChanged',this.proxy(this.onChange)) +this.$textarea.on('froalaEditor.html.get',this.proxy(this.onSyncContent)) +this.$textarea.on('froalaEditor.html.set',this.proxy(this.onSetContent)) +this.$textarea.on('froalaEditor.paste.beforeCleanup',this.proxy(this.beforeCleanupPaste)) +this.$form.on('oc.beforeRequest',this.proxy(this.onFormBeforeRequest)) +this.$textarea.froalaEditor(froalaOptions) +this.editor=this.$textarea.data('froala.editor') +if(this.options.readOnly){this.editor.edit.off()} +this.$el.on('keydown','.fr-view figure',this.proxy(this.onFigureKeydown))} +RichEditor.prototype.dispose=function(){this.unregisterHandlers() +this.$textarea.froalaEditor('destroy') +this.$el.removeData('oc.richEditor') +this.options=null +this.$el=null +this.$textarea=null +this.$form=null +this.editor=null +BaseProto.dispose.call(this)} +RichEditor.prototype.unregisterHandlers=function(){this.$el.off('keydown','.fr-view figure',this.proxy(this.onFigureKeydown)) +this.$textarea.off('froalaEditor.initialized',this.proxy(this.build)) +this.$textarea.off('froalaEditor.contentChanged',this.proxy(this.onChange)) +this.$textarea.off('froalaEditor.html.get',this.proxy(this.onSyncContent)) +this.$textarea.off('froalaEditor.html.set',this.proxy(this.onSetContent)) +this.$textarea.off('froalaEditor.paste.beforeCleanup',this.proxy(this.beforeCleanupPaste)) +this.$form.off('oc.beforeRequest',this.proxy(this.onFormBeforeRequest)) +$(window).off('resize',this.proxy(this.updateLayout)) +$(window).off('oc.updateUi',this.proxy(this.updateLayout)) +this.$el.off('dispose-control',this.proxy(this.dispose))} +RichEditor.prototype.build=function(event,editor){this.updateLayout() +$(window).on('resize',this.proxy(this.updateLayout)) +$(window).on('oc.updateUi',this.proxy(this.updateLayout)) +editor.events.on('keydown',this.proxy(this.onKeydown),true) +this.$textarea.trigger('init.oc.richeditor',[this])} +RichEditor.prototype.isCodeViewActive=function(){return this.editor&&this.editor.codeView&&this.editor.codeView.isActive()} +RichEditor.prototype.getElement=function(){return this.$el} +RichEditor.prototype.getEditor=function(){return this.editor} +RichEditor.prototype.getTextarea=function(){return this.$textarea} +RichEditor.prototype.getContent=function(){return this.editor.html.get()} +RichEditor.prototype.setContent=function(html){this.editor.html.set(html)} +RichEditor.prototype.syncContent=function(){this.editor.events.trigger('contentChanged')} +RichEditor.prototype.updateLayout=function(){var $editor=$('.fr-wrapper',this.$el),$codeEditor=$('.fr-code',this.$el),$toolbar=$('.fr-toolbar',this.$el),$box=$('.fr-box',this.$el) +if(!$editor.length){return} +if(this.$el.hasClass('stretch')&&!$box.hasClass('fr-fullscreen')){var height=$toolbar.outerHeight(true) +$editor.css('top',height+1) +$codeEditor.css('top',height)} +else{$editor.css('top','') +$codeEditor.css('top','')}} +RichEditor.prototype.insertHtml=function(html){this.editor.html.insert(html) +this.editor.selection.restore()} +RichEditor.prototype.insertElement=function($el){this.insertHtml($('
    ').append($el.clone()).remove().html())} +RichEditor.prototype.insertUiBlock=function($node){this.$textarea.froalaEditor('figures.insert',$node)} +RichEditor.prototype.insertVideo=function(url,title){this.$textarea.froalaEditor('figures.insertVideo',url,title)} +RichEditor.prototype.insertAudio=function(url,title){this.$textarea.froalaEditor('figures.insertAudio',url,title)} +RichEditor.prototype.onSetContent=function(ev,editor){this.$textarea.trigger('setContent.oc.richeditor',[this])} +RichEditor.prototype.beforeCleanupPaste=function(ev,editor,clipboard_html){return ocSanitize(clipboard_html)} +RichEditor.prototype.onSyncContent=function(ev,editor,html){if(editor.codeBeautifier){html=editor.codeBeautifier.run(html,editor.opts.codeBeautifierOptions)} +var container={html:html} +this.$textarea.trigger('syncContent.oc.richeditor',[this,container]) +return container.html} +RichEditor.prototype.onFocus=function(){this.$el.addClass('editor-focus')} +RichEditor.prototype.onBlur=function(){this.$el.removeClass('editor-focus')} +RichEditor.prototype.onFigureKeydown=function(ev){this.$textarea.trigger('figureKeydown.oc.richeditor',[ev,this])} +RichEditor.prototype.onKeydown=function(ev,editor,keyEv){this.$textarea.trigger('keydown.oc.richeditor',[keyEv,this]) +if(ev.isDefaultPrevented()){return false}} +RichEditor.prototype.onChange=function(ev){this.$form.trigger('change')} +RichEditor.prototype.onFormBeforeRequest=function(ev){if(!this.editor){return} +if(this.isCodeViewActive()){this.editor.html.set(this.editor.codeView.get())} +this.$textarea.val(this.editor.html.get())} +var old=$.fn.richEditor +$.fn.richEditor=function(option){var args=Array.prototype.slice.call(arguments,1),result +this.each(function(){var $this=$(this) +var data=$this.data('oc.richEditor') +var options=$.extend({},RichEditor.DEFAULTS,$this.data(),typeof option=='object'&&option) +if(!data)$this.data('oc.richEditor',(data=new RichEditor(this,options))) +if(typeof option=='string')result=data[option].apply(data,args) +if(typeof result!='undefined')return false}) +return result?result:this} +$.fn.richEditor.Constructor=RichEditor +$.fn.richEditor.noConflict=function(){$.fn.richEditor=old +return this} +$(document).render(function(){$('[data-control="richeditor"]').richEditor()}) +if($.oc===undefined) +$.oc={} +$.oc.richEditorButtons=['paragraphFormat','paragraphStyle','quote','bold','italic','align','formatOL','formatUL','insertTable','insertLink','insertImage','insertVideo','insertAudio','insertFile','insertHR','fullscreen','html']}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/formwidgets/richeditor/assets/js/build-plugins.js b/modules/backend/formwidgets/richeditor/assets/js/build-plugins.js new file mode 100644 index 0000000..5924d56 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/js/build-plugins.js @@ -0,0 +1,15 @@ +/* + * This is a bundle file, you can compile this in two ways: + * (1) Using your favorite JS combiner + * (2) Using CLI command: + * php artisan october:util compile assets + * + * @see build-plugins-min.js + * + +=require plugins/mediamanager.js +=require plugins/pagelinks.js +=require plugins/figures.js +=require richeditor.js + +*/ diff --git a/modules/backend/formwidgets/richeditor/assets/js/build.js b/modules/backend/formwidgets/richeditor/assets/js/build.js new file mode 100644 index 0000000..6591918 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/js/build.js @@ -0,0 +1,47 @@ +/* + * This is a bundle file, you can compile this in two ways: + * (1) Using your favorite JS combiner + * (2) Using CLI command: + * php artisan october:util compile assets + * + * @see build-min.js + * + +// Cannot be minified twice +=require ../vendor/froala_drm/js/froala_editor.js + +// Buttons +=require ../vendor/froala_drm/js/plugins/paragraph_style.min.js +=require ../vendor/froala_drm/js/plugins/fullscreen_soft.js +=require ../vendor/froala_drm/js/plugins/code_view_ace.js +=require ../vendor/froala_drm/js/plugins/paragraph_format.min.js +=require ../vendor/froala_drm/js/plugins/align.min.js +=require ../vendor/froala_drm/js/plugins/lists.min.js +=require ../vendor/froala_drm/js/plugins/file_extended.js +=require ../vendor/froala_drm/js/plugins/image.min.js +=require ../vendor/froala_drm/js/plugins/inline_style.min.js +=require ../vendor/froala_drm/js/plugins/inline_class.min.js + +// Cannot be minified twice +=require ../vendor/froala_drm/js/plugins/link.js + +=require ../vendor/froala_drm/js/plugins/table.min.js +=require ../vendor/froala_drm/js/plugins/video_simple.js +=require ../vendor/froala_drm/js/plugins/audio.js +=require ../vendor/froala_drm/js/plugins/quote.min.js +=require ../vendor/froala_drm/js/plugins/font_size.min.js +=require ../vendor/froala_drm/js/plugins/font_family.min.js +=require ../vendor/froala_drm/js/plugins/emoticons.min.js +=require ../vendor/froala_drm/js/plugins/colors.min.js + +// Functional +=require ../vendor/froala_drm/js/plugins/url.min.js +=require ../vendor/froala_drm/js/plugins/line_breaker.min.js +=require ../vendor/froala_drm/js/plugins/entities.min.js +=require ../vendor/froala_drm/js/plugins/draggable.min.js +=require ../vendor/froala_drm/js/plugins/code_beautifier.min.js + +// More testing needed +//require ../vendor/froala_drm/js/plugins/quick_insert.js + +*/ diff --git a/modules/backend/formwidgets/richeditor/assets/js/plugins/figures.js b/modules/backend/formwidgets/richeditor/assets/js/plugins/figures.js new file mode 100644 index 0000000..fed8db5 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/js/plugins/figures.js @@ -0,0 +1,250 @@ +(function ($) { + // Add an option for your plugin. + // $.FroalaEditor.DEFAULTS = $.extend($.FroalaEditor.DEFAULTS, { + // myOption: false + // }); + + $.FroalaEditor.PLUGINS.figures = function (editor) { + + /** + * Insert UI Blocks + */ + function insertElement($el) { + var html = $('
    ').append($el.clone()).remove().html() + + // Make sure we have focus. + editor.events.focus(true) + editor.selection.restore() + + editor.html.insert(html) + editor.html.cleanEmptyTags() + + // Clean up wrapping paragraphs or empty paragraphs + $('figure', editor.$el).each(function() { + var $this = $(this), + $parent = $this.parent('p'), + $next = $this.next('p') + + // If block is inserted to a paragraph, insert it afterwards. + if (!!$parent.length) { + $this.insertAfter($parent) + } + + // Inserting a figure tag will put an empty paragraph tag + // directly after it, strip these instances out + if (!!$next.length && $.trim($next.text()).length == 0) { + $next.remove() + } + }) + + editor.undo.saveStep() + } + + function _makeUiBlockElement() { + var $node = $('
     
    ') + + $node.get(0).contentEditable = false + + return $node + } + + function insertVideo(url, text) { + var $node = _makeUiBlockElement() + + $node.attr('data-video', url) + $node.attr('data-label', text) + + insertElement($node) + } + + function insertAudio(url, text) { + var $node = _makeUiBlockElement() + + $node.attr('data-audio', url) + $node.attr('data-label', text) + + insertElement($node) + } + + /** + * Init UI Blocks + */ + function _initUiBlocks () { + $('[data-video], [data-audio]', editor.$el).each(function() { + $(this) + .addClass('fr-draggable') + .attr({ + 'data-ui-block': 'true', + 'draggable': 'true', + 'tabindex': '0' + }) + .html(' ') + + this.contentEditable = false + }) + } + + function _handleUiBlocksKeydown(ev) { + if (ev.key === 'ArrowDown' || ev.key === 'ArrowUp' || ev.key === 'Backspace' || ev.key === 'Delete') { + var $block = $(editor.selection.element()) + if ($block.is('br')) { + $block = $block.parent() + } + + if (!!$block.length) { + switch (ev.key) { + case 'ArrowUp': + _handleUiBlockCaretIn($block.prev()) + break + case 'ArrowDown': + _handleUiBlockCaretIn($block.next()) + break + case 'Delete': + _handleUiBlockCaretClearEmpty($block.next(), $block) + break + case 'Backspace': + _handleUiBlockCaretClearEmpty($block.prev(), $block) + break + } + } + } + } + + function _handleUiBlockCaretClearEmpty($block, $p) { + if ($block.attr('data-ui-block') !== undefined && $.trim($p.text()).length == 0) { + $p.remove() + _handleUiBlockCaretIn($block) + editor.undo.saveStep() + } + } + + function _handleUiBlockCaretIn($block) { + if ($block.attr('data-ui-block') !== undefined) { + $block.focus() + editor.selection.clear() + return true + } + + return false + } + + function _uiBlockKeyDown(ev, block) { + if (ev.key === 'ArrowDown' || ev.key === 'ArrowUp' || ev.key === 'Enter' || ev.key === 'Backspace' || ev.key === 'Delete') { + switch (ev.key) { + case 'ArrowDown': + _focusUiBlockOrText($(block).next(), true) + break + case 'ArrowUp': + _focusUiBlockOrText($(block).prev(), false) + break + case 'Enter': + var $paragraph = $('


    ') + $paragraph.insertAfter(block) + editor.selection.setAfter(block) + editor.selection.restore() + editor.undo.saveStep() + break + case 'Backspace': + case 'Delete': + var $nextFocus = $(block).next(), + gotoStart = true + + if ($nextFocus.length == 0) { + $nextFocus = $(block).prev() + gotoStart = false + } + + _focusUiBlockOrText($nextFocus, gotoStart) + + $(block).remove() + editor.undo.saveStep() + break + } + + ev.preventDefault() + } + } + + function _focusUiBlockOrText($block, gotoStart) { + if (!!$block.length) { + if (!_handleUiBlockCaretIn($block)) { + if (gotoStart) { + editor.selection.setAtStart($block.get(0)) + editor.selection.restore() + } + else { + editor.selection.setAtEnd($block.get(0)) + editor.selection.restore() + } + } + } + } + + /** + * Keydown + */ + function _onKeydown (ev) { + _handleUiBlocksKeydown(ev) + + if (ev.isDefaultPrevented()) { + return false + } + } + + function _onFigureKeydown(ev) { + if (ev.target && $(ev.target).attr('data-ui-block') !== undefined) { + _uiBlockKeyDown(ev, ev.target) + } + + if (ev.isDefaultPrevented()) { + return false + } + } + + /** + * Sync + */ + function _onSync(html) { + var $domTree = $('
    ' + html + '
    ') + + $domTree.find('[data-video], [data-audio]').each(function(){ + $(this) + .removeAttr('contenteditable data-ui-block tabindex draggable') + .removeClass('fr-draggable fr-dragging') + }) + + return $domTree.html() + } + + /** + * Init. + */ + function _init () { + editor.events.on('initialized', _initUiBlocks) + + editor.events.on('html.set', _initUiBlocks) + + editor.events.on('html.get', _onSync) + + editor.events.on('keydown', _onKeydown) + + editor.events.on('destroy', _destroy, true) + + editor.$el.on('keydown', 'figure', _onFigureKeydown) + } + + /** + * Destroy. + */ + function _destroy () { + editor.$el.off('keydown', 'figure', _onFigureKeydown) + } + + return { + _init: _init, + insert: insertElement, + insertVideo: insertVideo, + insertAudio: insertAudio + } + } +})(jQuery); diff --git a/modules/backend/formwidgets/richeditor/assets/js/plugins/mediamanager.js b/modules/backend/formwidgets/richeditor/assets/js/plugins/mediamanager.js new file mode 100644 index 0000000..3fe9de3 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/js/plugins/mediamanager.js @@ -0,0 +1,287 @@ +(function ($) { + + $.FroalaEditor.PLUGINS.mediaManager = function (editor) { + + function onInsertFile() { + new $.oc.mediaManager.popup({ + alias: 'ocmediamanager', + cropAndInsertButton: false, + onInsert: function(items) { + if (!items.length) { + $.oc.alert($.oc.lang.get('mediamanager.invalid_file_empty_insert')) + return + } + + if (items.length > 1) { + $.oc.alert($.oc.lang.get('mediamanager.invalid_file_single_insert')) + return + } + + var link, + text = editor.selection.text(), + textIsEmpty = $.trim(text) === '' + + for (var i=0, len=items.length; i' + text + ''); + + // Get the file. + var $file = editor.$el.find('#fr-inserted-file'); + $file.removeAttr('id'); + + editor.undo.saveStep() + this.hide() + } + }) + } + + function onInsertImage() { + var $currentImage = editor.image.get(), + selection = editor.selection.get(), + range = editor.selection.ranges(0); + + new $.oc.mediaManager.popup({ + alias: 'ocmediamanager', + cropAndInsertButton: true, + onInsert: function(items) { + editor.selection.clear(); + selection.addRange(range); + + if (!items.length) { + $.oc.alert($.oc.lang.get('mediamanager.invalid_image_empty_insert')) + return + } + + var imagesInserted = 0 + + for (var i=0, len=items.length; i 1) { + $.oc.alert($.oc.lang.get('mediamanager.invalid_file_single_insert')) + return + } + + var item = items[0] + + if (item.documentType !== 'video') { + $.oc.alert($.oc.lang.get('mediamanager.invalid_video_invalid_insert', 'The file "'+item.title+'" is not a video.')) + return + } + + var $richEditorNode = editor.$el.closest('[data-control="richeditor"]') + + $richEditorNode.richEditor('insertVideo', item.publicUrl, item.title) + + this.hide() + } + }) + } + + function onInsertAudio() { + new $.oc.mediaManager.popup({ + alias: 'ocmediamanager', + cropAndInsertButton: false, + onInsert: function(items) { + if (!items.length) { + $.oc.alert($.oc.lang.get('mediamanager.invalid_audio_empty_insert')) + return + } + + if (items.length > 1) { + $.oc.alert($.oc.lang.get('mediamanager.invalid_file_single_insert')) + return + } + + var item = items[0] + + if (item.documentType !== 'audio') { + $.oc.alert($.oc.lang.get('mediamanager.invalid_audio_invalid_insert', 'The file "'+item.title+'" is not an audio file.')) + return + } + + var $richEditorNode = editor.$el.closest('[data-control="richeditor"]') + + $richEditorNode.richEditor('insertAudio', item.publicUrl, item.title) + + this.hide() + } + }) + } + + function _insertVideoFallback(link) { + var $richEditorNode = editor.$el.closest('[data-control="richeditor"]') + + var title = link.substring(link.lastIndexOf('/') + 1) + + $richEditorNode.richEditor('insertVideo', link, title) + + editor.popups.hide('video.insert') + } + + function _insertAudioFallback(link) { + var $richEditorNode = editor.$el.closest('[data-control="richeditor"]') + + var title = link.substring(link.lastIndexOf('/') + 1) + + $richEditorNode.richEditor('insertAudio', link, title) + + editor.popups.hide('audio.insert') + } + + /** + * Init. + */ + function _init () { + editor.events.on('destroy', _destroy, true) + + editor.events.on('video.linkError', _insertVideoFallback) + + editor.events.on('audio.linkError', _insertAudioFallback) + } + + /** + * Destroy. + */ + function _destroy () { + } + + // Expose public methods. If _init is not public then the plugin won't be initialized. + // Public method can be accessed through the editor API: + // $('.selector').froalaEditor('mediaManager.publicMethod'); + return { + _init: _init, + insertFile: onInsertFile, + insertImage: onInsertImage, + insertVideo: onInsertVideo, + insertAudio: onInsertAudio + } + } + + if (!$.FE.PLUGINS.link || !$.FE.PLUGINS.file || !$.FE.PLUGINS.image || !$.FE.PLUGINS.video) { + throw new Error('Media manager plugin requires link, file, image and video plugin.'); + } + + // + // Image + // + + $.FE.DEFAULTS.imageInsertButtons.push('mmImageManager'); + + $.FE.RegisterCommand('mmImageManager', { + title: 'Browse', + undo: false, + focus: false, + callback: function () { + this.mediaManager.insertImage(); + }, + plugin: 'mediaManager' + }) + + // Add the font size icon. + $.FE.DefineIcon('mmImageManager', { + NAME: 'folder' + }); + + // + // File + // + + $.FE.DEFAULTS.fileInsertButtons.push('mmFileManager'); + + $.FE.RegisterCommand('mmFileManager', { + title: 'Browse', + undo: false, + focus: false, + callback: function () { + this.mediaManager.insertFile(); + }, + plugin: 'mediaManager' + }) + + // Add the font size icon. + $.FE.DefineIcon('mmFileManager', { + NAME: 'folder' + }); + + // + // Video + // + + $.FE.DEFAULTS.videoInsertButtons.push('mmVideoManager'); + + $.FE.RegisterCommand('mmVideoManager', { + title: 'Browse', + undo: false, + focus: false, + callback: function () { + this.mediaManager.insertVideo(); + }, + plugin: 'mediaManager' + }) + + // Add the font size icon. + $.FE.DefineIcon('mmVideoManager', { + NAME: 'folder' + }); + + // + // Audio + // + + $.FE.DEFAULTS.audioInsertButtons.push('mmAudioManager'); + + $.FE.RegisterCommand('mmAudioManager', { + title: 'Browse', + undo: false, + focus: false, + callback: function () { + this.mediaManager.insertAudio(); + }, + plugin: 'mediaManager' + }) + + // Add the font size icon. + $.FE.DefineIcon('mmAudioManager', { + NAME: 'folder' + }); + +})(jQuery); diff --git a/modules/backend/formwidgets/richeditor/assets/js/plugins/pagelinks.js b/modules/backend/formwidgets/richeditor/assets/js/plugins/pagelinks.js new file mode 100644 index 0000000..d338cde --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/js/plugins/pagelinks.js @@ -0,0 +1,104 @@ +// +// Page links +// + +var richeditorPageLinksPlugin + +function richeditorPageLinksSelectPage($form) { + richeditorPageLinksPlugin.setLinkValueFromPopup($form) +} + +$.FroalaEditor.DEFAULTS = $.extend($.FroalaEditor.DEFAULTS, { + pageLinksHandler: 'onLoadPageLinksForm' +}); + +$.FroalaEditor.DEFAULTS.key = 'JA6B2B5A1qB1F1F4D3I1A15A11D3E6B5dVh1VCQWa1EOQFe1NCb1=='; + +(function ($) { + $.FroalaEditor.PLUGINS.pageLinks = function (editor) { + + function setLinkValueFromPopup($form) { + var $select = $('select[name=pagelink]', $form) + + var link = { + text: $('option:selected', $select).text().trim(), + href: $select.val() + } + + // Wait for popup to close + setTimeout(function() { + editor.popups.show('link.insert') + + setLinkValue(link) + }, 300) + } + + function setLinkValue(link) { + var $popup = editor.popups.get('link.insert'); + var text_inputs = $popup.find('input.fr-link-attr[type="text"]'); + var check_inputs = $popup.find('input.fr-link-attr[type="checkbox"]'); + + var $input; + var i; + for (i = 0; i < text_inputs.length; i++) { + $input = $(text_inputs[i]); + if (link[$input.attr('name')]) { + $input.val(link[$input.attr('name')]); + } + else if ($input.attr('name') != 'text') { + $input.val(''); + } + } + + for (i = 0; i < check_inputs.length; i++) { + $input = $(check_inputs[i]); + $input.prop('checked', $input.data('checked') == link[$input.attr('name')]); + } + + // Restore selection, so that the link gets inserted properly. + editor.selection.restore(); + } + + function insertLink() { + richeditorPageLinksPlugin = this + + editor.$el.popup({ + handler: editor.opts.pageLinksHandler + }).one('shown.oc.popup.pageLinks', function () { + // Save the current selection so it can be restored after popup is closed. + editor.selection.save() + }) + } + + /** + * Init. + */ + function _init () { + } + + return { + _init: _init, + setLinkValueFromPopup: setLinkValueFromPopup, + setLinkValue: setLinkValue, + insertLink: insertLink + } + } + + $.FE.DEFAULTS.linkInsertButtons = ['linkBack', '|', 'linkPageLinks'] + + $.FE.RegisterCommand('linkPageLinks', { + title: 'Choose Link', + undo: false, + focus: false, + callback: function () { + this.pageLinks.insertLink() + }, + plugin: 'pageLinks' + }) + + // Add the font size icon. + $.FE.DefineIcon('linkPageLinks', { + NAME: 'search' + }); + +})(jQuery); diff --git a/modules/backend/formwidgets/richeditor/assets/js/richeditor.js b/modules/backend/formwidgets/richeditor/assets/js/richeditor.js new file mode 100755 index 0000000..230ff8f --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/js/richeditor.js @@ -0,0 +1,483 @@ +/* + * Rich text editor form field control (WYSIWYG) + * + * Data attributes: + * - data-control="richeditor" - enables the rich editor plugin + * + * JavaScript API: + * $('textarea').richEditor() + * + * Dependancies: + * - Froala Editor (froala_editor.js) + */ ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + // RICHEDITOR CLASS DEFINITION + // ============================ + + var RichEditor = function(element, options) { + this.options = options + this.$el = $(element) + this.$textarea = this.$el.find('>textarea:first') + this.$form = this.$el.closest('form') + this.editor = null + + $.oc.foundation.controlUtils.markDisposable(element) + + Base.call(this) + + this.init() + } + + RichEditor.prototype = Object.create(BaseProto) + RichEditor.prototype.constructor = RichEditor + + RichEditor.DEFAULTS = { + linksHandler: null, + uploadHandler: null, + stylesheet: null, + fullpage: false, + editorLang: 'en', + useMediaManager: false, + toolbarButtons: null, + allowEmptyTags: null, + allowTags: null, + noWrapTags: null, + removeTags: null, + lineBreakerTags: null, + imageStyles: null, + linkStyles: null, + paragraphStyles: null, + paragraphFormat: null, + tableStyles: null, + tableCellStyles: null, + aceVendorPath: '/', + readOnly: false + } + + RichEditor.prototype.init = function() { + var self = this; + + this.$el.one('dispose-control', this.proxy(this.dispose)) + + /* + * Textarea must have an identifier + */ + if (!this.$textarea.attr('id')) { + this.$textarea.attr('id', 'element-' + Math.random().toString(36).substring(7)) + } + + /* + * Initialize Froala editor + */ + this.initFroala() + } + + RichEditor.prototype.initFroala = function() { + var froalaOptions = { + editorClass: 'control-richeditor', + language: this.options.editorLang, + fullPage: this.options.fullpage, + pageLinksHandler: this.options.linksHandler, + uploadHandler: this.options.uploadHandler, + aceEditorVendorPath: this.options.aceVendorPath, + toolbarSticky: false + } + + if (this.options.toolbarButtons) { + froalaOptions.toolbarButtons = this.options.toolbarButtons.split(',') + } + else { + froalaOptions.toolbarButtons = $.oc.richEditorButtons + } + + froalaOptions.imageStyles = this.options.imageStyles + ? this.options.imageStyles + : { + 'oc-img-rounded': 'Rounded', + 'oc-img-bordered': 'Bordered' + } + + froalaOptions.linkStyles = this.options.linkStyles + ? this.options.linkStyles + : { + 'oc-link-green': 'Green', + 'oc-link-strong': 'Thick' + } + + froalaOptions.paragraphStyles = this.options.paragraphStyles + ? this.options.paragraphStyles + : { + 'oc-text-gray': 'Gray', + 'oc-text-bordered': 'Bordered', + 'oc-text-spaced': 'Spaced', + 'oc-text-uppercase': 'Uppercase' + } + + froalaOptions.paragraphFormat = this.options.paragraphFormat + ? this.options.paragraphFormat + : { + 'N': 'Normal', + 'H1': 'Heading 1', + 'H2': 'Heading 2', + 'H3': 'Heading 3', + 'H4': 'Heading 4', + 'PRE': 'Code' + } + + froalaOptions.tableStyles = this.options.tableStyles + ? this.options.tableStyles + : { + 'oc-dashed-borders': 'Dashed Borders', + 'oc-alternate-rows': 'Alternate Rows' + } + + froalaOptions.tableCellStyles = this.options.tableCellStyles + ? this.options.tableCellStyles + : { + 'oc-cell-highlighted': 'Highlighted', + 'oc-cell-thick-border': 'Thick' + } + + froalaOptions.toolbarButtonsMD = froalaOptions.toolbarButtons + froalaOptions.toolbarButtonsSM = froalaOptions.toolbarButtons + froalaOptions.toolbarButtonsXS = froalaOptions.toolbarButtons + + if (this.options.allowEmptyTags) { + froalaOptions.htmlAllowedEmptyTags = []; + + this.options.allowEmptyTags.split(/[\s,]+/).forEach( + function (selector) { + var tag = selector.split('.', 2) + if (froalaOptions.htmlAllowedEmptyTags.indexOf(tag[0]) === -1) { + froalaOptions.htmlAllowedEmptyTags.push(selector) + } + } + ) + } else { + froalaOptions.htmlAllowedEmptyTags = ['textarea', 'a', 'iframe', 'object', 'video', 'style', 'script', '.fa', '.fr-emoticon', '.fr-inner', 'path', 'line', 'hr', 'i'] + } + + froalaOptions.htmlAllowedTags = this.options.allowTags + ? this.options.allowTags.split(/[\s,]+/) + : ['a', 'abbr', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'blockquote', 'br', 'button', 'canvas', 'caption', 'cite', 'code', 'col', 'colgroup', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'keygen', 'label', 'legend', 'li', 'link', 'main', 'map', 'mark', 'menu', 'menuitem', 'meter', 'nav', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p', 'param', 'pre', 'progress', 'queue', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'style', 'section', 'select', 'small', 'source', 'span', 'strike', 'strong', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'track', 'u', 'ul', 'var', 'video', 'wbr'] + + froalaOptions.htmlDoNotWrapTags = this.options.noWrapTags + ? this.options.noWrapTags.split(/[\s,]+/) + : ['figure', 'script', 'style'] + + froalaOptions.htmlRemoveTags = this.options.removeTags + ? this.options.removeTags.split(/[\s,]+/) + : ['script', 'style', 'base'] + + froalaOptions.lineBreakerTags = this.options.lineBreakerTags + ? this.options.lineBreakerTags.split(/[\s,]+/) + : ['figure, table, hr, iframe, form, dl'] + + froalaOptions.shortcutsEnabled = ['show', 'bold', 'italic', 'underline', 'indent', 'outdent', 'undo', 'redo'] + + // Ensure that October recognizes AJAX requests from Froala + froalaOptions.requestHeaders = { + 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'), + 'X-Requested-With': 'XMLHttpRequest' + } + + // Get the data from the parent form for including in the request + var $form = this.$el.closest('form') + var formData = {}; + if ($form.length > 0) { + $.each($form.serializeArray(), function (index, field) { + formData[field.name] = field.value; + }) + } + + // File upload + froalaOptions.imageUploadURL = froalaOptions.fileUploadURL = window.location + froalaOptions.imageUploadParam = froalaOptions.fileUploadParam = 'file_data' + froalaOptions.imageUploadParams = froalaOptions.fileUploadParams = $.extend(formData, { + _handler: froalaOptions.uploadHandler, + }) + + var placeholder = this.$textarea.attr('placeholder') + froalaOptions.placeholderText = placeholder ? placeholder : '' + + froalaOptions.height = this.$el.hasClass('stretch') + ? Infinity + : $('.height-indicator', this.$el).height() + + if (!this.options.useMediaManager) { + delete $.FroalaEditor.PLUGINS.mediaManager + } + + $.FroalaEditor.ICON_TEMPLATES = { + font_awesome: '', + text: '[NAME]', + image: '[ALT]' + } + + this.$textarea.on('froalaEditor.initialized', this.proxy(this.build)) + this.$textarea.on('froalaEditor.contentChanged', this.proxy(this.onChange)) + this.$textarea.on('froalaEditor.html.get', this.proxy(this.onSyncContent)) + this.$textarea.on('froalaEditor.html.set', this.proxy(this.onSetContent)) + this.$textarea.on('froalaEditor.paste.beforeCleanup', this.proxy(this.beforeCleanupPaste)) + this.$form.on('oc.beforeRequest', this.proxy(this.onFormBeforeRequest)) + + this.$textarea.froalaEditor(froalaOptions) + + this.editor = this.$textarea.data('froala.editor') + + if (this.options.readOnly) { + this.editor.edit.off() + } + + this.$el.on('keydown', '.fr-view figure', this.proxy(this.onFigureKeydown)) + } + + RichEditor.prototype.dispose = function() { + this.unregisterHandlers() + + this.$textarea.froalaEditor('destroy') + + this.$el.removeData('oc.richEditor') + + this.options = null + this.$el = null + this.$textarea = null + this.$form = null + this.editor = null + + BaseProto.dispose.call(this) + } + + RichEditor.prototype.unregisterHandlers = function() { + this.$el.off('keydown', '.fr-view figure', this.proxy(this.onFigureKeydown)) + + this.$textarea.off('froalaEditor.initialized', this.proxy(this.build)) + this.$textarea.off('froalaEditor.contentChanged', this.proxy(this.onChange)) + this.$textarea.off('froalaEditor.html.get', this.proxy(this.onSyncContent)) + this.$textarea.off('froalaEditor.html.set', this.proxy(this.onSetContent)) + this.$textarea.off('froalaEditor.paste.beforeCleanup', this.proxy(this.beforeCleanupPaste)) + this.$form.off('oc.beforeRequest', this.proxy(this.onFormBeforeRequest)) + + $(window).off('resize', this.proxy(this.updateLayout)) + $(window).off('oc.updateUi', this.proxy(this.updateLayout)) + this.$el.off('dispose-control', this.proxy(this.dispose)) + } + + RichEditor.prototype.build = function(event, editor) { + this.updateLayout() + + $(window).on('resize', this.proxy(this.updateLayout)) + $(window).on('oc.updateUi', this.proxy(this.updateLayout)) + + // Bind the keydown listener here to ensure it gets handled before the Froala handlers + editor.events.on('keydown', this.proxy(this.onKeydown), true) + + this.$textarea.trigger('init.oc.richeditor', [this]) + } + + RichEditor.prototype.isCodeViewActive = function() { + return this.editor && this.editor.codeView && this.editor.codeView.isActive() + } + + RichEditor.prototype.getElement = function() { + return this.$el + } + + RichEditor.prototype.getEditor = function() { + return this.editor + } + + RichEditor.prototype.getTextarea = function() { + return this.$textarea + } + + RichEditor.prototype.getContent = function() { + return this.editor.html.get() + } + + RichEditor.prototype.setContent = function(html) { + this.editor.html.set(html) + } + + RichEditor.prototype.syncContent = function() { + this.editor.events.trigger('contentChanged') + } + + RichEditor.prototype.updateLayout = function() { + var $editor = $('.fr-wrapper', this.$el), + $codeEditor = $('.fr-code', this.$el), + $toolbar = $('.fr-toolbar', this.$el), + $box = $('.fr-box', this.$el) + + if (!$editor.length) { + return + } + + if (this.$el.hasClass('stretch') && !$box.hasClass('fr-fullscreen')) { + var height = $toolbar.outerHeight(true) + $editor.css('top', height+1) + $codeEditor.css('top', height) + } + else { + $editor.css('top', '') + $codeEditor.css('top', '') + } + } + + RichEditor.prototype.insertHtml = function(html) { + this.editor.html.insert(html) + this.editor.selection.restore() + } + + RichEditor.prototype.insertElement = function($el) { + this.insertHtml($('
    ').append($el.clone()).remove().html()) + } + + /* + * Inserts non-editable block (used for snippets, audio and video) + */ + RichEditor.prototype.insertUiBlock = function($node) { + this.$textarea.froalaEditor('figures.insert', $node) + } + + RichEditor.prototype.insertVideo = function(url, title) { + this.$textarea.froalaEditor('figures.insertVideo', url, title) + } + + RichEditor.prototype.insertAudio = function(url, title) { + this.$textarea.froalaEditor('figures.insertAudio', url, title) + } + + // EVENT HANDLERS + // ============================ + + RichEditor.prototype.onSetContent = function(ev, editor) { + this.$textarea.trigger('setContent.oc.richeditor', [this]) + } + + RichEditor.prototype.beforeCleanupPaste = function (ev, editor, clipboard_html) { + return ocSanitize(clipboard_html) + } + + RichEditor.prototype.onSyncContent = function(ev, editor, html) { + // Beautify HTML. + if (editor.codeBeautifier) { + html = editor.codeBeautifier.run(html, editor.opts.codeBeautifierOptions) + } + + var container = { + html: html + } + + this.$textarea.trigger('syncContent.oc.richeditor', [this, container]) + + return container.html + } + + RichEditor.prototype.onFocus = function() { + this.$el.addClass('editor-focus') + } + + RichEditor.prototype.onBlur = function() { + this.$el.removeClass('editor-focus') + } + + RichEditor.prototype.onFigureKeydown = function(ev) { + this.$textarea.trigger('figureKeydown.oc.richeditor', [ev, this]) + } + + RichEditor.prototype.onKeydown = function(ev, editor, keyEv) { + this.$textarea.trigger('keydown.oc.richeditor', [keyEv, this]) + + if (ev.isDefaultPrevented()) { + return false + } + } + + RichEditor.prototype.onChange = function(ev) { + this.$form.trigger('change') + } + + /* + * Instantly synchronizes HTML content. + * The onSyncContent() method (above) is involved into this call, + * so the resulting HTML is (optionally) beautified. + */ + RichEditor.prototype.onFormBeforeRequest = function(ev) { + if (!this.editor) { + return + } + + if (this.isCodeViewActive()) { + this.editor.html.set(this.editor.codeView.get()) + } + + this.$textarea.val(this.editor.html.get()) + } + + // RICHEDITOR PLUGIN DEFINITION + // ============================ + + var old = $.fn.richEditor + + $.fn.richEditor = function (option) { + var args = Array.prototype.slice.call(arguments, 1), result + this.each(function () { + var $this = $(this) + var data = $this.data('oc.richEditor') + var options = $.extend({}, RichEditor.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.richEditor', (data = new RichEditor(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : this + } + + $.fn.richEditor.Constructor = RichEditor + + // RICHEDITOR NO CONFLICT + // ================= + + $.fn.richEditor.noConflict = function() { + $.fn.richEditor = old + return this + } + + // RICHEDITOR DATA-API + // =============== + $(document).render(function() { + $('[data-control="richeditor"]').richEditor() + }) + + + // BUTTON DEFINITIONS + // ================= + + if ($.oc === undefined) + $.oc = {} + + $.oc.richEditorButtons = [ + 'paragraphFormat', + 'paragraphStyle', + 'quote', + 'bold', + 'italic', + 'align', + 'formatOL', + 'formatUL', + 'insertTable', + 'insertLink', + 'insertImage', + 'insertVideo', + 'insertAudio', + 'insertFile', + 'insertHR', + 'fullscreen', + 'html' + ] + +}(window.jQuery); diff --git a/modules/backend/formwidgets/richeditor/assets/less/_base_styles.less b/modules/backend/formwidgets/richeditor/assets/less/_base_styles.less new file mode 100644 index 0000000..ff3acc7 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/less/_base_styles.less @@ -0,0 +1,175 @@ +// Vars +@image-margin: 5px; +@table-border: 1px solid #DDD; +@blockquote-level1-color: #5E35B1; +@blockquote-level2-color: #00BCD4; +@blockquote-level3-color: #43A047; +@editor-text: #000; + +.image-style() { + img { + position: relative; + max-width: 100%; + + &.fr-dib { + margin: @image-margin auto; + display: block; + float: none; + vertical-align: top; + + &.fr-fil { + margin-left: 0; + } + + &.fr-fir { + margin-right: 0; + } + } + + &.fr-dii { + display: inline-block; + float: none; + vertical-align: bottom; + margin-left: @image-margin; + margin-right: @image-margin; + max-width: calc(100% - (2 * @image-margin)); + + &.fr-fil { + float: left; + margin: @image-margin @image-margin @image-margin 0; + max-width: calc(100% - @image-margin); + } + + &.fr-fir { + float: right; + margin: @image-margin 0 @image-margin @image-margin; + max-width: calc(100% - @image-margin); + } + } + } +} + +.video-style() { + .fr-video { + text-align: center; + position: relative; + + > * { + .box-sizing(content-box); + max-width: 100%; + border: none; + } + + &.fr-dvb { + display: block; + clear: both; + + &.fr-fvl { + text-align: left; + } + + &.fr-fvr { + text-align: right; + } + } + + &.fr-dvi { + display: inline-block; + + &.fr-fvl { + float: left; + } + + &.fr-fvr { + float: right; + } + } + } +} + +.fr-view { + strong { + font-weight: 700; + } + + table { + border: none; + border-collapse: collapse; + empty-cells: show; + max-width: 100%; + + td, th { + border: @table-border; + + &:empty { + height: 20px; + } + } + + th { + background: mix(white, @editor-text, 90%);; + } + } + + hr { + clear: both; + .user-select(none); + page-break-after: always; + } + + .fr-file { + position: relative; + + &::after { + position: relative; + content: "\1F4CE"; + font-weight: normal; + } + } + + pre { + white-space: pre-wrap; + word-wrap: break-word; + } + + blockquote { + border-left: solid 2px @blockquote-level1-color; + margin-left: 0; + padding-left: 5px; + color: @blockquote-level1-color; + + blockquote { + border-color: @blockquote-level2-color; + color: @blockquote-level2-color; + + blockquote { + border-color: @blockquote-level3-color; + color: @blockquote-level3-color; + } + } + } + + span.fr-emoticon { + font-weight: normal; + font-family: "Apple Color Emoji","Segoe UI Emoji","NotoColorEmoji","Segoe UI Symbol","Android Emoji","EmojiSymbols"; + display: inline; + line-height: 0; + + &.fr-emoticon-img { + background-repeat: no-repeat !important; + font-size: inherit; + height: 1em; + width: 1em; + min-height: 20px; + min-width: 20px; + display: inline-block; + margin: -.1em .1em .1em; + line-height: 1; + vertical-align: middle; + } + } + + .image-style(); + + .video-style(); +} diff --git a/modules/backend/formwidgets/richeditor/assets/less/_froala.less b/modules/backend/formwidgets/richeditor/assets/less/_froala.less new file mode 100644 index 0000000..4163fa7 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/less/_froala.less @@ -0,0 +1,183 @@ +// +// Mods to Froala Editor +// + +// Give soft priority to all styles +body { + + // + // Wrapper + // + + .fr-box.fr-basic.fr-top .fr-wrapper, + .fr-box.fr-basic.fr-bottom .fr-wrapper { + .box-shadow(none); + } + + // + // Code mode + // + + .fr-box { + .ace_editor { + display: none; + } + .ace_editor { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: 0; + } + + &.fr-code-view .ace_editor { + display: block; + } + } + + // + // Full screen + // + + .fr-command.fr-btn[data-cmd=fullscreen] { + float: right; + } + + .fr-box.fr-fullscreen { + z-index: @zindex-fullscreen !important; + } + + // + // Toolbar + // + + .fr-toolbar { + border-top-color: transparent; + background: #f2f2f2; + } + + .fr-popup.fr-desktop, + .fr-toolbar.fr-inline.fr-desktop { + .fr-arrow { + top: -@arrow-size; + } + + &.fr-above { + .fr-arrow { + bottom: -@arrow-size; + } + } + } + + // Command button. + .fr-toolbar, .fr-popup { + .fr-command.fr-btn { + // Dropdown is visible. + &.fr-dropdown.fr-active { + color: @btn-active-text; + } + } + } + + .fr-toolbar.fr-bottom, + .fr-toolbar.fr-top { + border-bottom: 2px solid @color-list-border; + .box-shadow(none); + } + + // + // Popup Buttons + // + + .fr-popup .fr-action-buttons { + button.fr-command { + .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small); + .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border; @btn-primary-bg; @btn-primary-bg); + + margin-top: 6px; + + font-size: @font-size-base - 1; + text-align: left; + height: auto; + outline: none !important; + .box-shadow(~"inset 0 -2px 0 rgba(0,0,0,.15)"); + + &[disabled] { + color: rgba(255,255,255,.6); + } + + &.active, + &:active { + .box-shadow(inset 0 1px 0 rgba(0,0,0,.3)); + } + } + } + + // + // Popup Toolbar + // + + .fr-popup .fr-buttons { + border-bottom: 2px solid @color-list-border; + .box-shadow(none); + } + + // + // Dropdown + // + + .fr-command.fr-btn + .fr-dropdown-menu { + .fr-dropdown-wrapper .fr-dropdown-content ul.fr-dropdown-list li { + font-size: @font-size-base; + a { + color: #666666; + } + } + } + + // + // Inputs + // + + .fr-popup .fr-input-line { + + input[type="text"], textarea { + -webkit-appearance: none; + border: 1px solid @input-border; + background-color: @input-bg; + color: @input-color; + margin-bottom: 0; + .box-shadow(@input-box-shadow); + .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small); + .transition(margin @transition-timing); + + &:focus { + border: 1px solid @input-border; + } + + &.fr-not-empty { + margin-top: 12px; + } + } + + textarea { + height: auto; + } + + input + label, textarea + label { + background: transparent!important; + } + + input.fr-not-empty:focus + label, textarea.fr-not-empty:focus + label { + color: @color-label; + } + } + + .fr-popup .fr-checkbox { + span { + border-color: @input-border; + } + } + +} diff --git a/modules/backend/formwidgets/richeditor/assets/less/richeditor.less b/modules/backend/formwidgets/richeditor/assets/less/richeditor.less new file mode 100755 index 0000000..d171d35 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/less/richeditor.less @@ -0,0 +1,287 @@ +@import "../../../../assets/less/core/boot.less"; + +@richeditor-toolbar-size: 30px; +@richeditor-zindex: 600; +@richeditor-gutter: 20px; + +@color-richeditor-toolbar: #dddddd; +@color-richeditor-toolbar-btn-color: #404040; +@color-richeditor-toolbar-btn-bg-hover: #999999; +@color-richeditor-toolbar-btn-bg-active: #404040; +@color-richeditor-toolbar-btn-color-hover: #ffffff; + +@import "../vendor/froala_drm/less/froala.less"; + +// Buttons +@import "../vendor/froala_drm/less/plugins/fullscreen.less"; +@import "../vendor/froala_drm/less/plugins/code_view.less"; +@import "../vendor/froala_drm/less/plugins/file.less"; +@import "../vendor/froala_drm/less/plugins/image.less"; +@import "../vendor/froala_drm/less/plugins/table.less"; +@import "../vendor/froala_drm/less/plugins/video.less"; +@import "../vendor/froala_drm/less/plugins/colors.less"; +@import "../vendor/froala_drm/less/plugins/emoticons.less"; + +// Functional +@import "../vendor/froala_drm/less/plugins/line_breaker.less"; +@import "../vendor/froala_drm/less/plugins/draggable.less"; + +// More testing needed +//import "../vendor/froala_drm/less/plugins/quick_insert.less"; + +// Base styles +@import "_base_styles.less"; + +.fr-view { + @import "../../../../models/editorsetting/default_styles.less"; +} + +// Modifications +@import "_froala.less"; + +@font-family: @font-family-sans-serif; +@border-radius: @input-border-radius; +@tooltip-bg: #34495e; // Taken from toolbar.variables.less +@tooltip-font-size: @font-size-small; +@arrow-size: 7px; +@ui-bg: #f9f9f9; +@ui-border-color: @input-border-color; +@ui-border-top: 1px solid @ui-border-color; +@editor-padding: 20px; +@btn-hover-bg: #ddd; +@btn-text: fade(@btn-secondary-color, 80%); +@btn-font-size: 14; +@btn-active-text: #000; +@input-label-color: @color-label; + +// +// Make the focus ring and textarea fill the whole rich editor container +// + +.fr-element { + height: 100%; +} + +// +// Rich Editor +// + +.field-flush .field-richeditor { + &, &.editor-focus { + border: none; + } +} + +.richeditor-set-height(@size) { + .fr-wrapper { + height: @size; + .fr-view { + min-height: @size; + } + } + + .height-indicator { + height: @size; + display: none; + } +} + +.field-richeditor { + border: 1px solid @input-border; + .box-shadow(@input-box-shadow); + .border-radius(@input-border-radius); + .transition(@input-transition); + + // Prevents an ugly flash during the time the editor loads + > textarea { + display: none; + } + + &.editor-focus { + border-color: @color-form-field-border-focus; + } + + &.size-tiny { .richeditor-set-height(@size-tiny); } + &.size-small { .richeditor-set-height(@size-small); } + &.size-large { .richeditor-set-height(@size-large); } + &.size-huge { .richeditor-set-height(@size-huge); } + &.size-giant { .richeditor-set-height(@size-giant); } + + &.stretch { + &.size-tiny { min-height: @size-tiny; } + &.size-small { min-height: @size-small; } + &.size-large { min-height: @size-large; } + &.size-huge { min-height: @size-huge; } + &.size-giant { min-height: @size-giant; } + } +} + +.fr-tooltip { + z-index: 9997 !important; +} + +.fr-popup { + z-index: 9995 !important; +} + +.fr-toolbar { + z-index: 11 !important; +} + +.fr-separator.fr-hs { + width: 100%; +} + +// +// Stretch +// + +.field-richeditor.stretch { + .fr-box:not(.fr-fullscreen) { + display: block; + position: relative; + height: 100% !important; + width: 100% !important; + .border-radius(0) !important; + overflow: visible; + + .fr-toolbar { + .border-radius(0) !important; + border-top-color: white; + } + + .fr-wrapper { + width: 100% !important; + left: 0; + top: 0; + bottom: 0; + position: absolute; + height: auto !important; + .fr-view { + min-height: 0; + } + } + + .fr-view, textarea { + height: 100%; + } + + .fr-placeholder { + top: 20px; + left: 20px; + } + } +} + +// +// Placeholders and snippets +// + +.control-richeditor { + .richeditor-snippet() { + display: inline-block; + width: 100%; + margin: 0 0 15px 0; + padding: 10px 10px 10px 36px; + border: 2px dotted #bdc3c7; + background: white; + position: relative; + cursor: pointer; + color: #6c7071; + font: 15px @font-family-base; + font-weight: 500; + line-height: 150%; + .border-radius(3px); + + &:focus, &.inspector-open { + border-color: #2581b8; + border-style: solid; + outline: none; + } + } + + figure[data-ui-block] { + .richeditor-snippet(); + } + + figure[data-video], figure[data-audio] { + padding-left: 13px; + + &:after { + content: attr(data-label); + } + + &:before { + position: static; + margin-right: 8px; + } + } + + figure[data-video] { + &:before { + .icon(@video-camera); + } + } + + figure[data-audio] { + &:before { + .icon(@volume-up); + } + } +} + +// +// Quick Insert +// + +.fr-quick-insert { + a.fr-floating-btn { + color: @btn-text; + text-decoration: none; + } +} + +// +// Additions to disabled state +// + +.fr-box.fr-basic { + // Toolbar + .fr-toolbar.fr-disabled { + .fr-command { + cursor: not-allowed; + + &:hover, &:focus { + color: #bdbdbd; + -webkit-box-shadow: none; + box-shadow: none; + + &::after { + border-top-color: #bdbdbd!important; + } + } + + &.fr-btn-hover { + color: #bdbdbd; background: transparent; + + &::after { + border-top-color:#bdbdbd !important + } + } + + &.fr-btn.fr-options { + &:hover, &:focus { + border-left:solid 1px transparent; + } + &.fr-btn-hover { + border-left:solid 1px transparent; + } + } + } + } + + // Content + .fr-element.fr-disabled { + cursor: not-allowed; + } +} diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/.gitignore b/modules/backend/formwidgets/richeditor/assets/vendor/.gitignore new file mode 100644 index 0000000..0270e46 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/.gitignore @@ -0,0 +1 @@ +/froala_drm diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ar.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ar.js new file mode 100644 index 0000000..ec928c8 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ar.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Arabic + */ + +$.FE.LANGUAGE['ar'] = { + translation: { + // Place holder + "Type something": "\u0627\u0643\u062a\u0628 \u0634\u064a\u0626\u0627", + + // Basic formatting + "Bold": "\u063a\u0627\u0645\u0642", + "Italic": "\u0645\u0627\u0626\u0644", + "Underline": "\u062a\u0633\u0637\u064a\u0631", + "Strikethrough": "\u064a\u062a\u0648\u0633\u0637 \u062e\u0637", + + // Main buttons + "Insert": "\u0625\u062f\u0631\u0627\u062c", + "Delete": "\u062d\u0630\u0641", + "Cancel": "\u0625\u0644\u063a\u0627\u0621", + "OK": "\u0645\u0648\u0627\u0641\u0642", + "Back": "\u0638\u0647\u0631", + "Remove": "\u0625\u0632\u0627\u0644\u0629", + "More": "\u0623\u0643\u062b\u0631", + "Update": "\u0627\u0644\u062a\u062d\u062f\u064a\u062b", + "Style": "\u0623\u0633\u0644\u0648\u0628", + + // Font + "Font Family": "\u0639\u0627\u0626\u0644\u0629 \u0627\u0644\u062e\u0637", + "Font Size": "\u062d\u062c\u0645 \u0627\u0644\u062e\u0637", + + // Colors + "Colors": "\u0627\u0644\u0623\u0644\u0648\u0627\u0646", + "Background": "\u0627\u0644\u062e\u0644\u0641\u064a\u0629", + "Text": "\u0627\u0644\u0646\u0635", + "HEX Color": "عرافة اللون", + + // Paragraphs + "Paragraph Format": "\u062a\u0646\u0633\u064a\u0642 \u0627\u0644\u0641\u0642\u0631\u0629", + "Normal": "\u0637\u0628\u064a\u0639\u064a", + "Code": "\u0643\u0648\u062f", + "Heading 1": "\u0627\u0644\u0639\u0646\u0627\u0648\u064a\u0646 1", + "Heading 2": "\u0627\u0644\u0639\u0646\u0627\u0648\u064a\u0646 2", + "Heading 3": "\u0627\u0644\u0639\u0646\u0627\u0648\u064a\u0646 3", + "Heading 4": "\u0627\u0644\u0639\u0646\u0627\u0648\u064a\u0646 4", + + // Style + "Paragraph Style": "\u0646\u0645\u0637 \u0627\u0644\u0641\u0642\u0631\u0629", + "Inline Style": "\u0627\u0644\u0646\u0645\u0637 \u0627\u0644\u0645\u0636\u0645\u0646", + + // Alignment + "Align": "\u0645\u062d\u0627\u0630\u0627\u0629", + "Align Left": "\u0645\u062d\u0627\u0630\u0627\u0629 \u0627\u0644\u0646\u0635 \u0644\u0644\u064a\u0633\u0627\u0631", + "Align Center": "\u062a\u0648\u0633\u064a\u0637", + "Align Right": "\u0645\u062d\u0627\u0630\u0627\u0629 \u0627\u0644\u0646\u0635 \u0644\u0644\u064a\u0645\u064a\u0646", + "Align Justify": "\u0636\u0628\u0637", + "None": "\u0644\u0627 \u0634\u064a\u0621", + + // Lists + "Ordered List": "\u0642\u0627\u0626\u0645\u0629 \u0645\u0631\u062a\u0628\u0629", + "Default": "الافتراضي", + "Lower Alpha": "أقل ألفا", + "Lower Greek": "أقل اليونانية", + "Lower Roman": "انخفاض الروماني", + "Upper Alpha": "العلوي ألفا", + "Upper Roman": "الروماني العلوي", + + "Unordered List": "\u0642\u0627\u0626\u0645\u0629 \u063a\u064a\u0631 \u0645\u0631\u062a\u0628\u0629", + "Circle": "دائرة", + "Disc": "القرص", + "Square": "ميدان", + + // Line height + "Line Height": "ارتفاع خط", + "Single": "غير مرتبطة", + "Double": "مزدوج", + + // Indent + "Decrease Indent": "\u0627\u0646\u062e\u0641\u0627\u0636 \u0627\u0644\u0645\u0633\u0627\u0641\u0629 \u0627\u0644\u0628\u0627\u062f\u0626\u0629", + "Increase Indent": "\u0632\u064a\u0627\u062f\u0629 \u0627\u0644\u0645\u0633\u0627\u0641\u0629 \u0627\u0644\u0628\u0627\u062f\u0626\u0629", + + // Links + "Insert Link": "\u0625\u062f\u0631\u0627\u062c \u0631\u0627\u0628\u0637", + "Open in new tab": "\u0641\u062a\u062d \u0641\u064a \u0639\u0644\u0627\u0645\u0629 \u062a\u0628\u0648\u064a\u0628 \u062c\u062f\u064a\u062f\u0629", + "Open Link": "\u0627\u0641\u062a\u062d \u0627\u0644\u0631\u0627\u0628\u0637", + "Edit Link": "\u0627\u0631\u062a\u0628\u0627\u0637 \u062a\u062d\u0631\u064a\u0631", + "Unlink": "\u062d\u0630\u0641 \u0627\u0644\u0631\u0627\u0628\u0637", + "Choose Link": "\u0627\u062e\u062a\u064a\u0627\u0631 \u0635\u0644\u0629", + + // Images + "Insert Image": "\u0625\u062f\u0631\u0627\u062c \u0635\u0648\u0631\u0629", + "Upload Image": "\u062a\u062d\u0645\u064a\u0644 \u0635\u0648\u0631\u0629", + "By URL": "\u0628\u0648\u0627\u0633\u0637\u0629 URL", + "Browse": "\u062a\u0635\u0641\u062d", + "Drop image": "\u0625\u0633\u0642\u0627\u0637 \u0635\u0648\u0631\u0629", + "or click": "\u0623\u0648 \u0627\u0646\u0642\u0631 \u0641\u0648\u0642", + "Manage Images": "\u0625\u062f\u0627\u0631\u0629 \u0627\u0644\u0635\u0648\u0631", + "Loading": "\u062a\u062d\u0645\u064a\u0644", + "Deleting": "\u062d\u0630\u0641", + "Tags": "\u0627\u0644\u0643\u0644\u0645\u0627\u062a", + "Are you sure? Image will be deleted.": "\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f\u061f \u0633\u064a\u062a\u0645 \u062d\u0630\u0641 \u0627\u0644\u0635\u0648\u0631\u0629\u002e", + "Replace": "\u0627\u0633\u062a\u0628\u062f\u0627\u0644", + "Uploading": "\u062a\u062d\u0645\u064a\u0644", + "Loading image": "\u0635\u0648\u0631\u0629 \u062a\u062d\u0645\u064a\u0644", + "Display": "\u0639\u0631\u0636", + "Inline": "\u0641\u064a \u062e\u0637", + "Break Text": "\u0646\u0635 \u0627\u0633\u062a\u0631\u0627\u062d\u0629", + "Alternative Text": "\u0646\u0635 \u0628\u062f\u064a\u0644", + "Change Size": "\u062a\u063a\u064a\u064a\u0631 \u062d\u062c\u0645", + "Width": "\u0639\u0631\u0636", + "Height": "\u0627\u0631\u062a\u0641\u0627\u0639", + "Something went wrong. Please try again.": ".\u062d\u062f\u062b \u062e\u0637\u0623 \u0645\u0627. \u062d\u0627\u0648\u0644 \u0645\u0631\u0629 \u0627\u062e\u0631\u0649", + "Image Caption": "تعليق على الصورة", + "Advanced Edit": "تعديل متقدم", + + // Video + "Insert Video": "\u0625\u062f\u0631\u0627\u062c \u0641\u064a\u062f\u064a\u0648", + "Embedded Code": "\u0627\u0644\u062a\u0639\u0644\u064a\u0645\u0627\u062a \u0627\u0644\u0628\u0631\u0645\u062c\u064a\u0629 \u0627\u0644\u0645\u0636\u0645\u0646\u0629", + "Paste in a video URL": "لصق في عنوان ورل للفيديو", + "Drop video": "انخفاض الفيديو", + "Your browser does not support HTML5 video.": "متصفحك لا يدعم فيديو HTML5.", + "Upload Video": "رفع فيديو", + + // Tables + "Insert Table": "\u0625\u062f\u0631\u0627\u062c \u062c\u062f\u0648\u0644", + "Table Header": "\u0631\u0623\u0633 \u0627\u0644\u062c\u062f\u0648\u0644", + "Remove Table": "\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u062c\u062f\u0648\u0644", + "Table Style": "\u0646\u0645\u0637 \u0627\u0644\u062c\u062f\u0648\u0644", + "Horizontal Align": "\u0645\u062d\u0627\u0630\u0627\u0629 \u0623\u0641\u0642\u064a\u0629", + "Row": "\u0635\u0641", + "Insert row above": "\u0625\u062f\u0631\u0627\u062c \u0635\u0641 \u0644\u0644\u0623\u0639\u0644\u0649", + "Insert row below": "\u0625\u062f\u0631\u0627\u062c \u0635\u0641 \u0644\u0644\u0623\u0633\u0641\u0644", + "Delete row": "\u062d\u0630\u0641 \u0635\u0641", + "Column": "\u0639\u0645\u0648\u062f", + "Insert column before": "\u0625\u062f\u0631\u0627\u062c \u0639\u0645\u0648\u062f \u0644\u0644\u064a\u0633\u0627\u0631", + "Insert column after": "\u0625\u062f\u0631\u0627\u062c \u0639\u0645\u0648\u062f \u0644\u0644\u064a\u0645\u064a\u0646", + "Delete column": "\u062d\u0630\u0641 \u0639\u0645\u0648\u062f", + "Cell": "\u062e\u0644\u064a\u0629", + "Merge cells": "\u062f\u0645\u062c \u062e\u0644\u0627\u064a\u0627", + "Horizontal split": "\u0627\u0646\u0642\u0633\u0627\u0645 \u0623\u0641\u0642\u064a", + "Vertical split": "\u0627\u0644\u0627\u0646\u0642\u0633\u0627\u0645 \u0627\u0644\u0639\u0645\u0648\u062f\u064a", + "Cell Background": "\u062e\u0644\u0641\u064a\u0629 \u0627\u0644\u062e\u0644\u064a\u0629", + "Vertical Align": "\u0645\u062d\u0627\u0630\u0627\u0629 \u0639\u0645\u0648\u062f\u064a\u0629", + "Top": "\u0623\u0639\u0644\u0649", + "Middle": "\u0648\u0633\u0637", + "Bottom": "\u0623\u0633\u0641\u0644", + "Align Top": "\u0645\u062d\u0627\u0630\u0627\u0629 \u0623\u0639\u0644\u0649", + "Align Middle": "\u0645\u062d\u0627\u0630\u0627\u0629 \u0648\u0633\u0637", + "Align Bottom": "\u0645\u062d\u0627\u0630\u0627\u0629 \u0627\u0644\u0623\u0633\u0641\u0644", + "Cell Style": "\u0646\u0645\u0637 \u0627\u0644\u062e\u0644\u064a\u0629", + + // Files + "Upload File": "\u062a\u062d\u0645\u064a\u0644 \u0627\u0644\u0645\u0644\u0641", + "Drop file": "\u0627\u0646\u062e\u0641\u0627\u0636 \u0627\u0644\u0645\u0644\u0641", + + // Emoticons + "Emoticons": "\u0627\u0644\u0645\u0634\u0627\u0639\u0631", + "Grinning face": "\u064a\u0643\u0634\u0631 \u0648\u062c\u0647\u0647", + "Grinning face with smiling eyes": "\u0645\u0628\u062a\u0633\u0645\u0627 \u0648\u062c\u0647 \u0645\u0639 \u064a\u0628\u062a\u0633\u0645 \u0627\u0644\u0639\u064a\u0646", + "Face with tears of joy": "\u0648\u062c\u0647 \u0645\u0639 \u062f\u0645\u0648\u0639 \u0627\u0644\u0641\u0631\u062d", + "Smiling face with open mouth": "\u0627\u0644\u0648\u062c\u0647 \u0627\u0644\u0645\u0628\u062a\u0633\u0645 \u0645\u0639 \u0641\u062a\u062d \u0627\u0644\u0641\u0645", + "Smiling face with open mouth and smiling eyes": "\u0627\u0644\u0648\u062c\u0647 \u0627\u0644\u0645\u0628\u062a\u0633\u0645 \u0645\u0639 \u0641\u062a\u062d \u0627\u0644\u0641\u0645 \u0648\u0627\u0644\u0639\u064a\u0646\u064a\u0646 \u064a\u0628\u062a\u0633\u0645", + "Smiling face with open mouth and cold sweat": "\u0627\u0644\u0648\u062c\u0647 \u0627\u0644\u0645\u0628\u062a\u0633\u0645 \u0645\u0639 \u0641\u062a\u062d \u0627\u0644\u0641\u0645 \u0648\u0627\u0644\u0639\u0631\u0642 \u0627\u0644\u0628\u0627\u0631\u062f", + "Smiling face with open mouth and tightly-closed eyes": "\u0627\u0644\u0648\u062c\u0647 \u0627\u0644\u0645\u0628\u062a\u0633\u0645 \u0645\u0639 \u0641\u062a\u062d \u0627\u0644\u0641\u0645 \u0648\u0627\u0644\u0639\u064a\u0646\u064a\u0646 \u0645\u063a\u0644\u0642\u0629 \u0628\u0625\u062d\u0643\u0627\u0645", + "Smiling face with halo": "\u0627\u0644\u0648\u062c\u0647 \u0627\u0644\u0645\u0628\u062a\u0633\u0645 \u0645\u0639 \u0647\u0627\u0644\u0629", + "Smiling face with horns": "\u0627\u0644\u0648\u062c\u0647 \u0627\u0644\u0645\u0628\u062a\u0633\u0645 \u0628\u0642\u0631\u0648\u0646", + "Winking face": "\u0627\u0644\u063a\u0645\u0632 \u0648\u062c\u0647", + "Smiling face with smiling eyes": "\u064a\u0628\u062a\u0633\u0645 \u0648\u062c\u0647 \u0645\u0639 \u0639\u064a\u0648\u0646 \u062a\u0628\u062a\u0633\u0645", + "Face savoring delicious food": "\u064a\u0648\u0627\u062c\u0647 \u0644\u0630\u064a\u0630 \u0627\u0644\u0645\u0630\u0627\u0642 \u0644\u0630\u064a\u0630 \u0627\u0644\u0637\u0639\u0627\u0645", + "Relieved face": "\u0648\u062c\u0647 \u0628\u0627\u0644\u0627\u0631\u062a\u064a\u0627\u062d", + "Smiling face with heart-shaped eyes": "\u0627\u0644\u0648\u062c\u0647 \u0627\u0644\u0645\u0628\u062a\u0633\u0645 \u0628\u0639\u064a\u0646\u064a\u0646 \u0639\u0644\u0649 \u0634\u0643\u0644 \u0642\u0644\u0628", + "Smiling face with sunglasses": "\u0627\u0644\u0648\u062c\u0647 \u0627\u0644\u0645\u0628\u062a\u0633\u0645 \u0645\u0639 \u0627\u0644\u0646\u0638\u0627\u0631\u0627\u062a \u0627\u0644\u0634\u0645\u0633\u064a\u0629", + "Smirking face": "\u0633\u0645\u064a\u0631\u0643\u064a\u0646\u062c \u0627\u0644\u0648\u062c\u0647", + "Neutral face": "\u0645\u062d\u0627\u064a\u062f \u0627\u0644\u0648\u062c\u0647", + "Expressionless face": "\u0648\u062c\u0647 \u0627\u0644\u062a\u0639\u0627\u0628\u064a\u0631", + "Unamused face": "\u0644\u0627 \u0645\u0633\u0644\u064a\u0627 \u0627\u0644\u0648\u062c\u0647", + "Face with cold sweat": "\u0648\u062c\u0647 \u0645\u0639 \u0639\u0631\u0642 \u0628\u0627\u0631\u062f", + "Pensive face": "\u0648\u062c\u0647 \u0645\u062a\u0623\u0645\u0644", + "Confused face": "\u0648\u062c\u0647 \u0627\u0644\u062e\u0644\u0637", + "Confounded face": "\u0648\u062c\u0647 \u0645\u0631\u062a\u0628\u0643", + "Kissing face": "\u062a\u0642\u0628\u064a\u0644 \u0627\u0644\u0648\u062c\u0647", + "Face throwing a kiss": "\u0645\u0648\u0627\u062c\u0647\u0629 \u0631\u0645\u064a \u0642\u0628\u0644\u0629", + "Kissing face with smiling eyes": "\u062a\u0642\u0628\u064a\u0644 \u0648\u062c\u0647 \u0645\u0639 \u0639\u064a\u0648\u0646 \u062a\u0628\u062a\u0633\u0645", + "Kissing face with closed eyes": "\u062a\u0642\u0628\u064a\u0644 \u0648\u062c\u0647 \u0645\u0639 \u0639\u064a\u0648\u0646 \u0645\u063a\u0644\u0642\u0629", + "Face with stuck out tongue": "\u0627\u0644\u0648\u062c\u0647 \u0645\u0639 \u062a\u0645\u0633\u0643 \u0628\u0647\u0627 \u0627\u0644\u0644\u0633\u0627\u0646", + "Face with stuck out tongue and winking eye": "\u0627\u0644\u0648\u062c\u0647 \u0645\u0639 \u062a\u0645\u0633\u0643 \u0628\u0647\u0627 \u0627\u0644\u0644\u0633\u0627\u0646 \u0648\u0627\u0644\u0639\u064a\u0646 \u0627\u0644\u062a\u063a\u0627\u0636\u064a", + "Face with stuck out tongue and tightly-closed eyes": "\u0627\u0644\u0648\u062c\u0647 \u0645\u0639 \u062a\u0645\u0633\u0643 \u0628\u0647\u0627 \u0627\u0644\u0644\u0633\u0627\u0646 \u0648\u0627\u0644\u0639\u064a\u0648\u0646 \u0645\u063a\u0644\u0642\u0629 \u0628\u0623\u062d\u0643\u0627\u0645\u002d", + "Disappointed face": "\u0648\u062c\u0647\u0627 \u062e\u064a\u0628\u0629 \u0623\u0645\u0644", + "Worried face": "\u0648\u062c\u0647\u0627 \u0627\u0644\u0642\u0644\u0642\u0648\u0646", + "Angry face": "\u0648\u062c\u0647 \u063a\u0627\u0636\u0628", + "Pouting face": "\u0627\u0644\u0639\u0628\u0648\u0633 \u0648\u062c\u0647", + "Crying face": "\u0627\u0644\u0628\u0643\u0627\u0621 \u0627\u0644\u0648\u062c\u0647", + "Persevering face": "\u0627\u0644\u0645\u062b\u0627\u0628\u0631\u0629 \u0648\u062c\u0647\u0647", + "Face with look of triumph": "\u0648\u0627\u062c\u0647 \u0645\u0639 \u0646\u0638\u0631\u0629 \u0627\u0646\u062a\u0635\u0627\u0631", + "Disappointed but relieved face": "\u0628\u062e\u064a\u0628\u0629 \u0623\u0645\u0644 \u0648\u0644\u0643\u0646 \u064a\u0639\u0641\u0649 \u0648\u062c\u0647", + "Frowning face with open mouth": "\u0645\u0642\u0637\u0628 \u0627\u0644\u0648\u062c\u0647 \u0645\u0639 \u0641\u062a\u062d \u0627\u0644\u0641\u0645", + "Anguished face": "\u0627\u0644\u0648\u062c\u0647 \u0627\u0644\u0645\u0624\u0644\u0645", + "Fearful face": "\u0627\u0644\u0648\u062c\u0647 \u0627\u0644\u0645\u062e\u064a\u0641", + "Weary face": "\u0648\u062c\u0647\u0627 \u0628\u0627\u0644\u0636\u062c\u0631", + "Sleepy face": "\u0648\u062c\u0647 \u0646\u0639\u0633\u0627\u0646", + "Tired face": "\u0648\u062c\u0647 \u0645\u062a\u0639\u0628", + "Grimacing face": "\u0648\u062e\u0631\u062c \u0633\u064a\u0633 \u0627\u0644\u0648\u062c\u0647", + "Loudly crying face": "\u0627\u0644\u0628\u0643\u0627\u0621 \u0628\u0635\u0648\u062a \u0639\u0627\u0644 \u0648\u062c\u0647\u0647", + "Face with open mouth": "\u0648\u0627\u062c\u0647 \u0645\u0639 \u0641\u062a\u062d \u0627\u0644\u0641\u0645", + "Hushed face": "\u0648\u062c\u0647\u0627 \u0627\u0644\u062a\u0643\u062a\u0645", + "Face with open mouth and cold sweat": "\u0648\u0627\u062c\u0647 \u0645\u0639 \u0641\u062a\u062d \u0627\u0644\u0641\u0645 \u0648\u0627\u0644\u0639\u0631\u0642 \u0627\u0644\u0628\u0627\u0631\u062f", + "Face screaming in fear": "\u0648\u0627\u062c\u0647 \u064a\u0635\u0631\u062e \u0641\u064a \u062e\u0648\u0641", + "Astonished face": "\u0648\u062c\u0647\u0627 \u062f\u0647\u0634", + "Flushed face": "\u0627\u062d\u0645\u0631\u0627\u0631 \u0627\u0644\u0648\u062c\u0647", + "Sleeping face": "\u0627\u0644\u0646\u0648\u0645 \u0627\u0644\u0648\u062c\u0647", + "Dizzy face": "\u0648\u062c\u0647\u0627 \u0628\u0627\u0644\u062f\u0648\u0627\u0631", + "Face without mouth": "\u0648\u0627\u062c\u0647 \u062f\u0648\u0646 \u0627\u0644\u0641\u0645", + "Face with medical mask": "\u0648\u0627\u062c\u0647 \u0645\u0639 \u0642\u0646\u0627\u0639 \u0627\u0644\u0637\u0628\u064a\u0629", + + // Line breaker + "Break": "\u0627\u0644\u0627\u0646\u0642\u0633\u0627\u0645", + + // Math + "Subscript": "\u0645\u0646\u062e\u0641\u0636", + "Superscript": "\u062d\u0631\u0641 \u0641\u0648\u0642\u064a", + + // Full screen + "Fullscreen": "\u0643\u0627\u0645\u0644 \u0627\u0644\u0634\u0627\u0634\u0629", + + // Horizontal line + "Insert Horizontal Line": "\u0625\u062f\u0631\u0627\u062c \u062e\u0637 \u0623\u0641\u0642\u064a", + + // Clear formatting + "Clear Formatting": "\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u062a\u0646\u0633\u064a\u0642", + + // Save + "Save": "\u062d\u0641\u0638", + + // Undo, redo + "Undo": "\u062a\u0631\u0627\u062c\u0639", + "Redo": "\u0625\u0639\u0627\u062f\u0629", + + // Select all + "Select All": "\u062a\u062d\u062f\u064a\u062f \u0627\u0644\u0643\u0644", + + // Code view + "Code View": "\u0639\u0631\u0636 \u0627\u0644\u062a\u0639\u0644\u064a\u0645\u0627\u062a \u0627\u0644\u0628\u0631\u0645\u062c\u064a\u0629", + + // Quote + "Quote": "\u0627\u0642\u062a\u0628\u0633", + "Increase": "\u0632\u064a\u0627\u062f\u0629", + "Decrease": "\u0627\u0646\u062e\u0641\u0627\u0636", + + // Quick Insert + "Quick Insert": "\u0625\u062f\u0631\u0627\u062c \u0633\u0631\u064a\u0639", + + // Spcial Characters + "Special Characters": "أحرف خاصة", + "Latin": "لاتينية", + "Greek": "الإغريقي", + "Cyrillic": "السيريلية", + "Punctuation": "علامات ترقيم", + "Currency": "دقة", + "Arrows": "السهام", + "Math": "الرياضيات", + "Misc": "متفرقات", + + // Print. + "Print": "طباعة", + + // Spell Checker. + "Spell Checker": "مدقق املائي", + + // Help + "Help": "مساعدة", + "Shortcuts": "اختصارات", + "Inline Editor": "محرر مضمنة", + "Show the editor": "عرض المحرر", + "Common actions": "الإجراءات المشتركة", + "Copy": "نسخ", + "Cut": "يقطع", + "Paste": "معجون", + "Basic Formatting": "التنسيق الأساسي", + "Increase quote level": "زيادة مستوى الاقتباس", + "Decrease quote level": "انخفاض مستوى الاقتباس", + "Image / Video": "صورة / فيديو", + "Resize larger": "تغيير حجم أكبر", + "Resize smaller": "تغيير حجم أصغر", + "Table": "الطاولة", + "Select table cell": "حدد خلية الجدول", + "Extend selection one cell": "توسيع اختيار خلية واحدة", + "Extend selection one row": "تمديد اختيار صف واحد", + "Navigation": "التنقل", + "Focus popup / toolbar": "التركيز المنبثقة / شريط الأدوات", + "Return focus to previous position": "عودة التركيز إلى الموقف السابق", + + // Embed.ly + "Embed URL": "تضمين عنوان ورل", + "Paste in a URL to embed": "الصق في عنوان ورل لتضمينه", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "المحتوى الذي تم لصقه قادم من وثيقة كلمة ميكروسوفت. هل تريد الاحتفاظ بالتنسيق أو تنظيفه؟", + "Keep": "احتفظ", + "Clean": "نظيف", + "Word Paste Detected": "تم اكتشاف معجون الكلمات" + }, + direction: "rtl" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/bs.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/bs.js new file mode 100644 index 0000000..c6c6234 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/bs.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Bosnian + */ + +$.FE.LANGUAGE['bs'] = { + translation: { + // Place holder + "Type something": "Ukucajte ne\u0161tp", + + // Basic formatting + "Bold": "Bold", + "Italic": "Italic", + "Underline": "Podvu\u010deno", + "Strikethrough": "Precrtano", + + // Main buttons + "Insert": "Umetni", + "Delete": "Obri\u0161i", + "Cancel": "Otka\u017ei", + "OK": "U redu", + "Back": "Natrag", + "Remove": "Ukloni", + "More": "Vi\u0161e", + "Update": "A\u017euriranje", + "Style": "Stil", + + // Font + "Font Family": "Odaberi font", + "Font Size": "Veli\u010dina fonta", + + // Colors + "Colors": "Boje", + "Background": "Pozadine", + "Text": "Teksta", + "HEX Color": "Hex boje", + + // Paragraphs + "Paragraph Format": "Paragraf formatu", + "Normal": "Normalno", + "Code": "Izvorni kod", + "Heading 1": "Naslov 1", + "Heading 2": "Naslov 2", + "Heading 3": "Naslov 3", + "Heading 4": "Naslov 4", + + // Style + "Paragraph Style": "Paragraf stil", + "Inline Style": "Inline stil", + + // Alignment + "Alignment": "Poravnanje", + "Align Left": "Poravnaj lijevo", + "Align Center": "Poravnaj po sredini", + "Align Right": "Poravnaj desno", + "Align Justify": "Obostrano poravnanje", + "None": "Nijedan", + + // Lists + "Ordered List": "Ure\u0111ena lista", + "Default": "Default", + "Lower Alpha": "Niži alfa", + "Lower Greek": "Niži grčki", + "Lower Roman": "Lower roman", + "Upper Alpha": "Upper alpha", + "Upper Roman": "Upper roman", + + "Unordered List": "Nesre\u0111ene lista", + "Circle": "Krug", + "Disc": "Disk", + "Square": "Kvadrat", + + // Line height + "Line Height": "Visina linije", + "Single": "Single", + "Double": "Double", + + // Indent + "Decrease Indent": "Smanjenje alineja", + "Increase Indent": "Pove\u0107anje alineja", + + // Links + "Insert Link": "Umetni link", + "Open in new tab": "Otvori u novom prozoru", + "Open Link": "Otvori link", + "Edit Link": "Uredi link", + "Unlink": "Ukloni link", + "Choose Link": "Izabrati link", + + // Images + "Insert Image": "Umetni sliku", + "Upload Image": "Upload sliku", + "By URL": "Preko URL", + "Browse": "Pregledaj", + "Drop image": "Izbaci sliku", + "or click": "ili odaberi", + "Manage Images": "Upravljanje ilustracijama", + "Loading": "Koji tovari", + "Deleting": "Brisanje", + "Tags": "Oznake", + "Are you sure? Image will be deleted.": "Da li ste sigurni da \u017eelite da obri\u0161ete ovu ilustraciju?", + "Replace": "Zamijenite", + "Uploading": "Uploading", + "Loading image": "Koji tovari sliku", + "Display": "Prikaz", + "Inline": "Inline", + "Break Text": "Break tekst", + "Alternative Text": "Alternativna tekst", + "Change Size": "Promijeni veli\u010dinu", + "Width": "\u0161irina", + "Height": "Visina", + "Something went wrong. Please try again.": "Ne\u0161to je po\u0161lo po zlu. Molimo vas da poku\u0161ate ponovo.", + "Image Caption": "Caption slika", + "Advanced Edit": "Napredna izmjena", + + // Video + "Insert Video": "Umetni video", + "Embedded Code": "Embedded kod", + "Paste in a video URL": "Nalepite u video url", + "Drop video": "Drop video", + "Your browser does not support HTML5 video.": "Vaš pretraživač ne podržava html5 video.", + "Upload Video": "Otpremite video", + + // Tables + "Insert Table": "Umetni tabelu", + "Table Header": "Tabelu zaglavlja", + "Remove Table": "Uklonite tabelu", + "Table Style": "Tabela stil", + "Horizontal Align": "Horizontalno poravnaj", + "Row": "Red", + "Insert row above": "Umetni red iznad", + "Insert row below": "Umetni red ispod", + "Delete row": "Obri\u0161i red", + "Column": "Kolona", + "Insert column before": "Umetni kolonu prije", + "Insert column after": "Umetni kolonu poslije", + "Delete column": "Obri\u0161i kolonu", + "Cell": "\u0106elija", + "Merge cells": "Spoji \u0107elija", + "Horizontal split": "Horizontalno razdvajanje polja", + "Vertical split": "Vertikalno razdvajanje polja", + "Cell Background": "\u0106elija pozadini", + "Vertical Align": "Vertikalni poravnaj", + "Top": "Vrh", + "Middle": "Srednji", + "Bottom": "Dno", + "Align Top": "Poravnaj vrh", + "Align Middle": "Poravnaj srednji", + "Align Bottom": "Poravnaj dno", + "Cell Style": "\u0106elija stil", + + // Files + "Upload File": "Upload datoteke", + "Drop file": "Drop datoteke", + + // Emoticons + "Emoticons": "Emotikona", + "Grinning face": "Cere\u0107i lice", + "Grinning face with smiling eyes": "Cere\u0107i lice nasmijana o\u010dima", + "Face with tears of joy": "Lice sa suze radosnice", + "Smiling face with open mouth": "Nasmijana lica s otvorenih usta", + "Smiling face with open mouth and smiling eyes": "Nasmijana lica s otvorenih usta i nasmijana o\u010di", + "Smiling face with open mouth and cold sweat": "Nasmijana lica s otvorenih usta i hladan znoj", + "Smiling face with open mouth and tightly-closed eyes": "Nasmijana lica s otvorenih usta i \u010dvrsto-zatvorenih o\u010diju", + "Smiling face with halo": "Nasmijana lica sa halo", + "Smiling face with horns": "Nasmijana lica s rogovima", + "Winking face": "Namigivanje lice", + "Smiling face with smiling eyes": "Nasmijana lica sa nasmijana o\u010dima", + "Face savoring delicious food": "Suo\u010davaju u\u017eivaju\u0107i ukusna hrana", + "Relieved face": "Laknulo lice", + "Smiling face with heart-shaped eyes": "Nasmijana lica sa obliku srca o\u010di", + "Smiling face with sunglasses": "Nasmijana lica sa sun\u010dane nao\u010dare", + "Smirking face": "Namr\u0161tena lica", + "Neutral face": "Neutral lice", + "Expressionless face": "Bezizra\u017eajno lice", + "Unamused face": "Nije zabavno lice", + "Face with cold sweat": "Lice s hladnim znojem", + "Pensive face": "Zami\u0161ljen lice", + "Confused face": "Zbunjen lice", + "Confounded face": "Uzbu\u0111en lice", + "Kissing face": "Ljubakanje lice", + "Face throwing a kiss": "Suo\u010davaju bacanje poljubac", + "Kissing face with smiling eyes": "Ljubljenje lice nasmijana o\u010dima", + "Kissing face with closed eyes": "Ljubljenje lice sa zatvorenim o\u010dima", + "Face with stuck out tongue": "Lice sa ispru\u017eio jezik", + "Face with stuck out tongue and winking eye": "Lice sa ispru\u017eio jezik i trep\u0107u\u0107e \u0107e oko", + "Face with stuck out tongue and tightly-closed eyes": "Lice sa ispru\u017eio jezik i \u010dvrsto zatvorene o\u010di", + "Disappointed face": "Razo\u010daran lice", + "Worried face": "Zabrinuti lice", + "Angry face": "Ljut lice", + "Pouting face": "Napu\u0107enim lice", + "Crying face": "Plakanje lice", + "Persevering face": "Istrajan lice", + "Face with look of triumph": "Lice s pogledom trijumfa", + "Disappointed but relieved face": "Razo\u010daran, ali olak\u0161anje lice", + "Frowning face with open mouth": "Namr\u0161tiv\u0161i lice s otvorenih usta", + "Anguished face": "Bolnom lice", + "Fearful face": "Pla\u0161ljiv lice", + "Weary face": "Umoran lice", + "Sleepy face": "Pospan lice", + "Tired face": "Umorno lice", + "Grimacing face": "Grimase lice", + "Loudly crying face": "Glasno pla\u010de lice", + "Face with open mouth": "Lice s otvorenih usta", + "Hushed face": "Smiren lice", + "Face with open mouth and cold sweat": "Lice s otvorenih usta i hladan znoj", + "Face screaming in fear": "Suo\u010davaju vri\u0161ti u strahu", + "Astonished face": "Zapanjen lice", + "Flushed face": "Rumeno lice", + "Sleeping face": "Usnulo lice", + "Dizzy face": "O\u0161amu\u0107en lice", + "Face without mouth": "Lice bez usta", + "Face with medical mask": "Lice sa medicinskom maskom", + + // Line breaker + "Break": "Slomiti", + + // Math + "Subscript": "Potpisan", + "Superscript": "Natpis", + + // Full screen + "Fullscreen": "Preko cijelog zaslona", + + // Horizontal line + "Insert Horizontal Line": "Umetni vodoravna liniju", + + // Clear formatting + "Clear Formatting": "Izbrisati formatiranje", + + // Save + "Save":"Spremi", + + // Undo, redo + "Undo": "Korak nazad", + "Redo": "Korak naprijed", + + // Select all + "Select All": "Ozna\u010di sve", + + // Code view + "Code View": "Kod pogled", + + // Quote + "Quote": "Citat", + "Increase": "Pove\u0107ati", + "Decrease": "Smanjenje", + + // Quick Insert + "Quick Insert": "Brzo umetak", + + // Spcial Characters + "Special Characters": "Posebni znakovi", + "Latin": "Latin", + "Greek": "Greek", + "Cyrillic": "Ćirilično", + "Punctuation": "Interpunkcija", + "Currency": "Valuta", + "Arrows": "Strelice", + "Math": "Matematika", + "Misc": "Misc", + + // Print. + "Print": "Print", + + // Spell Checker. + "Spell Checker": "Proveru pravopisa", + + // Help + "Help": "Pomoć", + "Shortcuts": "Prečice", + "Inline Editor": "Inline editor", + "Show the editor": "Pokaži urednika", + "Common actions": "Zajedničke akcije", + "Copy": "Kopiraj", + "Cut": "Cut", + "Paste": "Paste", + "Basic Formatting": "Osnovno oblikovanje", + "Increase quote level": "Povećati cijeni", + "Decrease quote level": "Smanjiti nivo ponude", + "Image / Video": "Slika / video", + "Resize larger": "Veće veličine", + "Resize smaller": "Manja promjena veličine", + "Table": "Stol", + "Select table cell": "Izaberite ćeliju tablice", + "Extend selection one cell": "Produžiti izbor jedne ćelije", + "Extend selection one row": "Produžiti izbor jedan red", + "Navigation": "Navigacija", + "Focus popup / toolbar": "Focus popup / toolbar", + "Return focus to previous position": "Vratite fokus na prethodnu poziciju", + + // Embed.ly + "Embed URL": "Ugraditi url", + "Paste in a URL to embed": "Paste u URL adresu za ugradnju", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Nalepeni sadržaj dolazi iz Microsoft Word dokumenta. da li želite da zadržite format ili da ga očistite?", + "Keep": "Zadržati", + "Clean": "Čist", + "Word Paste Detected": "Otkrivena je slovna reč" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/cs.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/cs.js new file mode 100644 index 0000000..7addd2e --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/cs.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Czech + */ + +$.FE.LANGUAGE['cs'] = { + translation: { + // Place holder + "Type something": "Napi\u0161te n\u011bco", + + // Basic formatting + "Bold": "Tu\u010dn\u00e9", + "Italic": "Kurz\u00edva", + "Underline": "Podtr\u017een\u00e9", + "Strikethrough": "P\u0159e\u0161krtnut\u00e9", + + // Main buttons + "Insert": "Vlo\u017eit", + "Delete": "Vymazat", + "Cancel": "Zru\u0161it", + "OK": "OK", + "Back": "Zp\u011bt", + "Remove": "Odstranit", + "More": "V\u00edce", + "Update": "Aktualizovat", + "Style": "Styl", + + // Font + "Font Family": "Typ p\u00edsma", + "Font Size": "Velikost p\u00edsma", + + // Colors + "Colors": "Barvy", + "Background": "Pozad\u00ed", + "Text": "P\u00edsmo", + "HEX Color": "Hex Barvy", + + // Paragraphs + "Paragraph Format": "Form\u00e1t odstavec", + "Normal": "Norm\u00e1ln\u00ed", + "Code": "K\u00f3d", + "Heading 1": "Nadpis 1", + "Heading 2": "Nadpis 2", + "Heading 3": "Nadpis 3", + "Heading 4": "Nadpis 4", + + // Style + "Paragraph Style": "Odstavec styl", + "Inline Style": "Inline styl", + + // Alignment + "Align": "Zarovn\u00e1n\u00ed", + "Align Left": "Zarovnat vlevo", + "Align Center": "Zarovnat na st\u0159ed", + "Align Right": "Zarovnat vpravo", + "Align Justify": "Zarovnat do bloku", + "None": "Nikdo", + + // Lists + "Ordered List": "\u010c\u00edslovan\u00fd seznam", + "Default": "Výchozí", + "Lower Alpha": "Nižší alfa", + "Lower Greek": "Nižší řečtina", + "Lower Roman": "Nižší římský", + "Upper Alpha": "Horní alfa", + "Upper Roman": "Horní římský", + + "Unordered List": "Ne\u010d\u00edslovan\u00fd seznam", + "Circle": "Kruh", + "Disc": "Disk", + "Square": "Náměstí", + + // Line height + "Line Height": "Výška řádku", + "Single": "Singl", + "Double": "Dvojnásobek", + + // Indent + "Decrease Indent": "Zmen\u0161it odsazen\u00ed", + "Increase Indent": "Zv\u011bt\u0161it odsazen\u00ed", + + // Links + "Insert Link": "Vlo\u017eit odkaz", + "Open in new tab": "Otev\u0159\u00edt v nov\u00e9 z\u00e1lo\u017ece", + "Open Link": "Otev\u0159\u00edt odkaz", + "Edit Link": "Upravit odkaz", + "Unlink": "Odstranit odkaz", + "Choose Link": "Zvolte odkaz", + + // Images + "Insert Image": "Vlo\u017eit obr\u00e1zek", + "Upload Image": "Nahr\u00e1t obr\u00e1zek", + "By URL": "Podle URL", + "Browse": "Proch\u00e1zet", + "Drop image": "P\u0159et\u00e1hn\u011bte sem obr\u00e1zek", + "or click": "nebo zde klepn\u011bte", + "Manage Images": "Spr\u00e1va obr\u00e1zk\u016f", + "Loading": "Nakl\u00e1d\u00e1n\u00ed", + "Deleting": "Odstran\u011bn\u00ed", + "Tags": "Zna\u010dky", + "Are you sure? Image will be deleted.": "Ur\u010dit\u011b? Obr\u00e1zek bude smaz\u00e1n.", + "Replace": "Nahradit", + "Uploading": "Nahr\u00e1v\u00e1n\u00ed", + "Loading image": "Obr\u00e1zek se na\u010d\u00edt\u00e1", + "Display": "Zobrazit", + "Inline": "Inline", + "Break Text": "P\u0159est\u00e1vka textu", + "Alternative Text": "Alternativn\u00ed textu", + "Change Size": "Zm\u011bnit velikost", + "Width": "\u0160\u00ed\u0159ka", + "Height": "V\u00fd\u0161ka", + "Something went wrong. Please try again.": "N\u011bco se pokazilo. Pros\u00edm zkuste to znovu.", + "Image Caption": "Obrázek titulku", + "Advanced Edit": "Pokročilá úprava", + + // Video + "Insert Video": "Vlo\u017eit video", + "Embedded Code": "Vlo\u017een\u00fd k\u00f3d", + "Paste in a video URL": "Vložit adresu URL videa", + "Drop video": "Drop video", + "Your browser does not support HTML5 video.": "Váš prohlížeč nepodporuje video html5.", + "Upload Video": "Nahrát video", + + // Tables + "Insert Table": "Vlo\u017eit tabulku", + "Table Header": "Hlavi\u010dka tabulky", + "Remove Table": "Odstranit tabulku", + "Table Style": "Styl tabulky", + "Horizontal Align": "Horizont\u00e1ln\u00ed zarovn\u00e1n\u00ed", + "Row": "\u0158\u00e1dek", + "Insert row above": "Vlo\u017eit \u0159\u00e1dek nad", + "Insert row below": "Vlo\u017eit \u0159\u00e1dek pod", + "Delete row": "Smazat \u0159\u00e1dek", + "Column": "Sloupec", + "Insert column before": "Vlo\u017eit sloupec vlevo", + "Insert column after": "Vlo\u017eit sloupec vpravo", + "Delete column": "Smazat sloupec", + "Cell": "Bu\u0148ka", + "Merge cells": "Slou\u010dit bu\u0148ky", + "Horizontal split": "Horizont\u00e1ln\u00ed rozd\u011blen\u00ed", + "Vertical split": "Vertik\u00e1ln\u00ed rozd\u011blen\u00ed", + "Cell Background": "Bu\u0148ka pozad\u00ed", + "Vertical Align": "Vertik\u00e1ln\u00ed zarovn\u00e1n\u00ed", + "Top": "Vrchol", + "Middle": "St\u0159ed", + "Bottom": "Spodn\u00ed", + "Align Top": "Zarovnat vrchol", + "Align Middle": "Zarovnat st\u0159ed", + "Align Bottom": "Zarovnat spodn\u00ed", + "Cell Style": "Styl bu\u0148ky", + + // Files + "Upload File": "Nahr\u00e1t soubor", + "Drop file": "P\u0159et\u00e1hn\u011bte sem soubor", + + // Emoticons + "Emoticons": "Emotikony", + "Grinning face": "S \u00fasm\u011bvem tv\u00e1\u0159", + "Grinning face with smiling eyes": "S \u00fasm\u011bvem obli\u010dej s o\u010dima s \u00fasm\u011bvem", + "Face with tears of joy": "tv\u00e1\u0159 se slzami radosti", + "Smiling face with open mouth": "Usm\u00edvaj\u00edc\u00ed se obli\u010dej s otev\u0159en\u00fdmi \u00fasty", + "Smiling face with open mouth and smiling eyes": "Usm\u00edvaj\u00edc\u00ed se obli\u010dej s otev\u0159en\u00fdmi \u00fasty a o\u010dima s \u00fasm\u011bvem", + "Smiling face with open mouth and cold sweat": "Usm\u00edvaj\u00edc\u00ed se tv\u00e1\u0159 s otev\u0159en\u00fdmi \u00fasty a studen\u00fd pot", + "Smiling face with open mouth and tightly-closed eyes": "Usm\u00edvaj\u00edc\u00ed se tv\u00e1\u0159 s otev\u0159en\u00fdmi \u00fasty a t\u011bsn\u011b zav\u0159en\u00e9 o\u010di", + "Smiling face with halo": "Usm\u00edvaj\u00edc\u00ed se obli\u010dej s halo", + "Smiling face with horns": "Usm\u00edvaj\u00edc\u00ed se obli\u010dej s rohy", + "Winking face": "Mrk\u00e1n\u00ed tv\u00e1\u0159", + "Smiling face with smiling eyes": "Usm\u00edvaj\u00edc\u00ed se obli\u010dej s o\u010dima s \u00fasm\u011bvem", + "Face savoring delicious food": "Tv\u00e1\u0159 vychutn\u00e1val chutn\u00e9 j\u00eddlo", + "Relieved face": "Ulevilo tv\u00e1\u0159", + "Smiling face with heart-shaped eyes": "Usm\u00edvaj\u00edc\u00ed se tv\u00e1\u0159 ve tvaru srdce o\u010dima", + "Smiling face with sunglasses": "Usm\u00edvaj\u00edc\u00ed se tv\u00e1\u0159 se slune\u010dn\u00edmi br\u00fdlemi", + "Smirking face": "Uculoval tv\u00e1\u0159", + "Neutral face": "Neutr\u00e1ln\u00ed tv\u00e1\u0159", + "Expressionless face": "Bezv\u00fdrazn\u00fd obli\u010dej", + "Unamused face": "Ne pobaven\u00fd tv\u00e1\u0159", + "Face with cold sweat": "Tv\u00e1\u0159 se studen\u00fdm potem", + "Pensive face": "Zamy\u0161len\u00fd obli\u010dej", + "Confused face": "Zmaten\u00fd tv\u00e1\u0159", + "Confounded face": "Na\u0161tvan\u00fd tv\u00e1\u0159", + "Kissing face": "L\u00edb\u00e1n\u00ed tv\u00e1\u0159", + "Face throwing a kiss": "Tv\u00e1\u0159 h\u00e1zet polibek", + "Kissing face with smiling eyes": "L\u00edb\u00e1n\u00ed obli\u010dej s o\u010dima s \u00fasm\u011bvem", + "Kissing face with closed eyes": "L\u00edb\u00e1n\u00ed tv\u00e1\u0159 se zav\u0159en\u00fdma o\u010dima", + "Face with stuck out tongue": "Tv\u00e1\u0159 s tr\u010dely jazyk", + "Face with stuck out tongue and winking eye": "Tv\u00e1\u0159 s tr\u010dely jazykem a mrkat o\u010dima", + "Face with stuck out tongue and tightly-closed eyes": "Suo\u010diti s tr\u010dely jazykem t\u011bsn\u011b zav\u0159en\u00e9 vidikovce", + "Disappointed face": "Zklaman\u00fd tv\u00e1\u0159", + "Worried face": "Boj\u00ed\u0161 se tv\u00e1\u0159", + "Angry face": "Rozzloben\u00fd tv\u00e1\u0159", + "Pouting face": "Na\u0161pulen\u00e9 tv\u00e1\u0159", + "Crying face": "Pl\u00e1\u010d tv\u00e1\u0159", + "Persevering face": "Vytrval\u00fdm tv\u00e1\u0159", + "Face with look of triumph": "Tv\u00e1\u0159 s v\u00fdrazem triumfu", + "Disappointed but relieved face": "Zklaman\u00fd ale ulevilo tv\u00e1\u0159", + "Frowning face with open mouth": "Zamra\u010dil se obli\u010dej s otev\u0159en\u00fdmi \u00fasty", + "Anguished face": "\u00fazkostn\u00e9 tv\u00e1\u0159", + "Fearful face": "Stra\u0161n\u00fd tv\u00e1\u0159", + "Weary face": "Unaven\u00fd tv\u00e1\u0159", + "Sleepy face": "Ospal\u00fd tv\u00e1\u0159", + "Tired face": "Unaven\u00fd tv\u00e1\u0159", + "Grimacing face": "\u0161klebil tv\u00e1\u0159", + "Loudly crying face": "Hlasit\u011b pl\u00e1\u010de tv\u00e1\u0159", + "Face with open mouth": "Obli\u010dej s otev\u0159en\u00fdmi \u00fasty", + "Hushed face": "Tlumen\u00fd tv\u00e1\u0159", + "Face with open mouth and cold sweat": "Obli\u010dej s otev\u0159en\u00fdmi \u00fasty a studen\u00fd pot", + "Face screaming in fear": "Tv\u00e1\u0159 k\u0159i\u010d\u00ed ve strachu", + "Astonished face": "V \u00fa\u017easu tv\u00e1\u0159", + "Flushed face": "Zarudnut\u00ed v obli\u010deji", + "Sleeping face": "Sp\u00edc\u00ed tv\u00e1\u0159", + "Dizzy face": "Z\u00e1vrat\u011b tv\u00e1\u0159", + "Face without mouth": "Tv\u00e1\u0159 bez \u00fast", + "Face with medical mask": "Tv\u00e1\u0159 s l\u00e9ka\u0159sk\u00fdm maskou", + + // Line breaker + "Break": "P\u0159eru\u0161en\u00ed", + + // Math + "Subscript": "Doln\u00ed index", + "Superscript": "Horn\u00ed index", + + // Full screen + "Fullscreen": "Cel\u00e1 obrazovka", + + // Horizontal line + "Insert Horizontal Line": "Vlo\u017eit vodorovnou \u010d\u00e1ru", + + // Clear formatting + "Clear Formatting": "Vymazat form\u00e1tov\u00e1n\u00ed", + + // Save + "Save": "\u0055\u006c\u006f\u017e\u0069\u0074", + + // Undo, redo + "Undo": "Zp\u011bt", + "Redo": "Znovu", + + // Select all + "Select All": "Vybrat v\u0161e", + + // Code view + "Code View": "Zobrazen\u00ed k\u00f3d", + + // Quote + "Quote": "Cit\u00e1t", + "Increase": "Nav\u00fd\u0161it", + "Decrease": "Sn\u00ed\u017een\u00ed", + + // Quick Insert + "Quick Insert": "Rychl\u00e1 vlo\u017eka", + + // Spcial Characters + "Special Characters": "Speciální znaky", + "Latin": "Latinský", + "Greek": "Řecký", + "Cyrillic": "Cyrilice", + "Punctuation": "Interpunkce", + "Currency": "Měna", + "Arrows": "Šipky", + "Math": "Matematika", + "Misc": "Misc", + + // Print. + "Print": "Tisk", + + // Spell Checker. + "Spell Checker": "Kontrola pravopisu", + + // Help + "Help": "Pomoc", + "Shortcuts": "Zkratky", + "Inline Editor": "Inline editor", + "Show the editor": "Zobrazit editor", + "Common actions": "Společné akce", + "Copy": "Kopírovat", + "Cut": "Střih", + "Paste": "Vložit", + "Basic Formatting": "Základní formátování", + "Increase quote level": "Zvýšení cenové hladiny", + "Decrease quote level": "Snížit úroveň cenové nabídky", + "Image / Video": "Obraz / video", + "Resize larger": "Změna velikosti větší", + "Resize smaller": "Změnit velikost menší", + "Table": "Stůl", + "Select table cell": "Vyberte buňku tabulky", + "Extend selection one cell": "Rozšířit výběr o jednu buňku", + "Extend selection one row": "Rozšířit výběr o jeden řádek", + "Navigation": "Navigace", + "Focus popup / toolbar": "Popup / panel nástrojů zaostření", + "Return focus to previous position": "Návrat na předchozí pozici", + + // Embed.ly + "Embed URL": "Vložte url", + "Paste in a URL to embed": "Vložit adresu URL, kterou chcete vložit", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Vložený obsah pochází z dokumentu Microsoft Word. chcete formát uchovat nebo jej vyčistit?", + "Keep": "Držet", + "Clean": "Čistý", + "Word Paste Detected": "Slovní vložka zjištěna" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/da.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/da.js new file mode 100644 index 0000000..e076579 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/da.js @@ -0,0 +1,333 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Danish + */ + +$.FE.LANGUAGE['da'] = { + translation: { + // Place holder + "Type something": "Skriv her", + + // Basic formatting + "Bold": "Fed", + "Italic": "Kursiv", + "Underline": "Understreget", + "Strikethrough": "Gennemstreget", + + // Main buttons + "Insert": "Indsæt", + "Delete": "Slet", + "Cancel": "Fortryd", + "OK": "Ok", + "Back": "Tilbage", + "Remove": "Fjern", + "More": "Mere", + "Update": "Opdater", + "Style": "Udseende", + + // Font + "Font Family": "Skrifttype", + "Font Size": "Skriftstørrelse", + + // Colors + "Colors": "Farver", + "Background": "Baggrund", + "Text": "Tekst", + "HEX Color": "Hex farve", + + // Paragraphs + "Paragraph Format": "Typografi", + "Normal": "Normal", + "Code": "Kode", + "Heading 1": "Overskrift 1", + "Heading 2": "Overskrift 2", + "Heading 3": "Overskrift 3", + "Heading 4": "Overskrift 4", + + // Style + "Paragraph Style": "Afsnit", + "Inline Style": "På linje", + + // Alignment + "Align": "Tilpasning", + "Align Left": "Venstrejusteret", + "Align Center": "Centreret", + "Align Right": "Højrejusteret", + "Align Justify": "Justeret", + "None": "Ingen", + + // Lists + "Ordered List": "Punktopstilling", + "Default": "Standard", + "Lower Alpha": "Lavere alfa", + "Lower Greek": "Lavere græsk", + "Lower Roman": "Lavere romersk", + "Upper Alpha": "Øvre alfa", + "Upper Roman": "Øvre romersk", + + "Unordered List": "Punktopstilling med tal", + "Circle": "Cirkel", + "Disc": "Disk", + "Square": "Firkant", + + // Line height + "Line Height": "Linjehøjde", + "Single": "Enkelt", + "Double": "Dobbelt", + + // Indent + "Decrease Indent": "Formindsk indrykning", + "Increase Indent": "Forøg indrykning", + + // Links + "Insert Link": "Indsæt link", + "Open in new tab": "Åbn i ny fane", + "Open Link": "Åbn link", + "Edit Link": "Rediger link", + "Unlink": "Fjern link", + "Choose Link": "Vælg link", + + // Images + "Insert Image": "Indsæt billede", + "Upload Image": "Upload billede", + "By URL": "Fra URL", + "Browse": "Gennemse", + "Drop image": "Træk billedet herind", + "or click": "eller klik", + "Manage Images": "Administrer billeder", + "Loading": "Henter", + "Deleting": "Sletter", + "Tags": "Tags", + "Are you sure? Image will be deleted.": "Er du sikker? Billedet vil blive slettet.", + "Replace": "Udskift", + "Uploading": "Uploader", + "Loading image": "Henter billede", + "Display": "Layout", + "Inline": "På linje", + "Break Text": "Ombryd tekst", + "Alternative Text": "Supplerende tekst", + "Change Size": "Tilpas størrelse", + "Width": "Bredde", + "Height": "Højde", + "Something went wrong. Please try again.": "Noget gik galt. Prøv igen.", + "Image Caption": "Billedtekst", + "Advanced Edit": "Avanceret redigering", + + // Video + "Insert Video": "Indsæt video", + "Embedded Code": "Indlejret kode", + "Paste in a video URL": "Indsæt en video via URL", + "Drop video": "Træk videoen herind", + "Your browser does not support HTML5 video.": "Din browser understøtter ikke HTML5 video.", + "Upload Video": "Upload video", + + // Tables + "Insert Table": "Indsæt tabel", + "Table Header": "Tabeloverskrift", + "Remove Table": "Fjern tabel", + "Table Style": "Tabeludseende", + "Horizontal Align": "Vandret tilpasning", + "Row": "Række", + "Insert row above": "Indsæt række over", + "Insert row below": "Indsæt række under", + "Delete row": "Slet række", + "Column": "Kolonne", + "Insert column before": "Indsæt kolonne før", + "Insert column after": "Indsæt kolonne efter", + "Delete column": "Slet kolonne", + "Cell": "Celle", + "Merge cells": "Flet celler", + "Horizontal split": "Vandret split", + "Vertical split": "Lodret split", + "Cell Background": "Cellebaggrund", + "Vertical Align": "Lodret tilpasning", + "Top": "Top", + "Middle": "Midte", + "Bottom": "Bund", + "Align Top": "Tilpas i top", + "Align Middle": "Tilpas i midte", + "Align Bottom": "Tilpas i bund", + "Cell Style": "Celleudseende", + + // Files + "Upload File": "Upload fil", + "Drop file": "Træk filen herind", + + // Emoticons + "Emoticons": "Humørikoner", + "Grinning face": "Grinende ansigt", + "Grinning face with smiling eyes": "Grinende ansigt med smilende øjne", + "Face with tears of joy": "Ansigt med glædestårer", + "Smiling face with open mouth": "Smilende ansigt med åben mund", + "Smiling face with open mouth and smiling eyes": "Smilende ansigt med åben mund og smilende øjne", + "Smiling face with open mouth and cold sweat": "Smilende ansigt med åben mund og koldsved", + "Smiling face with open mouth and tightly-closed eyes": "Smilende ansigt med åben mund og stramtlukkede øjne", + "Smiling face with halo": "Smilende ansigt med glorie", + "Smiling face with horns": "Smilende ansigt med horn", + "Winking face": "Blinkede ansigt", + "Smiling face with smiling eyes": "Smilende ansigt med smilende øjne", + "Face savoring delicious food": "Ansigt der savler over lækker mad", + "Relieved face": "Lettet ansigt", + "Smiling face with heart-shaped eyes": "Smilende ansigt med hjerteformede øjne", + "Smiling face with sunglasses": "Smilende ansigt med solbriller", + "Smirking face": "Smilende ansigt", + "Neutral face": "Neutralt ansigt", + "Expressionless face": "Udtryksløst ansigt", + "Unamused face": "Utilfredst ansigt", + "Face with cold sweat": "Ansigt med koldsved", + "Pensive face": "Eftertænksomt ansigt", + "Confused face": "Forvirret ansigt", + "Confounded face": "Irriteret ansigt", + "Kissing face": "Kyssende ansigt", + "Face throwing a kiss": "Ansigt der luftkysser", + "Kissing face with smiling eyes": "Kyssende ansigt med smilende øjne", + "Kissing face with closed eyes": "Kyssende ansigt med lukkede øjne", + "Face with stuck out tongue": "Ansigt med tungen ud af munden", + "Face with stuck out tongue and winking eye": "Ansigt med tungen ud af munden og blinkede øje", + "Face with stuck out tongue and tightly-closed eyes": "Ansigt med tungen ud af munden og stramt lukkede øjne", + "Disappointed face": "Skuffet ansigt", + "Worried face": "Bekymret ansigt", + "Angry face": "Vredt ansigt", + "Pouting face": "Surmulende ansigt", + "Crying face": "Grædende ansigt", + "Persevering face": "Vedholdende ansigt", + "Face with look of triumph": "Hoverende ansigt", + "Disappointed but relieved face": "Skuffet, men lettet ansigt", + "Frowning face with open mouth": "Ansigt med åben mund og rynket pande", + "Anguished face": "Forpintt ansigt", + "Fearful face": "Angst ansigt", + "Weary face": "Udmattet ansigt", + "Sleepy face": "Søvnigt ansigt", + "Tired face": "Træt ansigt", + "Grimacing face": "Ansigt der laver en grimasse", + "Loudly crying face": "Vrælende ansigt", + "Face with open mouth": "Ansigt med åben mund", + "Hushed face": "Tyst ansigt", + "Face with open mouth and cold sweat": "Ansigt med åben mund og koldsved", + "Face screaming in fear": "Ansigt der skriger i frygt", + "Astonished face": "Forbløffet ansigt", + "Flushed face": "Blussende ansigt", + "Sleeping face": "Sovende ansigt", + "Dizzy face": "Svimmelt ansigt", + "Face without mouth": "Ansigt uden mund", + "Face with medical mask": "Ansigt med mundbind", + + // Line breaker + "Break": "Linjeskift", + + // Math + "Subscript": "Sænket skrift", + "Superscript": "Hævet skrift", + + // Full screen + "Fullscreen": "Fuldskærm", + + // Horizontal line + "Insert Horizontal Line": "Indsæt vandret linie", + + // Clear formatting + "Clear Formatting": "Fjern formatering", + + // Undo, redo + "Undo": "Fortryd", + "Redo": "Annuller fortryd", + + // Select all + "Select All": "Vælg alt", + + // Code view + "Code View": "Kodevisning", + + // Quote + "Quote": "Citat", + "Increase": "Forøg", + "Decrease": "Formindsk", + + // Quick Insert + "Quick Insert": "Kvik-indsæt", + + // Spcial Characters + "Special Characters": "Specialtegn", + "Latin": "Latin", + "Greek": "Græsk", + "Cyrillic": "Kyrillisk", + "Punctuation": "Tegnsætning", + "Currency": "Valuta", + "Arrows": "Pile", + "Math": "Matematik", + "Misc": "Diverse", + + // Print. + "Print": "Print", + + // Spell Checker. + "Spell Checker": "Stavekontrol", + + // Help + "Help": "Hjælp", + "Shortcuts": "Genveje", + "Inline Editor": "Indlejret editor", + "Show the editor": "Vis editor", + "Common actions": "Almindelige handlinger", + "Copy": "Kopier", + "Cut": "Klip", + "Paste": "Sæt ind", + "Basic Formatting": "Grundlæggende formatering", + "Increase quote level": "Hæv citatniveau", + "Decrease quote level": "Sænk citatniveau", + "Image / Video": "Billede / video", + "Resize larger": "Ændre til større", + "Resize smaller": "Ændre til mindre", + "Table": "Tabel", + "Select table cell": "Vælg tabelcelle", + "Extend selection one cell": "Udvid markeringen med én celle", + "Extend selection one row": "Udvid markeringen med én række", + "Navigation": "Navigation", + "Focus popup / toolbar": "Fokuser popup / værktøjslinje", + "Return focus to previous position": "Skift fokus tilbage til tidligere position", + + // Embed.ly + "Embed URL": "Integrer URL", + "Paste in a URL to embed": "Indsæt en URL for at indlejre", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Det indsatte indhold kommer fra et Microsoft Word-dokument. Vil du beholde formateringen eller fjerne den?", + "Keep": "Behold", + "Clean": "Fjern", + "Word Paste Detected": "Indsættelse fra Word opdaget" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/de.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/de.js new file mode 100644 index 0000000..d37e226 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/de.js @@ -0,0 +1,337 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * German + */ + +$.FE.LANGUAGE['de'] = { + translation: { + // Place holder + "Type something": "Hier tippen", + + // Basic formatting + "Bold": "Fett", + "Italic": "Kursiv", + "Underline": "Unterstrichen", + "Strikethrough": "Durchgestrichen", + + // Main buttons + "Insert": "Einfügen", + "Delete": "Löschen", + "Cancel": "Abbrechen", + "OK": "OK", + "Back": "Zurück", + "Remove": "Entfernen", + "More": "Mehr", + "Update": "Aktualisieren", + "Style": "Stil", + + // Font + "Font Family": "Schriftart", + "Font Size": "Schriftgröße", + + // Colors + "Colors": "Farben", + "Background": "Hintergrund", + "Text": "Text", + "HEX Color": "Hexadezimaler Farbwert", + + // Paragraphs + "Paragraph Format": "Formatierung", + "Normal": "Normal", + "Code": "Quelltext", + "Heading 1": "Überschrift 1", + "Heading 2": "Überschrift 2", + "Heading 3": "Überschrift 3", + "Heading 4": "Überschrift 4", + + // Style + "Paragraph Style": "Absatzformatierung", + "Inline Style": "Inlineformatierung", + + // Alignment + "Align": "Ausrichtung", + "Align Left": "Linksbündig ausrichten", + "Align Center": "Zentriert ausrichten", + "Align Right": "Rechtsbündig ausrichten", + "Align Justify": "Blocksatz", + "None": "Keine", + + // Lists + "Ordered List": "Nummerierte Liste", + "Default": "Standard", + "Lower Alpha": "Kleinbuchstaben", + "Lower Greek": "Griechisches Alphabet", + "Lower Roman": "Römische Ziffern (klein)", + "Upper Alpha": "Grossbuchstaben", + "Upper Roman": "Römische Ziffern (gross)", + + "Unordered List": "Unnummerierte Liste", + "Circle": "Kreis", + "Disc": "Kreis gefüllt", + "Square": "Quadrat", + + // Line height + "Line Height": "Zeilenhöhe", + "Single": "Einfach", + "Double": "Doppelt", + + // Indent + "Decrease Indent": "Einzug verkleinern", + "Increase Indent": "Einzug vergrößern", + + // Links + "Insert Link": "Link einfügen", + "Open in new tab": "In neuem Tab öffnen", + "Open Link": "Link öffnen", + "Edit Link": "Link bearbeiten", + "Unlink": "Link entfernen", + "Choose Link": "Einen Link auswählen", + + // Images + "Insert Image": "Bild einfügen", + "Upload Image": "Bild hochladen", + "By URL": "Von URL", + "Browse": "Durchsuchen", + "Drop image": "Bild hineinziehen", + "or click": "oder hier klicken", + "Manage Images": "Bilder verwalten", + "Loading": "Laden", + "Deleting": "Löschen", + "Tags": "Tags", + "Are you sure? Image will be deleted.": "Wollen Sie das Bild wirklich löschen?", + "Replace": "Ersetzen", + "Uploading": "Hochladen", + "Loading image": "Das Bild wird geladen", + "Display": "Textausrichtung", + "Inline": "Mit Text in einer Zeile", + "Break Text": "Text umbrechen", + "Alternative Text": "Alternativtext", + "Change Size": "Größe ändern", + "Width": "Breite", + "Height": "Höhe", + "Something went wrong. Please try again.": "Etwas ist schief gelaufen. Bitte versuchen Sie es erneut.", + "Image Caption": "Bildbeschreibung", + "Advanced Edit": "Erweiterte Bearbeitung", + + // Video + "Insert Video": "Video einfügen", + "Embedded Code": "Eingebetteter Code", + "Paste in a video URL": "Fügen Sie die Video-URL ein", + "Drop video": "Video hineinziehen", + "Your browser does not support HTML5 video.": "Ihr Browser unterstützt keine HTML5-Videos.", + "Upload Video": "Video hochladen", + + // Tables + "Insert Table": "Tabelle einfügen", + "Table Header": "Tabellenkopf", + "Remove Table": "Tabelle entfernen", + "Table Style": "Tabellenformatierung", + "Horizontal Align": "Horizontale Ausrichtung", + "Row": "Zeile", + "Insert row above": "Neue Zeile davor einfügen", + "Insert row below": "Neue Zeile danach einfügen", + "Delete row": "Zeile löschen", + "Column": "Spalte", + "Insert column before": "Neue Spalte davor einfügen", + "Insert column after": "Neue Spalte danach einfügen", + "Delete column": "Spalte löschen", + "Cell": "Zelle", + "Merge cells": "Zellen verbinden", + "Horizontal split": "Horizontal teilen", + "Vertical split": "Vertikal teilen", + "Cell Background": "Zellenfarbe", + "Vertical Align": "Vertikale Ausrichtung", + "Top": "Oben", + "Middle": "Zentriert", + "Bottom": "Unten", + "Align Top": "Oben ausrichten", + "Align Middle": "Zentriert ausrichten", + "Align Bottom": "Unten ausrichten", + "Cell Style": "Zellen-Stil", + + // Files + "Insert File": "Datei einfügen", + "Upload File": "Datei hochladen", + "Drop file": "Datei hineinziehen", + + // Emoticons + "Emoticons": "Emoticons", + "Grinning face": "Grinsendes Gesicht", + "Grinning face with smiling eyes": "Grinsend Gesicht mit lächelnden Augen", + "Face with tears of joy": "Gesicht mit Tränen der Freude", + "Smiling face with open mouth": "Lächelndes Gesicht mit offenem Mund", + "Smiling face with open mouth and smiling eyes": "Lächelndes Gesicht mit offenem Mund und lächelnden Augen", + "Smiling face with open mouth and cold sweat": "Lächelndes Gesicht mit offenem Mund und kaltem Schweiß", + "Smiling face with open mouth and tightly-closed eyes": "Lächelndes Gesicht mit offenem Mund und fest geschlossenen Augen", + "Smiling face with halo": "Lächeln Gesicht mit Heiligenschein", + "Smiling face with horns": "Lächeln Gesicht mit Hörnern", + "Winking face": "Zwinkerndes Gesicht", + "Smiling face with smiling eyes": "Lächelndes Gesicht mit lächelnden Augen", + "Face savoring delicious food": "Gesicht leckeres Essen genießend", + "Relieved face": "Erleichtertes Gesicht", + "Smiling face with heart-shaped eyes": "Lächelndes Gesicht mit herzförmigen Augen", + "Smiling face with sunglasses": "Lächelndes Gesicht mit Sonnenbrille", + "Smirking face": "Grinsendes Gesicht", + "Neutral face": "Neutrales Gesicht", + "Expressionless face": "Ausdrucksloses Gesicht", + "Unamused face": "Genervtes Gesicht", + "Face with cold sweat": "Gesicht mit kaltem Schweiß", + "Pensive face": "Nachdenkliches Gesicht", + "Confused face": "Verwirrtes Gesicht", + "Confounded face": "Elendes Gesicht", + "Kissing face": "Küssendes Gesicht", + "Face throwing a kiss": "Gesicht wirft einen Kuss", + "Kissing face with smiling eyes": "Küssendes Gesicht mit lächelnden Augen", + "Kissing face with closed eyes": "Küssendes Gesicht mit geschlossenen Augen", + "Face with stuck out tongue": "Gesicht mit herausgestreckter Zunge", + "Face with stuck out tongue and winking eye": "Gesicht mit herausgestreckter Zunge und zwinkerndem Auge", + "Face with stuck out tongue and tightly-closed eyes": "Gesicht mit herausgestreckter Zunge und fest geschlossenen Augen", + "Disappointed face": "Enttäuschtes Gesicht", + "Worried face": "Besorgtes Gesicht", + "Angry face": "Verärgertes Gesicht", + "Pouting face": "Schmollendes Gesicht", + "Crying face": "Weinendes Gesicht", + "Persevering face": "Ausharrendes Gesicht", + "Face with look of triumph": "Gesicht mit triumphierenden Blick", + "Disappointed but relieved face": "Enttäuschtes, aber erleichtertes Gesicht", + "Frowning face with open mouth": "Entsetztes Gesicht mit offenem Mund", + "Anguished face": "Gequältes Gesicht", + "Fearful face": "Angstvolles Gesicht", + "Weary face": "Müdes Gesicht", + "Sleepy face": "Schläfriges Gesicht", + "Tired face": "Gähnendes Gesicht", + "Grimacing face": "Grimassenschneidendes Gesicht", + "Loudly crying face": "Laut weinendes Gesicht", + "Face with open mouth": "Gesicht mit offenem Mund", + "Hushed face": "Besorgtes Gesicht mit offenem Mund", + "Face with open mouth and cold sweat": "Gesicht mit offenem Mund und kaltem Schweiß", + "Face screaming in fear": "Vor Angst schreiendes Gesicht", + "Astonished face": "Erstauntes Gesicht", + "Flushed face": "Gerötetes Gesicht", + "Sleeping face": "Schlafendes Gesicht", + "Dizzy face": "Schwindliges Gesicht", + "Face without mouth": "Gesicht ohne Mund", + "Face with medical mask": "Gesicht mit Mundschutz", + + // Line breaker + "Break": "Zeilenumbruch", + + // Math + "Subscript": "Tiefgestellt", + "Superscript": "Hochgestellt", + + // Full screen + "Fullscreen": "Vollbild", + + // Horizontal line + "Insert Horizontal Line": "Horizontale Linie einfügen", + + // Clear formatting + "Clear Formatting": "Formatierung löschen", + + // Save + "Save": "Sparen", + + // Undo, redo + "Undo": "Rückgängig", + "Redo": "Wiederholen", + + // Select all + "Select All": "Alles auswählen", + + // Code view + "Code View": "Code-Ansicht", + + // Quote + "Quote": "Zitieren", + "Increase": "Vergrößern", + "Decrease": "Verkleinern", + + // Quick Insert + "Quick Insert": "Schnell einfügen", + + // Spcial Characters + "Special Characters": "Sonderzeichen", + "Latin": "Lateinisch", + "Greek": "Griechisch", + "Cyrillic": "Kyrillisch", + "Punctuation": "Satzzeichen", + "Currency": "Währung", + "Arrows": "Pfeile", + "Math": "Mathematik", + "Misc": "Sonstige", + + // Print. + "Print": "Drucken", + + // Spell Checker. + "Spell Checker": "Rechtschreibprüfung", + + // Help + "Help": "Hilfe", + "Shortcuts": "Verknüpfungen", + "Inline Editor": "Inline-Editor", + "Show the editor": "Editor anzeigen", + "Common actions": "Häufig verwendete Befehle", + "Copy": "Kopieren", + "Cut": "Ausschneiden", + "Paste": "Einfügen", + "Basic Formatting": "Grundformatierung", + "Increase quote level": "Zitatniveau erhöhen", + "Decrease quote level": "Zitatniveau verringern", + "Image / Video": "Bild / Video", + "Resize larger": "Vergrößern", + "Resize smaller": "Verkleinern", + "Table": "Tabelle", + "Select table cell": "Tabellenzelle auswählen", + "Extend selection one cell": "Erweitere Auswahl um eine Zelle", + "Extend selection one row": "Erweitere Auswahl um eine Zeile", + "Navigation": "Navigation", + "Focus popup / toolbar": "Fokus-Popup / Symbolleiste", + "Return focus to previous position": "Fokus auf vorherige Position", + + // Embed.ly + "Embed URL": "URL einbetten", + "Paste in a URL to embed": "URL einfügen um sie einzubetten", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Der eingefügte Inhalt kommt aus einem Microsoft Word-Dokument. Möchten Sie die Formatierungen behalten oder verwerfen?", + "Keep": "Behalten", + "Clean": "Bereinigen", + "Word Paste Detected": "Aus Word einfügen" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/el.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/el.js new file mode 100644 index 0000000..1d30e8f --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/el.js @@ -0,0 +1,342 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Arabic + */ + +$.FE.LANGUAGE['el'] = { + translation: { +// Place holder + "Type something": "Εισάγετε κείμενο", + + // Basic formatting + "Bold": "Έντονα", + "Italic": "Πλάγια", + "Underline": "Υπογραμμισμένα", + "Strikethrough": "Διαγραμμένα", + + // Main buttons + "Insert": "Εισαγωγή", + "Delete": "Διαγραφή", + "Cancel": "Ακύρωση", + "OK": "OK", + "Back": "Πίσω", + "Remove": "Αφαίρεση", + "More": "Περισσότερα", + "Update": "Ενημέρωση", + "Style": "Εξατομίκευση", + + // Font + "Font Family": "Γραμματοσειρά", + "Font Size": "Μέγεθος", + + // Colors + "Colors": "Χρώματα", + "Background": "Φόντο", + "Text": "Κείμενο", + "HEX Color": "Χρώμα HEX", + + // Paragraphs + "Paragraph Format": "Μορφή παραγράφου", + "Normal": "Κανονική", + "Code": "Κώδικας", + "Heading 1": "Επικεφαλίδα 1", + "Heading 2": "Επικεφαλίδα 2", + "Heading 3": "Επικεφαλίδα 3", + "Heading 4": "Επικεφαλίδα 4", + + // Style + "Paragraph Style": "Εξατομίκευση παραγράφου", + "Gray": "Γκρι", + "Spaced": "Αραιά", + "Uppercase": "Κεφαλαία", + "Inline Style": "Ενσωματωμένος τύπος", + + // Alignment + "Align": "Ευθυγράμμιση", + "Align Left": "Αριστερά", + "Align Center": "Κέντρο", + "Align Right": "Δεξιά", + "Align Justify": "Γέμισμα", + "None": "Χωρίς ευθυγράμμιση", + + // Lists + "Ordered List": "Διεταγμένη λίστα", + "Default": "Προκαθορισμένο", + "Lower Alpha": "Χαμηλότερο άλφα", + "Lower Greek": "Κάτω ελληνικά", + "Lower Roman": "Χαμηλότερο ρωμαϊκό", + "Upper Alpha": "Ανώτερο άλφα", + "Upper Roman": "Ανώτερο ρωμαϊκό", + + "Unordered List": "Αναδιάταχτη λίστα", + "Circle": "Κύκλος", + "Disc": "Δίσκος", + "Square": "Τετράγωνο", + + // Line height + "Line Height": "Ύψος γραμμής", + "Single": "Μονόκλινο", + "Double": "Διπλό", + + // Indent + "Decrease Indent": "Μείωση πλαισίου", + "Increase Indent": "Αύξηση πλαισίου", + + // Links + "Insert Link": "Εισαγωγή συνδέσμου", + "Open in new tab": "Άνοιγμα σε νέα καρτέλα", + "Open Link": "Άνοιγμα συνδέσμου", + "Edit Link": "Επεξεργασία συνδέσμου", + "Unlink": "Αποσύνδεση", + "Choose Link": "Επιλογή συνδέσμου", + + // Images + "Insert Image": "Εισαγωγή εικόνας", + "Upload Image": "Ανέβασμα εικόνας", + "By URL": "Από URL", + "Browse": "Περιήγηση", + "Drop image": "Σύρετε εικόνα", + "or click": "ή κάντε κλικ", + "Manage Images": "Διαχείριση εικόνων", + "Loading": "Φόρτωση", + "Deleting": "Διαγραφή", + "Tags": "Ετικέτες", + "Are you sure? Image will be deleted.": "Σίγουρα; Η εικόνα θα διαγραφεί.", + "Replace": "Αντικατάσταση", + "Uploading": "Ανέβασμα", + "Loading image": "Φόρτωση εικόνας", + "Display": "Προβολή", + "Inline": "Ενσωματωμένη", + "Break Text": "Σπάσιμο κειμένου", + "Alternative Text": "Εναλλακτικό κείμενο", + "Change Size": "Αλλαγή μεγέθους", + "Width": "Πλάτος", + "Height": "Ύψος", + "Something went wrong. Please try again.": "Κάτι πήγε στραβά. Προσπαθήστε ξανά.", + "Image Caption": "Λεζάντα εικόνας", + "Advanced Edit": "Προχωρημένη επεξεργασία", + "Rounded": "Κυκλικός", + "Bordered": "Πλαίσιο", + "Shadow": "Σκια", + + // Video + "Insert Video": "Εισαγωγή βίντεο", + "Embedded Code": "Ενσωμάτωση κώδικα", + "Paste in a video URL": "Εισαγωγή URL βίντεο", + "Drop video": "Σύρετε βίντεο", + "Your browser does not support HTML5 video.": "Ο περιηγητής σας δεν υποστηρίζει βίντεο τύπου HTML5.", + "Upload Video": "Ανέβασμα βίντεο", + + // Tables + "Insert Table": "Εισαγωγή πίνακα", + "Table Header": "Επικεφαλίδα πίνακα", + "Remove Table": "Αφαίρεση πίνακα", + "Table Style": "Εξατομίκευση πίνακα", + "Horizontal Align": "Οριζόντια ευθυγράμμιση", + "Row": "Σειρά", + "Insert row above": "Εισαγωγή σειράς από πάνω", + "Insert row below": "Εισαγωγή σειράς από κάτω", + "Delete row": "Διαγραφή σειράς", + "Column": "Στήλη", + "Insert column before": "Εισαγωγή στήλης πριν", + "Insert column after": "Εισαγωγή στήλης μετά", + "Delete column": "Διαγραφή στήλης", + "Cell": "Κελί", + "Merge cells": "Συγχώνευση κελιών", + "Horizontal split": "Οριζόντος διαχωρισμός", + "Vertical split": "Κατακόρυφος διαχωρισμός", + "Cell Background": "Φόντο κελιού", + "Vertical Align": "Κατακόρυφη ευθυγράμμιση", + "Top": "Κορυφή", + "Middle": "Μέση", + "Bottom": "Βάθος", + "Align Top": "Ευθυγράμμιση κορυφής", + "Align Middle": "Ευθυγράμμιση μέσης", + "Align Bottom": "Ευθυγράμμιση βάθους", + "Cell Style": "Εξατομίκευση κελιού", + + // Files + "Upload File": "Ανέβασμα αρχείου", + "Drop file": "Σύρετε αρχείο", + + // Emoticons + "Emoticons": "Emoticons", + "Grinning face": "Γέλιο", + "Grinning face with smiling eyes": "Γέλιο με γελαστά μάτια", + "Face with tears of joy": "Δάκρυα γέλιου (LOL)", + "Smiling face with open mouth": "Χαμόγελο με ανοιχτό στόμα", + "Smiling face with open mouth and smiling eyes": "Χαμόγελο με ανοιχτό στόμα και γελαστά μάτια", + "Smiling face with open mouth and cold sweat": "Χαμόγελο με ανοιχτό στόμα και σταγόνα ιδρώτα", + "Smiling face with open mouth and tightly-closed eyes": "Χαμόγελο με ανοιχτό στόμα και σφιχτά κλεισμένα μάτια", + "Smiling face with halo": "Χαμόγελο με φωτοστέφανο", + "Smiling face with horns": "Χαμογελαστό διαβολάκι", + "Winking face": "Κλείσιμο ματιού", + "Smiling face with smiling eyes": "Χαμόγελο με γελαστά μάτια", + "Face savoring delicious food": "Νόστιμο", + "Relieved face": "Ανακούφιση", + "Smiling face with heart-shaped eyes": "Χαμόγελο με μάτια σε σχήμα καρδιάς", + "Smiling face with sunglasses": "Χαμόγελο με γυαλιά ηλίου", + "Smirking face": "Ειρωνία", + "Neutral face": "Ουδέτερο", + "Expressionless face": "Ανέκφραστο", + "Unamused face": "Αψυχαγώγητο", + "Face with cold sweat": "Σταγόνα ιδρώτα", + "Pensive face": "Σκεπτικό", + "Confused face": "Σύγχιση", + "Confounded face": "Ακράτεια", + "Kissing face": "Φιλί", + "Face throwing a kiss": "Πάσα φιλιού", + "Kissing face with smiling eyes": "Φιλί με γελαστά μάτια", + "Kissing face with closed eyes": "Φιλί με κλειστά μάτια", + "Face with stuck out tongue": "Γλώσσα", + "Face with stuck out tongue and winking eye": "Γλώσσα με κλείσιμο ματιού", + "Face with stuck out tongue and tightly-closed eyes": "Γλώσσα με σφιχτά κλεισμένα μάτια", + "Disappointed face": "Απογοήτευση", + "Worried face": "Ανυσηχία", + "Angry face": "Θυμός", + "Pouting face": "Έξαλλο", + "Crying face": "Κλάμα θυμού", + "Persevering face": "Έτοιμο να εκραγεί", + "Face with look of triumph": "Θρίαμβος", + "Disappointed but relieved face": "Απογοήτευση με ανακούφιση", + "Frowning face with open mouth": "Απορία", + "Anguished face": "Αγωνία", + "Fearful face": "Φόβος", + "Weary face": "Κούραση", + "Sleepy face": "Εξάντληση", + "Tired face": "Γκρίνια", + "Grimacing face": "Γκριμάτσα", + "Loudly crying face": "Δυνατό κλάμα", + "Face with open mouth": "Έκπληξη", + "Hushed face": "Σιωπή", + "Face with open mouth and cold sweat": "Έκπληξη με ιδρώτα", + "Face screaming in fear": "Πανικός", + "Astonished face": "Ηλίθιο", + "Flushed face": "Ντροπαλό", + "Sleeping face": "Ύπνος", + "Dizzy face": "Ζαλάδα", + "Face without mouth": "Άφωνο", + "Face with medical mask": "Νοσηλευτική μάσκα", + + // Line breaker + "Break": "Σπάσιμο", + + // Math + "Subscript": "Υποκείμενο", + "Superscript": "Υπερκείμενο", + + // Full screen + "Fullscreen": "Πλήρης οθόνη", + + // Horizontal line + "Insert Horizontal Line": "Εισαγωγή οριζόντιας γραμμής", + + // Clear formatting + "Clear Formatting": "Εκαθάριση μορφοποίησης", + + // Save + "Save": "Αποθηκεύσετε", + + // Undo, redo + "Undo": "Αναίρεση", + "Redo": "Επανάληψη", + + // Select all + "Select All": "Επιλογή Όλων", + + // Code view + "Code View": "Προβολή Κώδικα", + + // Quote + "Quote": "Απόσπασμα", + "Increase": "Αύξηση", + "Decrease": "Μείωση", + + // Quick Insert + "Quick Insert": "Γρήγορη εισαγωγή", + + // Spcial Characters + "Special Characters": "Ειδικοί χαρακτήρες", + "Latin": "Λατινικοί", + "Greek": "Ελληνικοί", + "Cyrillic": "Κρυλλικοί", + "Punctuation": "Σημεία στήξης", + "Currency": "Συνάλλαγμα", + "Arrows": "Βέλη", + "Math": "Μαθηματικά", + "Misc": "Διάφοροι", + + // Print. + "Print": "Εκτύπωση", + + // Spell Checker. + "Spell Checker": "Έλεγχος ορθογραφίας", + + // Help + "Help": "Βοήθεια", + "Shortcuts": "Συντομεύσεις", + "Inline Editor": "Ενσωματωμένος επεξεργαστής", + "Show the editor": "Εμφάνιση επεξεργαστή", + "Common actions": "Κοινές ενέργειες", + "Copy": "Αντιγραφή", + "Cut": "Αποκοπή", + "Paste": "Επικόλληση", + "Basic Formatting": "Βασική διαμόρφωση", + "Increase quote level": "Αύξηση επιπέδου αποσπάσματος", + "Decrease quote level": "Μείωση επιπέδου αποσπάσματος", + "Image / Video": "Εικόνα / Βίντεο", + "Resize larger": "Αύξηση μεγέθους", + "Resize smaller": "Μείωση μεγέθους", + "Table": "Πίνακας", + "Select table cell": "Επιλογή κελιού από πίνακα", + "Extend selection one cell": "Επέκταση επιλογής κατά ένα κελί", + "Extend selection one row": "Επέκταση επιλογής κατά μια σειρά", + "Navigation": "Πλοήγηση", + "Focus popup / toolbar": "Εστίαση αναδυόμενου / εργαλειοθήκης", + "Return focus to previous position": "Επιστροφή εστίασης στην προηγούμενη θέση", + + // Embed.ly + "Embed URL": "Ενσωμάτωση URL", + "Paste in a URL to embed": "Εισάγετε ένα URL για ενσωμάτωση", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Το περιεχόμενο που επικολλήσατε προέρχεται από ένα έγγραφο του Microsoft Word. Θέλετε να διατηρήσετε το έγγραφο ή να το καταργήσετε;", + "Keep": "Διατήρηση", + "Clean": "Κατάργηση", + "Word Paste Detected": "Εντοπίστηκε επικόλληση από αρχείο Word" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/en_ca.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/en_ca.js new file mode 100644 index 0000000..7b218f4 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/en_ca.js @@ -0,0 +1,280 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * English spoken in Canada + */ + +$.FE.LANGUAGE['en_ca'] = { + translation: { + // Place holder + "Type something": "Type something", + + // Basic formatting + "Bold": "Bold", + "Italic": "Italic", + "Underline": "Underline", + "Strikethrough": "Strikethrough", + + // Main buttons + "Insert": "Insert", + "Delete": "Delete", + "Cancel": "Cancel", + "OK": "OK", + "Back": "Back", + "Remove": "Remove", + "More": "More", + "Update": "Update", + "Style": "Style", + + // Font + "Font Family": "Font Family", + "Font Size": "Font Size", + + // Colors + "Colors": "Colours", + "Background": "Background", + "Text": "Text", + "HEX Color": "HEX Colour", + + // Paragraphs + "Paragraph Format": "Paragraph Format", + "Normal": "Normal", + "Code": "Code", + "Heading 1": "Heading 1", + "Heading 2": "Heading 2", + "Heading 3": "Heading 3", + "Heading 4": "Heading 4", + + // Style + "Paragraph Style": "Paragraph Style", + "Inline Style": "Inline Style", + + // Alignment + "Align": "Align", + "Align Left": "Align Left", + "Align Center": "Align Centre", + "Align Right": "Align Right", + "Align Justify": "Align Justify", + "None": "None", + + // Lists + "Ordered List": "Ordered List", + "Default": "", + "Lower Alpha": "Lower Alpha", + "Lower Greek": "Lower Greek", + "Lower Roman": "Lower Roman", + "Upper Alpha": "Upper Alpha", + "Upper Roman": "Upper Roman", + + "Unordered List": "Unordered List", + "Circle": "Circle", + "Disc": "Disc", + "Square": "Square", + + // Line height + "Line Height": "Line Height", + "Single": "Single", + "Double": "Double", + + // Indent + "Decrease Indent": "Decrease Indent", + "Increase Indent": "Increase Indent", + + // Links + "Insert Link": "Insert Link", + "Open in new tab": "Open in new tab", + "Open Link": "Open Link", + "Edit Link": "Edit Link", + "Unlink": "Unlink", + "Choose Link": "Choose Link", + + // Images + "Insert Image": "Insert Image", + "Upload Image": "Upload Image", + "By URL": "By URL", + "Browse": "Browse", + "Drop image": "Drop image", + "or click": "or click", + "Manage Images": "Manage Images", + "Loading": "Loading", + "Deleting": "Deleting", + "Tags": "Tags", + "Are you sure? Image will be deleted.": "Are you sure? Image will be deleted.", + "Replace": "Replace", + "Uploading": "Uploading", + "Loading image": "Loading image", + "Display": "Display", + "Inline": "Inline", + "Break Text": "Break Text", + "Alternative Text": "Alternative Text", + "Change Size": "Change Size", + "Width": "Width", + "Height": "Height", + "Something went wrong. Please try again.": "Something went wrong. Please try again.", + "Image Caption": "Image Caption", + "Advanced Edit": "Advanced Edit", + + // Video + "Insert Video": "Insert Video", + "Embedded Code": "Embedded Code", + "Paste in a video URL": "Paste in a video URL", + "Drop video": "Drop video", + "Your browser does not support HTML5 video.": "Your browser does not support HTML5 video.", + "Upload Video": "Upload Video", + + // Tables + "Insert Table": "Insert Table", + "Table Header": "Table Header", + "Remove Table": "Remove Table", + "Table Style": "Table Style", + "Horizontal Align": "Horizontal Align", + "Row": "Row", + "Insert row above": "Insert row above", + "Insert row below": "Insert row below", + "Delete row": "Delete row", + "Column": "Column", + "Insert column before": "Insert column before", + "Insert column after": "Insert column after", + "Delete column": "Delete column", + "Cell": "Cell", + "Merge cells": "Merge cells", + "Horizontal split": "Horizontal split", + "Vertical split": "Vertical split", + "Cell Background": "Cell Background", + "Vertical Align": "Vertical Align", + "Top": "Top", + "Middle": "Middle", + "Bottom": "Bottom", + "Align Top": "Align Top", + "Align Middle": "Align Middle", + "Align Bottom": "Align Bottom", + "Cell Style": "Cell Style", + + // Files + "Upload File": "Upload File", + "Drop file": "Drop file", + + // Emoticons + "Emoticons": "Emoticons", + + // Line breaker + "Break": "Break", + + // Math + "Subscript": "Subscript", + "Superscript": "Superscript", + + // Full screen + "Fullscreen": "Fullscreen", + + // Horizontal line + "Insert Horizontal Line": "Insert Horizontal Line", + + // Clear formatting + "Clear Formatting": "Clear Formatting", + + // Save + "Save": "Save", + + // Undo, redo + "Undo": "Undo", + "Redo": "Redo", + + // Select all + "Select All": "Select All", + + // Code view + "Code View": "Code View", + + // Quote + "Quote": "Quote", + "Increase": "Increase", + "Decrease": "Decrease", + + // Quick Insert + "Quick Insert": "Quick Insert", + + // Spcial Characters + "Special Characters": "Special Characters", + "Latin": "Latin", + "Greek": "Greek", + "Cyrillic": "Cyrillic", + "Punctuation": "Punctuation", + "Currency": "Currency", + "Arrows": "Arrows", + "Math": "Math", + "Misc": "Misc", + + // Print. + "Print": "Print", + + // Spell Checker. + "Spell Checker": "Spell Checker", + + // Help + "Help": "Help", + "Shortcuts": "Shortcuts", + "Inline Editor": "Inline Editor", + "Show the editor": "Show the editor", + "Common actions": "Common actions", + "Copy": "Copy", + "Cut": "Cut", + "Paste": "Paste", + "Basic Formatting": "Basic Formatting", + "Increase quote level": "Increase quote level", + "Decrease quote level": "Decrease quote level", + "Image / Video": "Image / Video", + "Resize larger": "Resize larger", + "Resize smaller": "Resize smaller", + "Table": "Table", + "Select table cell": "Select table cell", + "Extend selection one cell": "Extend selection one cell", + "Extend selection one row": "Extend selection one row", + "Navigation": "Navigation", + "Focus popup / toolbar": "Focus popup / toolbar", + "Return focus to previous position": "Return focus to previous position", + + // Embed.ly + "Embed URL": "Embed URL", + "Paste in a URL to embed": "Paste in a URL to embed", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?", + "Keep": "Keep", + "Clean": "Clean", + "Word Paste Detected": "Word Paste Detected" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/en_gb.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/en_gb.js new file mode 100644 index 0000000..a538bd2 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/en_gb.js @@ -0,0 +1,280 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * English spoken in Great Britain + */ + +$.FE.LANGUAGE['en_gb'] = { + translation: { + // Place holder + "Type something": "Type something", + + // Basic formatting + "Bold": "Bold", + "Italic": "Italic", + "Underline": "Underline", + "Strikethrough": "Strikethrough", + + // Main buttons + "Insert": "Insert", + "Delete": "Delete", + "Cancel": "Cancel", + "OK": "OK", + "Back": "Back", + "Remove": "Remove", + "More": "More", + "Update": "Update", + "Style": "Style", + + // Font + "Font Family": "Font Family", + "Font Size": "Font Size", + + // Colors + "Colors": "Colours", + "Background": "Background", + "Text": "Text", + "HEX Color": "HEX Colour", + + // Paragraphs + "Paragraph Format": "Paragraph Format", + "Normal": "Normal", + "Code": "Code", + "Heading 1": "Heading 1", + "Heading 2": "Heading 2", + "Heading 3": "Heading 3", + "Heading 4": "Heading 4", + + // Style + "Paragraph Style": "Paragraph Style", + "Inline Style": "Inline Style", + + // Alignment + "Align": "Align", + "Align Left": "Align Left", + "Align Center": "Align Centre", + "Align Right": "Alight Right", + "Align Justify": "Align Justify", + "None": "None", + + // Lists + "Ordered List": "Ordered List", + "Default": "", + "Lower Alpha": "Lower Alpha", + "Lower Greek": "Lower Greek", + "Lower Roman": "Lower Roman", + "Upper Alpha": "Upper Alpha", + "Upper Roman": "Upper Roman", + + "Unordered List": "Unordered List", + "Circle": "Circle", + "Disc": "Disc", + "Square": "Square", + + // Line height + "Line Height": "Line Height", + "Single": "Single", + "Double": "Double", + + // Indent + "Decrease Indent": "Decrease Indent", + "Increase Indent": "Increase Indent", + + // Links + "Insert Link": "Insert Link", + "Open in new tab": "Open in new tab", + "Open Link": "Open Link", + "Edit Link": "Edit Link", + "Unlink": "Unlink", + "Choose Link": "Choose Link", + + // Images + "Insert Image": "Insert Image", + "Upload Image": "Upload Image", + "By URL": "By URL", + "Browse": "Browse", + "Drop image": "Drop image", + "or click": "or click", + "Manage Images": "Manage Images", + "Loading": "Loading", + "Deleting": "Deleting", + "Tags": "Tags", + "Are you sure? Image will be deleted.": "Are you sure? Image will be deleted.", + "Replace": "Replace", + "Uploading": "Uploading", + "Loading image": "Loading image", + "Display": "Display", + "Inline": "Inline", + "Break Text": "Break Text", + "Alternative Text": "Alternative Text", + "Change Size": "Change Size", + "Width": "Width", + "Height": "Height", + "Something went wrong. Please try again.": "Something went wrong. Please try again.", + "Image Caption": "Image Caption", + "Advanced Edit": "Advanced Edit", + + // Video + "Insert Video": "Insert Video", + "Embedded Code": "Embedded Code", + "Paste in a video URL": "Paste in a video URL", + "Drop video": "Drop video", + "Your browser does not support HTML5 video.": "Your browser does not support HTML5 video.", + "Upload Video": "Upload Video", + + // Tables + "Insert Table": "Insert Table", + "Table Header": "Table Header", + "Remove Table": "Remove Table", + "Table Style": "Table Style", + "Horizontal Align": "Horizontal Align", + "Row": "Row", + "Insert row above": "Insert row above", + "Insert row below": "Insert row below", + "Delete row": "Delete row", + "Column": "Column", + "Insert column before": "Insert column before", + "Insert column after": "Insert column after", + "Delete column": "Delete column", + "Cell": "Cell", + "Merge cells": "Merge cells", + "Horizontal split": "Horizontal split", + "Vertical split": "Vertical split", + "Cell Background": "Cell Background", + "Vertical Align": "Vertical Align", + "Top": "Top", + "Middle": "Middle", + "Bottom": "Bottom", + "Align Top": "Align Top", + "Align Middle": "Align Middle", + "Align Bottom": "Align Bottom", + "Cell Style": "Cell Style", + + // Files + "Upload File": "Upload File", + "Drop file": "Drop file", + + // Emoticons + "Emoticons": "Emoticons", + + // Line breaker + "Break": "Break", + + // Math + "Subscript": "Subscript", + "Superscript": "Superscript", + + // Full screen + "Fullscreen": "Fullscreen", + + // Horizontal line + "Insert Horizontal Line": "Insert Horizontal Line", + + // Clear formatting + "Clear Formatting": "Clear Formatting", + + // Save + "Save": "Save", + + // Undo, redo + "Undo": "Undo", + "Redo": "Redo", + + // Select all + "Select All": "Select All", + + // Code view + "Code View": "Code View", + + // Quote + "Quote": "Quote", + "Increase": "Increase", + "Decrease": "Decrease", + + // Quick Insert + "Quick Insert": "Quick Insert", + + // Spcial Characters + "Special Characters": "Special Characters", + "Latin": "Latin", + "Greek": "Greek", + "Cyrillic": "Cyrillic", + "Punctuation": "Punctuation", + "Currency": "Currency", + "Arrows": "Arrows", + "Math": "Math", + "Misc": "Misc", + + // Print. + "Print": "Print", + + // Spell Checker. + "Spell Checker": "Spell Checker", + + // Help + "Help": "Help", + "Shortcuts": "Shortcuts", + "Inline Editor": "Inline Editor", + "Show the editor": "Show the editor", + "Common actions": "Common actions", + "Copy": "Copy", + "Cut": "Cut", + "Paste": "Paste", + "Basic Formatting": "Basic Formatting", + "Increase quote level": "Increase quote level", + "Decrease quote level": "Decrease quote level", + "Image / Video": "Image / Video", + "Resize larger": "Resize larger", + "Resize smaller": "Resize smaller", + "Table": "Table", + "Select table cell": "Select table cell", + "Extend selection one cell": "Extend selection one cell", + "Extend selection one row": "Extend selection one row", + "Navigation": "Navigation", + "Focus popup / toolbar": "Focus popup / toolbar", + "Return focus to previous position": "Return focus to previous position", + + // Embed.ly + "Embed URL": "Embed URL", + "Paste in a URL to embed": "Paste in a URL to embed", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?", + "Keep": "Keep", + "Clean": "Clean", + "Word Paste Detected": "Word Paste Detected" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/es.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/es.js new file mode 100644 index 0000000..acfa7b8 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/es.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Spanish + */ + +$.FE.LANGUAGE['es'] = { + translation: { + // Place holder + "Type something": "Escriba algo", + + // Basic formatting + "Bold": "Negrita", + "Italic": "It\u00e1lica", + "Underline": "Subrayado", + "Strikethrough": "Tachado", + + // Main buttons + "Insert": "Insertar", + "Delete": "Borrar", + "Cancel": "Cancelar", + "OK": "Ok", + "Back": "Atr\u00e1s", + "Remove": "Quitar", + "More": "M\u00e1s", + "Update": "Actualizaci\u00f3n", + "Style": "Estilo", + + // Font + "Font Family": "Familia de fuentes", + "Font Size": "Tama\u00f1o de fuente", + + // Colors + "Colors": "Colores", + "Background": "Fondo", + "Text": "Texto", + "HEX Color": "Color hexadecimal", + + // Paragraphs + "Paragraph Format": "Formato de p\u00e1rrafo", + "Normal": "Normal", + "Code": "C\u00f3digo", + "Heading 1": "Encabezado 1", + "Heading 2": "Encabezado 2", + "Heading 3": "Encabezado 3", + "Heading 4": "Encabezado 4", + + // Style + "Paragraph Style": "Estilo de p\u00e1rrafo", + "Inline Style": "Estilo en l\u00ednea", + + // Alignment + "Align": "Alinear", + "Align Left": "Alinear a la izquierda", + "Align Center": "Alinear al centro", + "Align Right": "Alinear a la derecha", + "Align Justify": "Justificar", + "None": "Ninguno", + + // Lists + "Ordered List": "Lista ordenada", + "Default": "Defecto", + "Lower Alpha": "Alfa inferior", + "Lower Greek": "Griego inferior", + "Lower Roman": "Baja romana", + "Upper Alpha": "Alfa superior", + "Upper Roman": "Romano superior", + + "Unordered List": "Lista desordenada", + "Circle": "Circulo", + "Disc": "Dto", + "Square": "Cuadrado", + + // Line height + "Line Height": "Altura de la línea", + "Single": "Soltero", + "Double": "Doble", + + // Indent + "Decrease Indent": "Reducir sangr\u00eda", + "Increase Indent": "Aumentar sangr\u00eda", + + // Links + "Insert Link": "Insertar enlace", + "Open in new tab": "Abrir en una nueva pesta\u00F1a", + "Open Link": "Abrir enlace", + "Edit Link": "Editar enlace", + "Unlink": "Quitar enlace", + "Choose Link": "Elegir enlace", + + // Images + "Insert Image": "Insertar imagen", + "Upload Image": "Cargar imagen", + "By URL": "Por URL", + "Browse": "Examinar", + "Drop image": "Soltar la imagen", + "or click": "o haga clic en", + "Manage Images": "Administrar im\u00e1genes", + "Loading": "Cargando", + "Deleting": "Borrado", + "Tags": "Etiquetas", + "Are you sure? Image will be deleted.": "\u00bfEst\u00e1 seguro? Imagen ser\u00e1 borrada.", + "Replace": "Reemplazar", + "Uploading": "Carga", + "Loading image": "Cargando imagen", + "Display": "Mostrar", + "Inline": "En l\u00ednea", + "Break Text": "Romper texto", + "Alternative Text": "Texto alternativo", + "Change Size": "Cambiar tama\u00f1o", + "Width": "Ancho", + "Height": "Altura", + "Something went wrong. Please try again.": "Algo sali\u00f3 mal. Por favor, vuelva a intentarlo.", + "Image Caption": "Captura de imagen", + "Advanced Edit": "Edición avanzada", + + // Video + "Insert Video": "Insertar video", + "Embedded Code": "C\u00f3digo incrustado", + "Paste in a video URL": "Pegar en una URL de video", + "Drop video": "Soltar video", + "Your browser does not support HTML5 video.": "Su navegador no es compatible con video html5.", + "Upload Video": "Subir video", + + // Tables + "Insert Table": "Insertar tabla", + "Table Header": "Encabezado de la tabla", + "Remove Table": "Retire la tabla", + "Table Style": "Estilo de tabla", + "Horizontal Align": "Alinear horizontal", + "Row": "Fila", + "Insert row above": "Insertar fila antes", + "Insert row below": "Insertar fila despu\u00e9s", + "Delete row": "Eliminar fila", + "Column": "Columna", + "Insert column before": "Insertar columna antes", + "Insert column after": "Insertar columna despu\u00e9s", + "Delete column": "Eliminar columna", + "Cell": "Celda", + "Merge cells": "Combinar celdas", + "Horizontal split": "Divisi\u00f3n horizontal", + "Vertical split": "Divisi\u00f3n vertical", + "Cell Background": "Fondo de la celda", + "Vertical Align": "Alinear vertical", + "Top": "Cima", + "Middle": "Medio", + "Bottom": "Del fondo", + "Align Top": "Alinear a la parte superior", + "Align Middle": "Alinear media", + "Align Bottom": "Alinear abajo", + "Cell Style": "Estilo de celda", + + // Files + "Upload File": "Subir archivo", + "Drop file": "Soltar archivo", + + // Emoticons + "Emoticons": "Emoticones", + "Grinning face": "Sonriendo cara", + "Grinning face with smiling eyes": "Sonriendo cara con ojos sonrientes", + "Face with tears of joy": "Cara con l\u00e1grimas de alegr\u00eda", + "Smiling face with open mouth": "Cara sonriente con la boca abierta", + "Smiling face with open mouth and smiling eyes": "Cara sonriente con la boca abierta y los ojos sonrientes", + "Smiling face with open mouth and cold sweat": "Cara sonriente con la boca abierta y el sudor fr\u00edo", + "Smiling face with open mouth and tightly-closed eyes": "Cara sonriente con la boca abierta y los ojos fuertemente cerrados", + "Smiling face with halo": "Cara sonriente con halo", + "Smiling face with horns": "Cara sonriente con cuernos", + "Winking face": "Gui\u00f1o de la cara", + "Smiling face with smiling eyes": "Cara sonriente con ojos sonrientes", + "Face savoring delicious food": "Care saborear una deliciosa comida", + "Relieved face": "Cara Aliviado", + "Smiling face with heart-shaped eyes": "Cara sonriente con los ojos en forma de coraz\u00f3n", + "Smiling face with sunglasses": "Cara sonriente con gafas de sol", + "Smirking face": "Sonriendo cara", + "Neutral face": "Cara neutral", + "Expressionless face": "Rostro inexpresivo", + "Unamused face": "Cara no divertido", + "Face with cold sweat": "Cara con sudor fr\u00edo", + "Pensive face": "Rostro pensativo", + "Confused face": "Cara confusa", + "Confounded face": "Cara Averg\u00fc\u00e9ncense", + "Kissing face": "Besar la cara", + "Face throwing a kiss": "Cara lanzando un beso", + "Kissing face with smiling eyes": "Besar a cara con ojos sonrientes", + "Kissing face with closed eyes": "Besar a cara con los ojos cerrados", + "Face with stuck out tongue": "Cara con la lengua pegada", + "Face with stuck out tongue and winking eye": "Cara con pegado a la lengua y los ojos gui\u00f1o", + "Face with stuck out tongue and tightly-closed eyes": "Cara con la lengua pegada a y los ojos fuertemente cerrados", + "Disappointed face": "Cara decepcionado", + "Worried face": "Cara de preocupaci\u00f3n", + "Angry face": "Cara enojada", + "Pouting face": "Que pone mala cara", + "Crying face": "Cara llorando", + "Persevering face": "Perseverar cara", + "Face with look of triumph": "Cara con expresi\u00f3n de triunfo", + "Disappointed but relieved face": "Decepcionado pero el rostro aliviado", + "Frowning face with open mouth": "Con el ce\u00f1o fruncido la cara con la boca abierta", + "Anguished face": "Rostro angustiado", + "Fearful face": "Cara Temeroso", + "Weary face": "Rostro cansado", + "Sleepy face": "Rostro so\u00f1oliento", + "Tired face": "Rostro cansado", + "Grimacing face": "Haciendo una mueca cara", + "Loudly crying face": "Llorando en voz alta la cara", + "Face with open mouth": "Cara con la boca abierta", + "Hushed face": "Cara callada", + "Face with open mouth and cold sweat": "Cara con la boca abierta y el sudor frío", + "Face screaming in fear": "Cara gritando de miedo", + "Astonished face": "Cara asombrosa", + "Flushed face": "Cara enrojecida", + "Sleeping face": "Rostro dormido", + "Dizzy face": "Cara Mareado", + "Face without mouth": "Cara sin boca", + "Face with medical mask": "Cara con la m\u00e1scara m\u00e9dica", + + // Line breaker + "Break": "Romper", + + // Math + "Subscript": "Sub\u00edndice", + "Superscript": "Super\u00edndice", + + // Full screen + "Fullscreen": "Pantalla completa", + + // Horizontal line + "Insert Horizontal Line": "Insertar l\u00ednea horizontal", + + // Clear formatting + "Clear Formatting": "Quitar el formato", + + // Save + "Save": "Salvar", + + // Undo, redo + "Undo": "Deshacer", + "Redo": "Rehacer", + + // Select all + "Select All": "Seleccionar todo", + + // Code view + "Code View": "Vista de c\u00f3digo", + + // Quote + "Quote": "Cita", + "Increase": "Aumentar", + "Decrease": "Disminuci\u00f3n", + + // Quick Insert + "Quick Insert": "Inserci\u00f3n r\u00e1pida", + + // Spcial Characters + "Special Characters": "Caracteres especiales", + "Latin": "Latín", + "Greek": "Griego", + "Cyrillic": "Cirílico", + "Punctuation": "Puntuación", + "Currency": "Moneda", + "Arrows": "Flechas", + "Math": "Mates", + "Misc": "Misc", + + // Print. + "Print": "Impresión", + + // Spell Checker. + "Spell Checker": "Corrector ortográfico", + + // Help + "Help": "Ayuda", + "Shortcuts": "Atajos", + "Inline Editor": "Editor en línea", + "Show the editor": "Mostrar al editor", + "Common actions": "Acciones comunes", + "Copy": "Dupdo", + "Cut": "Cortar", + "Paste": "Pegar", + "Basic Formatting": "Formato básico", + "Increase quote level": "Aumentar el nivel de cotización", + "Decrease quote level": "Disminuir el nivel de cotización", + "Image / Video": "Imagen / video", + "Resize larger": "Redimensionar más grande", + "Resize smaller": "Redimensionar más pequeño", + "Table": "Mesa", + "Select table cell": "Celda de tabla select", + "Extend selection one cell": "Ampliar la selección una celda", + "Extend selection one row": "Ampliar la selección una fila", + "Navigation": "Navegación", + "Focus popup / toolbar": "Focus popup / toolbar", + "Return focus to previous position": "Volver al foco a la posición anterior", + + // Embed.ly + "Embed URL": "URL de inserción", + "Paste in a URL to embed": "Pegar en una url para incrustar", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "El contenido pegado viene de un documento de Microsoft Word. ¿Quieres mantener el formato o limpiarlo?", + "Keep": "Guardar", + "Clean": "Limpiar", + "Word Paste Detected": "Palabra detectada" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/et.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/et.js new file mode 100644 index 0000000..6f64920 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/et.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Estonian + */ + +$.FE.LANGUAGE['et'] = { + translation: { + // Place holder + "Type something": "Kirjuta midagi", + + // Basic formatting + "Bold": "Rasvane", + "Italic": "Kursiiv", + "Underline": "Allajoonitud", + "Strikethrough": "L\u00e4bikriipsutatud", + + // Main buttons + "Insert": "Lisa", + "Delete": "Kustuta", + "Cancel": "T\u00fchista", + "OK": "OK", + "Back": "Tagasi", + "Remove": "Eemaldama", + "More": "Rohkem", + "Update": "Ajakohastama", + "Style": "Stiil", + + // Font + "Font Family": "Fondi perekond", + "Font Size": "Fondi suurus", + + // Colors + "Colors": "V\u00e4rvid", + "Background": "Taust", + "Text": "Tekst", + "HEX Color": "Hex värvi", + + // Paragraphs + "Paragraph Format": "Paragrahv formaat", + "Normal": "Normaalne", + "Code": "Kood", + "Heading 1": "P\u00e4is 1", + "Heading 2": "P\u00e4is 2", + "Heading 3": "P\u00e4is 3", + "Heading 4": "P\u00e4is 4", + + // Style + "Paragraph Style": "Paragrahv stiil", + "Inline Style": "J\u00e4rjekorras stiil", + + // Alignment + "Align": "Joonda", + "Align Left": "Joonda vasakule", + "Align Center": "Joonda keskele", + "Align Right": "Joonda paremale", + "Align Justify": "R\u00f6\u00f6pjoondus", + "None": "Mitte \u00fckski", + + // Lists + "Ordered List": "Tellitud nimekirja", + "Default": "Vaikimisi", + "Lower Alpha": "Alumine alfa", + "Lower Greek": "Alumine kreeklane", + "Lower Roman": "Madalam roomlane", + "Upper Alpha": "Ülemine alfa", + "Upper Roman": "Ülemine rooma", + + "Unordered List": "Tavalise nimekirja", + "Circle": "Ringi", + "Disc": "Plaat", + "Square": "Ruut", + + // Line height + "Line Height": "Reakõrgus", + "Single": "Üksik", + "Double": "Topelt", + + // Indent + "Decrease Indent": "V\u00e4henemine taane", + "Increase Indent": "Suurenda taanet", + + // Links + "Insert Link": "Lisa link", + "Open in new tab": "Ava uues sakis", + "Open Link": "Avatud link", + "Edit Link": "Muuda link", + "Unlink": "Eemalda link", + "Choose Link": "Vali link", + + // Images + "Insert Image": "Lisa pilt", + "Upload Image": "Laadige pilt", + "By URL": "Poolt URL", + "Browse": "sirvida", + "Drop image": "Aseta pilt", + "or click": "v\u00f5i kliki", + "Manage Images": "Halda pilte", + "Loading": "Laadimine", + "Deleting": "Kustutamine", + "Tags": "Sildid", + "Are you sure? Image will be deleted.": "Oled sa kindel? Pilt kustutatakse.", + "Replace": "Asendama", + "Uploading": "Laadimise pilti", + "Loading image": "Laadimise pilti", + "Display": "Kuvama", + "Inline": "J\u00e4rjekorras", + "Break Text": "Murdma teksti", + "Alternative Text": "Asendusliikme teksti", + "Change Size": "Muuda suurust", + "Width": "Laius", + "Height": "K\u00f5rgus", + "Something went wrong. Please try again.": "Midagi l\u00e4ks valesti. Palun proovi uuesti.", + "Image Caption": "Pildi pealkiri", + "Advanced Edit": "Täiustatud redigeerimine", + + // Video + "Insert Video": "Lisa video", + "Embedded Code": "Varjatud koodi", + "Paste in a video URL": "Kleebi video URL-i", + "Drop video": "Tilk videot", + "Your browser does not support HTML5 video.": "Teie brauser ei toeta html5-videot.", + "Upload Video": "Video üleslaadimine", + + // Tables + "Insert Table": "Sisesta tabel", + "Table Header": "Tabel p\u00e4ise kaudu", + "Remove Table": "Eemalda tabel", + "Table Style": "Tabel stiili", + "Horizontal Align": "Horisontaalne joonda", + "Row": "Rida", + "Insert row above": "Sisesta rida \u00fcles", + "Insert row below": "Sisesta rida alla", + "Delete row": "Kustuta rida", + "Column": "Veerg", + "Insert column before": "Sisesta veerg ette", + "Insert column after": "Sisesta veerg j\u00e4rele", + "Delete column": "Kustuta veerg", + "Cell": "Lahter", + "Merge cells": "\u00fchenda lahtrid", + "Horizontal split": "Poolita horisontaalselt", + "Vertical split": "Poolita vertikaalselt", + "Cell Background": "Lahter tausta", + "Vertical Align": "Vertikaalne joonda", + "Top": "\u00fclemine", + "Middle": "Keskmine", + "Bottom": "P\u00f5hi", + "Align Top": "Joonda \u00fclemine", + "Align Middle": "Joonda keskmine", + "Align Bottom": "Joonda P\u00f5hi", + "Cell Style": "Lahter stiili", + + // Files + "Upload File": "Lae fail \u00fcles", + "Drop file": "Aseta fail", + + // Emoticons + "Emoticons": "Emotikonid", + "Grinning face": "Irvitas n\u00e4kku", + "Grinning face with smiling eyes": "Irvitas n\u00e4kku naeratavad silmad", + "Face with tears of joy": "N\u00e4gu r\u00f5\u00f5mupisaratega", + "Smiling face with open mouth": "Naeratav n\u00e4gu avatud suuga", + "Smiling face with open mouth and smiling eyes": "Naeratav n\u00e4gu avatud suu ja naeratavad silmad", + "Smiling face with open mouth and cold sweat": "Naeratav n\u00e4gu avatud suu ja k\u00fclm higi", + "Smiling face with open mouth and tightly-closed eyes": "Naeratav n\u00e4gu avatud suu ja tihedalt suletud silmad", + "Smiling face with halo": "Naeratav n\u00e4gu halo", + "Smiling face with horns": "Naeratav n\u00e4gu sarved", + "Winking face": "Pilgutab n\u00e4gu", + "Smiling face with smiling eyes": "Naeratav n\u00e4gu naeratab silmad", + "Face savoring delicious food": "N\u00e4gu nautides maitsvat toitu", + "Relieved face": "P\u00e4\u00e4stetud n\u00e4gu", + "Smiling face with heart-shaped eyes": "Naeratav n\u00e4gu s\u00fcdajas silmad", + "Smiling face with sunglasses": "Naeratav n\u00e4gu p\u00e4ikeseprillid", + "Smirking face": "Muigama n\u00e4gu ", + "Neutral face": "Neutraalne n\u00e4gu", + "Expressionless face": "Ilmetu n\u00e4gu", + "Unamused face": "Morn n\u00e4gu", + "Face with cold sweat": "N\u00e4gu k\u00fclma higiga", + "Pensive face": "M\u00f5tlik n\u00e4gu", + "Confused face": "Segaduses n\u00e4gu", + "Confounded face": "Segas n\u00e4gu", + "Kissing face": "Suudlevad n\u00e4gu", + "Face throwing a kiss": "N\u00e4gu viskamine suudlus", + "Kissing face with smiling eyes": "Suudlevad n\u00e4gu naeratab silmad", + "Kissing face with closed eyes": "Suudlevad n\u00e4gu, silmad kinni", + "Face with stuck out tongue": "N\u00e4gu ummikus v\u00e4lja keele", + "Face with stuck out tongue and winking eye": "N\u00e4gu ummikus v\u00e4lja keele ja silma pilgutav silma", + "Face with stuck out tongue and tightly-closed eyes": "N\u00e4gu ummikus v\u00e4lja keele ja silmad tihedalt suletuna", + "Disappointed face": "Pettunud n\u00e4gu", + "Worried face": "Mures n\u00e4gu", + "Angry face": "Vihane n\u00e4gu", + "Pouting face": "Tursik n\u00e4gu", + "Crying face": "Nutt n\u00e4gu", + "Persevering face": "Püsiv n\u00e4gu", + "Face with look of triumph": "N\u00e4gu ilme triumf", + "Disappointed but relieved face": "Pettunud kuid vabastati n\u00e4gu", + "Frowning face with open mouth": "Kulmukortsutav n\u00e4gu avatud suuga", + "Anguished face": "Ahastavad n\u00e4gu", + "Fearful face": "Hirmunult n\u00e4gu", + "Weary face": "Grimasse", + "Sleepy face": "Unine n\u00e4gu", + "Tired face": "V\u00e4sinud n\u00e4gu", + "Grimacing face": "Grimassitavaks n\u00e4gu", + "Loudly crying face": "Valjusti nutma n\u00e4gu", + "Face with open mouth": "N\u00e4gu avatud suuga", + "Hushed face": "Raskel n\u00e4gu", + "Face with open mouth and cold sweat": "N\u00e4gu avatud suu ja k\u00fclm higi", + "Face screaming in fear": "N\u00e4gu karjuvad hirm", + "Astonished face": "Lummatud n\u00e4gu", + "Flushed face": "Punetav n\u00e4gu", + "Sleeping face": "Uinuv n\u00e4gu", + "Dizzy face": "Uimane n\u00fcgu", + "Face without mouth": "N\u00e4gu ilma suu", + "Face with medical mask": "N\u00e4gu meditsiinilise mask", + + // Line breaker + "Break": "Murdma", + + // Math + "Subscript": "Allindeks", + "Superscript": "\u00dclaindeks", + + // Full screen + "Fullscreen": "T\u00e4isekraanil", + + // Horizontal line + "Insert Horizontal Line": "Sisesta horisontaalne joon", + + // Clear formatting + "Clear Formatting": "Eemalda formaatimine", + + // Save + "Save": "Salvesta", + + // Undo, redo + "Undo": "V\u00f5ta tagasi", + "Redo": "Tee uuesti", + + // Select all + "Select All": "Vali k\u00f5ik", + + // Code view + "Code View": "Koodi vaadata", + + // Quote + "Quote": "Tsitaat", + "Increase": "Suurendama", + "Decrease": "V\u00e4henda", + + // Quick Insert + "Quick Insert": "Kiire sisestada", + + // Spcial Characters + "Special Characters": "Erimärgid", + "Latin": "Latin", + "Greek": "Kreeka keel", + "Cyrillic": "Kirillitsa", + "Punctuation": "Kirjavahemärgid", + "Currency": "Valuuta", + "Arrows": "Nooled", + "Math": "Matemaatika", + "Misc": "Misc", + + // Print. + "Print": "Printige", + + // Spell Checker. + "Spell Checker": "Õigekirja kontrollija", + + // Help + "Help": "Abi", + "Shortcuts": "Otseteed", + "Inline Editor": "Sisemine redaktor", + "Show the editor": "Näita redaktorit", + "Common actions": "Ühised meetmed", + "Copy": "Koopia", + "Cut": "Lõigake", + "Paste": "Kleepige", + "Basic Formatting": "Põhiline vormindamine", + "Increase quote level": "Suurendada tsiteerimise taset", + "Decrease quote level": "Langetada tsiteerimise tase", + "Image / Video": "Pilt / video", + "Resize larger": "Suuruse muutmine suurem", + "Resize smaller": "Väiksema suuruse muutmine", + "Table": "Laud", + "Select table cell": "Vali tabeli lahtrisse", + "Extend selection one cell": "Laiendage valikut üks lahtrisse", + "Extend selection one row": "Laiendage valikut ühe reana", + "Navigation": "Navigeerimine", + "Focus popup / toolbar": "Fookuse hüpikakna / tööriistariba", + "Return focus to previous position": "Tagasi pöörata tähelepanu eelmisele positsioonile", + + // Embed.ly + "Embed URL": "Embed url", + "Paste in a URL to embed": "Kleepige URL-i sisestamiseks", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Kleepitud sisu pärineb Microsoft Wordi dokumendist. kas soovite vormi säilitada või puhastada?", + "Keep": "Pidage seda", + "Clean": "Puhas", + "Word Paste Detected": "Avastatud sõna pasta" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/fa.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/fa.js new file mode 100644 index 0000000..c843076 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/fa.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Persian + */ + +$.FE.LANGUAGE['fa'] = { + translation: { + // Place holder + "Type something": "\u0686\u06cc\u0632\u06cc \u0628\u0646\u0648\u06cc\u0633\u06cc\u062f", + + // Basic formatting + "Bold": "ضخیم", + "Italic": "خط کج", + "Underline": "خط زیر", + "Strikethrough": "\u062e\u0637 \u062e\u0648\u0631\u062f\u0647", + + // Main buttons + "Insert": "\u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646", + "Delete": "\u062d\u0630\u0641 \u06a9\u0631\u062f\u0646", + "Cancel": "\u0644\u063a\u0648", + "OK": "\u0628\u0627\u0634\u0647", + "Back": "\u0628\u0647 \u0639\u0642\u0628", + "Remove": "\u0628\u0631\u062f\u0627\u0634\u062a\u0646", + "More": "\u0628\u06cc\u0634\u062a\u0631", + "Update": "\u0628\u0647 \u0631\u0648\u0632 \u0631\u0633\u0627\u0646\u06cc", + "Style": "\u0633\u0628\u06a9", + + // Font + "Font Family": "\u0642\u0644\u0645", + "Font Size": "\u0627\u0646\u062f\u0627\u0632\u0647 \u0642\u0644\u0645", + + // Colors + "Colors": "\u0631\u0646\u06af", + "Background": "\u0632\u0645\u06cc\u0646\u0647 \u0645\u062a\u0646", + "Text": "\u0645\u062a\u0646", + "HEX Color": "کد رنگ", + + // Paragraphs + "Paragraph Format": "\u0642\u0627\u0644\u0628", + "Normal": "\u0637\u0628\u06cc\u0639\u06cc - Normal", + "Code": "\u062f\u0633\u062a\u0648\u0631\u0627\u0644\u0639\u0645\u0644\u0647\u0627 - Code", + "Heading 1": "\u0633\u0631\u200c\u0635\u0641\u062d\u0647 1", + "Heading 2": "\u0633\u0631\u200c\u0635\u0641\u062d\u0647 2", + "Heading 3": "\u0633\u0631\u200c\u0635\u0641\u062d\u0647 3", + "Heading 4": "\u0633\u0631\u200c\u0635\u0641\u062d\u0647 4", + + // Style + "Paragraph Style": "\u067e\u0627\u0631\u0627\u06af\u0631\u0627\u0641 \u0633\u0628\u06a9", + "Inline Style": "\u062e\u0637\u06cc \u0633\u0628\u06a9", + + // Alignment + "Align": "\u0631\u062f\u06cc\u0641 \u0628\u0646\u062f\u06cc \u0646\u0648\u0634\u062a\u0647", + "Align Left": "\u0686\u067e \u0686\u06cc\u0646", + "Align Center": "\u0648\u0633\u0637 \u0686\u06cc\u0646", + "Align Right": "\u0631\u0627\u0633\u062a \u0686\u06cc\u0646", + "Align Justify": "\u0645\u0633\u0627\u0648\u06cc \u0627\u0632 \u0637\u0631\u0641\u06cc\u0646", + "None": "\u0647\u06cc\u0686", + + // Lists + "Ordered List": "\u0644\u06cc\u0633\u062a \u0634\u0645\u0627\u0631\u0647 \u0627\u06cc", + "Default": "به طور پیش فرض", + "Lower Alpha": "آلفای پایین", + "Lower Greek": "قرن پایین تر", + "Lower Roman": "رومی پایین تر", + "Upper Alpha": "آلفای بالا", + "Upper Roman": "رومانی بالا", + + "Unordered List": "\u0644\u06cc\u0633\u062a \u062f\u0627\u06cc\u0631\u0647 \u0627\u06cc", + "Circle": "دایره", + "Disc": "دیسک", + "Square": "مربع", + + // Line height + "Line Height": "ارتفاع خط", + "Single": "تنها", + "Double": "دو برابر", + + // Indent + "Decrease Indent": "\u06a9\u0627\u0647\u0634 \u062a\u0648 \u0631\u0641\u062a\u06af\u06cc", + "Increase Indent": "\u0627\u0641\u0632\u0627\u06cc\u0634 \u062a\u0648 \u0631\u0641\u062a\u06af\u06cc", + + // Links + "Insert Link": "\u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u0644\u06cc\u0646\u06a9", + "Open in new tab": "\u0628\u0627\u0632 \u06a9\u0631\u062f\u0646 \u062f\u0631 \u0628\u0631\u06af\u0647 \u062c\u062f\u06cc\u062f", + "Open Link": "\u0644\u06cc\u0646\u06a9 \u0647\u0627\u06cc \u0628\u0627\u0632", + "Edit Link": "\u0644\u06cc\u0646\u06a9 \u0648\u06cc\u0631\u0627\u06cc\u0634", + "Unlink": "\u062d\u0630\u0641 \u0644\u06cc\u0646\u06a9", + "Choose Link": "\u0644\u06cc\u0646\u06a9 \u0631\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u06cc\u062f", + + // Images + "Insert Image": "\u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u062a\u0635\u0648\u06cc\u0631", + "Upload Image": "\u0622\u067e\u0644\u0648\u062f \u062a\u0635\u0648\u06cc\u0631", + "By URL": "URL \u062a\u0648\u0633\u0637", + "Browse": "\u0641\u0647\u0631\u0633\u062a", + "Drop image": "\u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u0627\u06cc\u0646\u062c\u0627 \u0628\u06cc\u0646\u062f\u0627\u0632\u06cc\u062f", + "or click": "\u06cc\u0627 \u06a9\u0644\u06cc\u06a9 \u06a9\u0646\u06cc\u062f", + "Manage Images": "\u0645\u062f\u06cc\u0631\u06cc\u062a \u062a\u0635\u0627\u0648\u06cc\u0631", + "Loading": "\u0628\u0627\u0631\u06af\u06cc\u0631\u06cc", + "Deleting": "\u062d\u0630\u0641", + "Tags": "\u0628\u0631\u0686\u0633\u0628 \u0647\u0627", + "Are you sure? Image will be deleted.": ".\u0622\u06cc\u0627 \u0645\u0637\u0645\u0626\u0646 \u0647\u0633\u062a\u06cc\u062f\u061f \u062a\u0635\u0648\u06cc\u0631 \u062d\u0630\u0641 \u062e\u0648\u0627\u0647\u062f \u0634\u062f", + "Replace": "\u062c\u0627\u06cc\u06af\u0632\u06cc\u0646 \u06a9\u0631\u062f\u0646", + "Uploading": "\u0622\u067e\u0644\u0648\u062f", + "Loading image": "\u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u062a\u0635\u0648\u06cc\u0631", + "Display": "\u0646\u0634\u0627\u0646 \u062f\u0627\u062f\u0646", + "Inline": "\u062e\u0637\u06cc", + "Break Text": "\u0634\u06a9\u0633\u062a\u0646 \u0627\u0633\u062a\u0631\u0627\u062d\u062a", + "Alternative Text": "\u0645\u062a\u0646 \u062c\u0627\u06cc\u06af\u0632\u06cc\u0646", + "Change Size": "\u062a\u063a\u06cc\u06cc\u0631 \u0627\u0646\u062f\u0627\u0632\u0647", + "Width": "\u0639\u0631\u0636", + "Height": "\u0627\u0631\u062a\u0641\u0627\u0639", + "Something went wrong. Please try again.": "خطایی رخ داده است ، لطفا مجددا تلاش کنید", + "Image Caption": "عنوان تصویر", + "Advanced Edit": "ویرایش پیشرفته", + + // Video + "Insert Video": "\u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u0641\u0627\u06cc\u0644 \u062a\u0635\u0648\u06cc\u0631\u06cc", + "Embedded Code": "\u06a9\u062f \u062c\u0627\u0633\u0627\u0632\u06cc \u0634\u062f\u0647", + "Paste in a video URL": "در URL ویدیو وارد کنید", + "Drop video": "رها کردن ویدیو", + "Your browser does not support HTML5 video.": "مرورگر شما ویدیو HTML5 را پشتیبانی نمی کند.", + "Upload Video": "آپلود ویدیو", + + // Tables + "Insert Table": "\u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u062c\u062f\u0648\u0644", + "Table Header": "\u0647\u062f\u0631 \u062c\u062f\u0648\u0644", + "Remove Table": "\u062d\u0630\u0641 \u062c\u062f\u0648\u0644", + "Table Style": "\u0633\u0628\u06a9 \u062c\u062f\u0648\u0644", + "Horizontal Align": "\u062a\u0646\u0638\u06cc\u0645 \u0627\u0641\u0642\u06cc", + "Row": "\u0633\u0637\u0631", + "Insert row above": "\u062f\u0631\u062c \u0631\u062f\u06cc\u0641 \u062f\u0631 \u0628\u0627\u0644\u0627", + "Insert row below": "\u0633\u0637\u0631 \u0632\u06cc\u0631 \u0631\u0627 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f", + "Delete row": "\u062d\u0630\u0641 \u0633\u0637\u0631", + "Column": "\u0633\u062a\u0648\u0646", + "Insert column before": "\u062f\u0631\u062c \u0633\u062a\u0648\u0646 \u0642\u0628\u0644", + "Insert column after": "\u062f\u0631\u062c \u0633\u062a\u0648\u0646 \u0628\u0639\u062f", + "Delete column": "\u062d\u0630\u0641 \u0633\u062a\u0648\u0646", + "Cell": "\u0633\u0644\u0648\u0644", + "Merge cells": "\u0627\u062f\u063a\u0627\u0645 \u0633\u0644\u0648\u0644\u200c\u0647\u0627", + "Horizontal split": "\u062a\u0642\u0633\u06cc\u0645 \u0627\u0641\u0642\u06cc", + "Vertical split": "\u062a\u0642\u0633\u06cc\u0645 \u0639\u0645\u0648\u062f\u06cc", + "Cell Background": "\u067e\u0633 \u0632\u0645\u06cc\u0646\u0647 \u0647\u0645\u0631\u0627\u0647", + "Vertical Align": "\u0631\u062f\u06cc\u0641 \u0639\u0645\u0648\u062f\u06cc", + "Top": "\u0628\u0627\u0644\u0627", + "Middle": "\u0645\u062a\u0648\u0633\u0637", + "Bottom": "\u067e\u0627\u06cc\u06cc\u0646", + "Align Top": "\u062a\u0631\u0627\u0632 \u0628\u0627\u0644\u0627\u06cc", + "Align Middle": "\u062a\u0631\u0627\u0632 \u0648\u0633\u0637", + "Align Bottom": "\u062a\u0631\u0627\u0632 \u067e\u0627\u06cc\u06cc\u0646", + "Cell Style": "\u0633\u0628\u06a9 \u0647\u0627\u06cc \u0647\u0645\u0631\u0627\u0647", + + // Files + "Upload File": "\u0622\u067e\u0644\u0648\u062f \u0641\u0627\u06cc\u0644", + "Drop file": "\u0627\u0641\u062a \u0641\u0627\u06cc\u0644", + + // Emoticons + "Emoticons": "\u0634\u06a9\u0644\u06a9 \u0647\u0627", + "Grinning face": "\u0686\u0647\u0631\u0647 \u067e\u0648\u0632\u062e\u0646\u062f", + "Grinning face with smiling eyes": "\u0686\u0647\u0631\u0647 \u067e\u0648\u0632\u062e\u0646\u062f \u0628\u0627 \u0686\u0634\u0645\u0627\u0646 \u062e\u0646\u062f\u0627\u0646", + "Face with tears of joy": "\u0686\u0647\u0631\u0647 \u0628\u0627 \u0627\u0634\u06a9 \u0634\u0627\u062f\u06cc", + "Smiling face with open mouth": "\u0686\u0647\u0631\u0647 \u062e\u0646\u062f\u0627\u0646 \u0628\u0627 \u062f\u0647\u0627\u0646 \u0628\u0627\u0632", + "Smiling face with open mouth and smiling eyes": "\u0686\u0647\u0631\u0647 \u062e\u0646\u062f\u0627\u0646 \u0628\u0627 \u062f\u0647\u0627\u0646 \u0628\u0627\u0632 \u0648 \u062e\u0646\u062f\u0627\u0646 \u0686\u0634\u0645", + "Smiling face with open mouth and cold sweat": "\u0686\u0647\u0631\u0647 \u062e\u0646\u062f\u0627\u0646 \u0628\u0627 \u062f\u0647\u0627\u0646 \u0628\u0627\u0632 \u0648 \u0639\u0631\u0642 \u0633\u0631\u062f", + "Smiling face with open mouth and tightly-closed eyes": "\u0686\u0647\u0631\u0647 \u062e\u0646\u062f\u0627\u0646 \u0628\u0627 \u062f\u0647\u0627\u0646 \u0628\u0627\u0632 \u0648 \u0686\u0634\u0645 \u062f\u0631\u0628\u062f\u0627\u0631", + "Smiling face with halo": "\u0686\u0647\u0631\u0647 \u062e\u0646\u062f\u0627\u0646 \u0628\u0627 \u0647\u0627\u0644\u0647", + "Smiling face with horns": "\u0686\u0647\u0631\u0647 \u062e\u0646\u062f\u0627\u0646 \u0628\u0627 \u0634\u0627\u062e", + "Winking face": "\u062d\u0631\u06a9\u062a \u067e\u0630\u06cc\u0631\u06cc", + "Smiling face with smiling eyes": "\u0686\u0647\u0631\u0647 \u062e\u0646\u062f\u0627\u0646 \u0628\u0627 \u0686\u0634\u0645 \u0644\u0628\u062e\u0646\u062f", + "Face savoring delicious food": "\u0686\u0647\u0631\u0647 \u0644\u0630\u06cc\u0630 \u063a\u0630\u0627\u06cc \u062e\u0648\u0634\u0645\u0632\u0647", + "Relieved face": "\u0686\u0647\u0631\u0647 \u0631\u0647\u0627", + "Smiling face with heart-shaped eyes": "\u0686\u0647\u0631\u0647 \u062e\u0646\u062f\u0627\u0646 \u0628\u0627 \u0686\u0634\u0645 \u0628\u0647 \u0634\u06a9\u0644 \u0642\u0644\u0628", + "Smiling face with sunglasses": "\u0686\u0647\u0631\u0647 \u062e\u0646\u062f\u0627\u0646 \u0628\u0627 \u0639\u06cc\u0646\u06a9 \u0622\u0641\u062a\u0627\u0628\u06cc", + "Smirking face": "\u067e\u0648\u0632\u062e\u0646\u062f \u0686\u0647\u0631\u0647", + "Neutral face": "\u0686\u0647\u0631\u0647 \u0647\u0627\u06cc \u062e\u0646\u062b\u06cc", + "Expressionless face": "\u0686\u0647\u0631\u0647 \u0646\u0627\u06af\u0648\u06cc\u0627", + "Unamused face": "\u0686\u0647\u0631\u0647 \u062e\u0648\u0634\u062d\u0627\u0644 \u0646\u06cc\u0633\u062a", + "Face with cold sweat": "\u0686\u0647\u0631\u0647 \u0628\u0627 \u0639\u0631\u0642 \u0633\u0631\u062f", + "Pensive face": "\u0686\u0647\u0631\u0647 \u0627\u0641\u0633\u0631\u062f\u0647", + "Confused face": "\u0686\u0647\u0631\u0647 \u0627\u0634\u062a\u0628\u0627\u0647", + "Confounded face": "\u0686\u0647\u0631\u0647 \u0633\u0631 \u062f\u0631 \u06af\u0645", + "Kissing face": "\u0628\u0648\u0633\u06cc\u062f\u0646 \u0635\u0648\u0631\u062a", + "Face throwing a kiss": "\u0686\u0647\u0631\u0647 \u067e\u0631\u062a\u0627\u0628 \u06cc\u06a9 \u0628\u0648\u0633\u0647", + "Kissing face with smiling eyes": "\u0628\u0648\u0633\u06cc\u062f\u0646 \u0686\u0647\u0631\u0647 \u0628\u0627 \u0686\u0634\u0645 \u0644\u0628\u062e\u0646\u062f", + "Kissing face with closed eyes": "\u0628\u0648\u0633\u06cc\u062f\u0646 \u0635\u0648\u0631\u062a \u0628\u0627 \u0686\u0634\u0645\u0627\u0646 \u0628\u0633\u062a\u0647", + "Face with stuck out tongue": "\u0686\u0647\u0631\u0647 \u0628\u0627 \u06af\u06cc\u0631 \u06a9\u0631\u062f\u0646 \u0632\u0628\u0627\u0646", + "Face with stuck out tongue and winking eye": "\u0686\u0647\u0631\u0647 \u0628\u0627 \u0632\u0628\u0627\u0646 \u06af\u06cc\u0631 \u06a9\u0631\u062f\u0646 \u0648 \u062d\u0631\u06a9\u062a \u0686\u0634\u0645", + "Face with stuck out tongue and tightly-closed eyes": "\u0635\u0648\u0631\u062a \u0628\u0627 \u0632\u0628\u0627\u0646 \u06af\u06cc\u0631 \u06a9\u0631\u062f\u0646 \u0648 \u0686\u0634\u0645 \u0631\u0627 \u0645\u062d\u06a9\u0645 \u0628\u0633\u062a\u0647", + "Disappointed face": "\u0686\u0647\u0631\u0647 \u0646\u0627 \u0627\u0645\u06cc\u062f", + "Worried face": "\u0686\u0647\u0631\u0647 \u0646\u06af\u0631\u0627\u0646", + "Angry face": "\u0686\u0647\u0631\u0647 \u0639\u0635\u0628\u0627\u0646\u06cc", + "Pouting face": "\u0628\u063a \u0686\u0647\u0631\u0647", + "Crying face": "\u06af\u0631\u06cc\u0647 \u0686\u0647\u0631\u0647", + "Persevering face": "\u067e\u0627\u06cc\u062f\u0627\u0631\u06cc \u0686\u0647\u0631\u0647", + "Face with look of triumph": "\u0686\u0647\u0631\u0647 \u0628\u0627 \u0646\u06af\u0627\u0647\u06cc \u0627\u0632 \u067e\u06cc\u0631\u0648\u0632\u06cc", + "Disappointed but relieved face": "\u0646\u0627 \u0627\u0645\u06cc\u062f \u0627\u0645\u0627 \u0622\u0633\u0648\u062f\u0647 \u0686\u0647\u0631\u0647", + "Frowning face with open mouth": "\u0627\u062e\u0645 \u0635\u0648\u0631\u062a \u0628\u0627 \u062f\u0647\u0627\u0646 \u0628\u0627\u0632", + "Anguished face": "\u0686\u0647\u0631\u0647 \u0646\u06af\u0631\u0627\u0646", + "Fearful face": "\u0686\u0647\u0631\u0647 \u062a\u0631\u0633", + "Weary face": "\u0686\u0647\u0631\u0647 \u062e\u0633\u062a\u0647", + "Sleepy face": "\u0686\u0647\u0631\u0647 \u062e\u0648\u0627\u0628 \u0622\u0644\u0648\u062f", + "Tired face": "\u0686\u0647\u0631\u0647 \u062e\u0633\u062a\u0647", + "Grimacing face": "\u0627\u0634 \u0686\u0647\u0631\u0647", + "Loudly crying face": "\u0646\u062f\u0627\u06cc\u06cc \u0631\u0633\u0627 \u06af\u0631\u06cc\u0647 \u0686\u0647\u0631\u0647", + "Face with open mouth": "\u0686\u0647\u0631\u0647 \u0628\u0627 \u062f\u0647\u0627\u0646 \u0628\u0627\u0632", + "Hushed face": "\u0686\u0647\u0631\u0647 \u0633\u06a9\u0648\u062a", + "Face with open mouth and cold sweat": "\u0686\u0647\u0631\u0647 \u0628\u0627 \u062f\u0647\u0627\u0646 \u0628\u0627\u0632 \u0648 \u0639\u0631\u0642 \u0633\u0631\u062f", + "Face screaming in fear": "\u0686\u0647\u0631\u0647 \u062c\u06cc\u063a \u062f\u0631 \u062a\u0631\u0633", + "Astonished face": "\u0686\u0647\u0631\u0647 \u0634\u06af\u0641\u062a \u0632\u062f\u0647", + "Flushed face": "\u0686\u0647\u0631\u0647 \u0628\u0631\u0627\u0641\u0631\u0648\u062e\u062a\u0647", + "Sleeping face": "\u062e\u0648\u0627\u0628 \u0686\u0647\u0631\u0647", + "Dizzy face": "\u0686\u0647\u0631\u0647 \u062f\u06cc\u0632\u06cc", + "Face without mouth": "\u0686\u0647\u0631\u0647 \u0628\u062f\u0648\u0646 \u062f\u0647\u0627\u0646", + "Face with medical mask": "\u0686\u0647\u0631\u0647 \u0628\u0627 \u0645\u0627\u0633\u06a9 \u0647\u0627\u06cc \u067e\u0632\u0634\u06a9\u06cc", + + // Line breaker + "Break": "\u0634\u06a9\u0633\u062a\u0646", + + // Math + "Subscript": "\u067e\u0627\u064a\u064a\u0646 \u0646\u0648\u064a\u0633", + "Superscript": "\u0628\u0627\u0644\u0627 \u0646\u06af\u0627\u0634\u062a", + + // Full screen + "Fullscreen": "\u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647", + + // Horizontal line + "Insert Horizontal Line": "\u0642\u0631\u0627\u0631 \u062f\u0627\u062f\u0646 \u0627\u0641\u0642\u06cc \u062e\u0637", + + // Clear formatting + "Clear Formatting": "\u062d\u0630\u0641 \u0642\u0627\u0644\u0628 \u0628\u0646\u062f\u06cc", + + // Save + "Save": "\u0635\u0631\u0641\u0647 \u062c\u0648\u06cc\u06cc", + + // Undo, redo + "Undo": "\u0628\u0627\u0637\u0644 \u06a9\u0631\u062f\u0646", + "Redo": "\u0627\u0646\u062c\u0627\u0645 \u062f\u0648\u0628\u0627\u0631\u0647", + + // Select all + "Select All": "\u0627\u0646\u062a\u062e\u0627\u0628 \u0647\u0645\u0647", + + // Code view + "Code View": "\u0645\u0634\u0627\u0647\u062f\u0647 \u06a9\u062f", + + // Quote + "Quote": "\u0646\u0642\u0644 \u0642\u0648\u0644", + "Increase": "\u0627\u0641\u0632\u0627\u06cc\u0634 \u062f\u0627\u062f\u0646", + "Decrease": "\u0646\u0632\u0648\u0644 \u06a9\u0631\u062f\u0646", + + // Quick Insert + "Quick Insert": "\u062f\u0631\u062c \u0633\u0631\u06cc\u0639", + + // Spcial Characters + "Special Characters": "کاراکترهای خاص", + "Latin": "لاتین", + "Greek": "یونانی", + "Cyrillic": "سیریلیک", + "Punctuation": "نقطه گذاری", + "Currency": "واحد پول", + "Arrows": "فلش ها", + "Math": "ریاضی", + "Misc": "متاسفم", + + // Print. + "Print": "چاپ", + + // Spell Checker. + "Spell Checker": "بررسی کننده غلط املایی", + + // Help + "Help": "کمک", + "Shortcuts": "کلید های میانبر", + "Inline Editor": "ویرایشگر خطی", + "Show the editor": "ویرایشگر را نشان بده", + "Common actions": "اقدامات مشترک", + "Copy": "کپی کنید", + "Cut": "برش", + "Paste": "چسباندن", + "Basic Formatting": "قالب بندی اولیه", + "Increase quote level": "افزایش سطح نقل قول", + "Decrease quote level": "کاهش میزان نقل قول", + "Image / Video": "تصویر / ویدئو", + "Resize larger": "تغییر اندازه بزرگتر", + "Resize smaller": "تغییر اندازه کوچکتر", + "Table": "جدول", + "Select table cell": "سلول جدول را انتخاب کنید", + "Extend selection one cell": "انتخاب یک سلول را گسترش دهید", + "Extend selection one row": "یک ردیف را انتخاب کنید", + "Navigation": "جهت یابی", + "Focus popup / toolbar": "تمرکز پنجره / نوار ابزار", + "Return focus to previous position": "تمرکز بازگشت به موقعیت قبلی", + + // Embed.ly + "Embed URL": "آدرس جاسازی", + "Paste in a URL to embed": "یک URL برای جاسازی کپی کنید", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "محتوای جا به جا از یک سند Word Microsoft می آید. آیا می خواهید فرمت را نگه دارید یا پاک کنید؟", + "Keep": "نگاه داشتن", + "Clean": "پاک کن", + "Word Paste Detected": "کلمه رب تشخیص داده شده است" + }, + direction: "rtl" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/fi.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/fi.js new file mode 100644 index 0000000..f6ebc8e --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/fi.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Finnish + */ + +$.FE.LANGUAGE['fi'] = { + translation: { + // Place holder + "Type something": "Kirjoita jotain", + + // Basic formatting + "Bold": "Lihavointi", + "Italic": "Kursivointi", + "Underline": "Alleviivaus", + "Strikethrough": "Yliviivaus", + + // Main buttons + "Insert": "Lis\u00e4\u00e4", + "Delete": "Poista", + "Cancel": "Peruuta", + "OK": "Ok", + "Back": "Takaisin", + "Remove": "Poista", + "More": "Lis\u00e4\u00e4", + "Update": "P\u00e4ivitys", + "Style": "Tyyli", + + // Font + "Font Family": "Fontti", + "Font Size": "Fonttikoko", + + // Colors + "Colors": "V\u00e4rit", + "Background": "Taustan", + "Text": "Tekstin", + "HEX Color": "Heksadesimaali", + + // Paragraphs + "Paragraph Format": "Muotoilut", + "Normal": "Normaali", + "Code": "Koodi", + "Heading 1": "Otsikko 1", + "Heading 2": "Otsikko 2", + "Heading 3": "Otsikko 3", + "Heading 4": "Otsikko 4", + + // Style + "Paragraph Style": "Kappaleen tyyli", + "Inline Style": "Linjassa tyyli", + + // Alignment + "Align": "Tasaa", + "Align Left": "Tasaa vasemmalle", + "Align Center": "Keskit\u00e4", + "Align Right": "Tasaa oikealle", + "Align Justify": "Tasaa", + "None": "Ei mit\u00e4\u00e4n", + + // Lists + "Ordered List": "J\u00e4rjestetty lista", + "Default": "Oletusarvo", + "Lower Alpha": "Alempi alfa", + "Lower Greek": "Alempi kreikka", + "Lower Roman": "Alempi roomalainen", + "Upper Alpha": "Ylempi alfa", + "Upper Roman": "Ylempi roomalainen", + + "Unordered List": "J\u00e4rjest\u00e4m\u00e4t\u00f6n lista", + "Circle": "Ympyrä", + "Disc": "Levy", + "Square": "Neliö-", + + // Line height + "Line Height": "Viivankorkeus", + "Single": "Yksittäinen", + "Double": "Kaksinkertainen", + + // Indent + "Decrease Indent": "Sisenn\u00e4", + "Increase Indent": "Loitonna", + + // Links + "Insert Link": "Lis\u00e4\u00e4 linkki", + "Open in new tab": "Avaa uudessa v\u00e4lilehdess\u00e4", + "Open Link": "Avaa linkki", + "Edit Link": "Muokkaa linkki", + "Unlink": "Poista linkki", + "Choose Link": "Valitse linkki", + + // Images + "Insert Image": "Lis\u00e4\u00e4 kuva", + "Upload Image": "Lataa kuva", + "By URL": "Mukaan URL", + "Browse": "Selailla", + "Drop image": "Pudota kuva", + "or click": "tai napsauta", + "Manage Images": "Hallitse kuvia", + "Loading": "Lastaus", + "Deleting": "Poistaminen", + "Tags": "Tagit", + "Are you sure? Image will be deleted.": "Oletko varma? Kuva poistetaan.", + "Replace": "Vaihda", + "Uploading": "Lataaminen", + "Loading image": "Lastaus kuva", + "Display": "N\u00e4ytt\u00e4", + "Inline": "Linjassa", + "Break Text": "Rikkoa teksti", + "Alternative Text": "Vaihtoehtoinen teksti", + "Change Size": "Muuta kokoa", + "Width": "Leveys", + "Height": "Korkeus", + "Something went wrong. Please try again.": "Jotain meni pieleen. Yrit\u00e4 uudelleen.", + "Image Caption": "Kuva-otsikko", + "Advanced Edit": "Edistynyt muokkaus", + + // Video + "Insert Video": "Lis\u00e4\u00e4 video", + "Embedded Code": "Upotettu koodi", + "Paste in a video URL": "Liitä video url", + "Drop video": "Pudota video", + "Your browser does not support HTML5 video.": "Selaimesi ei tue html5-videota.", + "Upload Video": "Lataa video", + + // Tables + "Insert Table": "Lis\u00e4\u00e4 taulukko", + "Table Header": "Taulukko yl\u00e4tunniste", + "Remove Table": "Poista taulukko", + "Table Style": "Taulukko tyyli", + "Horizontal Align": "Vaakasuora tasaa", + "Row": "Rivi", + "Insert row above": "Lis\u00e4\u00e4 rivi ennen", + "Insert row below": "Lis\u00e4\u00e4 rivi j\u00e4lkeen", + "Delete row": "Poista rivi", + "Column": "Sarake", + "Insert column before": "Lis\u00e4\u00e4 sarake ennen", + "Insert column after": "Lis\u00e4\u00e4 sarake j\u00e4lkeen", + "Delete column": "Poista sarake", + "Cell": "Solu", + "Merge cells": "Yhdist\u00e4 solut", + "Horizontal split": "Jaa vaakasuora", + "Vertical split": "Jaa pystysuora", + "Cell Background": "Solun tausta", + "Vertical Align": "Pystysuora tasaa", + "Top": "Alku", + "Middle": "Keskimm\u00e4inen", + "Bottom": "Pohja", + "Align Top": "Tasaa alkuun", + "Align Middle": "Tasaa keskimm\u00e4inen", + "Align Bottom": "Tasaa pohja", + "Cell Style": "Solun tyyli", + + // Files + "Upload File": "Lataa tiedosto", + "Drop file": "Pudota tiedosto", + + // Emoticons + "Emoticons": "Hymi\u00f6it\u00e4", + "Grinning face": "Virnisteli kasvot", + "Grinning face with smiling eyes": "Virnisteli kasvot hymyilev\u00e4t silm\u00e4t", + "Face with tears of joy": "Kasvot ilon kyyneleit\u00e4", + "Smiling face with open mouth": "Hymyilev\u00e4 kasvot suu auki", + "Smiling face with open mouth and smiling eyes": "Hymyilev\u00e4 kasvot suu auki ja hymyilee silm\u00e4t", + "Smiling face with open mouth and cold sweat": "Hymyilev\u00e4 kasvot suu auki ja kylm\u00e4 hiki", + "Smiling face with open mouth and tightly-closed eyes": "Hymyilev\u00e4 kasvot suu auki ja tiiviisti suljettu silm\u00e4t", + "Smiling face with halo": "Hymyilev\u00e4 kasvot Halo", + "Smiling face with horns": "Hymyilev\u00e4 kasvot sarvet", + "Winking face": "Silm\u00e4niskut kasvot", + "Smiling face with smiling eyes": "Hymyilev\u00e4 kasvot hymyilev\u00e4t silm\u00e4t", + "Face savoring delicious food": "Kasvot maistella herkullista ruokaa", + "Relieved face": "Vapautettu kasvot", + "Smiling face with heart-shaped eyes": "Hymyilev\u00e4t kasvot syd\u00e4men muotoinen silm\u00e4t", + "Smiling face with sunglasses": "Hymyilev\u00e4 kasvot aurinkolasit", + "Smirking face": "Hym\u00e4t\u00e4\u00e4 kasvot", + "Neutral face": "Neutraali kasvot", + "Expressionless face": "Ilmeet\u00f6n kasvot", + "Unamused face": "Ei huvittanut kasvo", + "Face with cold sweat": "Kasvot kylm\u00e4 hiki", + "Pensive face": "Mietteli\u00e4s kasvot", + "Confused face": "Sekava kasvot", + "Confounded face": "Sekoitti kasvot", + "Kissing face": "Suudella kasvot", + "Face throwing a kiss": "Kasvo heitt\u00e4\u00e4 suudelma", + "Kissing face with smiling eyes": "Suudella kasvot hymyilev\u00e4t silm\u00e4t", + "Kissing face with closed eyes": "Suudella kasvot silm\u00e4t ummessa", + "Face with stuck out tongue": "Kasvot ojensi kieli", + "Face with stuck out tongue and winking eye": "Kasvot on juuttunut pois kielen ja silm\u00e4niskuja silm\u00e4", + "Face with stuck out tongue and tightly-closed eyes": "Kasvot on juuttunut pois kielen ja tiiviisti suljettuna silm\u00e4t", + "Disappointed face": "Pettynyt kasvot", + "Worried face": "Huolissaan kasvot", + "Angry face": "Vihainen kasvot", + "Pouting face": "Pouting kasvot", + "Crying face": "Itku kasvot", + "Persevering face": "Pitk\u00e4j\u00e4nteinen kasvot", + "Face with look of triumph": "Kasvot ilme Triumph", + "Disappointed but relieved face": "Pettynyt mutta helpottunut kasvot", + "Frowning face with open mouth": "Frowning kasvot suu auki", + "Anguished face": "Tuskainen kasvot", + "Fearful face": "Pelokkuus kasvot", + "Weary face": "V\u00e4synyt kasvot", + "Sleepy face": "Unelias kasvot", + "Tired face": "V\u00e4synyt kasvot", + "Grimacing face": "Irvist\u00e4en kasvot", + "Loudly crying face": "\u00e4\u00e4nekk\u00e4\u00e4sti itku kasvot", + "Face with open mouth": "Kasvot suu auki", + "Hushed face": "Hiljentynyt kasvot", + "Face with open mouth and cold sweat": "Kasvot suu auki ja kylm\u00e4 hiki", + "Face screaming in fear": "Kasvot huutaa pelosta", + "Astonished face": "H\u00e4mm\u00e4stynyt kasvot", + "Flushed face": "Kasvojen punoitus", + "Sleeping face": "Nukkuva kasvot", + "Dizzy face": "Huimausta kasvot", + "Face without mouth": "Kasvot ilman suuhun", + "Face with medical mask": "Kasvot l\u00e4\u00e4ketieteen naamio", + + // Line breaker + "Break": "Rikkoa", + + // Math + "Subscript": "Alaindeksi", + "Superscript": "Yl\u00e4indeksi", + + // Full screen + "Fullscreen": "Koko n\u00e4ytt\u00f6", + + // Horizontal line + "Insert Horizontal Line": "Lis\u00e4\u00e4 vaakasuora viiva", + + // Clear formatting + "Clear Formatting": "Poista muotoilu", + + // Save + "Save": "Tallentaa", + + // Undo, redo + "Undo": "Peru", + "Redo": "Tee uudelleen", + + // Select all + "Select All": "Valitse kaikki", + + // Code view + "Code View": "Koodi n\u00e4kym\u00e4", + + // Quote + "Quote": "Lainaus", + "Increase": "Lis\u00e4t\u00e4", + "Decrease": "Pienenn\u00e4", + + // Quick Insert + "Quick Insert": "Nopea insertti", + + // Spcial Characters + "Special Characters": "Erikoismerkkejä", + "Latin": "Latina", + "Greek": "Kreikkalainen", + "Cyrillic": "Kyrillinen", + "Punctuation": "Välimerkit", + "Currency": "Valuutta", + "Arrows": "Nuolet", + "Math": "Matematiikka", + "Misc": "Sekalaista", + + // Print. + "Print": "Tulosta", + + // Spell Checker. + "Spell Checker": "Oikeinkirjoittaja", + + // Help + "Help": "Auta", + "Shortcuts": "Pikakuvakkeet", + "Inline Editor": "Inline-editori", + "Show the editor": "Näytä editori", + "Common actions": "Yhteisiä toimia", + "Copy": "Kopio", + "Cut": "Leikata", + "Paste": "Tahna", + "Basic Formatting": "Perusmuotoilu", + "Increase quote level": "Lisää lainaustasoa", + "Decrease quote level": "Laskea lainaustasoa", + "Image / Video": "Kuva / video", + "Resize larger": "Kokoa suurempi", + "Resize smaller": "Pienempi koko", + "Table": "Pöytä", + "Select table cell": "Valitse taulukon solu", + "Extend selection one cell": "Laajentaa valinta yhden solun", + "Extend selection one row": "Laajenna valinta yksi rivi", + "Navigation": "Suunnistus", + "Focus popup / toolbar": "Painopistevalo / työkalurivi", + "Return focus to previous position": "Palauta tarkennus edelliseen asentoon", + + // Embed.ly + "Embed URL": "Upottaa URL-osoite", + "Paste in a URL to embed": "Liitä upotettu URL-osoite", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Liitetty sisältö tulee Microsoft Word -asiakirjasta. Haluatko säilyttää muodon tai puhdistaa sen?", + "Keep": "Pitää", + "Clean": "Puhdas", + "Word Paste Detected": "Sana-tahna havaittu" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/fr.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/fr.js new file mode 100644 index 0000000..472171f --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/fr.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * French + */ + +$.FE.LANGUAGE['fr'] = { + translation: { + // Place holder + "Type something": "Tapez quelque chose", + + // Basic formatting + "Bold": "Gras", + "Italic": "Italique", + "Underline": "Soulign\u00e9", + "Strikethrough": "Barr\u00e9", + + // Main buttons + "Insert": "Ins\u00e9rer", + "Delete": "Supprimer", + "Cancel": "Annuler", + "OK": "Ok", + "Back": "Retour", + "Remove": "Supprimer", + "More": "Plus", + "Update": "Actualiser", + "Style": "Style", + + // Font + "Font Family": "Polices de caract\u00e8res", + "Font Size": "Taille de police", + + // Colors + "Colors": "Couleurs", + "Background": "Arri\u00e8re-plan", + "Text": "Texte", + "HEX Color": "Couleur hexad\u00e9cimale", + + // Paragraphs + "Paragraph Format": "Format de paragraphe", + "Normal": "Normal", + "Code": "Code", + "Heading 1": "Titre 1", + "Heading 2": "Titre 2", + "Heading 3": "Titre 3", + "Heading 4": "Titre 4", + + // Style + "Paragraph Style": "Style de paragraphe", + "Inline Style": "Style en ligne", + + // Alignment + "Align": "Aligner", + "Align Left": "Aligner \u00e0 gauche", + "Align Center": "Aligner au centre", + "Align Right": "Aligner \u00e0 droite", + "Align Justify": "Justifier", + "None": "Aucun", + + // Lists + "Ordered List": "Liste ordonn\u00e9e", + "Default": "Défaut", + "Lower Alpha": "Alpha inférieur", + "Lower Greek": "Grec inférieur", + "Lower Roman": "Bas romain", + "Upper Alpha": "Alpha supérieur", + "Upper Roman": "Haut romain", + + "Unordered List": "Liste non ordonn\u00e9e", + "Circle": "Cercle", + "Disc": "Disque", + "Square": "Carré", + + // Line height + "Line Height": "Hauteur de la ligne", + "Single": "Unique", + "Double": "Double", + + // Indent + "Decrease Indent": "Diminuer le retrait", + "Increase Indent": "Augmenter le retrait", + + // Links + "Insert Link": "Ins\u00e9rer un lien", + "Open in new tab": "Ouvrir dans un nouvel onglet", + "Open Link": "Ouvrir le lien", + "Edit Link": "Modifier le lien", + "Unlink": "Enlever le lien", + "Choose Link": "Choisir le lien", + + // Images + "Insert Image": "Ins\u00e9rer une image", + "Upload Image": "T\u00e9l\u00e9verser une image", + "By URL": "Par URL", + "Browse": "Parcourir", + "Drop image": "D\u00e9poser une image", + "or click": "ou cliquer", + "Manage Images": "G\u00e9rer les images", + "Loading": "Chargement", + "Deleting": "Suppression", + "Tags": "\u00c9tiquettes", + "Are you sure? Image will be deleted.": "Etes-vous certain? L'image sera supprim\u00e9e.", + "Replace": "Remplacer", + "Uploading": "En t\u00e9l\u00e9versement d'images", + "Loading image": "En chargement d'images", + "Display": "Afficher", + "Inline": "En ligne", + "Break Text": "Rompre le texte", + "Alternative Text": "Texte alternatif", + "Change Size": "Changer la dimension", + "Width": "Largeur", + "Height": "Hauteur", + "Something went wrong. Please try again.": "Quelque chose a mal tourn\u00e9. Veuillez r\u00e9essayer.", + "Image Caption": "L\u00e9gende de l'image", + "Advanced Edit": "\u00c9dition avanc\u00e9e", + + // Video + "Insert Video": "Ins\u00e9rer une vid\u00e9o", + "Embedded Code": "Code int\u00e9gr\u00e9", + "Paste in a video URL": "Coller l'URL d'une vid\u00e9o", + "Drop video": "D\u00e9poser une vid\u00e9o", + "Your browser does not support HTML5 video.": "Votre navigateur ne supporte pas les vid\u00e9os en format HTML5.", + "Upload Video": "T\u00e9l\u00e9verser une vid\u00e9o", + + // Tables + "Insert Table": "Ins\u00e9rer un tableau", + "Table Header": "Ent\u00eate de tableau", + "Remove Table": "Supprimer le tableau", + "Table Style": "Style de tableau", + "Horizontal Align": "Alignement horizontal", + "Row": "Ligne", + "Insert row above": "Ins\u00e9rer une ligne au-dessus", + "Insert row below": "Ins\u00e9rer une ligne en-dessous", + "Delete row": "Supprimer la ligne", + "Column": "Colonne", + "Insert column before": "Ins\u00e9rer une colonne avant", + "Insert column after": "Ins\u00e9rer une colonne apr\u00e8s", + "Delete column": "Supprimer la colonne", + "Cell": "Cellule", + "Merge cells": "Fusionner les cellules", + "Horizontal split": "Diviser horizontalement", + "Vertical split": "Diviser verticalement", + "Cell Background": "Arri\u00e8re-plan de la cellule", + "Vertical Align": "Alignement vertical", + "Top": "En haut", + "Middle": "Au centre", + "Bottom": "En bas", + "Align Top": "Aligner en haut", + "Align Middle": "Aligner au centre", + "Align Bottom": "Aligner en bas", + "Cell Style": "Style de cellule", + + // Files + "Upload File": "T\u00e9l\u00e9verser un fichier", + "Drop file": "D\u00e9poser un fichier", + + // Emoticons + "Emoticons": "\u00c9motic\u00f4nes", + "Grinning face": "Souriant visage", + "Grinning face with smiling eyes": "Souriant visage aux yeux souriants", + "Face with tears of joy": "Visage \u00e0 des larmes de joie", + "Smiling face with open mouth": "Visage souriant avec la bouche ouverte", + "Smiling face with open mouth and smiling eyes": "Visage souriant avec la bouche ouverte et les yeux en souriant", + "Smiling face with open mouth and cold sweat": "Visage souriant avec la bouche ouverte et la sueur froide", + "Smiling face with open mouth and tightly-closed eyes": "Visage souriant avec la bouche ouverte et les yeux herm\u00e9tiquement clos", + "Smiling face with halo": "Sourire visage avec halo", + "Smiling face with horns": "Visage souriant avec des cornes", + "Winking face": "Clin d'oeil visage", + "Smiling face with smiling eyes": "Sourire visage aux yeux souriants", + "Face savoring delicious food": "Visage savourant de d\u00e9licieux plats", + "Relieved face": "Soulag\u00e9 visage", + "Smiling face with heart-shaped eyes": "Visage souriant avec des yeux en forme de coeur", + "Smiling face with sunglasses": "Sourire visage avec des lunettes de soleil", + "Smirking face": "Souriant visage", + "Neutral face": "Visage neutre", + "Expressionless face": "Visage sans expression", + "Unamused face": "Visage pas amus\u00e9", + "Face with cold sweat": "Face \u00e0 la sueur froide", + "Pensive face": "pensif visage", + "Confused face": "Visage confus", + "Confounded face": "visage maudit", + "Kissing face": "Embrasser le visage", + "Face throwing a kiss": "Visage jetant un baiser", + "Kissing face with smiling eyes": "Embrasser le visage avec les yeux souriants", + "Kissing face with closed eyes": "Embrasser le visage avec les yeux ferm\u00e9s", + "Face with stuck out tongue": "Visage avec sortait de la langue", + "Face with stuck out tongue and winking eye": "Visage avec sortait de la langue et des yeux clignotante", + "Face with stuck out tongue and tightly-closed eyes": "Visage avec sortait de la langue et les yeux ferm\u00e9s herm\u00e9tiquement", + "Disappointed face": "Visage d\u00e9\u00e7u", + "Worried face": "Visage inquiet", + "Angry face": "Visage en col\u00e9re", + "Pouting face": "Faire la moue face", + "Crying face": "Pleurer visage", + "Persevering face": "Pers\u00e9v\u00e9rer face", + "Face with look of triumph": "Visage avec le regard de triomphe", + "Disappointed but relieved face": "D\u00e9\u00e7u, mais le visage soulag\u00e9", + "Frowning face with open mouth": "Les sourcils fronc\u00e9s visage avec la bouche ouverte", + "Anguished face": "Visage angoiss\u00e9", + "Fearful face": "Craignant visage", + "Weary face": "Visage las", + "Sleepy face": "Visage endormi", + "Tired face": "Visage fatigu\u00e9", + "Grimacing face": "Visage grima\u00e7ante", + "Loudly crying face": "Pleurer bruyamment visage", + "Face with open mouth": "Visage \u00e0 la bouche ouverte", + "Hushed face": "Visage feutr\u00e9e", + "Face with open mouth and cold sweat": "Visage \u00e0 la bouche ouverte et la sueur froide", + "Face screaming in fear": "Visage hurlant de peur", + "Astonished face": "Visage \u00e9tonn\u00e9", + "Flushed face": "Visage congestionn\u00e9", + "Sleeping face": "Visage au bois dormant", + "Dizzy face": "Visage vertige", + "Face without mouth": "Visage sans bouche", + "Face with medical mask": "Visage avec un masque m\u00e9dical", + + // Line breaker + "Break": "Rompre", + + // Math + "Subscript": "Indice", + "Superscript": "Exposant", + + // Full screen + "Fullscreen": "Plein \u00e9cran", + + // Horizontal line + "Insert Horizontal Line": "Ins\u00e9rer une ligne horizontale", + + // Clear formatting + "Clear Formatting": "Effacer le formatage", + + // Save + "Save": "sauvegarder", + + // Undo, redo + "Undo": "Annuler", + "Redo": "R\u00e9tablir", + + // Select all + "Select All": "Tout s\u00e9lectionner", + + // Code view + "Code View": "Mode HTML", + + // Quote + "Quote": "Citation", + "Increase": "Augmenter", + "Decrease": "Diminuer", + + // Quick Insert + "Quick Insert": "Insertion rapide", + + // Spcial Characters + "Special Characters": "Caract\u00e8res sp\u00e9ciaux", + "Latin": "Latin", + "Greek": "Grec", + "Cyrillic": "Cyrillique", + "Punctuation": "Ponctuation", + "Currency": "Devise", + "Arrows": "Fl\u00e8ches", + "Math": "Math", + "Misc": "Divers", + + // Print. + "Print": "Imprimer", + + // Spell Checker. + "Spell Checker": "Correcteur orthographique", + + // Help + "Help": "Aide", + "Shortcuts": "Raccourcis", + "Inline Editor": "\u00c9diteur en ligne", + "Show the editor": "Montrer l'\u00e9diteur", + "Common actions": "Actions communes", + "Copy": "Copier", + "Cut": "Couper", + "Paste": "Coller", + "Basic Formatting": "Formatage de base", + "Increase quote level": "Augmenter le niveau de citation", + "Decrease quote level": "Diminuer le niveau de citation", + "Image / Video": "Image / vid\u00e9o", + "Resize larger": "Redimensionner plus grand", + "Resize smaller": "Redimensionner plus petit", + "Table": "Table", + "Select table cell": "S\u00e9lectionner la cellule du tableau", + "Extend selection one cell": "\u00c9tendre la s\u00e9lection d'une cellule", + "Extend selection one row": "\u00c9tendre la s\u00e9lection d'une ligne", + "Navigation": "Navigation", + "Focus popup / toolbar": "Focus popup / toolbar", + "Return focus to previous position": "Retourner l'accent sur le poste pr\u00e9c\u00e9dent", + + // Embed.ly + "Embed URL": "URL int\u00e9gr\u00e9e", + "Paste in a URL to embed": "Coller une URL int\u00e9gr\u00e9e", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Le contenu coll\u00e9 provient d'un document Microsoft Word. Voulez-vous conserver le format ou le nettoyer?", + "Keep": "Conserver", + "Clean": "Nettoyer", + "Word Paste Detected": "Copiage de mots d\u00e9tect\u00e9" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/he.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/he.js new file mode 100644 index 0000000..42a23b3 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/he.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Hebrew + */ + +$.FE.LANGUAGE['he'] = { + translation: { + // Place holder + "Type something": "\u05d4\u05e7\u05dc\u05d3 \u05db\u05d0\u05df", + + // Basic formatting + "Bold": "\u05de\u05d5\u05d3\u05d2\u05e9", + "Italic": "\u05de\u05d5\u05d8\u05d4", + "Underline": "\u05e7\u05d5 \u05ea\u05d7\u05ea\u05d9", + "Strikethrough": "\u05e7\u05d5 \u05d0\u05de\u05e6\u05e2\u05d9", + + // Main buttons + "Insert": "\u05d4\u05d5\u05e1\u05e4\u05ea", + "Delete": "\u05de\u05d7\u05d9\u05e7\u05d4", + "Cancel": "\u05d1\u05d9\u05d8\u05d5\u05dc", + "OK": "\u05d1\u05e6\u05e2", + "Back": "\u05d1\u05d7\u05d6\u05e8\u05d4", + "Remove": "\u05d4\u05e1\u05e8", + "More": "\u05d9\u05d5\u05ea\u05e8", + "Update": "\u05e2\u05d3\u05db\u05d5\u05df", + "Style": "\u05e1\u05d2\u05e0\u05d5\u05df", + + // Font + "Font Family": "\u05d2\u05d5\u05e4\u05df", + "Font Size": "\u05d2\u05d5\u05d3\u05dc \u05d4\u05d2\u05d5\u05e4\u05df", + + // Colors + "Colors": "\u05e6\u05d1\u05e2\u05d9\u05dd", + "Background": "\u05e8\u05e7\u05e2", + "Text": "\u05d4\u05d8\u05e1\u05d8", + "HEX Color": "צבע הקס", + + // Paragraphs + "Paragraph Format": "\u05e4\u05d5\u05e8\u05de\u05d8", + "Normal": "\u05e8\u05d2\u05d9\u05dc", + "Code": "\u05e7\u05d5\u05d3", + "Heading 1": "1 \u05db\u05d5\u05ea\u05e8\u05ea", + "Heading 2": "2 \u05db\u05d5\u05ea\u05e8\u05ea", + "Heading 3": "3 \u05db\u05d5\u05ea\u05e8\u05ea", + "Heading 4": "4 \u05db\u05d5\u05ea\u05e8\u05ea", + + // Style + "Paragraph Style": "\u05e1\u05d2\u05e0\u05d5\u05df \u05e4\u05e1\u05e7\u05d4", + "Inline Style": "\u05e1\u05d2\u05e0\u05d5\u05df \u05de\u05d5\u05d1\u05e0\u05d4", + + // Alignment + "Align": "\u05d9\u05d9\u05e9\u05d5\u05e8", + "Align Left": "\u05d9\u05d9\u05e9\u05d5\u05e8 \u05dc\u05e9\u05de\u05d0\u05dc", + "Align Center": "\u05d9\u05d9\u05e9\u05d5\u05e8 \u05dc\u05de\u05e8\u05db\u05d6", + "Align Right": "\u05d9\u05d9\u05e9\u05d5\u05e8 \u05dc\u05d9\u05de\u05d9\u05df", + "Align Justify": "\u05d9\u05d9\u05e9\u05d5\u05e8 \u05de\u05dc\u05d0", + "None": "\u05d0\u05e3 \u05d0\u05d7\u05d3", + + // Lists + "Ordered List": "\u05d4\u05d5\u05e1\u05e4\u05ea \u05e8\u05e9\u05d9\u05de\u05d4 \u05de\u05de\u05d5\u05e1\u05e4\u05e8\u05ea", + "Default": "ברירת המחדל", + "Lower Alpha": "אלפא נמוך יותר", + "Lower Greek": "נמוך יוונית", + "Lower Roman": "התחתון הרומית", + "Upper Alpha": "אלפא העליון", + "Upper Roman": "הרומאי העליון", + + "Unordered List": "\u05d4\u05d5\u05e1\u05e4\u05ea \u05e8\u05e9\u05d9\u05de\u05d4", + "Circle": "מעגל", + "Disc": "דיסק", + "Square": "כיכר", + + // Line height + "Line Height": "גובה קו", + "Single": "יחיד", + "Double": "כפול", + + // Indent + "Decrease Indent": "\u05d4\u05e7\u05d8\u05e0\u05ea \u05db\u05e0\u05d9\u05e1\u05d4", + "Increase Indent": "\u05d4\u05d2\u05d3\u05dc\u05ea \u05db\u05e0\u05d9\u05e1\u05d4", + + // Links + "Insert Link": "\u05d4\u05d5\u05e1\u05e4\u05ea \u05e7\u05d9\u05e9\u05d5\u05e8", + "Open in new tab": "\u05dc\u05e4\u05ea\u05d5\u05d7 \u05d1\u05d8\u05d0\u05d1 \u05d7\u05d3\u05e9", + "Open Link": "\u05e7\u05d9\u05e9\u05d5\u05e8 \u05e4\u05ea\u05d5\u05d7", + "Edit Link": "\u05e7\u05d9\u05e9\u05d5\u05e8 \u05e2\u05e8\u05d9\u05db\u05d4", + "Unlink": "\u05d4\u05e1\u05e8\u05ea \u05d4\u05e7\u05d9\u05e9\u05d5\u05e8", + "Choose Link": "\u05dc\u05d1\u05d7\u05d5\u05e8 \u05e7\u05d9\u05e9\u05d5\u05e8", + + // Images + "Insert Image": "\u05d4\u05d5\u05e1\u05e4\u05ea \u05ea\u05de\u05d5\u05e0\u05d4", + "Upload Image": "\u05ea\u05de\u05d5\u05e0\u05ea \u05d4\u05e2\u05dc\u05d0\u05d4", + "By URL": "URL \u05e2\u05dc \u05d9\u05d3\u05d9", + "Browse": "\u05dc\u05d2\u05dc\u05d5\u05e9", + "Drop image": "\u05e9\u05d7\u05e8\u05e8 \u05d0\u05ea \u05d4\u05ea\u05de\u05d5\u05e0\u05d4 \u05db\u05d0\u05df", + "or click": "\u05d0\u05d5 \u05dc\u05d7\u05e5", + "Manage Images": "\u05e0\u05d9\u05d4\u05d5\u05dc \u05d4\u05ea\u05de\u05d5\u05e0\u05d5\u05ea", + "Loading": "\u05d8\u05e2\u05d9\u05e0\u05d4", + "Deleting": "\u05de\u05d7\u05d9\u05e7\u05d4", + "Tags": "\u05ea\u05d2\u05d9\u05dd", + "Are you sure? Image will be deleted.": "\u05d4\u05d0\u05dd \u05d0\u05ea\u05d4 \u05d1\u05d8\u05d5\u05d7\u003f \u05d4\u05ea\u05de\u05d5\u05e0\u05d4 \u05ea\u05de\u05d7\u05e7\u002e", + "Replace": "\u05dc\u05d4\u05d7\u05dc\u05d9\u05e3", + "Uploading": "\u05d4\u05e2\u05dc\u05d0\u05d4", + "Loading image": "\u05ea\u05de\u05d5\u05e0\u05ea \u05d8\u05e2\u05d9\u05e0\u05d4", + "Display": "\u05ea\u05e6\u05d5\u05d2\u05d4", + "Inline": "\u05d1\u05e9\u05d5\u05e8\u05d4", + "Break Text": "\u05d8\u05e7\u05e1\u05d8 \u05d4\u05e4\u05e1\u05e7\u05d4", + "Alternative Text": "\u05d8\u05e7\u05e1\u05d8 \u05d7\u05dc\u05d5\u05e4\u05d9", + "Change Size": "\u05d2\u05d5\u05d3\u05dc \u05e9\u05d9\u05e0\u05d5\u05d9", + "Width": "\u05e8\u05d5\u05d7\u05d1", + "Height": "\u05d2\u05d5\u05d1\u05d4", + "Something went wrong. Please try again.": "\u05de\u05e9\u05d4\u05d5 \u05d4\u05e9\u05ea\u05d1\u05e9. \u05d1\u05d1\u05e7\u05e9\u05d4 \u05e0\u05e1\u05d4 \u05e9\u05d5\u05d1.", + "Image Caption": "כיתוב תמונה", + "Advanced Edit": "עריכה מתקדמת", + + // Video + "Insert Video": "\u05d4\u05d5\u05e1\u05e4\u05ea \u05d5\u05d9\u05d3\u05d9\u05d0\u05d5", + "Embedded Code": "\u05e7\u05d5\u05d3 \u05de\u05d5\u05d8\u05d1\u05e2", + "Paste in a video URL": "הדבק בכתובת אתר של סרטון", + "Drop video": "ירידה וידאו", + "Your browser does not support HTML5 video.": "הדפדפן שלך אינו תומך וידאו html5.", + "Upload Video": "להעלות וידאו", + + // Tables + "Insert Table": "\u05d4\u05db\u05e0\u05e1 \u05d8\u05d1\u05dc\u05d4", + "Table Header": "\u05db\u05d5\u05ea\u05e8\u05ea \u05d8\u05d1\u05dc\u05d4", + "Remove Table": "\u05d4\u05e1\u05e8 \u05e9\u05d5\u05dc\u05d7\u05df", + "Table Style": "\u05e1\u05d2\u05e0\u05d5\u05df \u05d8\u05d1\u05dc\u05d4", + "Horizontal Align": "\u05d0\u05d5\u05e4\u05e7\u05d9\u05ea \u05dc\u05d9\u05d9\u05e9\u05e8", + "Row": "\u05e9\u05d5\u05e8\u05d4", + "Insert row above": "\u05d4\u05d5\u05e1\u05e4\u05ea \u05e9\u05d5\u05e8\u05d4 \u05dc\u05e4\u05e0\u05d9", + "Insert row below": "\u05d4\u05d5\u05e1\u05e4\u05ea \u05e9\u05d5\u05e8\u05d4 \u05d0\u05d7\u05e8\u05d9", + "Delete row": "\u05de\u05d7\u05d9\u05e7\u05ea \u05e9\u05d5\u05e8\u05d4", + "Column": "\u05d8\u05d5\u05e8", + "Insert column before": "\u05d4\u05d5\u05e1\u05e4\u05ea \u05d8\u05d5\u05e8 \u05dc\u05e4\u05e0\u05d9", + "Insert column after": "\u05d4\u05d5\u05e1\u05e4\u05ea \u05d8\u05d5\u05e8 \u05d0\u05d7\u05e8\u05d9", + "Delete column": "\u05de\u05d7\u05d9\u05e7\u05ea \u05d8\u05d5\u05e8", + "Cell": "\u05ea\u05d0", + "Merge cells": "\u05de\u05d6\u05d2 \u05ea\u05d0\u05d9\u05dd", + "Horizontal split": "\u05e4\u05e6\u05dc \u05d0\u05d5\u05e4\u05e7\u05d9", + "Vertical split": "\u05e4\u05e6\u05dc \u05d0\u05e0\u05db\u05d9", + "Cell Background": "\u05e8\u05e7\u05e2 \u05ea\u05d0", + "Vertical Align": "\u05d9\u05d9\u05e9\u05d5\u05e8 \u05d0\u05e0\u05db\u05d9", + "Top": "\u05e2\u05b6\u05dc\u05b4\u05d9\u05d5\u05b9\u05df", + "Middle": "\u05ea\u05b4\u05d9\u05db\u05d5\u05b9\u05e0\u05b4\u05d9", + "Bottom": "\u05ea\u05d7\u05ea\u05d5\u05df", + "Align Top": "\u05dc\u05d9\u05d9\u05e9\u05e8 \u05e2\u05b6\u05dc\u05b4\u05d9\u05d5\u05b9\u05df", + "Align Middle": "\u05dc\u05d9\u05d9\u05e9\u05e8 \u05ea\u05b4\u05d9\u05db\u05d5\u05b9\u05e0\u05b4\u05d9", + "Align Bottom": "\u05dc\u05d9\u05d9\u05e9\u05e8 \u05ea\u05d7\u05ea\u05d5\u05df", + "Cell Style": "\u05e1\u05d2\u05e0\u05d5\u05df \u05ea\u05d0", + + // Files + "Upload File": "\u05d4\u05e2\u05dc\u05d0\u05ea \u05e7\u05d5\u05d1\u05e5", + "Drop file": "\u05d6\u05e8\u05d5\u05e7 \u05e7\u05d5\u05d1\u05e5 \u05db\u05d0\u05df", + + // Emoticons + "Emoticons": "\u05e1\u05de\u05d9\u05d9\u05dc\u05d9\u05dd", + "Grinning face": "\u05d7\u05d9\u05d9\u05da \u05e4\u05e0\u05d9\u05dd", + "Grinning face with smiling eyes": "\u05d7\u05d9\u05d9\u05da \u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05e2\u05d9\u05e0\u05d9\u05d9\u05dd \u05de\u05d7\u05d9\u05d9\u05db\u05d5\u05ea", + "Face with tears of joy": "\u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05d3\u05de\u05e2\u05d5\u05ea \u05e9\u05dc \u05e9\u05de\u05d7\u05d4", + "Smiling face with open mouth": "\u05d7\u05d9\u05d5\u05da \u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05e4\u05d4 \u05e4\u05ea\u05d5\u05d7", + "Smiling face with open mouth and smiling eyes": "\u05d7\u05d9\u05d5\u05da \u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05e4\u05d4 \u05e4\u05ea\u05d5\u05d7 \u05d5\u05de\u05d7\u05d9\u05d9\u05da \u05e2\u05d9\u05e0\u05d9\u05d9\u05dd", + "Smiling face with open mouth and cold sweat": "\u05d7\u05d9\u05d5\u05da \u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05e4\u05d4 \u05e4\u05ea\u05d5\u05d7 \u05d5\u05d6\u05d9\u05e2\u05d4 \u05e7\u05e8\u05d4", + "Smiling face with open mouth and tightly-closed eyes": "\u05d7\u05d9\u05d5\u05da \u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05e4\u05d4 \u05e4\u05ea\u05d5\u05d7 \u05d5\u05e2\u05d9\u05e0\u05d9\u05d9\u05dd \u05d1\u05d7\u05d5\u05d6\u05e7\u05d4\u002d\u05e1\u05d2\u05d5\u05e8\u05d5\u05ea", + "Smiling face with halo": "\u05d7\u05d9\u05d5\u05da \u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05d4\u05d9\u05dc\u05d4", + "Smiling face with horns": "\u05d7\u05d9\u05d5\u05da \u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05e7\u05e8\u05e0\u05d5\u05ea", + "Winking face": "\u05e7\u05e8\u05d9\u05e6\u05d4 \u05e4\u05e0\u05d9\u05dd", + "Smiling face with smiling eyes": "\u05d7\u05d9\u05d5\u05da \u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05e2\u05d9\u05e0\u05d9\u05d9\u05dd \u05de\u05d7\u05d9\u05d9\u05db\u05d5\u05ea", + "Face savoring delicious food": "\u05e4\u05e0\u05d9\u05dd \u05de\u05ea\u05e2\u05e0\u05d2 \u05d0\u05d5\u05db\u05dc \u05d8\u05e2\u05d9\u05dd", + "Relieved face": "\u05e4\u05e0\u05d9\u05dd \u05e9\u05dc \u05d4\u05e7\u05dc\u05d4", + "Smiling face with heart-shaped eyes": "\u05d7\u05d9\u05d5\u05da \u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05e2\u05d9\u05e0\u05d9\u05d9\u05dd \u05d1\u05e6\u05d5\u05e8\u05ea \u05dc\u05d1", + "Smiling face with sunglasses": "\u05d7\u05d9\u05d5\u05da \u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05de\u05e9\u05e7\u05e4\u05d9 \u05e9\u05de\u05e9", + "Smirking face": "\u05d4\u05d9\u05d0 \u05d7\u05d9\u05d9\u05db\u05d4 \u05d7\u05d9\u05d5\u05da \u05e0\u05d1\u05d6\u05d4 \u05e4\u05e0\u05d9\u05dd", + "Neutral face": "\u05e4\u05e0\u05d9\u05dd \u05e0\u05d9\u05d8\u05e8\u05dc\u05d9", + "Expressionless face": "\u05d1\u05e4\u05e0\u05d9\u05dd \u05d7\u05ea\u05d5\u05dd", + "Unamused face": "\u05e4\u05e0\u05d9\u05dd \u05dc\u05d0 \u05de\u05e9\u05d5\u05e2\u05e9\u05e2\u05d9\u05dd", + "Face with cold sweat": "\u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05d6\u05d9\u05e2\u05d4 \u05e7\u05e8\u05d4", + "Pensive face": "\u05d1\u05e4\u05e0\u05d9\u05dd \u05de\u05d4\u05d5\u05e8\u05d4\u05e8", + "Confused face": "\u05e4\u05e0\u05d9\u05dd \u05de\u05d1\u05d5\u05dc\u05d1\u05dc\u05d9\u05dd", + "Confounded face": "\u05e4\u05e0\u05d9\u05dd \u05de\u05d1\u05d5\u05dc\u05d1\u05dc", + "Kissing face": "\u05e0\u05e9\u05d9\u05e7\u05d5\u05ea \u05e4\u05e0\u05d9\u05dd", + "Face throwing a kiss": "\u05e4\u05e0\u05d9\u05dd \u05dc\u05d6\u05e8\u05d5\u05e7 \u05e0\u05e9\u05d9\u05e7\u05d4", + "Kissing face with smiling eyes": "\u05e0\u05e9\u05d9\u05e7\u05d5\u05ea \u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05e2\u05d9\u05e0\u05d9\u05d9\u05dd \u05de\u05d7\u05d9\u05d9\u05db\u05d5\u05ea", + "Kissing face with closed eyes": "\u05e0\u05e9\u05d9\u05e7\u05d5\u05ea \u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05e2\u05d9\u05e0\u05d9\u05d9\u05dd \u05e1\u05d2\u05d5\u05e8\u05d5\u05ea", + "Face with stuck out tongue": "\u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05dc\u05e9\u05d5\u05df \u05d1\u05dc\u05d8\u05d5", + "Face with stuck out tongue and winking eye": "\u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05dc\u05e9\u05d5\u05df \u05ea\u05e7\u05d5\u05e2\u05d4 \u05d4\u05d7\u05d5\u05e6\u05d4 \u05d5\u05e2\u05d9\u05df \u05e7\u05d5\u05e8\u05e6\u05ea", + "Face with stuck out tongue and tightly-closed eyes": "\u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05dc\u05e9\u05d5\u05df \u05ea\u05e7\u05d5\u05e2\u05d4 \u05d4\u05d7\u05d5\u05e6\u05d4 \u05d5\u05e2\u05d9\u05e0\u05d9\u05d9\u05dd \u05d1\u05d7\u05d5\u05d6\u05e7\u05d4\u002d\u05e1\u05d2\u05d5\u05e8\u05d5\u05ea", + "Disappointed face": "\u05e4\u05e0\u05d9\u05dd \u05de\u05d0\u05d5\u05db\u05d6\u05d1\u05d9\u05dd", + "Worried face": "\u05e4\u05e0\u05d9\u05dd \u05de\u05d5\u05d3\u05d0\u05d2\u05d9\u05dd", + "Angry face": "\u05e4\u05e0\u05d9\u05dd \u05db\u05d5\u05e2\u05e1\u05d9\u05dd", + "Pouting face": "\u05de\u05e9\u05d5\u05e8\u05d1\u05d1 \u05e4\u05e0\u05d9\u05dd", + "Crying face": "\u05d1\u05db\u05d9 \u05e4\u05e0\u05d9\u05dd", + "Persevering face": "\u05d4\u05ea\u05de\u05d3\u05ea \u05e4\u05e0\u05d9\u05dd", + "Face with look of triumph": "\u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05de\u05d1\u05d8 \u05e9\u05dc \u05e0\u05e6\u05d7\u05d5\u05df", + "Disappointed but relieved face": "\u05de\u05d0\u05d5\u05db\u05d6\u05d1 \u05d0\u05d1\u05dc \u05d4\u05d5\u05e7\u05dc \u05e4\u05e0\u05d9\u05dd", + "Frowning face with open mouth": "\u05e7\u05de\u05d8 \u05d0\u05ea \u05de\u05e6\u05d7 \u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05e4\u05d4 \u05e4\u05ea\u05d5\u05d7", + "Anguished face": "\u05e4\u05e0\u05d9\u05dd \u05de\u05d9\u05d5\u05e1\u05e8\u05d9\u05dd", + "Fearful face": "\u05e4\u05e0\u05d9\u05dd \u05e9\u05d7\u05e9\u05e9\u05d5", + "Weary face": "\u05e4\u05e0\u05d9\u05dd \u05d5\u05d9\u05e8\u05d9", + "Sleepy face": "\u05e4\u05e0\u05d9\u05dd \u05e9\u05dc \u05e1\u05dc\u05d9\u05e4\u05d9", + "Tired face": "\u05e4\u05e0\u05d9\u05dd \u05e2\u05d9\u05d9\u05e4\u05d9\u05dd", + "Grimacing face": "\u05d4\u05d5\u05d0 \u05d4\u05e2\u05d5\u05d5\u05d4 \u05d0\u05ea \u05e4\u05e0\u05d9 \u05e4\u05e0\u05d9\u05dd", + "Loudly crying face": "\u05d1\u05e7\u05d5\u05dc \u05e8\u05dd \u05d1\u05d5\u05db\u05d4 \u05e4\u05e0\u05d9\u05dd", + "Face with open mouth": "\u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05e4\u05d4 \u05e4\u05ea\u05d5\u05d7", + "Hushed face": "\u05e4\u05e0\u05d9\u05dd \u05e9\u05d5\u05e7\u05d8\u05d9\u05dd", + "Face with open mouth and cold sweat": "\u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05e4\u05d4 \u05e4\u05ea\u05d5\u05d7 \u05d5\u05d6\u05d9\u05e2\u05d4 \u05e7\u05e8\u05d4\u0022", + "Face screaming in fear": "\u05e4\u05e0\u05d9\u05dd \u05e6\u05d5\u05e8\u05d7\u05d9\u05dd \u05d1\u05e4\u05d7\u05d3", + "Astonished face": "\u05e4\u05e0\u05d9\u05d5 \u05e0\u05d3\u05d4\u05de\u05d5\u05ea", + "Flushed face": "\u05e4\u05e0\u05d9\u05d5 \u05e1\u05de\u05d5\u05e7\u05d5\u05ea", + "Sleeping face": "\u05e9\u05d9\u05e0\u05d4 \u05e4\u05e0\u05d9\u05dd", + "Dizzy face": "\u05e4\u05e0\u05d9\u05dd \u05e9\u05dc \u05d3\u05d9\u05d6\u05d9", + "Face without mouth": "\u05e4\u05e0\u05d9\u05dd \u05dc\u05dc\u05d0 \u05e4\u05d4", + "Face with medical mask": "\u05e4\u05e0\u05d9\u05dd \u05e2\u05dd \u05de\u05e1\u05db\u05d4 \u05e8\u05e4\u05d5\u05d0\u05d9\u05ea", + + // Line breaker + "Break": "\u05d4\u05e4\u05e1\u05e7\u05d4", + + // Math + "Subscript": "\u05db\u05ea\u05d1 \u05ea\u05d7\u05ea\u05d9", + "Superscript": "\u05e2\u05d9\u05dc\u05d9", + + // Full screen + "Fullscreen": "\u05de\u05e1\u05da \u05de\u05dc\u05d0", + + // Horizontal line + "Insert Horizontal Line": "\u05d4\u05d5\u05e1\u05e4\u05ea \u05e7\u05d5 \u05d0\u05d5\u05e4\u05e7\u05d9", + + // Clear formatting + "Clear Formatting": "\u05dc\u05d4\u05e1\u05d9\u05e8 \u05e2\u05d9\u05e6\u05d5\u05d1", + + // Save + "Save": "\u05dc\u05d4\u05e6\u05d9\u05dc", + + // Undo, redo + "Undo": "\u05d1\u05d9\u05d8\u05d5\u05dc", + "Redo": "\u05d1\u05e6\u05e2 \u05e9\u05d5\u05d1", + + // Select all + "Select All": "\u05d1\u05d7\u05e8 \u05d4\u05db\u05dc", + + // Code view + "Code View": "\u05ea\u05e6\u05d5\u05d2\u05ea \u05e7\u05d5\u05d3", + + // Quote + "Quote": "\u05e6\u05d9\u05d8\u05d5\u05d8", + "Increase": "\u05dc\u05d4\u05d2\u05d1\u05d9\u05e8", + "Decrease": "\u05d9\u05e8\u05d9\u05d3\u05d4", + + // Quick Insert + "Quick Insert": "\u05db\u05e0\u05e1 \u05de\u05d4\u05d9\u05e8", + + // Spcial Characters + "Special Characters": "תווים מיוחדים", + "Latin": "לָטִינִית", + "Greek": "יווני", + "Cyrillic": "קירילית", + "Punctuation": "פיסוק", + "Currency": "מַטְבֵּעַ", + "Arrows": "חצים", + "Math": "מתמטיקה", + "Misc": "שונות", + + // Print. + "Print": "הדפס", + + // Spell Checker. + "Spell Checker": "בודק איות", + + // Help + "Help": "עֶזרָה", + "Shortcuts": "קיצורי דרך", + "Inline Editor": "עורך מוטבע", + "Show the editor": "להראות את העורך", + "Common actions": "פעולות נפוצות", + "Copy": "עותק", + "Cut": "גזירה", + "Paste": "לְהַדבִּיק", + "Basic Formatting": "עיצוב בסיסי", + "Increase quote level": "רמת ציטוט", + "Decrease quote level": "רמת ציטוט ירידה", + "Image / Video": "תמונה / וידאו", + "Resize larger": "גודל גדול יותר", + "Resize smaller": "גודל קטן יותר", + "Table": "שולחן", + "Select table cell": "בחר תא תא - -", + "Extend selection one cell": "להאריך את הבחירה תא אחד", + "Extend selection one row": "להאריך את הבחירה שורה אחת", + "Navigation": "ניווט", + "Focus popup / toolbar": "מוקד קופץ / סרגל הכלים", + "Return focus to previous position": "חזרה להתמקד קודם", + + // Embed.ly + "Embed URL": "כתובת אתר להטביע", + "Paste in a URL to embed": "הדבק כתובת אתר להטביע", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "התוכן המודבק מגיע ממסמך Word של Microsoft. האם ברצונך לשמור את הפורמט או לנקות אותו?", + "Keep": "לִשְׁמוֹר", + "Clean": "לְנַקוֹת", + "Word Paste Detected": "הדבק מילה זוהתה" + }, + direction: "rtl" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/hr.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/hr.js new file mode 100644 index 0000000..d45c412 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/hr.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Croatian + */ + +$.FE.LANGUAGE['hr'] = { + translation: { + // Place holder + "Type something": "Napi\u0161i ne\u0161to", + + // Basic formatting + "Bold": "Podebljaj", + "Italic": "Kurziv", + "Underline": "Podcrtano", + "Strikethrough": "Precrtano", + + // Main buttons + "Insert": "Umetni", + "Delete": "Obri\u0161i", + "Cancel": "Otka\u017ei", + "OK": "U redu", + "Back": "Natrag", + "Remove": "Ukloni", + "More": "Vi\u0161e", + "Update": "A\u017euriraj", + "Style": "Stil", + + // Font + "Font Family": "Odaberi font", + "Font Size": "Veli\u010dina fonta", + + // Colors + "Colors": "Boje", + "Background": "Pozadina", + "Text": "Tekst", + "HEX Color": "Heksadecimalne boje", + + // Paragraphs + "Paragraph Format": "Format odlomka", + "Normal": "Normalno", + "Code": "Izvorni kod", + "Heading 1": "Naslov 1", + "Heading 2": "Naslov 2", + "Heading 3": "Naslov 3", + "Heading 4": "Naslov 4", + + // Style + "Paragraph Style": "Stil odlomka", + "Inline Style": "Stil u liniji", + + // Alignment + "Align": "Poravnaj", + "Align Left": "Poravnaj lijevo", + "Align Center": "Poravnaj po sredini", + "Align Right": "Poravnaj desno", + "Align Justify": "Obostrano poravnanje", + "None": "Nijedan", + + // Lists + "Ordered List": "Ure\u0111ena lista", + "Default": "Zadano", + "Lower Alpha": "Niži alfa", + "Lower Greek": "Donji grčki", + "Lower Roman": "Niži rimski", + "Upper Alpha": "Gornja alfa", + "Upper Roman": "Gornji rimski", + + "Unordered List": "Neure\u0111ena lista", + "Circle": "Krug", + "Disc": "Disk", + "Square": "Kvadrat", + + // Line height + "Line Height": "Visina crte", + "Single": "Singl", + "Double": "Dvostruko", + + // Indent + "Decrease Indent": "Uvuci odlomak", + "Increase Indent": "Izvuci odlomak", + + // Links + "Insert Link": "Umetni link", + "Open in new tab": "Otvori u novom prozoru", + "Open Link": "Otvori link", + "Edit Link": "Uredi link", + "Unlink": "Ukloni link", + "Choose Link": "Odaberi link", + + // Images + "Insert Image": "Umetni sliku", + "Upload Image": "Prijenos slike", + "By URL": "Prema URL", + "Browse": "Odabir", + "Drop image": "Ispusti sliku", + "or click": "ili odaberi", + "Manage Images": "Upravljanje slikama", + "Loading": "U\u010ditavanje", + "Deleting": "Brisanje", + "Tags": "Oznake", + "Are you sure? Image will be deleted.": "Da li ste sigurni da \u017eelite obrisati ovu sliku?", + "Replace": "Zamijeni", + "Uploading": "Prijenos", + "Loading image": "Otvaram sliku", + "Display": "Prika\u017ei", + "Inline": "U liniji", + "Break Text": "Odvojeni tekst", + "Alternative Text": "Alternativni tekst", + "Change Size": "Promjena veli\u010dine", + "Width": "\u0160irina", + "Height": "Visina", + "Something went wrong. Please try again.": "Ne\u0161to je po\u0161lo po zlu. Molimo poku\u0161ajte ponovno.", + "Image Caption": "Opis slike", + "Advanced Edit": "Napredno uređivanje", + + // Video + "Insert Video": "Umetni video", + "Embedded Code": "Ugra\u0111eni kod", + "Paste in a video URL": "Zalijepite u URL videozapisa", + "Drop video": "Ispusti video", + "Your browser does not support HTML5 video.": "Vaš preglednik ne podržava HTML video.", + "Upload Video": "Prenesi videozapis", + + // Tables + "Insert Table": "Umetni tablicu", + "Table Header": "Zaglavlje tablice", + "Remove Table": "Izbri\u0161i tablicu", + "Table Style": "Tablica stil", + "Horizontal Align": "Horizontalna poravnanje", + "Row": "Red", + "Insert row above": "Umetni red iznad", + "Insert row below": "Umetni red ispod", + "Delete row": "Obri\u0161i red", + "Column": "Stupac", + "Insert column before": "Umetni stupac prije", + "Insert column after": "Umetni stupac poslije", + "Delete column": "Obri\u0161i stupac", + "Cell": "Polje", + "Merge cells": "Spoji polja", + "Horizontal split": "Horizontalno razdvajanje polja", + "Vertical split": "Vertikalno razdvajanje polja", + "Cell Background": "Polje pozadine", + "Vertical Align": "Vertikalno poravnanje", + "Top": "Vrh", + "Middle": "Sredina", + "Bottom": "Dno", + "Align Top": "Poravnaj na vrh", + "Align Middle": "Poravnaj po sredini", + "Align Bottom": "Poravnaj na dno", + "Cell Style": "Stil polja", + + // Files + "Upload File": "Prijenos datoteke", + "Drop file": "Ispusti datoteku", + + // Emoticons + "Emoticons": "Emotikoni", + "Grinning face": "Nacereno lice", + "Grinning face with smiling eyes": "Nacereno lice s nasmije\u0161enim o\u010dima", + "Face with tears of joy": "Lice sa suzama radosnicama", + "Smiling face with open mouth": "Nasmijano lice s otvorenim ustima", + "Smiling face with open mouth and smiling eyes": "Nasmijano lice s otvorenim ustima i nasmijanim o\u010dima", + "Smiling face with open mouth and cold sweat": "Nasmijano lice s otvorenim ustima i hladnim znojem", + "Smiling face with open mouth and tightly-closed eyes": "Nasmijano lice s otvorenim ustima i \u010dvrsto zatvorenih o\u010diju", + "Smiling face with halo": "Nasmijano lice sa aureolom", + "Smiling face with horns": "Nasmijano lice s rogovima", + "Winking face": "Lice koje namiguje", + "Smiling face with smiling eyes": "Nasmijano lice s nasmiješenim o\u010dima", + "Face savoring delicious food": "Lice koje u\u017eiva ukusnu hranu", + "Relieved face": "Lice s olak\u0161anjem", + "Smiling face with heart-shaped eyes": "Nasmijano lice sa o\u010dima u obliku srca", + "Smiling face with sunglasses": "Nasmijano lice sa sun\u010danim nao\u010dalama", + "Smirking face": "Zlokobno nasmije\u0161eno lice", + "Neutral face": "Neutralno lice", + "Expressionless face": "Bezizra\u017eajno lice", + "Unamused face": "Nezainteresirano lice", + "Face with cold sweat": "Lice s hladnim znojem", + "Pensive face": "Zami\u0161ljeno lice", + "Confused face": "Zbunjeno lice", + "Confounded face": "Zbunjeno lice", + "Kissing face": "Lice s poljupcem", + "Face throwing a kiss": "Lice koje baca poljubac", + "Kissing face with smiling eyes": "Lice s poljupcem s nasmije\u0161enim o\u010dima", + "Kissing face with closed eyes": "Lice s poljupcem zatvorenih o\u010diju", + "Face with stuck out tongue": "Lice s ispru\u017eenim jezikom", + "Face with stuck out tongue and winking eye": "Lice s ispru\u017eenim jezikom koje namiguje", + "Face with stuck out tongue and tightly-closed eyes": "Lice s ispru\u017eenim jezikom i \u010dvrsto zatvorenih o\u010diju", + "Disappointed face": "Razo\u010darano lice", + "Worried face": "Zabrinuto lice", + "Angry face": "Ljutito lice", + "Pouting face": "Nadureno lice", + "Crying face": "Uplakano lice", + "Persevering face": "Lice s negodovanjem", + "Face with look of triumph": "Trijumfalno lice", + "Disappointed but relieved face": "Razo\u010darano ali olakšano lice", + "Frowning face with open mouth": "Namrgo\u0111eno lice s otvorenim ustima", + "Anguished face": "Tjeskobno lice", + "Fearful face": "Prestra\u0161eno lice", + "Weary face": "Umorno lice", + "Sleepy face": "Pospano lice", + "Tired face": "Umorno lice", + "Grimacing face": "Lice sa grimasama", + "Loudly crying face": "Glasno pla\u010du\u0107e lice", + "Face with open mouth": "Lice s otvorenim ustima", + "Hushed face": "Tiho lice", + "Face with open mouth and cold sweat": "Lice s otvorenim ustima i hladnim znojem", + "Face screaming in fear": "Lice koje vri\u0161ti u strahu", + "Astonished face": "Zaprepa\u0161teno lice", + "Flushed face": "Zajapureno lice", + "Sleeping face": "Spava\u0107e lice", + "Dizzy face": "Lice sa vrtoglavicom", + "Face without mouth": "Lice bez usta", + "Face with medical mask": "Lice s medicinskom maskom", + + // Line breaker + "Break": "Odvojeno", + + // Math + "Subscript": "Indeks", + "Superscript": "Eksponent", + + // Full screen + "Fullscreen": "Puni zaslon", + + // Horizontal line + "Insert Horizontal Line": "Umetni liniju", + + // Clear formatting + "Clear Formatting": "Ukloni oblikovanje", + + // Save + "Save": "\u0055\u0161\u0074\u0065\u0064\u006a\u0065\u0074\u0069", + + // Undo, redo + "Undo": "Korak natrag", + "Redo": "Korak naprijed", + + // Select all + "Select All": "Odaberi sve", + + // Code view + "Code View": "Pregled koda", + + // Quote + "Quote": "Citat", + "Increase": "Pove\u0107aj", + "Decrease": "Smanji", + + // Quick Insert + "Quick Insert": "Brzo umetak", + + // Spcial Characters + "Special Characters": "Posebni znakovi", + "Latin": "Latinski", + "Greek": "Grčki", + "Cyrillic": "Ćirilica", + "Punctuation": "Interpunkcija", + "Currency": "Valuta", + "Arrows": "Strelice", + "Math": "Matematika", + "Misc": "Razno", + + // Print. + "Print": "Otisak", + + // Spell Checker. + "Spell Checker": "Provjeritelj pravopisa", + + // Help + "Help": "Pomoć", + "Shortcuts": "Prečaci", + "Inline Editor": "Inline editor", + "Show the editor": "Prikaži urednika", + "Common actions": "Zajedničke radnje", + "Copy": "Kopirati", + "Cut": "Rez", + "Paste": "Zalijepiti", + "Basic Formatting": "Osnovno oblikovanje", + "Increase quote level": "Povećati razinu citata", + "Decrease quote level": "Smanjite razinu citata", + "Image / Video": "Slika / video", + "Resize larger": "Promijenite veličinu većeg", + "Resize smaller": "Promijenite veličinu manju", + "Table": "Stol", + "Select table cell": "Odaberite stolnu ćeliju", + "Extend selection one cell": "Proširiti odabir jedne ćelije", + "Extend selection one row": "Proširite odabir jednog retka", + "Navigation": "Navigacija", + "Focus popup / toolbar": "Fokus popup / alatnoj traci", + "Return focus to previous position": "Vratiti fokus na prethodnu poziciju", + + // Embed.ly + "Embed URL": "Uredi url", + "Paste in a URL to embed": "Zalijepite URL da biste ga ugradili", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Zalijepi sadržaj dolazi iz Microsoft Word dokumenta. Želite li zadržati format ili očistiti?", + "Keep": "Zadržati", + "Clean": "Čist", + "Word Paste Detected": "Otkrivena je zastavica riječi" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/hu.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/hu.js new file mode 100644 index 0000000..ac954d5 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/hu.js @@ -0,0 +1,340 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Hungarian + */ + +$.FE.LANGUAGE['hu'] = { + translation: { + // Place holder + "Type something": "Szöveg...", + + // Basic formatting + "Bold": "Félkövér", + "Italic": "Dőlt", + "Underline": "Aláhúzott", + "Strikethrough": "Áthúzott", + + // Main buttons + "Insert": "Beillesztés", + "Delete": "Törlés", + "Cancel": "Mégse", + "OK": "Rendben", + "Back": "Vissza", + "Remove": "Eltávolítás", + "More": "Több", + "Update": "Frissítés", + "Style": "Stílus", + + // Font + "Font Family": "Betűtípus", + "Font Size": "Betűméret", + + // Colors + "Colors": "Színek", + "Background": "Háttér", + "Text": "Szöveg", + "HEX Color": "HEX színkód", + + // Paragraphs + "Paragraph Format": "Formátumok", + "Normal": "Normál", + "Code": "Kód", + "Heading 1": "Címsor 1", + "Heading 2": "Címsor 2", + "Heading 3": "Címsor 3", + "Heading 4": "Címsor 4", + + // Style + "Paragraph Style": "Bekezdés stílusa", + "Inline Style": " Helyi stílus", + + // Alignment + "Align": "Igazítás", + "Align Left": "Balra igazít", + "Align Center": "Középre zár", + "Align Right": "Jobbra igazít", + "Align Justify": "Sorkizárás", + "None": "Egyik sem", + + // Lists + "Ordered List": "Számozás", + "Default": "Alapértelmezett", + "Lower Alpha": "Csökkenő alfa", + "Lower Greek": "Csökkenő görög", + "Lower Roman": "Csökkenő római", + "Upper Alpha": "Növekvő alfa", + "Upper Roman": "Növekvő római", + + "Unordered List": "Felsorolás", + "Circle": "Kör", + "Disc": "Korong", + "Square": "Négyzet", + + // Line height + "Line Height": "Vonal magassága", + "Single": "Szimpla", + "Double": "Dupla", + + // Indent + "Decrease Indent": "Behúzás csökkentése", + "Increase Indent": "Behúzás növelése", + + // Links + "Insert Link": "Hivatkozás beillesztése", + "Open in new tab": "Megnyitás új lapon", + "Open Link": "Hivatkozás megnyitása", + "Edit Link": "Hivatkozás szerkesztése", + "Unlink": "Hivatkozás törlése", + "Choose Link": "Keresés a lapok között", + + // Images + "Insert Image": "Kép beillesztése", + "Upload Image": "Kép feltöltése", + "By URL": "Webcím megadása", + "Browse": "Böngészés a Médiában", + "Drop image": "Húzza ide a képet", + "or click": "vagy kattintson ide", + "Manage Images": "Képek kezelése", + "Loading": "Betöltés...", + "Deleting": "Törlés...", + "Tags": "Címkék", + "Are you sure? Image will be deleted.": "Biztos benne? A kép törlésre kerül.", + "Replace": "Csere", + "Uploading": "Feltöltés", + "Loading image": "Kép betöltése", + "Display": "Kijelző", + "Inline": "Sorban", + "Break Text": "Szöveg törése", + "Alternative Text": "Alternatív szöveg", + "Change Size": "Méret módosítása", + "Width": "Szélesség", + "Height": "Magasság", + "Something went wrong. Please try again.": "Valami elromlott. Kérjük próbálja újra.", + "Image Caption": "Képaláírás", + "Advanced Edit": "Fejlett szerkesztés", + + // Video + "Insert Video": "Videó beillesztése", + "Embedded Code": "Kód bemásolása", + "Paste in a video URL": "Illessze be a videó webcímét", + "Drop video": "Húzza ide a videót", + "Your browser does not support HTML5 video.": "A böngészője nem támogatja a HTML5 videókat.", + "Upload Video": "Videó feltöltése", + + // Tables + "Insert Table": "Táblázat beillesztése", + "Table Header": "Táblázat fejléce", + "Remove Table": "Tábla eltávolítása", + "Table Style": "Táblázat stílusa", + "Horizontal Align": "Vízszintes igazítás", + "Row": "Sor", + "Insert row above": "Sor beszúrása elé", + "Insert row below": "Sor beszúrása mögé", + "Delete row": "Sor törlése", + "Column": "Oszlop", + "Insert column before": "Oszlop beszúrása elé", + "Insert column after": "Oszlop beszúrása mögé", + "Delete column": "Oszlop törlése", + "Cell": "Cella", + "Merge cells": "Cellák egyesítése", + "Horizontal split": "Vízszintes osztott", + "Vertical split": "Függőleges osztott", + "Cell Background": "Cella háttere", + "Vertical Align": "Függőleges igazítás", + "Top": "Felső", + "Middle": "Középső", + "Bottom": "Alsó", + "Align Top": "Igazítsa felülre", + "Align Middle": "Igazítsa középre", + "Align Bottom": "Igazítsa alúlra", + "Cell Style": "Cella stílusa", + + // Files + "Upload File": "Fájl feltöltése", + "Drop file": "Húzza ide a fájlt", + + // Emoticons + "Emoticons": "Hangulatjelek", + "Grinning face": "Vigyorgó arc", + "Grinning face with smiling eyes": "Vigyorgó arc mosolygó szemekkel", + "Face with tears of joy": "Arcon az öröm könnyei", + "Smiling face with open mouth": "Mosolygó arc tátott szájjal", + "Smiling face with open mouth and smiling eyes": "Mosolygó arc tátott szájjal és mosolygó szemek", + "Smiling face with open mouth and cold sweat": "Mosolygó arc tátott szájjal és hideg veríték", + "Smiling face with open mouth and tightly-closed eyes": "Mosolygó arc tátott szájjal és lehunyt szemmel", + "Smiling face with halo": "Mosolygó arc dicsfényben", + "Smiling face with horns": "Mosolygó arc szarvakkal", + "Winking face": "Kacsintós arc", + "Smiling face with smiling eyes": "Mosolygó arc mosolygó szemekkel", + "Face savoring delicious food": "Ízletes ételek kóstolása", + "Relieved face": "Megkönnyebbült arc", + "Smiling face with heart-shaped eyes": "Mosolygó arc szív alakú szemekkel", + "Smilin g face with sunglasses": "Mosolygó arc napszemüvegben", + "Smirking face": "Vigyorgó arc", + "Neutral face": "Semleges arc", + "Expressionless face": "Kifejezéstelen arc", + "Unamused face": "Unott arc", + "Face with cold sweat": "Arcán hideg verejtékkel", + "Pensive face": "Töprengő arc", + "Confused face": "Zavaros arc", + "Confounded face": "Rácáfolt arc", + "Kissing face": "Csókos arc", + "Face throwing a kiss": "Arcra dobott egy csókot", + "Kissing face with smiling eyes": "Csókos arcán mosolygó szemek", + "Kissing face with closed eyes": "Csókos arcán csukott szemmel", + "Face with stuck out tongue": "Kinyújototta a nyelvét", + "Face with stuck out tongue and winking eye": "Kinyújtotta a nyelvét és kacsintó szem", + "Face with stuck out tongue and tightly-closed eyes": "Kinyújtotta a nyelvét és szorosan lehunyt szemmel", + "Disappointed face": "Csalódott arc", + "Worried face": "Aggódó arc", + "Angry face": "Dühös arc", + "Pouting face": "Duzzogó arc", + "Crying face": "Síró arc", + "Persevering face": "Kitartó arc", + "Face with look of triumph": "Arcát diadalmas pillantást", + "Disappointed but relieved face": "Csalódott, de megkönnyebbült arc", + "Frowning face with open mouth": "Komor arc tátott szájjal", + "Anguished face": "Gyötrődő arc", + "Fearful face": "Félelmetes arc", + "Weary face": "Fáradt arc", + "Sleepy face": "Álmos arc", + "Tired face": "Fáradt arc", + "Grimacing face": "Elfintorodott arc", + "Loudly crying face": "Hangosan síró arc", + "Face with open mouth": "Arc nyitott szájjal", + "Hushed face": "Csitított arc", + "Face with open mouth and cold sweat": "Arc tátott szájjal és hideg veríték", + "Face screaming in fear": "Sikoltozó arc a félelemtől", + "Astonished face": "Meglepett arc", + "Flushed face": "Kipirult arc", + "Sleeping face": "Alvó arc", + "Dizzy face": " Szádülő arc", + "Face without mouth": "Arc nélküli száj", + "Face with medical mask": "Arcán orvosi maszk", + + // Line breaker + "Break": "Törés", + + // Math + "Subscript": "Alsó index", + "Superscript": "Felső index", + + // Full screen + "Fullscreen": "Teljes képernyő", + + // Horizontal line + "Insert Horizontal Line": "Vízszintes vonal", + + // Clear formatting + "Clear Formatting": "Formázás eltávolítása", + + // Save + "Save": "Mentés", + + // Undo, redo + "Undo": "Visszavonás", + "Redo": "Ismét", + + // Select all + "Select All": "Minden kijelölése", + + // Code view + "Code View": "Forráskód", + + // Quote + "Quote": "Idézet", + "Increase": "Növelés", + "Decrease": "Csökkentés", + + // Quick Insert + "Quick Insert": "Beillesztés", + + // Spcial Characters + "Special Characters": "Speciális karakterek", + "Latin": "Latin", + "Greek": "Görög", + "Cyrillic": "Cirill", + "Punctuation": "Központozás", + "Currency": "Valuta", + "Arrows": "Nyilak", + "Math": "Matematikai", + "Misc": "Egyéb", + + // Print + "Print": "Nyomtatás", + + // Spell Checker + "Spell Checker": "Helyesírás-ellenőrző", + + // Help + "Help": "Segítség", + "Shortcuts": "Hivatkozások", + "Inline Editor": "Inline szerkesztő", + "Show the editor": "Mutassa a szerkesztőt", + "Common actions": "Közös cselekvések", + "Copy": "Másolás", + "Cut": "Kivágás", + "Paste": "Beillesztés", + "Basic Formatting": "Alap formázás", + "Increase quote level": "Növeli az idézet behúzását", + "Decrease quote level": "Csökkenti az idézet behúzását", + "Image / Video": "Kép / videó", + "Resize larger": "Méretezés nagyobbra", + "Resize smaller": "Méretezés kisebbre", + "Table": "Asztal", + "Select table cell": "Válasszon táblázat cellát", + "Extend selection one cell": "Növelje meg egy sorral", + "Extend selection one row": "Csökkentse egy sorral", + "Navigation": "Navigáció", + "Focus popup / toolbar": "Felugró ablak / eszköztár", + "Return focus to previous position": "Visszaáll az előző pozícióra", + + // Embed.ly + "Embed URL": "Beágyazott webcím", + "Paste in a URL to embed": "Beilleszteni egy webcímet a beágyazáshoz", + + // Word Paste + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "A beillesztett tartalom egy Microsoft Word dokumentumból származik. Szeretné megtartani a formázását vagy sem?", + "Keep": "Megtartás", + "Clean": "Tisztítás", + "Word Paste Detected": "Word beillesztés észlelhető", + + // October CMS + "Insert Audio": "Audió beillesztése", + "Insert File": "Fájl beillesztése" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/id.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/id.js new file mode 100644 index 0000000..f79e17a --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/id.js @@ -0,0 +1,337 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Indonesian + */ + +$.FE.LANGUAGE['id'] = { + translation: { + // Place holder + "Type something": "Ketik sesuatu", + + // Basic formatting + "Bold": "Tebal", + "Italic": "Miring", + "Underline": "Garis bawah", + "Strikethrough": "Coret", + + // Main buttons + "Insert": "Memasukkan", + "Delete": "Hapus", + "Cancel": "Batal", + "OK": "Ok", + "Back": "Kembali", + "Remove": "Hapus", + "More": "Lebih", + "Update": "Memperbarui", + "Style": "Gaya", + + // Font + "Font Family": "Jenis Huruf", + "Font Size": "Ukuran leter", + + // Colors + "Colors": "Warna", + "Background": "Latar belakang", + "Text": "Teks", + "HEX Color": "Warna hex", + + // Paragraphs + "Paragraph Format": "Format", + "Normal": "Normal", + "Code": "Kode", + "Heading 1": "Header 1", + "Heading 2": "Header 2", + "Heading 3": "Header 3", + "Heading 4": "Header 4", + + // Style + "Paragraph Style": "Paragraf gaya", + "Inline Style": "Di barisan gaya", + + // Alignment + "Align": "Rate", + "Align Left": "Rate kiri", + "Align Center": "Rate tengah", + "Align Right": "Rata kanan", + "Align Justify": "Justifi", + "None": "Tak satupun", + + // Lists + "Ordered List": "List nomor", + "Default": "Standar", + "Lower Alpha": "Alpha lebih rendah", + "Lower Greek": "Yunani lebih rendah", + "Lower Roman": "Roman rendah", + "Upper Alpha": "Alpha atas", + "Upper Roman": "Roman atas", + + "Unordered List": "List simbol", + "Circle": "Lingkaran", + "Disc": "Cakram", + "Square": "Kotak", + + // Line height + "Line Height": "Tinggi garis", + "Single": "Tunggal", + "Double": "Dua kali lipat", + + // Indent + "Decrease Indent": "Turunkan inden", + "Increase Indent": "Tambah inden", + + // Links + "Insert Link": "Memasukkan link", + "Open in new tab": "Buka di tab baru", + "Open Link": "Buka tautan", + "Edit Link": "Mengedit link", + "Unlink": "Menghapus link", + "Choose Link": "Memilih link", + + // Images + "Insert Image": "Memasukkan gambar", + "Upload Image": "Meng-upload gambar", + "By URL": "Oleh URL", + "Browse": "Melihat-lihat", + "Drop image": "Jatuhkan gambar", + "or click": "atau klik", + "Manage Images": "Mengelola gambar", + "Loading": "Pemuatan", + "Deleting": "Menghapus", + "Tags": "Label", + "Are you sure? Image will be deleted.": "Apakah Anda yakin? Gambar akan dihapus.", + "Replace": "Mengganti", + "Uploading": "Gambar upload", + "Loading image": "Pemuatan gambar", + "Display": "Pameran", + "Inline": "Di barisan", + "Break Text": "Memecah teks", + "Alternative Text": "Teks alternatif", + "Change Size": "Ukuran perubahan", + "Width": "Lebar", + "Height": "Tinggi", + "Something went wrong. Please try again.": "Ada yang salah. Silakan coba lagi.", + "Image Caption": "Keterangan gambar", + "Advanced Edit": "Edit lanjutan", + + // Video + "Insert Video": "Memasukkan video", + "Embedded Code": "Kode tertanam", + "Paste in a video URL": "Paste di url video", + "Drop video": "Jatuhkan video", + "Your browser does not support HTML5 video.": "Browser Anda tidak mendukung video html5.", + "Upload Video": "Mengunggah video", + + // Tables + "Insert Table": "Sisipkan tabel", + "Table Header": "Header tabel", + "Remove Table": "Hapus tabel", + "Table Style": "Gaya tabel", + "Horizontal Align": "Menyelaraskan horisontal", + + "Row": "Baris", + "Insert row above": "Sisipkan baris di atas", + "Insert row below": "Sisipkan baris di bawah", + "Delete row": "Hapus baris", + "Column": "Kolom", + "Insert column before": "Sisipkan kolom sebelumSisipkan kolom sebelum", + "Insert column after": "Sisipkan kolom setelah", + "Delete column": "Hapus kolom", + "Cell": "Sel", + "Merge cells": "Menggabungkan sel", + "Horizontal split": "Perpecahan horisontal", + "Vertical split": "Perpecahan vertikal", + "Cell Background": "Latar belakang sel", + "Vertical Align": "Menyelaraskan vertikal", + "Top": "Teratas", + "Middle": "Tengah", + "Bottom": "Bagian bawah", + "Align Top": "Menyelaraskan atas", + "Align Middle": "Menyelaraskan tengah", + "Align Bottom": "Menyelaraskan bawah", + "Cell Style": "Gaya sel", + + // Files + "Upload File": "Meng-upload berkas", + "Drop file": "Jatuhkan berkas", + + // Emoticons + "Emoticons": "Emoticon", + "Grinning face": "Sambil tersenyum wajah", + "Grinning face with smiling eyes": "Sambil tersenyum wajah dengan mata tersenyum", + "Face with tears of joy": "Hadapi dengan air mata sukacita", + "Smiling face with open mouth": "Tersenyum wajah dengan mulut terbuka", + "Smiling face with open mouth and smiling eyes": "Tersenyum wajah dengan mulut terbuka dan tersenyum mata", + "Smiling face with open mouth and cold sweat": "Tersenyum wajah dengan mulut terbuka dan keringat dingin", + "Smiling face with open mouth and tightly-closed eyes": "Tersenyum wajah dengan mulut terbuka dan mata tertutup rapat", + "Smiling face with halo": "Tersenyum wajah dengan halo", + "Smiling face with horns": "Tersenyum wajah dengan tanduk", + "Winking face": "Mengedip wajah", + "Smiling face with smiling eyes": "Tersenyum wajah dengan mata tersenyum", + "Face savoring delicious food": "Wajah menikmati makanan lezat", + "Relieved face": "Wajah Lega", + "Smiling face with heart-shaped eyes": "Tersenyum wajah dengan mata berbentuk hati", + "Smiling face with sunglasses": "Tersenyum wajah dengan kacamata hitam", + "Smirking face": "Menyeringai wajah", + "Neutral face": "Wajah Netral", + "Expressionless face": "Wajah tanpa ekspresi", + "Unamused face": "Wajah tidak senang", + "Face with cold sweat": "Muka dengan keringat dingin", + "Pensive face": "Wajah termenung", + "Confused face": "Wajah Bingung", + "Confounded face": "Wajah kesal", + "Kissing face": "wajah mencium", + "Face throwing a kiss": "Wajah melempar ciuman", + "Kissing face with smiling eyes": "Berciuman wajah dengan mata tersenyum", + "Kissing face with closed eyes": "Berciuman wajah dengan mata tertutup", + "Face with stuck out tongue": "Muka dengan menjulurkan lidah", + "Face with stuck out tongue and winking eye": "Muka dengan menjulurkan lidah dan mengedip mata", + "Face with stuck out tongue and tightly-closed eyes": "Wajah dengan lidah terjebak dan mata erat-tertutup", + "Disappointed face": "Wajah kecewa", + "Worried face": "Wajah Khawatir", + "Angry face": "Wajah Marah", + "Pouting face": "Cemberut wajah", + "Crying face": "Menangis wajah", + "Persevering face": "Tekun wajah", + "Face with look of triumph": "Hadapi dengan tampilan kemenangan", + "Disappointed but relieved face": "Kecewa tapi lega wajah", + "Frowning face with open mouth": "Sambil mengerutkan kening wajah dengan mulut terbuka", + "Anguished face": "Wajah sedih", + "Fearful face": "Wajah Takut", + "Weary face": "Wajah lelah", + "Sleepy face": "wajah mengantuk", + "Tired face": "Wajah Lelah", + "Grimacing face": "Sambil meringis wajah", + "Loudly crying face": "Keras menangis wajah", + "Face with open mouth": "Hadapi dengan mulut terbuka", + "Hushed face": "Wajah dipetieskan", + "Face with open mouth and cold sweat": "Hadapi dengan mulut terbuka dan keringat dingin", + "Face screaming in fear": "Hadapi berteriak dalam ketakutan", + "Astonished face": "Wajah Kaget", + "Flushed face": "Wajah memerah", + "Sleeping face": "Tidur face", + "Dizzy face": "Wajah pusing", + "Face without mouth": "Wajah tanpa mulut", + "Face with medical mask": "Hadapi dengan masker medis", + + // Line breaker + "Break": "Memecah", + + // Math + "Subscript": "Subskrip", + "Superscript": "Superskrip", + + // Full screen + "Fullscreen": "Layar penuh", + + // Horizontal line + "Insert Horizontal Line": "Sisipkan Garis Horizontal", + + // Clear formatting + "Clear Formatting": "Menghapus format", + + // Save + "Save": "Menyimpan", + + // Undo, redo + "Undo": "Batal", + "Redo": "Ulang", + + // Select all + "Select All": "Pilih semua", + + // Code view + "Code View": "Melihat kode", + + // Quote + "Quote": "Kutipan", + "Increase": "Meningkat", + "Decrease": "Penurunan", + + // Quick Insert + "Quick Insert": "Memasukkan cepat", + + // Spcial Characters + "Special Characters": "Karakter spesial", + "Latin": "Latin", + "Greek": "Yunani", + "Cyrillic": "Kyrillic", + "Punctuation": "Tanda baca", + "Currency": "Mata uang", + "Arrows": "Panah", + "Math": "Matematika", + "Misc": "Misc", + + // Print. + "Print": "Mencetak", + + // Spell Checker. + "Spell Checker": "Pemeriksa ejaan", + + // Help + "Help": "Membantu", + "Shortcuts": "Jalan pintas", + "Inline Editor": "Editor inline", + "Show the editor": "Tunjukkan editornya", + "Common actions": "Tindakan umum", + "Copy": "Salinan", + "Cut": "Memotong", + "Paste": "Pasta", + "Basic Formatting": "Format dasar", + "Increase quote level": "Meningkatkan tingkat kutipan", + "Decrease quote level": "Menurunkan tingkat kutipan", + "Image / Video": "Gambar / video", + "Resize larger": "Mengubah ukuran lebih besar", + "Resize smaller": "Mengubah ukuran lebih kecil", + "Table": "Meja", + "Select table cell": "Pilih sel tabel", + "Extend selection one cell": "Memperpanjang seleksi satu sel", + "Extend selection one row": "Perpanjang pilihan satu baris", + "Navigation": "Navigasi", + "Focus popup / toolbar": "Fokus popup / toolbar", + "Return focus to previous position": "Kembali fokus ke posisi sebelumnya", + + // Embed.ly + "Embed URL": "Embed url", + "Paste in a URL to embed": "Paste di url untuk menanamkan", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Konten yang disisipkan berasal dari dokumen kata microsoft. apakah Anda ingin menyimpan format atau membersihkannya?", + "Keep": "Menjaga", + "Clean": "Bersih", + "Word Paste Detected": "Kata paste terdeteksi" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/it.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/it.js new file mode 100644 index 0000000..e87fdec --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/it.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Italian + */ + +$.FE.LANGUAGE['it'] = { + translation: { + // Place holder + "Type something": "Digita qualcosa", + + // Basic formatting + "Bold": "Grassetto", + "Italic": "Corsivo", + "Underline": "Sottolineato", + "Strikethrough": "Barrato", + + // Main buttons + "Insert": "Inserisci", + "Delete": "Cancella", + "Cancel": "Cancella", + "OK": "OK", + "Back": "Indietro", + "Remove": "Rimuovi", + "More": "Di pi\u00f9", + "Update": "Aggiorna", + "Style": "Stile", + + // Font + "Font Family": "Carattere", + "Font Size": "Dimensione Carattere", + + // Colors + "Colors": "Colori", + "Background": "Sfondo", + "Text": "Testo", + "HEX Color": "Colore Esadecimale", + + // Paragraphs + "Paragraph Format": "Formattazione", + "Normal": "Normale", + "Code": "Codice", + "Heading 1": "Intestazione 1", + "Heading 2": "Intestazione 2", + "Heading 3": "Intestazione 3", + "Heading 4": "Intestazione 4", + + // Style + "Paragraph Style": "Stile Paragrafo", + "Inline Style": "Stile in Linea", + + // Alignment + "Align": "Allinea", + "Align Left": "Allinea a Sinistra", + "Align Center": "Allinea al Cento", + "Align Right": "Allinea a Destra", + "Align Justify": "Giustifica", + "None": "Nessuno", + + // Lists + "Ordered List": "Elenchi Numerati", + "Default": "Predefinito", + "Lower Alpha": "Alfa inferiore", + "Lower Greek": "Basso greco", + "Lower Roman": "Romano inferiore", + "Upper Alpha": "Alfa superiore", + "Upper Roman": "Alto romano", + + "Unordered List": "Elenchi Puntati", + "Circle": "Cerchio", + "Disc": "Disco", + "Square": "Piazza", + + // Line height + "Line Height": "Altezza della linea", + "Single": "Singolo", + "Double": "Doppio", + + // Indent + "Decrease Indent": "Riduci Rientro", + "Increase Indent": "Aumenta Rientro", + + // Links + "Insert Link": "Inserisci Link", + "Open in new tab": "Apri in nuova scheda", + "Open Link": "Apri Link", + "Edit Link": "Modifica Link", + "Unlink": "Rimuovi Link", + "Choose Link": "Scegli Link", + + // Images + "Insert Image": "Inserisci Immagine", + "Upload Image": "Carica Immagine", + "By URL": "Inserisci URL", + "Browse": "Sfoglia", + "Drop image": "Rilascia immagine", + "or click": "oppure clicca qui", + "Manage Images": "Gestione Immagini", + "Loading": "Caricamento", + "Deleting": "Eliminazione", + "Tags": "Etichetta", + "Are you sure? Image will be deleted.": "Sei sicuro? L\'immagine verr\u00e0 cancellata.", + "Replace": "Sostituisci", + "Uploading": "Caricamento", + "Loading image": "Caricamento immagine", + "Display": "Visualizzazione", + "Inline": "In Linea", + "Break Text": "Separa dal Testo", + "Alternative Text": "Testo Alternativo", + "Change Size": "Cambia Dimensioni", + "Width": "Larghezza", + "Height": "Altezza", + "Something went wrong. Please try again.": "Qualcosa non ha funzionato. Riprova, per favore.", + "Image Caption": "Didascalia", + "Advanced Edit": "Avanzato", + + // Video + "Insert Video": "Inserisci Video", + "Embedded Code": "Codice Incorporato", + "Paste in a video URL": "Incolla l'URL del video", + "Drop video": "Rilascia video", + "Your browser does not support HTML5 video.": "Il tuo browser non supporta i video html5.", + "Upload Video": "Carica Video", + + // Tables + "Insert Table": "Inserisci Tabella", + "Table Header": "Intestazione Tabella", + "Remove Table": "Rimuovi Tabella", + "Table Style": "Stile Tabella", + "Horizontal Align": "Allineamento Orizzontale", + "Row": "Riga", + "Insert row above": "Inserisci una riga prima", + "Insert row below": "Inserisci una riga dopo", + "Delete row": "Cancella riga", + "Column": "Colonna", + "Insert column before": "Inserisci una colonna prima", + "Insert column after": "Inserisci una colonna dopo", + "Delete column": "Cancella colonna", + "Cell": "Cella", + "Merge cells": "Unisci celle", + "Horizontal split": "Dividi in orizzontale", + "Vertical split": "Dividi in verticale", + "Cell Background": "Sfondo Cella", + "Vertical Align": "Allineamento Verticale", + "Top": "Alto", + "Middle": "Centro", + "Bottom": "Basso", + "Align Top": "Allinea in Alto", + "Align Middle": "Allinea al Centro", + "Align Bottom": "Allinea in Basso", + "Cell Style": "Stile Cella", + + // Files + "Upload File": "Carica File", + "Drop file": "Rilascia file", + + // Emoticons + "Emoticons": "Emoticon", + "Grinning face": "Sorridente", + "Grinning face with smiling eyes": "Sorridente con gli occhi sorridenti", + "Face with tears of joy": "Con lacrime di gioia", + "Smiling face with open mouth": "Sorridente con la bocca aperta", + "Smiling face with open mouth and smiling eyes": "Sorridente con la bocca aperta e gli occhi sorridenti", + "Smiling face with open mouth and cold sweat": "Sorridente con la bocca aperta e sudore freddo", + "Smiling face with open mouth and tightly-closed eyes": "Sorridente con la bocca aperta e gli occhi stretti", + "Smiling face with halo": "Sorridente con aureola", + "Smiling face with horns": "Diavolo sorridente", + "Winking face": "Ammiccante", + "Smiling face with smiling eyes": "Sorridente imbarazzato", + "Face savoring delicious food": "Goloso", + "Relieved face": "Rassicurato", + "Smiling face with heart-shaped eyes": "Sorridente con gli occhi a forma di cuore", + "Smiling face with sunglasses": "Sorridente con gli occhiali da sole", + "Smirking face": "Compiaciuto", + "Neutral face": "Neutro", + "Expressionless face": "Inespressivo", + "Unamused face": "Annoiato", + "Face with cold sweat": "Sudare freddo", + "Pensive face": "Pensieroso", + "Confused face": "Perplesso", + "Confounded face": "Confuso", + "Kissing face": "Bacio", + "Face throwing a kiss": "Manda un bacio", + "Kissing face with smiling eyes": "Bacio con gli occhi sorridenti", + "Kissing face with closed eyes": "Bacio con gli occhi chiusi", + "Face with stuck out tongue": "Linguaccia", + "Face with stuck out tongue and winking eye": "Linguaccia ammiccante", + "Face with stuck out tongue and tightly-closed eyes": "Linguaccia con occhi stretti", + "Disappointed face": "Deluso", + "Worried face": "Preoccupato", + "Angry face": "Arrabbiato", + "Pouting face": "Imbronciato", + "Crying face": "Pianto", + "Persevering face": "Perseverante", + "Face with look of triumph": "Trionfante", + "Disappointed but relieved face": "Deluso ma rassicurato", + "Frowning face with open mouth": "Accigliato con la bocca aperta", + "Anguished face": "Angosciato", + "Fearful face": "Pauroso", + "Weary face": "Stanco", + "Sleepy face": "Assonnato", + "Tired face": "Snervato", + "Grimacing face": "Smorfia", + "Loudly crying face": "Pianto a gran voce", + "Face with open mouth": "Bocca aperta", + "Hushed face": "Silenzioso", + "Face with open mouth and cold sweat": "Bocca aperta e sudore freddo", + "Face screaming in fear": "Urlante dalla paura", + "Astonished face": "Stupito", + "Flushed face": "Arrossito", + "Sleeping face": "Addormentato", + "Dizzy face": "Stordito", + "Face without mouth": "Senza parole", + "Face with medical mask": "Malattia infettiva", + + // Line breaker + "Break": "Separatore", + + // Math + "Subscript": "Pedice", + "Superscript": "Apice", + + // Full screen + "Fullscreen": "Schermo intero", + + // Horizontal line + "Insert Horizontal Line": "Inserisci Divisore Orizzontale", + + // Clear formatting + "Clear Formatting": "Cancella Formattazione", + + // Save + "Save": "Salvare", + + // Undo, redo + "Undo": "Annulla", + "Redo": "Ripeti", + + // Select all + "Select All": "Seleziona Tutto", + + // Code view + "Code View": "Visualizza Codice", + + // Quote + "Quote": "Citazione", + "Increase": "Aumenta", + "Decrease": "Diminuisci", + + // Quick Insert + "Quick Insert": "Inserimento Rapido", + + // Spcial Characters + "Special Characters": "Caratteri Speciali", + "Latin": "Latino", + "Greek": "Greco", + "Cyrillic": "Cirillico", + "Punctuation": "Punteggiatura", + "Currency": "Valuta", + "Arrows": "Frecce", + "Math": "Matematica", + "Misc": "Misc", + + // Print. + "Print": "Stampa", + + // Spell Checker. + "Spell Checker": "Correttore Ortografico", + + // Help + "Help": "Aiuto", + "Shortcuts": "Scorciatoie", + "Inline Editor": "Editor in Linea", + "Show the editor": "Mostra Editor", + "Common actions": "Azioni comuni", + "Copy": "Copia", + "Cut": "Taglia", + "Paste": "Incolla", + "Basic Formatting": "Formattazione di base", + "Increase quote level": "Aumenta il livello di citazione", + "Decrease quote level": "Diminuisci il livello di citazione", + "Image / Video": "Immagine / Video", + "Resize larger": "Pi\u00f9 grande", + "Resize smaller": "Pi\u00f9 piccolo", + "Table": "Tabella", + "Select table cell": "Seleziona la cella della tabella", + "Extend selection one cell": "Estendi la selezione di una cella", + "Extend selection one row": "Estendi la selezione una riga", + "Navigation": "Navigazione", + "Focus popup / toolbar": "Metti a fuoco la barra degli strumenti", + "Return focus to previous position": "Rimetti il fuoco sulla posizione precedente", + + // Embed.ly + "Embed URL": "Incorpora URL", + "Paste in a URL to embed": "Incolla un URL da incorporare", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Il contenuto incollato proviene da un documento di Microsoft Word. Vuoi mantenere la formattazione di Word o pulirlo?", + "Keep": "Mantieni", + "Clean": "Pulisci", + "Word Paste Detected": "\u00c8 stato rilevato un incolla da Word" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ja.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ja.js new file mode 100644 index 0000000..70464b4 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ja.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Japanese + */ + +$.FE.LANGUAGE['ja'] = { + translation: { + // Place holder + "Type something": "\u3053\u3053\u306b\u5165\u529b\u3057\u307e\u3059", + + // Basic formatting + "Bold": "\u592a\u5b57", + "Italic": "\u659c\u4f53", + "Underline": "\u4e0b\u7dda", + "Strikethrough": "\u53d6\u308a\u6d88\u3057\u7dda", + + // Main buttons + "Insert": "\u633f\u5165", + "Delete": "\u524a\u9664", + "Cancel": "\u30ad\u30e3\u30f3\u30bb\u30eb", + "OK": "OK", + "Back": "\u623b\u308b", + "Remove": "\u524a\u9664", + "More": "\u3082\u3063\u3068", + "Update": "\u66f4\u65b0", + "Style": "\u30b9\u30bf\u30a4\u30eb", + + // Font + "Font Family": "\u30d5\u30a9\u30f3\u30c8", + "Font Size": "\u30d5\u30a9\u30f3\u30c8\u30b5\u30a4\u30ba", + + // Colors + "Colors": "\u8272", + "Background": "\u80cc\u666f", + "Text": "\u30c6\u30ad\u30b9\u30c8", + "HEX Color": "\u30d8\u30ad\u30b5\u306e\u8272", + + // Paragraphs + "Paragraph Format": "\u6bb5\u843d\u306e\u66f8\u5f0f", + "Normal": "\u6a19\u6e96", + "Code": "\u30b3\u30fc\u30c9", + "Heading 1": "\u30d8\u30c3\u30c0\u30fc 1", + "Heading 2": "\u30d8\u30c3\u30c0\u30fc 2", + "Heading 3": "\u30d8\u30c3\u30c0\u30fc 3", + "Heading 4": "\u30d8\u30c3\u30c0\u30fc 4", + + // Style + "Paragraph Style": "\u6bb5\u843d\u30b9\u30bf\u30a4\u30eb", + "Inline Style": "\u30a4\u30f3\u30e9\u30a4\u30f3\u30b9\u30bf\u30a4\u30eb", + + // Alignment + "Align": "\u914d\u7f6e", + "Align Left": "\u5de6\u63c3\u3048", + "Align Center": "\u4e2d\u592e\u63c3\u3048", + "Align Right": "\u53f3\u63c3\u3048", + "Align Justify": "\u4e21\u7aef\u63c3\u3048", + "None": "\u306a\u3057", + + // Lists + "Ordered List": "\u6bb5\u843d\u756a\u53f7", + "Default": "デフォルト", + "Lower Alpha": "下アルファ", + "Lower Greek": "下ギリシャ", + "Lower Roman": "下ローマ", + "Upper Alpha": "アッパーアルファ", + "Upper Roman": "アッパーローマン", + + "Unordered List": "\u7b87\u6761\u66f8\u304d", + "Circle": "サークル", + "Disc": "ディスク", + "Square": "平方", + + // Line height + "Line Height": "行の高さ", + "Single": "シングル", + "Double": "ダブル", + + // Indent + "Decrease Indent": "\u30a4\u30f3\u30c7\u30f3\u30c8\u3092\u6e1b\u3089\u3059", + "Increase Indent": "\u30a4\u30f3\u30c7\u30f3\u30c8\u3092\u5897\u3084\u3059", + + // Links + "Insert Link": "\u30ea\u30f3\u30af\u306e\u633f\u5165", + "Open in new tab": "\u65b0\u3057\u3044\u30bf\u30d6\u3067\u958b\u304f", + "Open Link": "\u30ea\u30f3\u30af\u3092\u958b\u304f", + "Edit Link": "\u30ea\u30f3\u30af\u306e\u7de8\u96c6", + "Unlink": "\u30ea\u30f3\u30af\u306e\u524a\u9664", + "Choose Link": "\u30ea\u30f3\u30af\u3092\u9078\u629e", + + // Images + "Insert Image": "\u753b\u50cf\u306e\u633f\u5165", + "Upload Image": "\u753b\u50cf\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9", + "By URL": "\u753b\u50cf\u306eURL\u3092\u5165\u529b", + "Browse": "\u53c2\u7167", + "Drop image": "\u753b\u50cf\u3092\u30c9\u30e9\u30c3\u30b0&\u30c9\u30ed\u30c3\u30d7", + "or click": "\u307e\u305f\u306f\u30af\u30ea\u30c3\u30af", + "Manage Images": "\u753b\u50cf\u306e\u7ba1\u7406", + "Loading": "\u8aad\u307f\u8fbc\u307f\u4e2d", + "Deleting": "\u524a\u9664", + "Tags": "\u30bf\u30b0", + "Are you sure? Image will be deleted.": "\u672c\u5f53\u306b\u524a\u9664\u3057\u307e\u3059\u304b\uff1f", + "Replace": "\u7f6e\u63db", + "Uploading": "\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u4e2d", + "Loading image": "\u753b\u50cf\u8aad\u307f\u8fbc\u307f\u4e2d", + "Display": "\u8868\u793a", + "Inline": "\u30a4\u30f3\u30e9\u30a4\u30f3", + "Break Text": "\u30c6\u30ad\u30b9\u30c8\u306e\u6539\u884c", + "Alternative Text": "\u4ee3\u66ff\u30c6\u30ad\u30b9\u30c8", + "Change Size": "\u30b5\u30a4\u30ba\u5909\u66f4", + "Width": "\u5e45", + "Height": "\u9ad8\u3055", + "Something went wrong. Please try again.": "\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u3082\u3046\u4e00\u5ea6\u3084\u308a\u76f4\u3057\u3066\u304f\u3060\u3055\u3044\u3002", + "Image Caption": "\u753b\u50cf\u30ad\u30e3\u30d7\u30b7\u30e7\u30f3", + "Advanced Edit": "\u9ad8\u5ea6\u306a\u7de8\u96c6", + + // Video + "Insert Video": "\u52d5\u753b\u306e\u633f\u5165", + "Embedded Code": "\u57cb\u3081\u8fbc\u307f\u30b3\u30fc\u30c9", + "Paste in a video URL": "\u52d5\u753bURL\u306b\u8cbc\u308a\u4ed8\u3051\u308b", + "Drop video": "\u52d5\u753b\u3092\u30c9\u30e9\u30c3\u30b0&\u30c9\u30ed\u30c3\u30d7", + "Your browser does not support HTML5 video.": "\u3042\u306a\u305f\u306e\u30d6\u30e9\u30a6\u30b6\u306fhtml5 video\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u305b\u3093\u3002", + "Upload Video": "\u52d5\u753b\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9", + + // Tables + "Insert Table": "\u8868\u306e\u633f\u5165", + "Table Header": "\u8868\u306e\u30d8\u30c3\u30c0\u30fc", + "Remove Table": "\u8868\u306e\u524a\u9664", + "Table Style": "\u8868\u306e\u30b9\u30bf\u30a4\u30eb", + "Horizontal Align": "\u6a2a\u4f4d\u7f6e", + "Row": "\u884c", + "Insert row above": "\u4e0a\u306b\u884c\u3092\u633f\u5165", + "Insert row below": "\u4e0b\u306b\u884c\u3092\u633f\u5165", + "Delete row": "\u884c\u306e\u524a\u9664", + "Column": "\u5217", + "Insert column before": "\u5de6\u306b\u5217\u3092\u633f\u5165", + "Insert column after": "\u53f3\u306b\u5217\u3092\u633f\u5165", + "Delete column": "\u5217\u306e\u524a\u9664", + "Cell": "\u30bb\u30eb", + "Merge cells": "\u30bb\u30eb\u306e\u7d50\u5408", + "Horizontal split": "\u6a2a\u5206\u5272", + "Vertical split": "\u7e26\u5206\u5272", + "Cell Background": "\u30bb\u30eb\u306e\u80cc\u666f", + "Vertical Align": "\u7e26\u4f4d\u7f6e", + "Top": "\u4e0a\u63c3\u3048", + "Middle": "\u4e2d\u592e\u63c3\u3048", + "Bottom": "\u4e0b\u63c3\u3048", + "Align Top": "\u4e0a\u306b\u63c3\u3048\u307e\u3059", + "Align Middle": "\u4e2d\u592e\u306b\u63c3\u3048\u307e\u3059", + "Align Bottom": "\u4e0b\u306b\u63c3\u3048\u307e\u3059", + "Cell Style": "\u30bb\u30eb\u30b9\u30bf\u30a4\u30eb", + + // Files + "Upload File": "\u30d5\u30a1\u30a4\u30eb\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9", + "Drop file": "\u30d5\u30a1\u30a4\u30eb\u3092\u30c9\u30e9\u30c3\u30b0&\u30c9\u30ed\u30c3\u30d7", + + // Emoticons + "Emoticons": "\u7d75\u6587\u5b57", + "Grinning face": "\u30cb\u30f3\u30de\u30ea\u9854", + "Grinning face with smiling eyes": "\u30cb\u30f3\u30de\u30ea\u9854(\u7b11\u3063\u3066\u3044\u308b\u76ee)", + "Face with tears of joy": "\u5b09\u3057\u6ce3\u304d\u3059\u308b\u9854", + "Smiling face with open mouth": "\u7b11\u9854(\u5e83\u3052\u305f\u53e3)", + "Smiling face with open mouth and smiling eyes": "\u7b11\u9854(\u5e83\u3052\u305f\u53e3\u3001\u7b11\u3063\u3066\u3044\u308b\u76ee)", + "Smiling face with open mouth and cold sweat": "\u7b11\u9854(\u5e83\u3052\u305f\u53e3\u3001\u51b7\u3084\u6c57)", + "Smiling face with open mouth and tightly-closed eyes": "\u7b11\u9854(\u5e83\u3052\u305f\u53e3\u3001\u3057\u3063\u304b\u308a\u9589\u3058\u305f\u76ee)", + "Smiling face with halo": "\u5929\u4f7f\u306e\u8f2a\u304c\u304b\u304b\u3063\u3066\u3044\u308b\u7b11\u9854", + "Smiling face with horns": "\u89d2\u306e\u3042\u308b\u7b11\u9854", + "Winking face": "\u30a6\u30a3\u30f3\u30af\u3057\u305f\u9854", + "Smiling face with smiling eyes": "\u7b11\u9854(\u7b11\u3063\u3066\u3044\u308b\u76ee)", + "Face savoring delicious food": "\u304a\u3044\u3057\u3044\u3082\u306e\u3092\u98df\u3079\u305f\u9854", + "Relieved face": "\u5b89\u5fc3\u3057\u305f\u9854", + "Smiling face with heart-shaped eyes": "\u76ee\u304c\u30cf\u30fc\u30c8\u306e\u7b11\u9854", + "Smiling face with sunglasses": "\u30b5\u30f3\u30b0\u30e9\u30b9\u3092\u304b\u3051\u305f\u7b11\u9854", + "Smirking face": "\u4f5c\u308a\u7b11\u3044", + "Neutral face": "\u7121\u8868\u60c5\u306e\u9854", + "Expressionless face": "\u7121\u8868\u60c5\u306a\u9854", + "Unamused face": "\u3064\u307e\u3089\u306a\u3044\u9854", + "Face with cold sweat": "\u51b7\u3084\u6c57\u3092\u304b\u3044\u305f\u9854", + "Pensive face": "\u8003\u3048\u4e2d\u306e\u9854", + "Confused face": "\u5c11\u3057\u3057\u3087\u3093\u307c\u308a\u3057\u305f\u9854", + "Confounded face": "\u56f0\u308a\u679c\u3066\u305f\u9854", + "Kissing face": "\u30ad\u30b9\u3059\u308b\u9854", + "Face throwing a kiss": "\u6295\u3052\u30ad\u30c3\u30b9\u3059\u308b\u9854", + "Kissing face with smiling eyes": "\u7b11\u3044\u306a\u304c\u3089\u30ad\u30b9\u3059\u308b\u9854", + "Kissing face with closed eyes": "\u76ee\u3092\u9589\u3058\u3066\u30ad\u30b9\u3059\u308b\u9854", + "Face with stuck out tongue": "\u304b\u3089\u304b\u3063\u305f\u9854(\u3042\u3063\u304b\u3093\u3079\u3048)", + "Face with stuck out tongue and winking eye": "\u30a6\u30a3\u30f3\u30af\u3057\u3066\u820c\u3092\u51fa\u3057\u305f\u9854", + "Face with stuck out tongue and tightly-closed eyes": "\u76ee\u3092\u9589\u3058\u3066\u820c\u3092\u51fa\u3057\u305f\u9854", + "Disappointed face": "\u843d\u3061\u8fbc\u3093\u3060\u9854", + "Worried face": "\u4e0d\u5b89\u306a\u9854", + "Angry face": "\u6012\u3063\u305f\u9854", + "Pouting face": "\u3075\u304f\u308c\u9854", + "Crying face": "\u6ce3\u3044\u3066\u3044\u308b\u9854", + "Persevering face": "\u5931\u6557\u9854", + "Face with look of triumph": "\u52dd\u3061\u307b\u3053\u3063\u305f\u9854", + "Disappointed but relieved face": "\u5b89\u5835\u3057\u305f\u9854", + "Frowning face with open mouth": "\u3044\u3084\u306a\u9854(\u958b\u3051\u305f\u53e3)", + "Anguished face": "\u3052\u3093\u306a\u308a\u3057\u305f\u9854", + "Fearful face": "\u9752\u3056\u3081\u305f\u9854", + "Weary face": "\u75b2\u308c\u305f\u9854", + "Sleepy face": "\u7720\u3044\u9854", + "Tired face": "\u3057\u3093\u3069\u3044\u9854", + "Grimacing face": "\u3061\u3087\u3063\u3068\u4e0d\u5feb\u306a\u9854", + "Loudly crying face": "\u5927\u6ce3\u304d\u3057\u3066\u3044\u308b\u9854", + "Face with open mouth": "\u53e3\u3092\u958b\u3051\u305f\u9854", + "Hushed face": "\u9ed9\u3063\u305f\u9854", + "Face with open mouth and cold sweat": "\u53e3\u3092\u958b\u3051\u305f\u9854(\u51b7\u3084\u6c57)", + "Face screaming in fear": "\u6050\u6016\u306e\u53eb\u3073\u9854", + "Astonished face": "\u9a5a\u3044\u305f\u9854", + "Flushed face": "\u71b1\u3063\u307d\u3044\u9854", + "Sleeping face": "\u5bdd\u9854", + "Dizzy face": "\u307e\u3044\u3063\u305f\u9854", + "Face without mouth": "\u53e3\u306e\u306a\u3044\u9854", + "Face with medical mask": "\u30de\u30b9\u30af\u3057\u305f\u9854", + + // Line breaker + "Break": "\u6539\u884c", + + // Math + "Subscript": "\u4e0b\u4ed8\u304d\u6587\u5b57", + "Superscript": "\u4e0a\u4ed8\u304d\u6587\u5b57", + + // Full screen + "Fullscreen": "\u5168\u753b\u9762\u8868\u793a", + + // Horizontal line + "Insert Horizontal Line": "\u6c34\u5e73\u7dda\u306e\u633f\u5165", + + // Clear formatting + "Clear Formatting": "\u66f8\u5f0f\u306e\u30af\u30ea\u30a2", + + // Save + "Save": "\u30bb\u30fc\u30d6", + + // Undo, redo + "Undo": "\u5143\u306b\u623b\u3059", + "Redo": "\u3084\u308a\u76f4\u3059", + + // Select all + "Select All": "\u5168\u3066\u3092\u9078\u629e", + + // Code view + "Code View": "HTML\u30bf\u30b0\u8868\u793a", + + // Quote + "Quote": "\u5f15\u7528", + "Increase": "\u5897\u52a0", + "Decrease": "\u6e1b\u5c11", + + // Quick Insert + "Quick Insert": "\u30af\u30a4\u30c3\u30af\u633f\u5165", + + // Spcial Characters + "Special Characters": "\u7279\u6b8a\u6587\u5b57", + "Latin": "\u30e9\u30c6\u30f3\u8a9e", + "Greek": "\u30ae\u30ea\u30b7\u30e3\u8a9e", + "Cyrillic": "\u30ad\u30ea\u30eb\u6587\u5b57", + "Punctuation": "\u53e5\u8aad\u70b9", + "Currency": "\u901a\u8ca8", + "Arrows": "\u77e2\u5370", + "Math": "\u6570\u5b66", + "Misc": "\u305d\u306e\u4ed6", + + // Print. + "Print": "\u5370\u5237", + + // Spell Checker. + "Spell Checker": "\u30b9\u30da\u30eb\u30c1\u30a7\u30c3\u30af", + + // Help + "Help": "\u30d8\u30eb\u30d7", + "Shortcuts": "\u30b7\u30e7\u30fc\u30c8\u30ab\u30c3\u30c8", + "Inline Editor": "\u30a4\u30f3\u30e9\u30a4\u30f3\u30a8\u30c7\u30a3\u30bf", + "Show the editor": "\u30a8\u30c7\u30a3\u30bf\u3092\u8868\u793a", + "Common actions": "\u4e00\u822c\u52d5\u4f5c", + "Copy": "\u30b3\u30d4\u30fc", + "Cut": "\u30ab\u30c3\u30c8", + "Paste": "\u8cbc\u308a\u4ed8\u3051", + "Basic Formatting": "\u57fa\u672c\u66f8\u5f0f", + "Increase quote level": "\u5f15\u7528\u3092\u5897\u3084\u3059", + "Decrease quote level": "\u5f15\u7528\u3092\u6e1b\u3089\u3059", + "Image / Video": "\u753b\u50cf/\u52d5\u753b", + "Resize larger": "\u5927\u304d\u304f\u3059\u308b", + "Resize smaller": "\u5c0f\u3055\u304f\u3059\u308b", + "Table": "\u8868", + "Select table cell": "\u30bb\u30eb\u3092\u9078\u629e", + "Extend selection one cell": "\u30bb\u30eb\u306e\u9078\u629e\u7bc4\u56f2\u3092\u5e83\u3052\u308b", + "Extend selection one row": "\u5217\u306e\u9078\u629e\u7bc4\u56f2\u3092\u5e83\u3052\u308b", + "Navigation": "\u30ca\u30d3\u30b2\u30fc\u30b7\u30e7\u30f3", + "Focus popup / toolbar": "\u30dd\u30c3\u30d7\u30a2\u30c3\u30d7/\u30c4\u30fc\u30eb\u30d0\u30fc\u3092\u30d5\u30a9\u30fc\u30ab\u30b9", + "Return focus to previous position": "\u524d\u306e\u4f4d\u7f6e\u306b\u30d5\u30a9\u30fc\u30ab\u30b9\u3092\u623b\u3059", + + //\u00a0Embed.ly + "Embed URL": "\u57cb\u3081\u8fbc\u307fURL", + "Paste in a URL to embed": "\u57cb\u3081\u8fbc\u307fURL\u306b\u8cbc\u308a\u4ed8\u3051\u308b", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "\u8cbc\u308a\u4ed8\u3051\u305f\u6587\u66f8\u306fMicrosoft Word\u304b\u3089\u53d6\u5f97\u3055\u308c\u307e\u3059\u3002\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u3092\u4fdd\u6301\u3057\u3066\u8cbc\u308a\u4ed8\u3051\u307e\u3059\u304b\uff1f", + "Keep": "\u66f8\u5f0f\u3092\u4fdd\u6301\u3059\u308b", + "Clean": "\u66f8\u5f0f\u3092\u4fdd\u6301\u3057\u306a\u3044", + "Word Paste Detected": "Microsoft Word\u306e\u8cbc\u308a\u4ed8\u3051\u304c\u691c\u51fa\u3055\u308c\u307e\u3057\u305f" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ko.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ko.js new file mode 100644 index 0000000..c18ade0 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ko.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Korean + */ + +$.FE.LANGUAGE['ko'] = { + translation: { + // Place holder + "Type something": "\ub0b4\uc6a9\uc744 \uc785\ub825\ud558\uc138\uc694", + + // Basic formatting + "Bold": "\uad75\uac8c", + "Italic": "\uae30\uc6b8\uc784\uaf34", + "Underline": "\ubc11\uc904", + "Strikethrough": "\ucde8\uc18c\uc120", + + // Main buttons + "Insert": "\uc0bd\uc785", + "Delete": "\uc0ad\uc81c", + "Cancel": "\ucde8\uc18c", + "OK": "\uc2b9\uc778", + "Back": "\ub4a4\ub85c", + "Remove": "\uc81c\uac70", + "More": "\ub354", + "Update": "\uc5c5\ub370\uc774\ud2b8", + "Style": "\uc2a4\ud0c0\uc77c", + + // Font + "Font Family": "\uae00\uaf34", + "Font Size": "\ud3f0\ud2b8 \ud06c\uae30", + + // Colors + "Colors": "\uc0c9\uc0c1", + "Background": "\ubc30\uacbd", + "Text": "\ud14d\uc2a4\ud2b8", + "HEX Color": "\ud5e5\uc2a4 \uc0c9\uc0c1", + + // Paragraphs + "Paragraph Format": "\ub2e8\ub77d", + "Normal": "\ud45c\uc900", + "Code": "\ucf54\ub4dc", + "Heading 1": "\uc81c\ubaa9 1", + "Heading 2": "\uc81c\ubaa9 2", + "Heading 3": "\uc81c\ubaa9 3", + "Heading 4": "\uc81c\ubaa9 4", + + // Style + "Paragraph Style": "\ub2e8\ub77d \uc2a4\ud0c0\uc77c", + "Inline Style": "\uc778\ub77c\uc778 \uc2a4\ud0c0\uc77c", + + // Alignment + "Align": "\uc815\ub82c", + "Align Left": "\uc67c\ucabd\uc815\ub82c", + "Align Center": "\uac00\uc6b4\ub370\uc815\ub82c", + "Align Right": "\uc624\ub978\ucabd\uc815\ub82c", + "Align Justify": "\uc591\ucabd\uc815\ub82c", + "None": "\uc5c6\uc74c", + + // Lists + "Ordered List": "\uc22b\uc790 \ub9ac\uc2a4\ud2b8", + "Default": "태만", + "Lower Alpha": "낮은 알파", + "Lower Greek": "낮은 그리스어", + "Lower Roman": "로마자 낮은", + "Upper Alpha": "상단 알파", + "Upper Roman": "상층 로마자", + + "Unordered List": "\uc810 \ub9ac\uc2a4\ud2b8", + "Circle": "원", + "Disc": "디스크", + "Square": "광장", + + // Line height + "Line Height": "라인 높이", + "Single": "단일", + "Double": "더블", + + // Indent + "Decrease Indent": "\ub0b4\uc5b4\uc4f0\uae30", + "Increase Indent": "\ub4e4\uc5ec\uc4f0\uae30", + + // Links + "Insert Link": "\ub9c1\ud06c \uc0bd\uc785", + "Open in new tab": "\uc0c8 \ud0ed\uc5d0\uc11c \uc5f4\uae30", + "Open Link": "\ub9c1\ud06c \uc5f4\uae30", + "Edit Link": "\ud3b8\uc9d1 \ub9c1\ud06c", + "Unlink": "\ub9c1\ud06c\uc0ad\uc81c", + "Choose Link": "\ub9c1\ud06c\ub97c \uc120\ud0dd", + + // Images + "Insert Image": "\uc774\ubbf8\uc9c0 \uc0bd\uc785", + "Upload Image": "\uc774\ubbf8\uc9c0 \uc5c5\ub85c\ub4dc", + "By URL": "URL \ub85c", + "Browse": "\uac80\uc0c9", + "Drop image": "\uc774\ubbf8\uc9c0\ub97c \ub4dc\ub798\uadf8&\ub4dc\ub86d", + "or click": "\ub610\ub294 \ud074\ub9ad", + "Manage Images": "\uc774\ubbf8\uc9c0 \uad00\ub9ac", + "Loading": "\ub85c\ub4dc", + "Deleting": "\uc0ad\uc81c", + "Tags": "\ud0dc\uadf8", + "Are you sure? Image will be deleted.": "\ud655\uc2e4\ud55c\uac00\uc694? \uc774\ubbf8\uc9c0\uac00 \uc0ad\uc81c\ub429\ub2c8\ub2e4.", + "Replace": "\uad50\uccb4", + "Uploading": "\uc5c5\ub85c\ub4dc", + "Loading image": "\uc774\ubbf8\uc9c0 \ub85c\ub4dc \uc911", + "Display": "\ub514\uc2a4\ud50c\ub808\uc774", + "Inline": "\uc778\ub77c\uc778", + "Break Text": "\uad6c\ubd84 \ud14d\uc2a4\ud2b8", + "Alternative Text": "\ub300\uccb4 \ud14d\uc2a4\ud2b8", + "Change Size": "\ud06c\uae30 \ubcc0\uacbd", + "Width": "\ud3ed", + "Height": "\ub192\uc774", + "Something went wrong. Please try again.": "\ubb38\uc81c\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud558\uc2ed\uc2dc\uc624.", + "Image Caption": "\uc774\ubbf8\uc9c0 \ucea1\uc158", + "Advanced Edit": "\uace0\uae09 \ud3b8\uc9d1", + + // Video + "Insert Video": "\ub3d9\uc601\uc0c1 \uc0bd\uc785", + "Embedded Code": "\uc784\ubca0\ub514\ub4dc \ucf54\ub4dc", + "Paste in a video URL": "\ub3d9\uc601\uc0c1 URL\uc5d0 \ubd99\uc5ec \ub123\uae30", + "Drop video": "\ub3d9\uc601\uc0c1\uc744 \ub4dc\ub798\uadf8&\ub4dc\ub86d", + "Your browser does not support HTML5 video.": "\uadc0\ud558\uc758 \ube0c\ub77c\uc6b0\uc800\ub294 html5 video\ub97c \uc9c0\uc6d0\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.", + "Upload Video": "\ub3d9\uc601\uc0c1 \uc5c5\ub85c\ub4dc", + + // Tables + "Insert Table": "\ud45c \uc0bd\uc785", + "Table Header": "\ud45c \ud5e4\ub354", + "Remove Table": "\ud45c \uc81c\uac70", + "Table Style": "\ud45c \uc2a4\ud0c0\uc77c", + "Horizontal Align": "\uc218\ud3c9 \uc815\ub82c", + "Row": "\ud589", + "Insert row above": "\uc55e\uc5d0 \ud589\uc744 \uc0bd\uc785", + "Insert row below": "\ub4a4\uc5d0 \ud589\uc744 \uc0bd\uc785", + "Delete row": "\ud589 \uc0ad\uc81c", + "Column": "\uc5f4", + "Insert column before": "\uc55e\uc5d0 \uc5f4\uc744 \uc0bd\uc785", + "Insert column after": "\ub4a4\uc5d0 \uc5f4\uc744 \uc0bd\uc785", + "Delete column": "\uc5f4 \uc0ad\uc81c", + "Cell": "\uc140", + "Merge cells": "\uc140 \ud569\uce58\uae30", + "Horizontal split": "\uc218\ud3c9 \ubd84\ud560", + "Vertical split": "\uc218\uc9c1 \ubd84\ud560", + "Cell Background": "\uc140 \ubc30\uacbd", + "Vertical Align": "\uc218\uc9c1 \uc815\ub82c", + "Top": "\uc704\ucabd \uc815\ub82c", + "Middle": "\uac00\uc6b4\ub370 \uc815\ub82c", + "Bottom": "\uc544\ub798\ucabd \uc815\ub82c", + "Align Top": "\uc704\ucabd\uc73c\ub85c \uc815\ub82c\ud569\ub2c8\ub2e4.", + "Align Middle": "\uac00\uc6b4\ub370\ub85c \uc815\ub82c\ud569\ub2c8\ub2e4.", + "Align Bottom": "\uc544\ub798\ucabd\uc73c\ub85c \uc815\ub82c\ud569\ub2c8\ub2e4.", + "Cell Style": "\uc140 \uc2a4\ud0c0\uc77c", + + // Files + "Upload File": "\ud30c\uc77c \ucca8\ubd80", + "Drop file": "\ud30c\uc77c\uc744 \ub4dc\ub798\uadf8&\ub4dc\ub86d", + + // Emoticons + "Emoticons": "\uc774\ubaa8\ud2f0\ucf58", + "Grinning face": "\uc5bc\uad74 \uc6c3\uae30\ub9cc", + "Grinning face with smiling eyes": "\ubbf8\uc18c\ub294 \ub208\uc744 \uac00\uc9c4 \uc5bc\uad74 \uc6c3\uae30\ub9cc", + "Face with tears of joy": "\uae30\uc068\uc758 \ub208\ubb3c\ub85c \uc5bc\uad74", + "Smiling face with open mouth": "\uc624\ud508 \uc785\uc73c\ub85c \uc6c3\ub294 \uc5bc\uad74", + "Smiling face with open mouth and smiling eyes": "\uc624\ud508 \uc785\uc73c\ub85c \uc6c3\ub294 \uc5bc\uad74\uacfc \ub208\uc744 \ubbf8\uc18c", + "Smiling face with open mouth and cold sweat": "\uc785\uc744 \uc5f4\uace0 \uc2dd\uc740 \ub540\uacfc \ud568\uaed8 \uc6c3\ub294 \uc5bc\uad74", + "Smiling face with open mouth and tightly-closed eyes": "\uc624\ud508 \uc785\uacfc \ubc00\uc811\ud558\uac8c \ub2eb\ud78c \ub41c \ub208\uc744 \uac00\uc9c4 \uc6c3\ub294 \uc5bc\uad74", + "Smiling face with halo": "\ud6c4\uad11 \uc6c3\ub294 \uc5bc\uad74", + "Smiling face with horns": "\ubfd4 \uc6c3\ub294 \uc5bc\uad74", + "Winking face": "\uc5bc\uad74 \uc719\ud06c", + "Smiling face with smiling eyes": "\uc6c3\ub294 \ub208\uc73c\ub85c \uc6c3\ub294 \uc5bc\uad74", + "Face savoring delicious food": "\ub9db\uc788\ub294 \uc74c\uc2dd\uc744 \uc74c\ubbf8 \uc5bc\uad74", + "Relieved face": "\uc548\ub3c4 \uc5bc\uad74", + "Smiling face with heart-shaped eyes": "\ud558\ud2b8 \ubaa8\uc591\uc758 \ub208\uc73c\ub85c \uc6c3\ub294 \uc5bc\uad74", + "Smiling face with sunglasses": "\uc120\uae00\ub77c\uc2a4 \uc6c3\ub294 \uc5bc\uad74", + "Smirking face": "\ub3c8\uc744 \uc9c0\ubd88 \uc5bc\uad74", + "Neutral face": "\uc911\ub9bd \uc5bc\uad74", + "Expressionless face": "\ubb34\ud45c\uc815 \uc5bc\uad74", + "Unamused face": "\uc990\uac81\uac8c\ud558\uc9c0 \uc5bc\uad74", + "Face with cold sweat": "\uc2dd\uc740 \ub540\uacfc \uc5bc\uad74", + "Pensive face": "\uc7a0\uaca8\uc788\ub294 \uc5bc\uad74", + "Confused face": "\ud63c\ub780 \uc5bc\uad74", + "Confounded face": "\ub9dd\ud560 \uac83 \uc5bc\uad74", + "Kissing face": "\uc5bc\uad74\uc744 \ud0a4\uc2a4", + "Face throwing a kiss": "\ud0a4\uc2a4\ub97c \ub358\uc9c0\uace0 \uc5bc\uad74", + "Kissing face with smiling eyes": "\ubbf8\uc18c\ub294 \ub208\uc744 \uac00\uc9c4 \uc5bc\uad74\uc744 \ud0a4\uc2a4", + "Kissing face with closed eyes": "\ub2eb\ud78c \ub41c \ub208\uc744 \uac00\uc9c4 \uc5bc\uad74\uc744 \ud0a4\uc2a4", + "Face with stuck out tongue": "\ub0b4\ubc00 \ud600 \uc5bc\uad74", + "Face with stuck out tongue and winking eye": "\ub0b4\ubc00 \ud600\uc640 \uc719\ud06c \ub208\uacfc \uc5bc\uad74", + "Face with stuck out tongue and tightly-closed eyes": "\ubc16\uc73c\ub85c \ubd99\uc5b4 \ud600\uc640 \ubc00\uc811\ud558\uac8c \ub2eb\ud78c \ub41c \ub208\uc744 \uac00\uc9c4 \uc5bc\uad74", + "Disappointed face": "\uc2e4\ub9dd \uc5bc\uad74", + "Worried face": "\uac71\uc815 \uc5bc\uad74", + "Angry face": "\uc131\ub09c \uc5bc\uad74", + "Pouting face": "\uc5bc\uad74\uc744 \uc090", + "Crying face": "\uc5bc\uad74 \uc6b0\ub294", + "Persevering face": "\uc5bc\uad74\uc744 \uc778\ub0b4", + "Face with look of triumph": "\uc2b9\ub9ac\uc758 \ud45c\uc815\uc73c\ub85c \uc5bc\uad74", + "Disappointed but relieved face": "\uc2e4\ub9dd\ud558\uc9c0\ub9cc \uc5bc\uad74\uc744 \uc548\uc2ec", + "Frowning face with open mouth": "\uc624\ud508 \uc785\uc73c\ub85c \uc5bc\uad74\uc744 \ucc21\uadf8\ub9bc", + "Anguished face": "\uace0\ub1cc\uc758 \uc5bc\uad74", + "Fearful face": "\ubb34\uc11c\uc6b4 \uc5bc\uad74", + "Weary face": "\uc9c0\uce5c \uc5bc\uad74", + "Sleepy face": "\uc2ac\ub9ac\ud53c \uc5bc\uad74", + "Tired face": "\ud53c\uace4 \uc5bc\uad74", + "Grimacing face": "\uc5bc\uad74\uc744 \ucc21\uadf8\ub9b0", + "Loudly crying face": "\ud070 \uc18c\ub9ac\ub85c \uc5bc\uad74\uc744 \uc6b8\uace0", + "Face with open mouth": "\uc624\ud508 \uc785\uc73c\ub85c \uc5bc\uad74", + "Hushed face": "\uc870\uc6a9\ud55c \uc5bc\uad74", + "Face with open mouth and cold sweat": "\uc785\uc744 \uc5f4\uace0 \uc2dd\uc740 \ub540\uc73c\ub85c \uc5bc\uad74", + "Face screaming in fear": "\uacf5\ud3ec\uc5d0 \ube44\uba85 \uc5bc\uad74", + "Astonished face": "\ub180\ub77c \uc5bc\uad74", + "Flushed face": "\ud50c\ub7ec\uc2dc \uc5bc\uad74", + "Sleeping face": "\uc5bc\uad74 \uc7a0\uc790\ub294", + "Dizzy face": "\ub514\uc9c0 \uc5bc\uad74", + "Face without mouth": "\uc785\uc5c6\uc774 \uc5bc\uad74", + "Face with medical mask": "\uc758\ub8cc \ub9c8\uc2a4\ud06c\ub85c \uc5bc\uad74", + + // Line breaker + "Break": "\ub2e8\uc808", + + // Math + "Subscript": "\uc544\ub798 \ucca8\uc790", + "Superscript": "\uc704 \ucca8\uc790", + + // Full screen + "Fullscreen": "\uc804\uccb4 \ud654\uba74", + + // Horizontal line + "Insert Horizontal Line": "\uc218\ud3c9\uc120\uc744 \uc0bd\uc785", + + // Clear formatting + "Clear Formatting": "\uc11c\uc2dd \uc81c\uac70", + + // Save + "Save": "\uad6c\ud558\ub2e4", + + // Undo, redo + "Undo": "\uc2e4\ud589 \ucde8\uc18c", + "Redo": "\ub418\ub3cc\ub9ac\uae30", + + // Select all + "Select All": "\uc804\uccb4\uc120\ud0dd", + + // Code view + "Code View": "\ucf54\ub4dc\ubcf4\uae30", + + // Quote + "Quote": "\uc778\uc6a9", + "Increase": "\uc99d\uac00", + "Decrease": "\uac10\uc18c", + + // Quick Insert + "Quick Insert": "\ube60\ub978 \uc0bd\uc785", + + // Spcial Characters + "Special Characters": "\ud2b9\uc218 \ubb38\uc790", + "Latin": "\ub77c\ud2f4\uc5b4", + "Greek": "\uadf8\ub9ac\uc2a4\uc5b4", + "Cyrillic": "\ud0a4\ub9b4 \ubb38\uc790", + "Punctuation": "\ubb38\uc7a5\ubd80\ud638", + "Currency": "\ud1b5\ud654", + "Arrows": "\ud654\uc0b4\ud45c", + "Math": "\uc218\ud559", + "Misc": "\uadf8 \uc678", + + // Print. + "Print": "\uc778\uc1c4", + + // Spell Checker. + "Spell Checker": "\ub9de\ucda4\ubc95 \uac80\uc0ac\uae30", + + // Help + "Help": "\ub3c4\uc6c0\ub9d0", + "Shortcuts": "\ub2e8\ucd95\ud0a4", + "Inline Editor": "\uc778\ub77c\uc778 \uc5d0\ub514\ud130", + "Show the editor": "\uc5d0\ub514\ud130 \ubcf4\uae30", + "Common actions": "\uc77c\ubc18 \ub3d9\uc791", + "Copy": "\ubcf5\uc0ac\ud558\uae30", + "Cut": "\uc798\ub77c\ub0b4\uae30", + "Paste": "\ubd99\uc5ec\ub123\uae30", + "Basic Formatting": "\uae30\ubcf8 \uc11c\uc2dd", + "Increase quote level": "\uc778\uc6a9 \uc99d\uac00", + "Decrease quote level": "\uc778\uc6a9 \uac10\uc18c", + "Image / Video": "\uc774\ubbf8\uc9c0 / \ub3d9\uc601\uc0c1", + "Resize larger": "\ud06c\uae30\ub97c \ub354 \ud06c\uac8c \uc870\uc815", + "Resize smaller": "\ud06c\uae30\ub97c \ub354 \uc791\uac8c \uc870\uc815", + "Table": "\ud45c", + "Select table cell": "\ud45c \uc140 \uc120\ud0dd", + "Extend selection one cell": "\uc140\uc758 \uc120\ud0dd \ubc94\uc704\ub97c \ud655\uc7a5", + "Extend selection one row": "\ud589\uc758 \uc120\ud0dd \ubc94\uc704\ub97c \ud655\uc7a5", + "Navigation": "\ub124\ube44\uac8c\uc774\uc158", + "Focus popup / toolbar": "\ud31d\uc5c5 / \ud234\ubc14\ub97c \ud3ec\ucee4\uc2a4", + "Return focus to previous position": "\uc774\uc804 \uc704\uce58\ub85c \ud3ec\ucee4\uc2a4 \ub418\ub3cc\ub9ac\uae30", + + // Embed.ly + "Embed URL": "\uc784\ubca0\ub4dc URL", + "Paste in a URL to embed": "\uc784\ubca0\ub4dc URL\uc5d0 \ubd99\uc5ec \ub123\uae30", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "\ubd99\uc5ec\ub123\uc740 \ubb38\uc11c\ub294 \ub9c8\uc774\ud06c\ub85c\uc18c\ud504\ud2b8 \uc6cc\ub4dc\uc5d0\uc11c \uac00\uc838\uc654\uc2b5\ub2c8\ub2e4. \ud3ec\ub9f7\uc744 \uc720\uc9c0\ud558\uac70\ub098 \uc815\ub9ac \ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?", + "Keep": "\uc720\uc9c0", + "Clean": "\uc815\ub9ac", + "Word Paste Detected": "\uc6cc\ub4dc \ubd99\uc5ec \ub123\uae30\uac00 \uac80\ucd9c \ub418\uc5c8\uc2b5\ub2c8\ub2e4." + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ku.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ku.js new file mode 100644 index 0000000..5998917 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ku.js @@ -0,0 +1,329 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Arabic + */ + +$.FE.LANGUAGE['ku'] = { + translation: { + // Place holder + "Type something": "شتێک بنووسە", + + // Basic formatting + "Bold": "تۆخکردنەوە", + "Italic": "لارکردنەوە", + "Underline": "هێڵ بەژێردا هێنان", + "Strikethrough": "هێڵ بە سەردا هێنان", + + // Main buttons + "Insert": "خستنە ناو", + "Delete": "سڕینەوە", + "Cancel": "پاشگەزبوونەوە", + "OK": "باشە", + "Back": "گەڕانەوە", + "Remove": "لابردن", + "More": "زیاتر", + "Update": "نوێکردنەوە", + "Style": "شێواز", + + // Font + "Font Family": "فۆنتی خێزان", + "Font Size": "قەبارەی فۆنت", + + // Colors + "Colors": "ڕەنگەکان", + "Background": "پاشبنەما(باکگراوند)", + "Text": "دەق", + + // Paragraphs بۆیە ڕەقەمەکانی خوارەوەم نەکردووە بە کوردی لە شوێنی تریش بینیوومە هەروا نوسراوەتەوە + "Paragraph Format": "شێوازی پەڕەگراف", + "Normal": "ئاسایی", + "Code": "کۆد", + "Heading 1": " 1", + "Heading 2": " 2", + "Heading 3": " 3", + "Heading 4": " 4", + + // Style + "Paragraph Style": "شێوازی پەڕەگراف", + "Inline Style": "شێوزای ناو دێڕ", + + // Alignment + "Align": "ڕیزکردن", + "Align Left": "ڕیزکردن لای چەپەوە", + "Align Center": "ڕیزکردن لە ناوەڕاستەوە", + "Align Right": "ڕیزکردن لای ڕاستەوە", + "Align Justify": "هاوڕێک", + "None": "هیچ", + + // Lists + "Ordered List": "لیستی داواکراو", + "Default": "Destçûnî", + "Lower Alpha": "Alpha kêm", + "Lower Greek": "Grek", + "Lower Roman": "Roman", + "Upper Alpha": "Alpha", + "Upper Roman": "Rûsî", + + "Unordered List": "لیستی داوانەکراو", + "Circle": "Çember", + "Disc": "Disc", + "Square": "Meydan", + + // Line height + "Line Height": "Hewayê", + "Single": "Yekoyek", + "Double": "Dûcar", + + // Indent + "Decrease Indent": "کەمکردنەوەی بۆشایی بەجێهێشتن", + "Increase Indent": "زیادکردنی بۆشایی بەجێهێشتن", + + // Links + "Insert Link": "دانانی بەستەر", + "Open in new tab": "کردنەوەی لە تابێکی نوێدا", + "Open Link": "کردنەوەی بەستەر", + "Edit Link": "دەستکاریکردنی بەستەر", + "Unlink": "سڕینەوەی بەستەر", + "Choose Link": "هەڵبژاردنی بەستەر", + + // Images + "Insert Image": "هێنانی وێنە", + "Upload Image": "بارکردنی وێنە", + "By URL": "بە شێوەی بەستەر", + "Browse": "هێنان", + "Drop image": "ڕاکێشانی وێنە", + "or click": "یان کرتە", + "Manage Images": "بەڕێوەبردنی وێنە", + "ئامادەکردن": "Cargando", + "Deleting": "سڕینەوە", + "Tags": "تاگەکان", + "Are you sure? Image will be deleted.": "دڵنیایت لە سڕینەوەی وێنەکە", + "Replace": "لەبری دانان", + "Uploading": "بارکردن", + "Loading image": "ئامادەکردنی وێنە", + "Display": "پیشان دان", + "Inline": "ناو دێڕ", + "Break Text": "ماوەی دەق", + "Alternative Text": "جێگرەوەی دەق", + "Change Size": "گۆڕینی قەبارەی", + "Width": "پانی", + "Height": "بەرزی", + "Something went wrong. Please try again.": "شتێک هە ڵەیە تکایە هەوڵبدەرەوە", + + // Video + "Insert Video": "دانانی ڤیدیۆ", + "Embedded Code": "کۆدی ئێمبد", + + // Tables + "Insert Table": "دانانی خشتە", + "Table Header": "خشتەی ناونیشان", + "Remove Table": "سڕینەوەی خشتە", + "Table Style": "شێوازی خشتە", + "Horizontal Align": "ڕێکخستنی ئاسۆیی", + "Row": "ڕیز", + "Insert row above": "دانانی ڕیز لەسەرەوە", + "Insert row below": "دانانی ڕیز لە خوارەوە", + "Delete row": "سڕینەوەی ڕیز", + "Column": "ستوون", + "Insert column before": "زیادکردنی ستونێک لە پێشەوە", + "Insert column after": "زیادکردنی ستونێک لە دوایەوە", + "Delete column": "سڕینەوەی ستونێک", + "Cell": "خانە", + "Merge cells": "تێکەڵکردنی خانەکان", + "Horizontal split": "جیاکردنەوەی هێڵی ئاسۆیی", + "Vertical split": "جیاکردنەوەی سەر بەرەو خوار", + "Cell Background": "خانەی باکگراوند", + "Vertical Align": "ڕیزکردن بەشێوەی سەر بەرەو خوار", + "Top": "سەرەوە", + "Middle": "ناوەڕاست", + "Bottom": "خوارەوە", + "Align Top": "ڕیزکردن لە سەرەوە", + "Align Middle": "ڕیزکردن لە ناوەڕاستەوە", + "Align Bottom": "ڕیزکردن لە خوارەوە", + "Cell Style": "شێوازی خانە", + + // Files + "Upload File": "بەرزکردنەوەی پەڕگە", + "Drop file": "ڕاکێشانی پەڕگە", + + // Emoticons + "Emoticons": "ئیمۆجی", + "Grinning face": "ڕوخسارێکی پێکەنیناوی", + "Grinning face with smiling eyes": "ڕوخسارێکی پێکەنیناوی لەگەڵ چاوێکی خەندە ئامێز", + "Face with tears of joy": "دەمووچاوێک لەگەڵ ئاو هاتنە خوارەوەوە بە چاودا", + "Smiling face with open mouth": "دەمووچاوێکی پێکەنیناوی لەگەڵ دەمکردنەوە", + "Smiling face with open mouth and smiling eyes": "دەمووچاوێکی پێکەنیناوی لەگەڵ دەمکردنەوە و چاوێکی خەندە ئامێز", + "Smiling face with open mouth and cold sweat": "دەمووچاوێکی پێکەنیناوی لەگەڵ دەمکردنەوە و ئارەق کردنەوە", + "Smiling face with open mouth and tightly-closed eyes": "Cara sonriente con la boca abierta y los ojos fuertemente cerrados", + "Smiling face with halo": "دەمووچاوێکی پێکەنیناوی و بوونی بازنەیەکی خڕ بەسەرتەوە", + "Smiling face with horns": "دەمووچاوێکی پێکەنیناوی لەگەڵ دوو قۆچدا", + "Winking face": "چاو داگرتن", + "Smiling face with smiling eyes": "دەمووچاوێکی پێکەنیناوی چاوی بچوک کردوەتەوە", + "Face savoring delicious food": "دەمووچاوی کەسێک کە حەزی لە خواردنە", + "Relieved face": "دەمووچاوێکی حەساوە", + "Smiling face with heart-shaped eyes": "دەمووچاوێک لەگەڵ بوونی دڵ لە چاودا", + "Smiling face with sunglasses": "دەمووچاوێک لەگەڵ چاویلکەدا", + "Smirking face": "دەمووچاوێکی فیزاوی", + "Neutral face": "دەم داخستن", + "Expressionless face": "دەم و چاو داخستن", + "Unamused face": "دەمووچاوێکی بێزار", + "Face with cold sweat": "ڕوخسارێک لەگەڵ ئارەقی سارددا", + "Pensive face": "ڕوخسارێکی خەمبار", + "Confused face": "ڕوخسارێکی قەلەق", + "Confounded face": "ڕوخسارێکی ئاڵۆز", + "Kissing face": "دەمووچاوێک و ماچ", + "Face throwing a kiss": "دەمووچاوێک ماچ هەڵبدات", + "Kissing face with smiling eyes": "دەمووچاوێک ماچ دەکات لەگەڵ ڕوخسارێکی پێکەنیناوی", + "Kissing face with closed eyes": "دەمووچاوێک ماچ دەکات و چاوی داخستووە", + "Face with stuck out tongue": "ڕوخسارێک زمانی دەرهێناوە", + "Face with stuck out tongue and winking eye": "ڕوخسارێک زمانی دەرهێناوە و چاوێکی لێت داگرتووە", + "Face with stuck out tongue and tightly-closed eyes": "هەردووچاوی داخستووە و زمان دەردێنێت", + "Disappointed face": "ڕوخسارێکی نائومێد کراو", + "Worried face": "ڕوخسارێکی بێتاقەت", + "Angry face": "ڕوخسارێکی توڕە", + "Pouting face": "ڕوخسارێک لچی دەرهێناوە", + "Crying face": "ڕوخسارێک دەگری", + "Persevering face": "ڕوخسارێکی تەواوی بێتاقەت", + "Face with look of triumph": "ڕوخسارێک کە سوورە لەسەر کارێک", + "Disappointed but relieved face": "ڕوخسارێکی خەمبارە و ئارەق دەکاتەوە", + "Frowning face with open mouth": "ڕوخسارێکی تووڕە و دەمی کراوەتەوە", + "Anguished face": "ڕوخسارێکی خەمناک", + "Fearful face": "دەموچاوێکی ترساو", + "Weary face": "ڕوخسارێکی ماندوو", + "Sleepy face": "ڕوخسارێکی خەوتوو", + "Tired face": "ڕوخسارێکی ماندوو", + "Grimacing face": "دان جیڕ کردنەوە", + "Loudly crying face": "ڕوخسارێک بە دەنگی بەرزەوە دەگری", + "Face with open mouth": "ڕوخسارێک دەمی کردوەتەوە", + "Hushed face": "ڕوخسارێکی بێدەنگ کراو", + "Face with open mouth and cold sweat": "دەمووچاوێک دەمی کردوەتەوە و ئارەق دەڕێژێت", + "Face screaming in fear": "دەمووچاوێک هاوار دەکات و لە شتێک دەترسێت", + "Astonished face": "ڕوخسارێکی سەرسام بوو", + "Flushed face": "ڕوخسارێکی سور بووەوە", + "Sleeping face": "ڕوخسارێکی خەوتوو", + "Dizzy face": "سەرگێژ خواردن", + "Face without mouth": "دەمووچاوێک بەبێ دەم", + "Face with medical mask": "دەمووچاوێک لەگەڵ ماسکی پزیشکی", + + // Line breaker + "Break": "بڕینی هێڵێک", + + // Math + "Subscript": "نوسین لە ژێرەوەی نوسینێکی دیکە", + "Superscript": "سەرنووس", + + // Full screen + "Fullscreen": "پڕ بە شاشە", + + // Horizontal line + "Insert Horizontal Line": "دانانی هێڵی ئاسۆیی", + + // Clear formatting + "Clear Formatting": "سڕینەوەی شێواز", + + // Save + "Save": "Rizgarkirin", + + // Undo, redo + "Undo": "گەڕانەوە", + "Redo": "هێنانەوەی هەنگاوی پێشتر", + + // Select all + "Select All": "دیاریکردنی هەموو", + + // Code view + "Code View": "بینینی کۆد", + + // Quote + "Quote": "وتە", + "Increase": "زیادکردن", + "Decrease": "کەمکردن", + + // Quick Insert + "Quick Insert": "خێرا خستنە ناو", + + // Spcial Characters + "Special Characters": "Special Characters", + "Latin": "Latin", + "Greek": "Greek", + "Cyrillic": "Cyrillic", + "Punctuation": "Punctuation", + "Currency": "Currency", + "Arrows": "Arrows", + "Math": "Math", + "Misc": "Misc", + + // Print. + "Print": "Print", + + // Spell Checker. + "Spell Checker": "Spell Checker", + + // Help + "Help": "Help", + "Shortcuts": "Shortcuts", + "Inline Editor": "Inline Editor", + "Show the editor": "Show the editor", + "Common actions": "Common actions", + "Copy": "Copy", + "Cut": "Cut", + "Paste": "Paste", + "Basic Formatting": "Basic Formatting", + "Increase quote level": "Increase quote level", + "Decrease quote level": "Decrease quote level", + "Image / Video": "Image / Video", + "Resize larger": "Resize larger", + "Resize smaller": "Resize smaller", + "Table": "Table", + "Select table cell": "Select table cell", + "Extend selection one cell": "Extend selection one cell", + "Extend selection one row": "Extend selection one row", + "Navigation": "Navigation", + "Focus popup / toolbar": "Focus popup / toolbar", + "Return focus to previous position": "Return focus to previous position", + + // Embed.ly + "Embed URL": "Embed URL", + "Paste in a URL to embed": "Paste in a URL to embed", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?", + "Keep": "Keep", + "Clean": "Clean", + "Word Paste Detected": "Word Paste Detected" + }, + direction: "rtl" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/me.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/me.js new file mode 100644 index 0000000..50135f5 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/me.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Montenegrin + */ + +$.FE.LANGUAGE['me'] = { + translation: { + // Place holder + "Type something": "Ukucajte ne\u0161tp", + + // Basic formatting + "Bold": "Bold", + "Italic": "Italic", + "Underline": "Podvu\u010deno", + "Strikethrough": "Prekri\u017eano", + + // Main buttons + "Insert": "Umetni", + "Delete": "Obri\u0161i", + "Cancel": "Otka\u017ei", + "OK": "U redu", + "Back": "Natrag", + "Remove": "Ukloni", + "More": "Vi\u0161e", + "Update": "A\u017euriranje", + "Style": "Stil", + + // Font + "Font Family": "Odaberi font", + "Font Size": "Veli\u010dina fonta", + + // Colors + "Colors": "Boje", + "Background": "Pozadine", + "Text": "Teksta", + "HEX Color": "HEX boje", + + // Paragraphs + "Paragraph Format": "Paragraf formatu", + "Normal": "Normalno", + "Code": "Izvorni kod", + "Heading 1": "Naslov 1", + "Heading 2": "Naslov 2", + "Heading 3": "Naslov 3", + "Heading 4": "Naslov 4", + + // Style + "Paragraph Style": "Paragraf stil", + "Inline Style": "Inline stil", + + // Alignment + "Align": "Poravnaj", + "Align Left": "Poravnaj lijevo", + "Align Center": "Poravnaj po sredini", + "Align Right": "Poravnaj desno", + "Align Justify": "Cjelokupno poravnanje", + "None": "Nijedan", + + // Lists + "Ordered List": "Ure\u0111ena lista", + "Default": "", + "Lower Alpha": "", + "Lower Greek": "", + "Lower Roman": "", + "Upper Alpha": "", + "Upper Roman": "", + + "Unordered List": "Nesre\u0111ene lista", + "Circle": "", + "Disc": "", + "Square": "", + + // Line height + "Line Height": "", + "Single": "", + "Double": "", + + // Indent + "Decrease Indent": "Smanjenje alineja", + "Increase Indent": "Pove\u0107anje alineja", + + // Links + "Insert Link": "Umetni link", + "Open in new tab": "Otvori u novom prozoru", + "Open Link": "Otvori link", + "Edit Link": "Uredi link", + "Unlink": "Ukloni link", + "Choose Link": "Izabrati link", + + // Images + "Insert Image": "Umetni sliku", + "Upload Image": "Upload sliku", + "By URL": "Preko URL", + "Browse": "Pregledaj", + "Drop image": "Izbaci sliku", + "or click": "ili odaberi", + "Manage Images": "Upravljanje ilustracijama", + "Loading": "Koji tovari", + "Deleting": "Brisanje", + "Tags": "Oznake", + "Are you sure? Image will be deleted.": "Da li ste sigurni da \u017eelite da obri\u0161ete ovu ilustraciju?", + "Replace": "Zamijenite", + "Uploading": "Uploading", + "Loading image": "Koji tovari sliku", + "Display": "Prikaz", + "Inline": "Inline", + "Break Text": "Break tekst", + "Alternative Text": "Alternativna tekst", + "Change Size": "Promijeni veli\u010dinu", + "Width": "\u0161irina", + "Height": "Visina", + "Something went wrong. Please try again.": "Ne\u0161to je po\u0161lo po zlu. Molimo vas da poku\u0161ate ponovo.", + "Image Caption": "Slika natpisa", + "Advanced Edit": "Napredno uređivanje", + + // Video + "Insert Video": "Umetni video", + "Embedded Code": "Embedded kod", + "Paste in a video URL": "Prilepite v URL video posnetka", + "Drop video": "Izbaci video", + "Your browser does not support HTML5 video.": "Váš prehliadač nepodporuje video HTML5.", + "Upload Video": "Upload video", + + // Tables + "Insert Table": "Umetni tabelu", + "Table Header": "Zaglavlje tabelu", + "Remove Table": "Izbri\u0161i tabelu", + "Table Style": "Tabelu stil", + "Horizontal Align": "Horizontalna poravnanje", + "Row": "Red", + "Insert row above": "Umetni red iznad", + "Insert row below": "Umetni red ispod", + "Delete row": "Obri\u0161i red", + "Column": "Kolona", + "Insert column before": "Umetni kolonu prije", + "Insert column after": "Umetni kolonu poslije", + "Delete column": "Obri\u0161i kolonu", + "Cell": "\u0106elija", + "Merge cells": "Spoji \u0107elija", + "Horizontal split": "Horizontalno razdvajanje polja", + "Vertical split": "Vertikalno razdvajanje polja", + "Cell Background": "\u0106elija pozadini", + "Vertical Align": "Vertikalni poravnaj", + "Top": "Vrh", + "Middle": "Srednji", + "Bottom": "Dno", + "Align Top": "Poravnaj vrh", + "Align Middle": "Poravnaj srednji", + "Align Bottom": "Poravnaj dno", + "Cell Style": "\u0106elija stil", + + // Files + "Upload File": "Upload datoteke", + "Drop file": "Drop datoteke", + + // Emoticons + "Emoticons": "Emotikona", + "Grinning face": "Cere\u0107i lice", + "Grinning face with smiling eyes": "Cere\u0107i lice nasmijana o\u010dima", + "Face with tears of joy": "Lice sa suze radosnice", + "Smiling face with open mouth": "Nasmijana lica s otvorenih usta", + "Smiling face with open mouth and smiling eyes": "Nasmijana lica s otvorenih usta i nasmijana o\u010di", + "Smiling face with open mouth and cold sweat": "Nasmijana lica s otvorenih usta i hladan znoj", + "Smiling face with open mouth and tightly-closed eyes": "Nasmijana lica s otvorenih usta i \u010dvrsto-zatvorenih o\u010diju", + "Smiling face with halo": "Nasmijana lica sa halo", + "Smiling face with horns": "Nasmijana lica s rogovima", + "Winking face": "Namigivanje lice", + "Smiling face with smiling eyes": "Nasmijana lica sa nasmijana o\u010dima", + "Face savoring delicious food": "Suo\u010davaju uživaju\u0107i ukusna hrana", + "Relieved face": "Laknulo lice", + "Smiling face with heart-shaped eyes": "Nasmijana lica sa obliku srca o\u010di", + "Smiling face with sunglasses": "Nasmijana lica sa sun\u010dane nao\u010dare", + "Smirking face": "Namr\u0161tena lica", + "Neutral face": "Neutral lice", + "Expressionless face": "Bezizra\u017eajno lice", + "Unamused face": "Nije zabavno lice", + "Face with cold sweat": "Lice s hladnim znojem", + "Pensive face": "Zami\u0161ljen lice", + "Confused face": "Zbunjen lice", + "Confounded face": "Uzbu\u0111en lice", + "Kissing face": "Ljubakanje lice", + "Face throwing a kiss": "Suo\u010davaju bacanje poljubac", + "Kissing face with smiling eyes": "Ljubljenje lice nasmijana o\u010dima", + "Kissing face with closed eyes": "Ljubljenje lice sa zatvorenim o\u010dima", + "Face with stuck out tongue": "Lice sa ispru\u017eio jezik", + "Face with stuck out tongue and winking eye": "Lice sa ispru\u017eio jezik i trep\u0107u\u0107e \u0107e oko", + "Face with stuck out tongue and tightly-closed eyes": "Lice sa ispru\u017eio jezik i \u010dvrsto zatvorene o\u010di", + "Disappointed face": "Razo\u010daran lice", + "Worried face": "Zabrinuti lice", + "Angry face": "Ljut lice", + "Pouting face": "Napu\u0107enim lice", + "Crying face": "Plakanje lice", + "Persevering face": "Istrajan lice", + "Face with look of triumph": "Lice s pogledom trijumfa", + "Disappointed but relieved face": "Razo\u010daran, ali olak\u0161anje lice", + "Frowning face with open mouth": "Namr\u0161tiv\u0161i lice s otvorenih usta", + "Anguished face": "Bolnom lice", + "Fearful face": "Pla\u0161ljiv lice", + "Weary face": "Umoran lice", + "Sleepy face": "Pospan lice", + "Tired face": "Umorno lice", + "Grimacing face": "Grimase lice", + "Loudly crying face": "Glasno pla\u010de lice", + "Face with open mouth": "Lice s otvorenih usta", + "Hushed face": "Smiren lice", + "Face with open mouth and cold sweat": "Lice s otvorenih usta i hladan znoj", + "Face screaming in fear": "Suo\u010davaju vri\u0161ti u strahu", + "Astonished face": "Zapanjen lice", + "Flushed face": "Rumeno lice", + "Sleeping face": "Usnulo lice", + "Dizzy face": "O\u0161amu\u0107en lice", + "Face without mouth": "Lice bez usta", + "Face with medical mask": "Lice sa medicinskom maskom", + + // Line breaker + "Break": "Slomiti", + + // Math + "Subscript": "Potpisan", + "Superscript": "Natpis", + + // Full screen + "Fullscreen": "Preko cijelog zaslona", + + // Horizontal line + "Insert Horizontal Line": "Umetni vodoravna liniju", + + // Clear formatting + "Clear Formatting": "Izbrisati formatiranje", + + // Save + "Save": "Save", + + // Undo, redo + "Undo": "Korak nazad", + "Redo": "Korak naprijed", + + // Select all + "Select All": "Ozna\u010di sve", + + // Code view + "Code View": "Kod pogled", + + // Quote + "Quote": "Citat", + "Increase": "Pove\u0107ati", + "Decrease": "Smanjenje", + + // Quick Insert + "Quick Insert": "Brzo umetni", + + // Spcial Characters + "Special Characters": "Specijalni znakovi", + "Latin": "Latino", + "Greek": "Grk", + "Cyrillic": "Ćirilica", + "Punctuation": "Interpunkcije", + "Currency": "Valuta", + "Arrows": "Strelice", + "Math": "Matematika", + "Misc": "Misc", + + // Print. + "Print": "Odštampaj", + + // Spell Checker. + "Spell Checker": "Kontrolor pravopisa", + + // Help + "Help": "Pomoć", + "Shortcuts": "Prečice", + "Inline Editor": "Pri upisivanju Editor", + "Show the editor": "Prikaži urednik", + "Common actions": "Zajedničke akcije", + "Copy": "Kopija", + "Cut": "Rez", + "Paste": "Nalepi", + "Basic Formatting": "Osnovno oblikovanje", + "Increase quote level": "Povećati ponudu za nivo", + "Decrease quote level": "Smanjenje ponude nivo", + "Image / Video": "Slika / Video", + "Resize larger": "Veće veličine", + "Resize smaller": "Promena veličine manji", + "Table": "Sto", + "Select table cell": "Select ćelije", + "Extend selection one cell": "Proširite selekciju jednu ćeliju", + "Extend selection one row": "Proširite selekciju jedan red", + "Navigation": "Navigacija", + "Focus popup / toolbar": "Fokus Iskačući meni / traka sa alatkama", + "Return focus to previous position": "Vratiti fokus na prethodnu poziciju", + + // Embed.ly + "Embed URL": "Ugradite URL", + "Paste in a URL to embed": "Nalepite URL adresu da biste ugradili", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Nalepljeni sadržaj dolazi iz Microsoft Word dokument. Da li želite zadržati u formatu ili počistiti?", + "Keep": "Nastavi", + "Clean": "Oиisti", + "Word Paste Detected": "Word Nalepi otkriven" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/nb.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/nb.js new file mode 100644 index 0000000..614c849 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/nb.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Norwegian + */ + +$.FE.LANGUAGE['nb'] = { + translation: { + // Place holder + "Type something": "Skriv noe", + + // Basic formatting + "Bold": "Fet", + "Italic": "Kursiv", + "Underline": "Understreket", + "Strikethrough": "Gjennomstreket", + + // Main buttons + "Insert": "Sett", + "Delete": "Slett", + "Cancel": "Avbryt", + "OK": "OK", + "Back": "Tilbake", + "Remove": "Fjern", + "More": "Mer", + "Update": "Oppdatering", + "Style": "Stil", + + // Font + "Font Family": "Skriftsnitt", + "Font Size": "St\u00f8rrelse", + + // Colors + "Colors": "Farger", + "Background": "Bakgrunn", + "Text": "Tekst", + "HEX Color": "Heksefarge", + + // Paragraphs + "Paragraph Format": "Stiler", + "Normal": "Normal", + "Code": "Kode", + "Heading 1": "Overskrift 1", + "Heading 2": "Overskrift 2", + "Heading 3": "Overskrift 3", + "Heading 4": "Overskrift 4", + + // Style + "Paragraph Style": "Avsnittsstil", + "Inline Style": "P\u00e5 linje stil", + + // Alignment + "Align": "Justering", + "Align Left": "Venstrejustert", + "Align Center": "Midtstilt", + "Align Right": "H\u00f8yrejustert", + "Align Justify": "Juster alle linjer", + "None": "None", + + // Lists + "Ordered List": "Ordnet liste", + "Default": "Misligholde", + "Lower Alpha": "Lavere alfa", + "Lower Greek": "Lavere greske", + "Lower Roman": "Lavere romersk", + "Upper Alpha": "Øvre alfa", + "Upper Roman": "Øvre roman", + + "Unordered List": "Uordnet liste", + "Circle": "Sirkel", + "Disc": "Plate", + "Square": "Torget", + + // Line height + "Line Height": "Linjehøyde", + "Single": "Enkelt", + "Double": "Dobbelt", + + // Indent + "Decrease Indent": "Reduser innrykk", + "Increase Indent": "\u00d8k innrykk", + + // Links + "Insert Link": "Sett inn lenke", + "Open in new tab": "\u00c5pne i ny fane", + "Open Link": "\u00c5pne lenke", + "Edit Link": "Rediger lenke", + "Unlink": "Fjern lenke", + "Choose Link": "Velge lenke", + + // Images + "Insert Image": "Sett inn bilde", + "Upload Image": "Last opp bilde", + "By URL": "Ved URL", + "Browse": "Bla", + "Drop image": "Slippe bilde", + "or click": "eller klikk", + "Manage Images": "Bildebehandling", + "Loading": "Lasting", + "Deleting": "Slette", + "Tags": "Tags", + "Are you sure? Image will be deleted.": "Er du sikker? Bildet vil bli slettet.", + "Replace": "Erstatte", + "Uploading": "Opplasting", + "Loading image": "Lasting bilde", + "Display": "Utstilling", + "Inline": "P\u00e5 linje", + "Break Text": "Brudd tekst", + "Alternative Text": "Alternativ tekst", + "Change Size": "Endre st\u00f8rrelse", + "Width": "Bredde", + "Height": "H\u00f8yde", + "Something went wrong. Please try again.": "Noe gikk galt. V\u00e6r s\u00e5 snill, pr\u00f8v p\u00e5 nytt.", + "Image Caption": "Bilde bildetekst", + "Advanced Edit": "Avansert redigering", + + // Video + "Insert Video": "Sett inn video", + "Embedded Code": "Embedded kode", + "Paste in a video URL": "Lim inn i en video-url", + "Drop video": "Slipp video", + "Your browser does not support HTML5 video.": "Nettleseren din støtter ikke html5 video.", + "Upload Video": "Last opp video", + + // Tables + "Insert Table": "Sett inn tabell", + "Table Header": "Tabell header", + "Remove Table": "Fjern tabell", + "Table Style": "Tabell stil", + "Horizontal Align": "Horisontal justering", + "Row": "Rad", + "Insert row above": "Sett inn rad f\u00f8r", + "Insert row below": "Sett in rad etter", + "Delete row": "Slett rad", + "Column": "Kolonne", + "Insert column before": "Sett inn kolonne f\u00f8r", + "Insert column after": "Sett inn kolonne etter", + "Delete column": "Slett kolonne", + "Cell": "Celle", + "Merge cells": "Sl\u00e5 sammen celler", + "Horizontal split": "Horisontalt delt", + "Vertical split": "Vertikal split", + "Cell Background": "Celle bakgrunn", + "Vertical Align": "Vertikal justering", + "Top": "Topp", + "Middle": "Midten", + "Bottom": "Bunn", + "Align Top": "Justere toppen", + "Align Middle": "Justere midten", + "Align Bottom": "Justere bunnen", + "Cell Style": "Celle stil", + + // Files + "Upload File": "Opplastingsfil", + "Drop file": "Slippe fil", + + // Emoticons + "Emoticons": "Emoticons", + "Grinning face": "Flirer ansikt", + "Grinning face with smiling eyes": "Flirer ansikt med smilende \u00f8yne", + "Face with tears of joy": "Ansikt med t\u00e5rer av glede", + "Smiling face with open mouth": "Smilende ansikt med \u00e5pen munn", + "Smiling face with open mouth and smiling eyes": "Smilende ansikt med \u00e5pen munn og smilende \u00f8yne", + "Smiling face with open mouth and cold sweat": "Smilende ansikt med \u00e5pen munn og kald svette", + "Smiling face with open mouth and tightly-closed eyes": "Smilende ansikt med \u00e5pen munn og tett lukkede \u00f8yne", + "Smiling face with halo": "Smilende ansikt med glorie", + "Smiling face with horns": "Smilende ansikt med horn", + "Winking face": "Blunk ansikt", + "Smiling face with smiling eyes": "Smilende ansikt med smilende \u00f8yne", + "Face savoring delicious food": "M\u00f8te nyter deilig mat", + "Relieved face": "Lettet ansikt", + "Smiling face with heart-shaped eyes": "Smilende ansikt med hjerteformede \u00f8yne", + "Smiling face with sunglasses": "Smilende ansikt med solbriller", + "Smirking face": "Tilfreds ansikt", + "Neutral face": "N\u00f8ytral ansikt", + "Expressionless face": "Uttrykksl\u00f8st ansikt", + "Unamused face": "Ikke moret ansikt", + "Face with cold sweat": "Ansikt med kald svette", + "Pensive face": "Tankefull ansikt", + "Confused face": "Forvirret ansikt", + "Confounded face": "Skamme ansikt", + "Kissing face": "Kyssing ansikt", + "Face throwing a kiss": "Ansikt kaste et kyss", + "Kissing face with smiling eyes": "Kyssing ansikt med smilende \u00f8yne", + "Kissing face with closed eyes": "Kyssing ansiktet med lukkede \u00f8yne", + "Face with stuck out tongue": "Ansikt med stakk ut tungen", + "Face with stuck out tongue and winking eye": "Ansikt med stakk ut tungen og blunke \u00f8ye", + "Face with stuck out tongue and tightly-closed eyes": "Ansikt med fast ut tungen og tett lukket \u00f8yne", + "Disappointed face": "Skuffet ansikt", + "Worried face": "Bekymret ansikt", + "Angry face": "Sint ansikt", + "Pouting face": "Trutmunn ansikt", + "Crying face": "Gr\u00e5ter ansikt", + "Persevering face": "Utholdende ansikt", + "Face with look of triumph": "Ansikt med utseendet til triumf", + "Disappointed but relieved face": "Skuffet men lettet ansikt", + "Frowning face with open mouth": "Rynke ansikt med \u00e5pen munn", + "Anguished face": "Forpint ansikt", + "Fearful face": "Engstelig ansikt", + "Weary face": "Slitne ansiktet", + "Sleepy face": "S\u00f8vnig ansikt", + "Tired face": "Tr\u00f8tt ansikt", + "Grimacing face": "Griner ansikt", + "Loudly crying face": "H\u00f8ylytt gr\u00e5tende ansikt", + "Face with open mouth": "Ansikt med \u00e5pen munn", + "Hushed face": "Lavm\u00e6lt ansikt", + "Face with open mouth and cold sweat": "Ansikt med \u00e5pen munn og kald svette", + "Face screaming in fear": "Ansikt skriker i frykt", + "Astonished face": "Forbauset ansikt", + "Flushed face": "Flushed ansikt", + "Sleeping face": "Sovende ansikt", + "Dizzy face": "Svimmel ansikt", + "Face without mouth": "Ansikt uten munn", + "Face with medical mask": "Ansikt med medisinsk maske", + + // Line breaker + "Break": "Brudd", + + // Math + "Subscript": "Senket skrift", + "Superscript": "Hevet skrift", + + // Full screen + "Fullscreen": "Full skjerm", + + // Horizontal line + "Insert Horizontal Line": "Sett inn horisontal linje", + + // Clear formatting + "Clear Formatting": "Fjerne formatering", + + // Save + "Save": "Lagre", + + // Undo, redo + "Undo": "Angre", + "Redo": "Utf\u00f8r likevel", + + // Select all + "Select All": "Marker alt", + + // Code view + "Code View": "Kodevisning", + + // Quote + "Quote": "Sitat", + "Increase": "\u00d8ke", + "Decrease": "Nedgang", + + // Quick Insert + "Quick Insert": "Hurtiginnsats", + + // Spcial Characters + "Special Characters": "Spesielle karakterer", + "Latin": "Latin", + "Greek": "Gresk", + "Cyrillic": "Kyrilliske", + "Punctuation": "Tegnsetting", + "Currency": "Valuta", + "Arrows": "Piler", + "Math": "Matte", + "Misc": "Misc", + + // Print. + "Print": "Skrive ut", + + // Spell Checker. + "Spell Checker": "Stavekontroll", + + // Help + "Help": "Hjelp", + "Shortcuts": "Snarveier", + "Inline Editor": "Inline editor", + "Show the editor": "Vis redaktøren", + "Common actions": "Felles handlinger", + "Copy": "Kopiere", + "Cut": "Kutte opp", + "Paste": "Lim inn", + "Basic Formatting": "Grunnleggende formatering", + "Increase quote level": "Øke tilbudsnivået", + "Decrease quote level": "Redusere tilbudsnivå", + "Image / Video": "Bilde / video", + "Resize larger": "Endre størrelsen større", + "Resize smaller": "Endre størrelsen mindre", + "Table": "Bord", + "Select table cell": "Velg tabellcelle", + "Extend selection one cell": "Utvide valg en celle", + "Extend selection one row": "Utvide valg en rad", + "Navigation": "Navigasjon", + "Focus popup / toolbar": "Fokus popup / verktøylinje", + "Return focus to previous position": "Returnere fokus til tidligere posisjon", + + // Embed.ly + "Embed URL": "Legge inn nettadressen", + "Paste in a URL to embed": "Lim inn i en URL for å legge inn", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Det limte innholdet kommer fra et Microsoft Word-dokument. vil du beholde formatet eller rydde det opp?", + "Keep": "Beholde", + "Clean": "Ren", + "Word Paste Detected": "Ordpasta oppdages" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/nl.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/nl.js new file mode 100644 index 0000000..f7f4a1f --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/nl.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Dutch + */ + +$.FE.LANGUAGE['nl'] = { + translation: { + // Place holder + "Type something": "Typ iets", + + // Basic formatting + "Bold": "Vet", + "Italic": "Cursief", + "Underline": "Onderstreept", + "Strikethrough": "Doorhalen", + + // Main buttons + "Insert": "Invoegen", + "Delete": "Verwijder", + "Cancel": "Annuleren", + "OK": "Ok\u00e9", + "Back": "Terug", + "Remove": "Verwijderen", + "More": "Meer", + "Update": "Bijwerken", + "Style": "Stijl", + + // Font + "Font Family": "Lettertype", + "Font Size": "Lettergrootte", + + // Colors + "Colors": "Kleuren", + "Background": "Achtergrond", + "Text": "Tekst", + "HEX Color": "HEX kleur", + + // Paragraphs + "Paragraph Format": "Opmaak", + "Normal": "Normaal", + "Code": "Code", + "Heading 1": "Kop 1", + "Heading 2": "Kop 2", + "Heading 3": "Kop 3", + "Heading 4": "Kop 4", + + // Style + "Paragraph Style": "Paragraaf stijl", + "Inline Style": "Inline stijl", + + // Alignment + "Align": "Uitlijnen", + "Align Left": "Links uitlijnen", + "Align Center": "Centreren", + "Align Right": "Rechts uitlijnen", + "Align Justify": "Uitvullen", + "None": "Geen", + + // Lists + "Ordered List": "Geordende lijst", + "Default": "Standaard", + "Lower Alpha": "Lagere alpha", + "Lower Greek": "Lager Grieks", + "Lower Roman": "Lager Romeins", + "Upper Alpha": "Bovenste alfa", + "Upper Roman": "Bovenste roman", + + "Unordered List": "Ongeordende lijst", + "Circle": "Cirkel", + "Disc": "Schijf", + "Square": "Plein", + + // Line height + "Line Height": "Lijnhoogte", + "Single": "Single", + "Double": "Dubbele", + + // Indent + "Decrease Indent": "Inspringen verkleinen", + "Increase Indent": "Inspringen vergroten", + + // Links + "Insert Link": "Link invoegen", + "Open in new tab": "Openen in nieuwe tab", + "Open Link": "Open link", + "Edit Link": "Link bewerken", + "Unlink": "Link verwijderen", + "Choose Link": "Link kiezen", + + // Images + "Insert Image": "Afbeelding invoegen", + "Upload Image": "Afbeelding uploaden", + "By URL": "Via URL", + "Browse": "Bladeren", + "Drop image": "Sleep afbeelding", + "or click": "of klik op", + "Manage Images": "Afbeeldingen beheren", + "Loading": "Bezig met laden", + "Deleting": "Verwijderen", + "Tags": "Labels", + "Are you sure? Image will be deleted.": "Weet je het zeker? Afbeelding wordt verwijderd.", + "Replace": "Vervangen", + "Uploading": "Uploaden", + "Loading image": "Afbeelding laden", + "Display": "Tonen", + "Inline": "Inline", + "Break Text": "Tekst afbreken", + "Alternative Text": "Alternatieve tekst", + "Change Size": "Grootte wijzigen", + "Width": "Breedte", + "Height": "Hoogte", + "Something went wrong. Please try again.": "Er is iets fout gegaan. Probeer opnieuw.", + "Image Caption": "Afbeelding caption", + "Advanced Edit": "Geavanceerd bewerken", + + // Video + "Insert Video": "Video invoegen", + "Embedded Code": "Ingebedde code", + "Paste in a video URL": "Voeg een video-URL toe", + "Drop video": "Sleep video", + "Your browser does not support HTML5 video.": "Je browser ondersteunt geen html5-video.", + "Upload Video": "Video uploaden", + + // Tables + "Insert Table": "Tabel invoegen", + "Table Header": "Tabel hoofd", + "Remove Table": "Verwijder tabel", + "Table Style": "Tabelstijl", + "Horizontal Align": "Horizontale uitlijning", + "Row": "Rij", + "Insert row above": "Voeg rij boven toe", + "Insert row below": "Voeg rij onder toe", + "Delete row": "Verwijder rij", + "Column": "Kolom", + "Insert column before": "Voeg kolom in voor", + "Insert column after": "Voeg kolom in na", + "Delete column": "Verwijder kolom", + "Cell": "Cel", + "Merge cells": "Cellen samenvoegen", + "Horizontal split": "Horizontaal splitsen", + "Vertical split": "Verticaal splitsen", + "Cell Background": "Cel achtergrond", + "Vertical Align": "Verticale uitlijning", + "Top": "Top", + "Middle": "Midden", + "Bottom": "Onder", + "Align Top": "Uitlijnen top", + "Align Middle": "Uitlijnen midden", + "Align Bottom": "Onder uitlijnen", + "Cell Style": "Celstijl", + + // Files + "Upload File": "Bestand uploaden", + "Drop file": "Sleep bestand", + + // Emoticons + "Emoticons": "Emoticons", + "Grinning face": "Grijnzend gezicht", + "Grinning face with smiling eyes": "Grijnzend gezicht met lachende ogen", + "Face with tears of joy": "Gezicht met tranen van vreugde", + "Smiling face with open mouth": "Lachend gezicht met open mond", + "Smiling face with open mouth and smiling eyes": "Lachend gezicht met open mond en lachende ogen", + "Smiling face with open mouth and cold sweat": "Lachend gezicht met open mond en koud zweet", + "Smiling face with open mouth and tightly-closed eyes": "Lachend gezicht met open mond en strak gesloten ogen", + "Smiling face with halo": "Lachend gezicht met halo", + "Smiling face with horns": "Lachend gezicht met hoorns", + "Winking face": "Knipogend gezicht", + "Smiling face with smiling eyes": "Lachend gezicht met lachende ogen", + "Face savoring delicious food": "Gezicht genietend van heerlijk eten", + "Relieved face": "Opgelucht gezicht", + "Smiling face with heart-shaped eyes": "Glimlachend gezicht met hart-vormige ogen", + "Smiling face with sunglasses": "Lachend gezicht met zonnebril", + "Smirking face": "Grijnzende gezicht", + "Neutral face": "Neutraal gezicht", + "Expressionless face": "Uitdrukkingsloos gezicht", + "Unamused face": "Niet geamuseerd gezicht", + "Face with cold sweat": "Gezicht met koud zweet", + "Pensive face": "Peinzend gezicht", + "Confused face": "Verward gezicht", + "Confounded face": "Beschaamd gezicht", + "Kissing face": "Zoenend gezicht", + "Face throwing a kiss": "Gezicht gooien van een kus", + "Kissing face with smiling eyes": "Zoenend gezicht met lachende ogen", + "Kissing face with closed eyes": "Zoenend gezicht met gesloten ogen", + "Face with stuck out tongue": "Gezicht met uitstekende tong", + "Face with stuck out tongue and winking eye": "Gezicht met uitstekende tong en knipoog", + "Face with stuck out tongue and tightly-closed eyes": "Gezicht met uitstekende tong en strak-gesloten ogen", + "Disappointed face": "Teleurgesteld gezicht", + "Worried face": "Bezorgd gezicht", + "Angry face": "Boos gezicht", + "Pouting face": "Pruilend gezicht", + "Crying face": "Huilend gezicht", + "Persevering face": "Volhardend gezicht", + "Face with look of triumph": "Gezicht met blik van triomf", + "Disappointed but relieved face": "Teleurgesteld, maar opgelucht gezicht", + "Frowning face with open mouth": "Fronsend gezicht met open mond", + "Anguished face": "Gekweld gezicht", + "Fearful face": "Angstig gezicht", + "Weary face": "Vermoeid gezicht", + "Sleepy face": "Slaperig gezicht", + "Tired face": "Moe gezicht", + "Grimacing face": "Grimassen trekkend gezicht", + "Loudly crying face": "Luid schreeuwend gezicht", + "Face with open mouth": "Gezicht met open mond", + "Hushed face": "Tot zwijgen gebracht gezicht", + "Face with open mouth and cold sweat": "Gezicht met open mond en koud zweet", + "Face screaming in fear": "Gezicht schreeuwend van angst", + "Astonished face": "Verbaasd gezicht", + "Flushed face": "Blozend gezicht", + "Sleeping face": "Slapend gezicht", + "Dizzy face": "Duizelig gezicht", + "Face without mouth": "Gezicht zonder mond", + "Face with medical mask": "Gezicht met medisch masker", + + // Line breaker + "Break": "Afbreken", + + // Math + "Subscript": "Subscript", + "Superscript": "Superscript", + + // Full screen + "Fullscreen": "Volledig scherm", + + // Horizontal line + "Insert Horizontal Line": "Horizontale lijn invoegen", + + // Clear formatting + "Clear Formatting": "Verwijder opmaak", + + // Save + "Save": "Opslaan", + + // Undo, redo + "Undo": "Ongedaan maken", + "Redo": "Opnieuw", + + // Select all + "Select All": "Alles selecteren", + + // Code view + "Code View": "Codeweergave", + + // Quote + "Quote": "Citaat", + "Increase": "Toenemen", + "Decrease": "Afnemen", + + // Quick Insert + "Quick Insert": "Snel invoegen", + + // Spcial Characters + "Special Characters": "Speciale tekens", + "Latin": "Latijns", + "Greek": "Grieks", + "Cyrillic": "Cyrillisch", + "Punctuation": "Interpunctie", + "Currency": "Valuta", + "Arrows": "Pijlen", + "Math": "Wiskunde", + "Misc": "Misc", + + // Print. + "Print": "Afdrukken", + + // Spell Checker. + "Spell Checker": "Spellingscontrole", + + // Help + "Help": "Hulp", + "Shortcuts": "Snelkoppelingen", + "Inline Editor": "Inline editor", + "Show the editor": "Laat de editor zien", + "Common actions": "Algemene acties", + "Copy": "Kopiëren", + "Cut": "Knippen", + "Paste": "Plakken", + "Basic Formatting": "Basisformattering", + "Increase quote level": "Citaat niveau verhogen", + "Decrease quote level": "Citaatniveau verminderen", + "Image / Video": "Beeld / video", + "Resize larger": "Groter maken", + "Resize smaller": "Kleiner maken", + "Table": "Tabel", + "Select table cell": "Selecteer tabelcel", + "Extend selection one cell": "Selecteer een cel uit", + "Extend selection one row": "Selecteer een rij uit", + "Navigation": "Navigatie", + "Focus popup / toolbar": "Focus pop-up / werkbalk", + "Return focus to previous position": "Focus terug naar vorige positie", + + // Embed.ly + "Embed URL": "Embed url", + "Paste in a URL to embed": "Voer een URL in om toe te voegen", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "De geplakte inhoud komt uit een Microsoft Word-document. wil je het formaat behouden of schoonmaken?", + "Keep": "Opmaak behouden", + "Clean": "Tekst schoonmaken", + "Word Paste Detected": "Word inhoud gedetecteerd" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/pl.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/pl.js new file mode 100644 index 0000000..80cf3a7 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/pl.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Polish + */ + +$.FE.LANGUAGE['pl'] = { + translation: { + // Place holder + "Type something": "Wpisz co\u015b", + + // Basic formatting + "Bold": "Pogrubienie", + "Italic": "Kursywa", + "Underline": "Podkre\u015blenie", + "Strikethrough": "Przekre\u015blenie", + + // Main buttons + "Insert": "Wstaw", + "Delete": "Usun\u0105\u0107", + "Cancel": "Anuluj", + "OK": "Ok", + "Back": "Plecy", + "Remove": "Usun\u0105\u0107", + "More": "Jeszcze", + "Update": "Aktualizacja", + "Style": "Styl", + + // Font + "Font Family": "Kr\u00f3j czcionki", + "Font Size": "Rozmiar czcionki", + + // Colors + "Colors": "Kolory", + "Background": "T\u0142o", + "Text": "Tekstu", + "HEX Color": "Sześciokąt", + + // Paragraphs + "Paragraph Format": "Formaty", + "Normal": "Normalny", + "Code": "Kod \u017ar\u00f3d\u0142owy", + "Heading 1": "Nag\u0142\u00f3wek 1", + "Heading 2": "Nag\u0142\u00f3wek 2", + "Heading 3": "Nag\u0142\u00f3wek 3", + "Heading 4": "Nag\u0142\u00f3wek 4", + + // Style + "Paragraph Style": "Styl akapitu", + "Inline Style": "Stylu zgodna", + + // Alignment + "Align": "Wyr\u00f3wnaj", + "Align Left": "Wyr\u00f3wnaj do lewej", + "Align Center": "Wyr\u00f3wnaj do \u015brodka", + "Align Right": "Wyr\u00f3wnaj do prawej", + "Align Justify": "Do lewej i prawej", + "None": "\u017baden", + + // Lists + "Ordered List": "Uporz\u0105dkowana lista", + "Default": "Domyślna", + "Lower Alpha": "Niższy alfa", + "Lower Greek": "Niższy grecki", + "Lower Roman": "Niższe rzymskie", + "Upper Alpha": "Górna alfa", + "Upper Roman": "Górny rzymski", + + "Unordered List": "Lista nieuporz\u0105dkowana", + "Circle": "Okrąg", + "Disc": "Dysk", + "Square": "Plac", + + // Line height + "Line Height": "Wysokość linii", + "Single": "Pojedynczy", + "Double": "Podwójnie", + + // Indent + "Decrease Indent": "Zmniejsz wci\u0119cie", + "Increase Indent": "Zwi\u0119ksz wci\u0119cie", + + // Links + "Insert Link": "Wstaw link", + "Open in new tab": "Otw\u00f3rz w nowej karcie", + "Open Link": "Otw\u00f3rz link", + "Edit Link": "Link edytuj", + "Unlink": "Usu\u0144 link", + "Choose Link": "Wybierz link", + + // Images + "Insert Image": "Wstaw obrazek", + "Upload Image": "Za\u0142aduj obrazek", + "By URL": "Przez URL", + "Browse": "Przegl\u0105danie", + "Drop image": "Upu\u015bci\u0107 obraz", + "or click": "lub kliknij", + "Manage Images": "Zarz\u0105dzanie zdj\u0119ciami", + "Loading": "\u0141adowanie", + "Deleting": "Usuwanie", + "Tags": "Tagi", + "Are you sure? Image will be deleted.": "Czy na pewno? Obraz zostanie skasowany.", + "Replace": "Zast\u0105pi\u0107", + "Uploading": "Zamieszczanie", + "Loading image": "\u0141adowanie obrazek", + "Display": "Wystawa", + "Inline": "Zgodna", + "Break Text": "Z\u0142ama\u0107 tekst", + "Alternative Text": "Tekst alternatywny", + "Change Size": "Zmie\u0144 rozmiar", + "Width": "Szeroko\u015b\u0107", + "Height": "Wysoko\u015b\u0107", + "Something went wrong. Please try again.": "Co\u015b posz\u0142o nie tak. Prosz\u0119 spr\u00f3buj ponownie.", + "Image Caption": "Podpis obrazu", + "Advanced Edit": "Zaawansowana edycja", + + // Video + "Insert Video": "Wstaw wideo", + "Embedded Code": "Kod osadzone", + "Paste in a video URL": "Wklej adres URL filmu", + "Drop video": "Upuść wideo", + "Your browser does not support HTML5 video.": "Twoja przeglądarka nie obsługuje wideo html5.", + "Upload Video": "Prześlij wideo", + + // Tables + "Insert Table": "Wstaw tabel\u0119", + "Table Header": "Nag\u0142\u00f3wek tabeli", + "Remove Table": "Usu\u0144 tabel\u0119", + "Table Style": "Styl tabeli", + "Horizontal Align": "Wyr\u00f3wnaj poziomy", + "Row": "Wiersz", + "Insert row above": "Wstaw wiersz przed", + "Insert row below": "Wstaw wiersz po", + "Delete row": "Usu\u0144 wiersz", + "Column": "Kolumna", + "Insert column before": "Wstaw kolumn\u0119 przed", + "Insert column after": "Wstaw kolumn\u0119 po", + "Delete column": "Usu\u0144 kolumn\u0119", + "Cell": "Kom\u00f3rka", + "Merge cells": "\u0141\u0105cz kom\u00f3rki", + "Horizontal split": "Podzia\u0142 poziomy", + "Vertical split": "Podzia\u0142 pionowy", + "Cell Background": "T\u0142a kom\u00f3rek", + "Vertical Align": "Pionowe wyr\u00f3wnanie", + "Top": "Top", + "Middle": "\u015arodkowy", + "Bottom": "Dno", + "Align Top": "Wyr\u00f3wnaj do g\u00f3ry", + "Align Middle": "Wyr\u00f3wnaj \u015brodku", + "Align Bottom": "Wyr\u00f3wnaj do do\u0142u", + "Cell Style": "Styl kom\u00f3rki", + + // Files + "Upload File": "Prze\u015blij plik", + "Drop file": "Upu\u015bci\u0107 plik", + + // Emoticons + "Emoticons": "Emotikony", + "Grinning face": "Z u\u015bmiechem twarz", + "Grinning face with smiling eyes": "Z u\u015bmiechem twarz z u\u015bmiechni\u0119tymi oczami", + "Face with tears of joy": "Twarz ze \u0142zami rado\u015bci", + "Smiling face with open mouth": "U\u015bmiechni\u0119ta twarz z otwartymi ustami", + "Smiling face with open mouth and smiling eyes": "U\u015bmiechni\u0119ta twarz z otwartymi ustami i u\u015bmiechni\u0119te oczy", + "Smiling face with open mouth and cold sweat": "U\u015bmiechni\u0119ta twarz z otwartymi ustami i zimny pot", + "Smiling face with open mouth and tightly-closed eyes": "U\u015bmiechni\u0119ta twarz z otwartymi ustami i szczelnie zamkni\u0119tych oczu", + "Smiling face with halo": "U\u015bmiechni\u0119ta twarz z halo", + "Smiling face with horns": "U\u015bmiechni\u0119ta twarz z rogami", + "Winking face": "Mrugaj\u0105ca twarz", + "Smiling face with smiling eyes": "U\u015bmiechni\u0119ta twarz z u\u015bmiechni\u0119tymi oczami", + "Face savoring delicious food": "Twarz smakuj\u0105 c pyszne jedzenie", + "Relieved face": "Z ulg\u0105 twarz", + "Smiling face with heart-shaped eyes": "U\u015bmiechni\u0119ta twarz z oczami w kszta\u0142cie serca", + "Smiling face with sunglasses": "U\u015bmiechni\u0119ta twarz z okulary", + "Smirking face": "Zadowolony z siebie twarz", + "Neutral face": "Neutralny twarzy", + "Expressionless face": "Bezwyrazowy twarzy", + "Unamused face": "Nie rozbawiony twarzy", + "Face with cold sweat": "Zimny pot z twarzy", + "Pensive face": "Zamy\u015blona twarz", + "Confused face": "Myli\u0107 twarzy", + "Confounded face": "Ha\u0144ba twarz", + "Kissing face": "Ca\u0142owanie twarz", + "Face throwing a kiss": "Twarz rzucaj\u0105c poca\u0142unek", + "Kissing face with smiling eyes": "Ca\u0142owanie twarz z u\u015bmiechni\u0119tymi oczami", + "Kissing face with closed eyes": "Ca\u0142owanie twarz z zamkni\u0119tymi oczami", + "Face with stuck out tongue": "Twarz z j\u0119zyka stercza\u0142y", + "Face with stuck out tongue and winking eye": "Twarz z stercza\u0142y j\u0119zyka i mrugaj\u0105c okiem", + "Face with stuck out tongue and tightly-closed eyes": "Twarz z stercza\u0142y j\u0119zyka i szczelnie zamkni\u0119tych oczu", + "Disappointed face": "Rozczarowany twarzy", + "Worried face": "Martwi twarzy", + "Angry face": "Gniewnych twarzy", + "Pouting face": "D\u0105sy twarzy", + "Crying face": "P\u0142acz\u0105cy", + "Persevering face": "Wytrwa\u0142a twarz", + "Face with look of triumph": "Twarz z wyrazem triumfu", + "Disappointed but relieved face": "Rozczarowany ale ulg\u0119 twarz", + "Frowning face with open mouth": "Krzywi\u0105c twarz z otwartymi ustami", + "Anguished face": "Bolesna twarz", + "Fearful face": "W obawie twarzy", + "Weary face": "Zm\u0119czona twarz", + "Sleepy face": "Je\u017adziec bez twarzy", + "Tired face": "Zm\u0119czonej twarzy", + "Grimacing face": "Skrzywi\u0142 twarz", + "Loudly crying face": "G\u0142o\u015bno p\u0142aka\u0107 twarz", + "Face with open mouth": "twarz z otwartymi ustami", + "Hushed face": "Uciszy\u0142 twarzy", + "Face with open mouth and cold sweat": "Twarz z otwartymi ustami i zimny pot", + "Face screaming in fear": "Twarz z krzykiem w strachu", + "Astonished face": "Zdziwienie twarzy", + "Flushed face": "Zaczerwienienie twarzy", + "Sleeping face": "\u015api\u0105ca twarz", + "Dizzy face": "Zawroty g\u0142owy twarzy", + "Face without mouth": "Twarz bez usta", + "Face with medical mask": "Twarz\u0105 w medycznych maski", + + // Line breaker + "Break": "Z\u0142ama\u0107", + + // Math + "Subscript": "Indeks dolny", + "Superscript": "Indeks g\u00f3rny", + + // Full screen + "Fullscreen": "Pe\u0142ny ekran", + + // Horizontal line + "Insert Horizontal Line": "Wstaw lini\u0119 poziom\u0105", + + // Clear formatting + "Clear Formatting": "Usu\u0144 formatowanie", + + // Save + "Save": "\u005a\u0061\u0070\u0069\u0073\u0061\u0107", + + // Undo, redo + "Undo": "Cofnij", + "Redo": "Pon\u00f3w", + + // Select all + "Select All": "Zaznacz wszystko", + + // Code view + "Code View": "Widok kod", + + // Quote + "Quote": "Cytat", + "Increase": "Wzrost", + "Decrease": "Zmniejszenie", + + // Quick Insert + "Quick Insert": "Szybkie wstaw", + + // Spcial Characters + "Special Characters": "Znaki specjalne", + "Latin": "Łacina", + "Greek": "Grecki", + "Cyrillic": "Cyrylica", + "Punctuation": "Interpunkcja", + "Currency": "Waluta", + "Arrows": "Strzałki", + "Math": "Matematyka", + "Misc": "Misc", + + // Print. + "Print": "Wydrukować", + + // Spell Checker. + "Spell Checker": "Sprawdzanie pisowni", + + // Help + "Help": "Wsparcie", + "Shortcuts": "Skróty", + "Inline Editor": "Edytor w wierszu", + "Show the editor": "Pokazać edytor", + "Common actions": "Wspólne działania", + "Copy": "Kopiuj", + "Cut": "Ciąć", + "Paste": "Pasta", + "Basic Formatting": "Podstawowe formatowanie", + "Increase quote level": "Zwiększyć poziom notowań", + "Decrease quote level": "Zmniejszyć poziom notowań", + "Image / Video": "Obraz / wideo", + "Resize larger": "Zmienić rozmiar większy", + "Resize smaller": "Zmienić rozmiar mniejszy", + "Table": "Stół", + "Select table cell": "Wybierz komórkę tabeli", + "Extend selection one cell": "Przedłużyć wybór jednej komórki", + "Extend selection one row": "Przedłużyć wybór jednego rzędu", + "Navigation": "Nawigacja", + "Focus popup / toolbar": "Focus popup / toolbar", + "Return focus to previous position": "Powrót do poprzedniej pozycji", + + // Embed.ly + "Embed URL": "Osadzaj url", + "Paste in a URL to embed": "Wklej w adresie URL do osadzenia", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Wklejana treść pochodzi z programu Microsoft Word. Czy chcesz zachować formatowanie czy wkleić jako zwykły tekst?", + "Keep": "Zachowaj formatowanie", + "Clean": "Wklej jako tekst", + "Word Paste Detected": "Wykryto sformatowany tekst" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/pt_br.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/pt_br.js new file mode 100644 index 0000000..69e46dd --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/pt_br.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Portuguese spoken in Brazil + */ + +$.FE.LANGUAGE['pt_br'] = { + translation: { + // Place holder + "Type something": "Digite algo", + + // Basic formatting + "Bold": "Negrito", + "Italic": "Itálito", + "Underline": "Sublinhar", + "Strikethrough": "Tachado", + + // Main buttons + "Insert": "Inserir", + "Delete": "Apagar", + "Cancel": "Cancelar", + "OK": "Ok", + "Back": "Voltar", + "Remove": "Remover", + "More": "Mais", + "Update": "Atualizar", + "Style": "Estilo", + + // Font + "Font Family": "Fonte", + "Font Size": "Tamanho", + + // Colors + "Colors": "Cores", + "Background": "Fundo", + "Text": "Texto", + "HEX Color": "Cor hexadecimal", + + // Paragraphs + "Paragraph Format": "Formatos", + "Normal": "Normal", + "Code": "Código", + "Heading 1": "Cabeçalho 1", + "Heading 2": "Cabeçalho 2", + "Heading 3": "Cabeçalho 3", + "Heading 4": "Cabeçalho 4", + + // Style + "Paragraph Style": "Estilo de parágrafo", + "Inline Style": "Estilo embutido", + + // Alignment + "Align": "Alinhar", + "Align Left": "Alinhar à esquerda", + "Align Center": "Centralizar", + "Align Right": "Alinhar à direita", + "Align Justify": "Justificar", + "None": "Nenhum", + + // Lists + "Ordered List": "Lista ordenada", + "Default": "Padrão", + "Lower Alpha": "Alpha inferior", + "Lower Greek": "Grego inferior", + "Lower Roman": "Baixa romana", + "Upper Alpha": "Alfa superior", + "Upper Roman": "Romana superior", + + "Unordered List": "Lista não ordenada", + "Circle": "Círculo", + "Disc": "Disco", + "Square": "Quadrado", + + // Line height + "Line Height": "Altura da linha", + "Single": "Solteiro", + "Double": "Em dobro", + + // Indent + "Decrease Indent": "Diminuir recuo", + "Increase Indent": "Aumentar recuo", + + // Links + "Insert Link": "Inserir link", + "Open in new tab": "Abrir em uma nova aba", + "Open Link": "Abrir link", + "Edit Link": "Editar link", + "Unlink": "Remover link", + "Choose Link": "Escolha o link", + + // Images + "Insert Image": "Inserir imagem", + "Upload Image": "Carregar imagem", + "By URL": "Por um endereço URL", + "Browse": "Procurar", + "Drop image": "Arraste sua imagem aqui", + "or click": "ou clique aqui", + "Manage Images": "Gerenciar imagens", + "Loading": "Carregando", + "Deleting": "Excluindo", + "Tags": "Etiquetas", + "Are you sure? Image will be deleted.": "Você tem certeza? A imagem será apagada.", + "Replace": "Substituir", + "Uploading": "Carregando imagem", + "Loading image": "Carregando imagem", + "Display": "Exibir", + "Inline": "Em linha", + "Break Text": "Texto de quebra", + "Alternate Text": "Texto alternativo", + "Change Size": "Alterar tamanho", + "Width": "Largura", + "Height": "Altura", + "Something went wrong. Please try again.": "Algo deu errado. Por favor, tente novamente.", + "Image Caption": "Legenda da imagem", + "Advanced Edit": "Edição avançada", + + // Video + "Insert Video": "Inserir vídeo", + "Embedded Code": "Código embutido", + "Paste in a video URL": "Colar um endereço de vídeo", + "Drop video": "Solte o vídeo", + "Your browser does not support HTML5 vídeo.": "Seu navegador não suporta vídeo em HTML5.", + "Upload Video": "Carregar vídeo", + + // Tables + "Insert Table": "Inserir tabela", + "Table Header": "Cabeçalho da tabela", + "Remove Table": "Remover tabela", + "Table Style": "Estilo de tabela", + "Horizontal Align": "Alinhamento horizontal", + "Row": "Linha", + "Insert row above": "Inserir linha antes", + "Insert row below": "Inserir linha depois", + "Delete row": "Excluir linha", + "Column": "Coluna", + "Insert column before": "Inserir coluna antes", + "Insert column after": "Inserir coluna depois", + "Delete column": "Excluir coluna", + "Cell": "Célula", + "Merge cells": "Agrupar células", + "Horizontal split": "Divisão horizontal", + "Vertical split": "Divisão vertical", + "Cell Background": "Fundo da célula", + "Vertical Align": "Alinhamento vertical", + "Top": "Topo", + "Middle": "Meio", + "Bottom": "Fundo", + "Align Top": "Alinhar topo", + "Align Middle": "Alinhar meio", + "Align Bottom": "Alinhar fundo", + "Cell Style": "Estilo de célula", + + // Files + "Upload File": "Carregar arquivo", + "Drop file": "Arraste seu arquivo aqui", + + // Emoticons + "Emoticons": "Emoticons", + "Grinning face": "Rosto sorrindo", + "Grinning face with smiling eyes": "Rosto sorrindo rosto com olhos sorridentes", + "Face with tears of joy": "Rosto com lágrimas de alegria", + "Smiling face with open mouth": "Rosto sorrindo com a boca aberta", + "Smiling face with open mouth and smiling eyes": "Rosto sorrindo com a boca aberta e olhos sorridentes", + "Smiling face with open mouth and cold sweat": "Rosto sorrindo com a boca aberta e suor frio", + "Smiling face with open mouth and tightly-closed eyes": "Rosto sorrindo com a boca aberta e os olhos bem fechados", + "Smiling face with halo": "Rosto sorrindo com aréola", + "Smiling face with horns": "Rosto sorrindo com chifres", + "Winking face": "Rosto piscando", + "Smiling face with smiling eyes": "Rosto sorrindo com olhos sorridentes", + "Face savoring delicious food": "Rosto saboreando uma deliciosa comida", + "Relieved face": "Rosto aliviado", + "Smiling face with heart-shaped eyes": "Rosto sorrindo com os olhos em forma de coração", + "Smiling face with sunglasses": "Rosto sorrindo com óculos de sol", + "Smirking face": "Rosto sorridente", + "Neutral face": "Rosto neutro", + "Expressionless face": "Rosto inexpressivo", + "Unamused face": "Rosto sem expressão", + "Face with cold sweat": "Rosto com suor frio", + "Pensive face": "Rosto pensativo", + "Confused face": "Rosto confuso", + "Confounded face": "Rosto atônito", + "Kissing face": "Rosto beijando", + "Face throwing a kiss": "Rosto jogando um beijo", + "Kissing face with smiling eyes": "Rosto beijando com olhos sorridentes", + "Kissing face with closed eyes": "Rosto beijando com os olhos fechados", + "Face with stuck out tongue": "Rosto com a língua para fora", + "Face with stuck out tongue and winking eye": "Rosto com a língua para fora e um olho piscando", + "Face with stuck out tongue and tightly-closed eyes": "Rosto com a língua para fora e os olhos bem fechados", + "Disappointed face": "Rosto decepcionado", + "Worried face": "Rosto preocupado", + "Angry face": "Rosto irritado", + "Pouting face": "Rosto com beicinho", + "Crying face": "Rosto chorando", + "Persevering face": "Rosto perseverante", + "Face with look of triumph": "Rosto com olhar de triunfo", + "Disappointed but relieved face": "Rosto decepcionado mas aliviado", + "Frowning face with open mouth": "Rosto franzido com a boca aberta", + "Anguished face": "Rosto angustiado", + "Fearful face": "Rosto com medo", + "Weary face": "Rosto cansado", + "Sleepy face": "Rosto com sono", + "Tired face": "Rosto cansado", + "Grimacing face": "Rosto fazendo careta", + "Loudly crying face": "Rosto chorando alto", + "Face with open mouth": "Rosto com a boca aberta", + "Hushed face": "Rosto silencioso", + "Face with open mouth and cold sweat": "Rosto com a boca aferta e suando frio", + "Face screaming in fear": "Rosto gritando de medo", + "Astonished face": "Rosto surpreso", + "Flushed face": "Rosto envergonhado", + "Sleeping face": "Rosto dormindo", + "Dizzy face": "Rosto tonto", + "Face without mouth": "Rosto sem boca", + "Face with medical mask": "Rosto com máscara médica", + + // Line breaker + "Break": "Quebrar linha", + + // Math + "Subscript": "Subscrito", + "Superscript": "Sobrescrito", + + // Full screen + "Fullscreen": "Tela cheia", + + // Horizontal line + "Insert Horizontal Line": "Inserir linha horizontal", + + // Clear formatting + "Clear Formatting": "Remover formatação", + + // Save + "Save": "\u0053\u0061\u006c\u0076\u0065", + + // Undo, redo + "Undo": "Desfazer", + "Redo": "Refazer", + + // Select all + "Select All": "Selecionar tudo", + + // Code view + "Code View": "Exibir de código", + + // Quote + "Quote": "Citação", + "Increase": "Aumentar", + "Decrease": "Diminuir", + + // Quick Insert + "Quick Insert": "Inserção rápida", + + // Spcial Characters + "Special Characters": "Caracteres especiais", + "Latin": "Latino", + "Greek": "Grego", + "Cyrillic": "Cirílico", + "Punctuation": "Pontuação", + "Currency": "Moeda", + "Arrows": "Setas", + "Math": "Matemática", + "Misc": "Misc", + + // Print. + "Print": "Impressão", + + // Spell Checker. + "Spell Checker": "Corretor ortográfico", + + // Help + "Help": "Ajuda", + "Shortcuts": "Atalhos", + "Inline Editor": "Editor em linha", + "Show the editor": "Mostre o editor", + "Common actions": "Ações comuns", + "Copy": "Cópia de", + "Cut": "Cortar", + "Paste": "Colar", + "Basic Formatting": "Formatação básica", + "Increase quote level": "Aumentar o nível de cotação", + "Decrease quote level": "Diminuir o nível de cotação", + "Image / Video": "Imagem / Vídeo", + "Resize larger": "Redimensionar maior", + "Resize smaller": "Redimensionar menor", + "Table": "Tabela", + "Select table cell": "Selecione a célula da tabela", + "Extend selection one cell": "Ampliar a seleção de uma célula", + "Extend selection one row": "Ampliar a seleção de uma linha", + "Navigation": "Navegação", + "Focus popup / toolbar": "Pop-up de foco / Barra de ferramentas", + "Return focus to previous position": "Retornar o foco para a posição anterior", + + // Embed.ly + "Embed URL": "URL de inserção", + "Paste in a URL to embed": "Colar um endereço URL para incorporar", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "O conteúdo colado vem de um documento Microsoft Word. Você quer manter o formato ou limpá-lo?", + "Keep": "Manter formatação", + "Clean": "Limpar formatação", + "Word Paste Detected": "Texto do Word detectado" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/pt_pt.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/pt_pt.js new file mode 100644 index 0000000..d163991 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/pt_pt.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Portuguese spoken in Portugal + */ + +$.FE.LANGUAGE['pt_pt'] = { + translation: { + // Place holder + "Type something": "Digite algo", + + // Basic formatting + "Bold": "Negrito", + "Italic": "It\u00e1lico", + "Underline": "Sublinhado", + "Strikethrough": "Rasurado", + + // Main buttons + "Insert": "Inserir", + "Delete": "Apagar", + "Cancel": "Cancelar", + "OK": "Ok", + "Back": "Voltar", + "Remove": "Remover", + "More": "Mais", + "Update": "Atualizar", + "Style": "Estilo", + + // Font + "Font Family": "Fonte", + "Font Size": "Tamanho da fonte", + + // Colors + "Colors": "Cores", + "Background": "Fundo", + "Text": "Texto", + "HEX Color": "Cor hexadecimal", + + // Paragraphs + "Paragraph Format": "Formatos", + "Normal": "Normal", + "Code": "C\u00f3digo", + "Heading 1": "Cabe\u00e7alho 1", + "Heading 2": "Cabe\u00e7alho 2", + "Heading 3": "Cabe\u00e7alho 3", + "Heading 4": "Cabe\u00e7alho 4", + + // Style + "Paragraph Style": "Estilo de par\u00e1grafo", + "Inline Style": "Estilo embutido", + + // Alignment + "Align": "Alinhar", + "Align Left": "Alinhar \u00e0 esquerda", + "Align Center": "Alinhar ao centro", + "Align Right": "Alinhar \u00e0 direita", + "Align Justify": "Justificado", + "None": "Nenhum", + + // Lists + "Ordered List": "Lista ordenada", + "Default": "Padrão", + "Lower Alpha": "Alpha inferior", + "Lower Greek": "Grego inferior", + "Lower Roman": "Baixa romana", + "Upper Alpha": "Alfa superior", + "Upper Roman": "Romana superior", + + "Unordered List": "Lista n\u00e3o ordenada", + "Circle": "Círculo", + "Disc": "Disco", + "Square": "Quadrado", + + // Line height + "Line Height": "Altura da linha", + "Single": "Solteiro", + "Double": "Em dobro", + + // Indent + "Decrease Indent": "Diminuir avan\u00e7o", + "Increase Indent": "Aumentar avan\u00e7o", + + // Links + "Insert Link": "Inserir link", + "Open in new tab": "Abrir em uma nova aba", + "Open Link": "Abrir link", + "Edit Link": "Editar link", + "Unlink": "Remover link", + "Choose Link": "Escolha o link", + + // Images + "Insert Image": "Inserir imagem", + "Upload Image": "Carregar imagem", + "By URL": "Por URL", + "Browse": "Procurar", + "Drop image": "Largue imagem", + "or click": "ou clique em", + "Manage Images": "Gerenciar as imagens", + "Loading": "Carregando", + "Deleting": "Excluindo", + "Tags": "Etiquetas", + "Are you sure? Image will be deleted.": "Voc\u00ea tem certeza? Imagem ser\u00e1 apagada.", + "Replace": "Substituir", + "Uploading": "Carregando imagem", + "Loading image": "Carregando imagem", + "Display": "Exibir", + "Inline": "Em linha", + "Break Text": "Texto de quebra", + "Alternative Text": "Texto alternativo", + "Change Size": "Alterar tamanho", + "Width": "Largura", + "Height": "Altura", + "Something went wrong. Please try again.": "Algo deu errado. Por favor, tente novamente.", + "Image Caption": "Legenda da imagem", + "Advanced Edit": "Edição avançada", + + // Video + "Insert Video": "Inserir v\u00eddeo", + "Embedded Code": "C\u00f3digo embutido", + "Paste in a video URL": "Colar em um URL de vídeo", + "Drop video": "Solte o video", + "Your browser does not support HTML5 video.": "Seu navegador não suporta o vídeo html5.", + "Upload Video": "Envio vídeo", + + // Tables + "Insert Table": "Inserir tabela", + "Table Header": "Cabe\u00e7alho da tabela", + "Remove Table": "Remover tabela", + "Table Style": "estilo de tabela", + "Horizontal Align": "Alinhamento horizontal", + "Row": "Linha", + "Insert row above": "Inserir linha antes", + "Insert row below": "Inserir linha depois", + "Delete row": "Eliminar linha", + "Column": "Coluna", + "Insert column before": "Inserir coluna antes", + "Insert column after": "Inserir coluna depois", + "Delete column": "Eliminar coluna", + "Cell": "C\u00e9lula", + "Merge cells": "Unir c\u00e9lulas", + "Horizontal split": "Divis\u00e3o horizontal", + "Vertical split": "Divis\u00e3o vertical", + "Cell Background": "Fundo da c\u00e9lula", + "Vertical Align": "Alinhar vertical", + "Top": "Topo", + "Middle": "Meio", + "Bottom": "Fundo", + "Align Top": "Alinhar topo", + "Align Middle": "Alinhar meio", + "Align Bottom": "Alinhar fundo", + "Cell Style": "Estilo de c\u00e9lula", + + // Files + "Upload File": "Upload de arquivo", + "Drop file": "Largar arquivo", + + // Emoticons + "Emoticons": "Emoticons", + "Grinning face": "Sorrindo a cara", + "Grinning face with smiling eyes": "Sorrindo rosto com olhos sorridentes", + "Face with tears of joy": "Rosto com l\u00e1grimas de alegria", + "Smiling face with open mouth": "Rosto de sorriso com a boca aberta", + "Smiling face with open mouth and smiling eyes": "Rosto de sorriso com a boca aberta e olhos sorridentes", + "Smiling face with open mouth and cold sweat": "Rosto de sorriso com a boca aberta e suor frio", + "Smiling face with open mouth and tightly-closed eyes": "Rosto de sorriso com a boca aberta e os olhos bem fechados", + "Smiling face with halo": "Rosto de sorriso com halo", + "Smiling face with horns": "Rosto de sorriso com chifres", + "Winking face": "Pisc a rosto", + "Smiling face with smiling eyes": "Rosto de sorriso com olhos sorridentes", + "Face savoring delicious food": "Rosto saboreando uma deliciosa comida", + "Relieved face": "Rosto aliviado", + "Smiling face with heart-shaped eyes": "Rosto de sorriso com os olhos em forma de cora\u00e7\u00e3o", + "Smiling face with sunglasses": "Rosto de sorriso com \u00f3culos de sol", + "Smirking face": "Rosto sorridente", + "Neutral face": "Rosto neutra", + "Expressionless face": "Rosto inexpressivo", + "Unamused face": "O rosto n\u00e3o divertido", + "Face with cold sweat": "Rosto com suor frio", + "Pensive face": "O rosto pensativo", + "Confused face": "Cara confusa", + "Confounded face": "Rosto at\u00f4nito", + "Kissing face": "Beijar Rosto", + "Face throwing a kiss": "Rosto jogando um beijo", + "Kissing face with smiling eyes": "Beijar rosto com olhos sorridentes", + "Kissing face with closed eyes": "Beijando a cara com os olhos fechados", + "Face with stuck out tongue": "Preso de cara com a l\u00edngua para fora", + "Face with stuck out tongue and winking eye": "Rosto com estendeu a l\u00edngua e olho piscando", + "Face with stuck out tongue and tightly-closed eyes": "Rosto com estendeu a língua e os olhos bem fechados", + "Disappointed face": "Rosto decepcionado", + "Worried face": "O rosto preocupado", + "Angry face": "Rosto irritado", + "Pouting face": "Beicinho Rosto", + "Crying face": "Cara de choro", + "Persevering face": "Perseverar Rosto", + "Face with look of triumph": "Rosto com olhar de triunfo", + "Disappointed but relieved face": "Fiquei Desapontado mas aliviado Rosto", + "Frowning face with open mouth": "Sobrancelhas franzidas rosto com a boca aberta", + "Anguished face": "O rosto angustiado", + "Fearful face": "Cara com medo", + "Weary face": "Rosto cansado", + "Sleepy face": "Cara de sono", + "Tired face": "Rosto cansado", + "Grimacing face": "Fazendo caretas face", + "Loudly crying face": "Alto chorando rosto", + "Face with open mouth": "Enfrentar com a boca aberta", + "Hushed face": "Flagrantes de rosto", + "Face with open mouth and cold sweat": "Enfrentar com a boca aberta e suor frio", + "Face screaming in fear": "Cara gritando de medo", + "Astonished face": "Cara de surpresa", + "Flushed face": "Rosto vermelho", + "Sleeping face": "O rosto de sono", + "Dizzy face": "Cara tonto", + "Face without mouth": "Rosto sem boca", + "Face with medical mask": "Rosto com m\u00e1scara m\u00e9dica", + + // Line breaker + "Break": "Partir", + + // Math + "Subscript": "Subscrito", + "Superscript": "Sobrescrito", + + // Full screen + "Fullscreen": "Tela cheia", + + // Horizontal line + "Insert Horizontal Line": "Inserir linha horizontal", + + // Clear formatting + "Clear Formatting": "Remover formata\u00e7\u00e3o", + + // Save + "Save": "\u0053\u0061\u006c\u0076\u0065", + + // Undo, redo + "Undo": "Anular", + "Redo": "Restaurar", + + // Select all + "Select All": "Seleccionar tudo", + + // Code view + "Code View": "Exibi\u00e7\u00e3o de c\u00f3digo", + + // Quote + "Quote": "Cita\u00e7\u00e3o", + "Increase": "Aumentar", + "Decrease": "Diminuir", + + // Quick Insert + "Quick Insert": "Inser\u00e7\u00e3o r\u00e1pida", + + // Spcial Characters + "Special Characters": "Caracteres especiais", + "Latin": "Latino", + "Greek": "Grego", + "Cyrillic": "Cirílico", + "Punctuation": "Pontuação", + "Currency": "Moeda", + "Arrows": "Setas; flechas", + "Math": "Matemática", + "Misc": "Misc", + + // Print. + "Print": "Impressão", + + // Spell Checker. + "Spell Checker": "Verificador ortográfico", + + // Help + "Help": "Socorro", + "Shortcuts": "Atalhos", + "Inline Editor": "Editor em linha", + "Show the editor": "Mostre o editor", + "Common actions": "Ações comuns", + "Copy": "Cópia de", + "Cut": "Cortar", + "Paste": "Colar", + "Basic Formatting": "Formatação básica", + "Increase quote level": "Aumentar o nível de cotação", + "Decrease quote level": "Diminuir o nível de cotação", + "Image / Video": "Imagem / video", + "Resize larger": "Redimensionar maior", + "Resize smaller": "Redimensionar menor", + "Table": "Tabela", + "Select table cell": "Selecione a célula da tabela", + "Extend selection one cell": "Ampliar a seleção de uma célula", + "Extend selection one row": "Ampliar a seleção uma linha", + "Navigation": "Navegação", + "Focus popup / toolbar": "Foco popup / barra de ferramentas", + "Return focus to previous position": "Retornar o foco para a posição anterior", + + // Embed.ly + "Embed URL": "URL de inserção", + "Paste in a URL to embed": "Colar em url para incorporar", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "O conteúdo colado vem de um documento Microsoft Word. Você quer manter o formato ou limpá-lo?", + "Keep": "Guarda", + "Clean": "Limpar \ limpo", + "Word Paste Detected": "Pasta de palavras detectada" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ro.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ro.js new file mode 100644 index 0000000..e8bb8ed --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ro.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Romanian + */ + +$.FE.LANGUAGE['ro'] = { + translation: { + // Place holder + "Type something": "Tasteaz\u0103 ceva", + + // Basic formatting + "Bold": "\u00cengro\u015fat", + "Italic": "Cursiv", + "Underline": "Subliniat", + "Strikethrough": "T\u0103iat", + + // Main buttons + "Insert": "Insereaz\u0103", + "Delete": "\u015eterge", + "Cancel": "Anuleaz\u0103", + "OK": "Ok", + "Back": "\u00cenapoi", + "Remove": "\u0218terge", + "More": "Mai mult", + "Update": "Actualizeaz\u0103", + "Style": "Stil", + + // Font + "Font Family": "Font", + "Font Size": "Dimensiune font", + + // Colors + "Colors": "Culoare", + "Background": "Fundal", + "Text": "Text", + "HEX Color": "Culoare Hexa", + + // Paragraphs + "Paragraph Format": "Format paragraf", + "Normal": "Normal", + "Code": "Cod", + "Heading 1": "Antet 1", + "Heading 2": "Antet 2", + "Heading 3": "Antet 3", + "Heading 4": "Antet 4", + + // Style + "Paragraph Style": "Stil paragraf", + "Inline Style": "Stil \u00een linie", + + // Alignment + "Align": "Aliniere", + "Align Left": "Aliniere la st\u00e2nga", + "Align Center": "Aliniere la centru", + "Align Right": "Aliniere la dreapta", + "Align Justify": "Aliniere pe toat\u0103 l\u0103\u021bimea", + "None": "Niciunul", + + // Lists + "Ordered List": "List\u0103 ordonat\u0103", + "Default": "Mod implicit", + "Lower Alpha": "Inferior alfa", + "Lower Greek": "Inferior grecesc", + "Lower Roman": "Inferior roman", + "Upper Alpha": "Alfa superioară", + "Upper Roman": "Superior roman", + + "Unordered List": "List\u0103 neordonat\u0103", + "Circle": "Cerc", + "Disc": "Disc", + "Square": "Pătrat", + + // Line height + "Line Height": "Inaltimea liniei", + "Single": "Singur", + "Double": "Dubla", + + // Indent + "Decrease Indent": "De-indenteaz\u0103", + "Increase Indent": "Indenteaz\u0103", + + // Links + "Insert Link": "Inserare link", + "Open in new tab": "Deschide \u00EEn tab nou", + "Open Link": "Deschide link", + "Edit Link": "Editare link", + "Unlink": "\u0218terge link-ul", + "Choose Link": "Alege link", + + // Images + "Insert Image": "Inserare imagine", + "Upload Image": "\u00cencarc\u0103 imagine", + "By URL": "Dup\u0103 URL", + "Browse": "R\u0103sfoie\u0219te", + "Drop image": "Trage imagine", + "or click": "sau f\u0103 click", + "Manage Images": "Gestionare imagini", + "Loading": "Se \u00eencarc\u0103", + "Deleting": "Se \u0219terge", + "Tags": "Etichete", + "Are you sure? Image will be deleted.": "Sunte\u021bi sigur? Imaginea va fi \u015ftears\u0103.", + "Replace": "\u00cenlocuire", + "Uploading": "Imaginea se \u00eencarc\u0103", + "Loading image": "Imaginea se \u00eencarc\u0103", + "Display": "Afi\u0219are", + "Inline": "\u00cen linie", + "Break Text": "Sparge text", + "Alternative Text": "Text alternativ", + "Change Size": "Modificare dimensiuni", + "Width": "L\u0103\u021bime", + "Height": "\u00cen\u0103l\u021bime", + "Something went wrong. Please try again.": "Ceva n-a mers bine. V\u0103 rug\u0103m s\u0103 \u00eencerca\u021bi din nou.", + "Image Caption": "Captura imaginii", + "Advanced Edit": "Editare avansată", + + // Video + "Insert Video": "Inserare video", + "Embedded Code": "Cod embedded", + "Paste in a video URL": "Lipiți o adresă URL pentru video", + "Drop video": "Trage video", + "Your browser does not support HTML5 video.": "Browserul dvs. nu acceptă videoclipul html5.", + "Upload Video": "Încărcați videoclipul", + + // Tables + "Insert Table": "Inserare tabel", + "Table Header": "Antet tabel", + "Remove Table": "\u0218terge tabel", + "Table Style": "Stil tabel", + "Horizontal Align": "Aliniere orizontal\u0103", + "Row": "Linie", + "Insert row above": "Insereaz\u0103 linie \u00eenainte", + "Insert row below": "Insereaz\u0103 linie dup\u0103", + "Delete row": "\u015eterge linia", + "Column": "Coloan\u0103", + "Insert column before": "Insereaz\u0103 coloan\u0103 \u00eenainte", + "Insert column after": "Insereaz\u0103 coloan\u0103 dup\u0103", + "Delete column": "\u015eterge coloana", + "Cell": "Celula", + "Merge cells": "Une\u015fte celulele", + "Horizontal split": "\u00cemparte orizontal", + "Vertical split": "\u00cemparte vertical", + "Cell Background": "Fundal celul\u0103", + "Vertical Align": "Aliniere vertical\u0103", + "Top": "Sus", + "Middle": "Mijloc", + "Bottom": "Jos", + "Align Top": "Aliniere sus", + "Align Middle": "Aliniere la mijloc", + "Align Bottom": "Aliniere jos", + "Cell Style": "Stil celul\u0103", + + // Files + "Upload File": "\u00cenc\u0103rca\u021bi fi\u0219ier", + "Drop file": "Trage fi\u0219ier", + + // Emoticons + "Emoticons": "Emoticoane", + "Grinning face": "Fa\u021b\u0103 r\u00e2njind", + "Grinning face with smiling eyes": "Fa\u021b\u0103 r\u00e2njind cu ochi z\u00e2mbitori", + "Face with tears of joy": "Fa\u021b\u0103 cu lacrimi de bucurie", + "Smiling face with open mouth": "Fa\u021b\u0103 z\u00e2mbitoare cu gura deschis\u0103", + "Smiling face with open mouth and smiling eyes": "Fa\u021b\u0103 z\u00e2mbitoare cu gura deschis\u0103 \u0219i ochi z\u00e2mbitori", + "Smiling face with open mouth and cold sweat": "Fa\u021b\u0103 z\u00e2mbitoare cu gura deschis\u0103 şi sudoare rece", + "Smiling face with open mouth and tightly-closed eyes": "Fa\u021b\u0103 z\u00e2mbitoare cu gura deschis\u0103 şi ochii ferm \u00eenchi\u0219i", + "Smiling face with halo": "Fa\u021b\u0103 z\u00e2mbitoare cu aur\u0103", + "Smiling face with horns": "Fa\u021b\u0103 z\u00e2mbitoare cu coarne", + "Winking face": "Fa\u021b\u0103 clipind", + "Smiling face with smiling eyes": "Fa\u021b\u0103 z\u00e2mbitoare cu ochi z\u00e2mbitori", + "Face savoring delicious food": "Fa\u021b\u0103 savur\u00e2nd preparate delicioase", + "Relieved face": "Fa\u021b\u0103 u\u0219urat\u0103", + "Smiling face with heart-shaped eyes": "Fa\u021b\u0103 z\u00e2mbitoare cu ochi in forma de inim\u0103", + "Smiling face with sunglasses": "Fa\u021b\u0103 z\u00e2mbitoare cu ochelari de soare", + "Smirking face": "Fa\u021b\u0103 cu sur\u00e2s afectat", + "Neutral face": "Fa\u021b\u0103 neutr\u0103", + "Expressionless face": "Fa\u021b\u0103 f\u0103r\u0103 expresie", + "Unamused face": "Fa\u021b\u0103 neamuzat\u0103", + "Face with cold sweat": "Fa\u021b\u0103 cu sudoare rece", + "Pensive face": "Fa\u021b\u0103 medit\u00e2nd", + "Confused face": "Fa\u021b\u0103 confuz\u0103", + "Confounded face": "Fa\u021b\u0103 z\u0103p\u0103cit\u0103", + "Kissing face": "Fa\u021b\u0103 s\u0103rut\u00e2nd", + "Face throwing a kiss": "Fa\u021b\u0103 arunc\u00e2nd un s\u0103rut", + "Kissing face with smiling eyes": "Fa\u021b\u0103 s\u0103rut\u00e2nd cu ochi z\u00e2mbitori", + "Kissing face with closed eyes": "Fa\u021b\u0103 s\u0103rut\u00e2nd cu ochii \u00eenchi\u0219i", + "Face with stuck out tongue": "Fa\u021b\u0103 cu limba afar\u0103", + "Face with stuck out tongue and winking eye": "Fa\u021b\u0103 cu limba scoas\u0103 clipind", + "Face with stuck out tongue and tightly-closed eyes": "Fa\u021b\u0103 cu limba scoas\u0103 \u0219i ochii ferm \u00eenchi\u0219i", + "Disappointed face": "Fa\u021b\u0103 dezam\u0103git\u0103", + "Worried face": "Fa\u021b\u0103 \u00eengrijorat\u0103", + "Angry face": "Fa\u021b\u0103 nervoas\u0103", + "Pouting face": "Fa\u021b\u0103 fierb\u00e2nd", + "Crying face": "Fa\u021b\u0103 pl\u00e2ng\u00e2nd", + "Persevering face": "Fa\u021b\u0103 perseverent\u0103", + "Face with look of triumph": "Fa\u021b\u0103 triumf\u0103toare", + "Disappointed but relieved face": "Fa\u021b\u0103 dezam\u0103git\u0103 dar u\u0219urat\u0103", + "Frowning face with open mouth": "Fa\u021b\u0103 \u00eencruntat\u0103 cu gura deschis\u0103", + "Anguished face": "Fa\u021b\u0103 \u00eendurerat\u0103", + "Fearful face": "Fa\u021b\u0103 tem\u0103toare", + "Weary face": "Fa\u021b\u0103 \u00eengrijorat\u0103", + "Sleepy face": "Fa\u021b\u0103 adormit\u0103", + "Tired face": "Fa\u021b\u0103 obosit\u0103", + "Grimacing face": "Fa\u021b\u0103 cu grimas\u0103", + "Loudly crying face": "Fa\u021b\u0103 pl\u00e2ng\u00e2nd zgomotos", + "Face with open mouth": "Fa\u021b\u0103 cu gura deschis\u0103", + "Hushed face": "Fa\u021b\u0103 discret\u0103", + "Face with open mouth and cold sweat": "Fa\u021b\u0103 cu gura deschis\u0103 si sudoare rece", + "Face screaming in fear": "Fa\u021b\u0103 \u021bip\u00e2nd de fric\u0103", + "Astonished face": "Fa\u021b\u0103 uimit\u0103", + "Flushed face": "Fa\u021b\u0103 sp\u0103lat\u0103", + "Sleeping face": "Fa\u021b\u0103 adormit\u0103", + "Dizzy face": "Fa\u021b\u0103 ame\u021bit\u0103", + "Face without mouth": "Fa\u021b\u0103 f\u0103r\u0103 gur\u0103", + "Face with medical mask": "Fa\u021b\u0103 cu masc\u0103 medical\u0103", + + // Line breaker + "Break": "Desparte", + + // Horizontal line + "Insert Horizontal Line": "Inserare linie orizontal\u0103", + + // Math + "Subscript": "Indice", + "Superscript": "Exponent", + + // Full screen + "Fullscreen": "Ecran complet", + + // Clear formatting + "Clear Formatting": "Elimina\u021bi formatarea", + + // Save + "Save": "\u0053\u0061\u006c\u0076\u0061\u021b\u0069", + + // Undo, redo + "Undo": "Reexecut\u0103", + "Redo": "Dezexecut\u0103", + + // Select all + "Select All": "Selecteaz\u0103 tot", + + // Code view + "Code View": "Vizualizare cod", + + // Quote + "Quote": "Citat", + "Increase": "Indenteaz\u0103", + "Decrease": "De-indenteaz\u0103", + + // Quick Insert + "Quick Insert": "Inserare rapid\u0103", + + // Spcial Characters + "Special Characters": "Caracterele speciale", + "Latin": "Latină", + "Greek": "Greacă", + "Cyrillic": "Chirilic", + "Punctuation": "Punctuaţie", + "Currency": "Valută", + "Arrows": "Săgeți", + "Math": "Matematică", + "Misc": "Diverse", + + // Print. + "Print": "Imprimare", + + // Spell Checker. + "Spell Checker": "Ortografie", + + // Help + "Help": "Ajutor", + "Shortcuts": "Comenzi rapide", + "Inline Editor": "Editor inline", + "Show the editor": "Arătați editorul", + "Common actions": "Acțiuni comune", + "Copy": "Copie", + "Cut": "A taia", + "Paste": "Lipire", + "Basic Formatting": "Formatul de bază", + "Increase quote level": "Creșteți nivelul cotației", + "Decrease quote level": "Micșorați nivelul cotației", + "Image / Video": "Imagine / video", + "Resize larger": "Redimensionați mai mare", + "Resize smaller": "Redimensionați mai puțin", + "Table": "Tabel", + "Select table cell": "Selectați celula tabelă", + "Extend selection one cell": "Extindeți selecția la o celulă", + "Extend selection one row": "Extindeți selecția cu un rând", + "Navigation": "Navigare", + "Focus popup / toolbar": "Focus popup / bara de instrumente", + "Return focus to previous position": "Reveniți la poziția anterioară", + + // Embed.ly + "Embed URL": "Încorporați url", + "Paste in a URL to embed": "Lipiți un URL pentru a-l încorpora", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Conținutul lipit vine dintr-un document word Microsoft. Doriți să păstrați formatul sau să îl curățați?", + "Keep": "A pastra", + "Clean": "Curat", + "Word Paste Detected": "A fost detectată lipire din Word" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ru.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ru.js new file mode 100644 index 0000000..4f45ac6 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/ru.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Russian + */ + +$.FE.LANGUAGE['ru'] = { + translation: { + // Place holder + "Type something": "\u041d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0447\u0442\u043e\u002d\u043d\u0438\u0431\u0443\u0434\u044c", + + // Basic formatting + "Bold": "\u0416\u0438\u0440\u043d\u044b\u0439", + "Italic": "\u041a\u0443\u0440\u0441\u0438\u0432", + "Underline": "\u041f\u043e\u0434\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044b\u0439", + "Strikethrough": "\u0417\u0430\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044b\u0439", + + // Main buttons + "Insert": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c", + "Delete": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c", + "Cancel": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c", + "OK": "\u041e\u043a", + "Back": "\u043d\u0430\u0437\u0430\u0434", + "Remove": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c", + "More": "\u0411\u043e\u043b\u044c\u0448\u0435", + "Update": "\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c", + "Style": "\u0421\u0442\u0438\u043b\u044c", + + // Font + "Font Family": "\u0428\u0440\u0438\u0444\u0442", + "Font Size": "\u0420\u0430\u0437\u043c\u0435\u0440 \u0448\u0440\u0438\u0444\u0442\u0430", + + // Colors + "Colors": "\u0426\u0432\u0435\u0442\u0430", + "Background": "\u0424\u043e\u043d", + "Text": "\u0422\u0435\u043a\u0441\u0442", + "HEX Color": "HEX цвет", + + // Paragraphs + "Paragraph Format": "\u0424\u043e\u0440\u043c\u0430\u0442 \u0430\u0431\u0437\u0430\u0446\u0430", + "Normal": "\u041d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u0439", + "Code": "\u041a\u043e\u0434", + "Heading 1": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 1", + "Heading 2": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 2", + "Heading 3": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 3", + "Heading 4": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 4", + + // Style + "Paragraph Style": "\u0421\u0442\u0438\u043b\u044c \u0430\u0431\u0437\u0430\u0446\u0430", + "Inline Style": "\u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0441\u0442\u0438\u043b\u044c", + + // Alignment + "Align": "\u0412\u044b\u0440\u043e\u0432\u043d\u044f\u0442\u044c \u043f\u043e", + "Align Left": "\u041f\u043e \u043b\u0435\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e", + "Align Center": "\u041f\u043e \u0446\u0435\u043d\u0442\u0440\u0443", + "Align Right": "\u041f\u043e \u043f\u0440\u0430\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e", + "Align Justify": "\u041f\u043e \u0448\u0438\u0440\u0438\u043d\u0435", + "None": "\u041d\u0438\u043a\u0430\u043a", + + // Lists + "Ordered List": "\u041d\u0443\u043c\u0435\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a", + "Default": "Дефолт", + "Lower Alpha": "Низшая альфа", + "Lower Greek": "Нижний греческий", + "Lower Roman": "Нижний римлянин", + "Upper Alpha": "Верхняя альфа", + "Upper Roman": "Верховный римлянин", + + "Unordered List": "\u041c\u0430\u0440\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a", + "Circle": "Круг", + "Disc": "Диск", + "Square": "Площадь", + + // Line height + "Line Height": "Высота линии", + "Single": "Не замужем", + "Double": "Двойной", + + // Indent + "Decrease Indent": "\u0423\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u043e\u0442\u0441\u0442\u0443\u043f", + "Increase Indent": "\u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c \u043e\u0442\u0441\u0442\u0443\u043f", + + // Links + "Insert Link": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443", + "Open in new tab": "\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u0432 \u043d\u043e\u0432\u043e\u0439 \u0432\u043a\u043b\u0430\u0434\u043a\u0435", + "Open Link": "\u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435", + "Edit Link": "\u041e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443", + "Unlink": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443", + "Choose Link": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u0441\u044b\u043b\u043a\u0443", + + // Images + "Insert Image": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435", + "Upload Image": "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435", + "By URL": "\u041f\u043e \u0441\u0441\u044b\u043b\u043a\u0435", + "Browse": "\u0417\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f", + "Drop image": "\u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u0435 \u0441\u044e\u0434\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435", + "or click": "\u0438\u043b\u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435", + "Manage Images": "\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u043c\u0438", + "Loading": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430", + "Deleting": "\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435", + "Tags": "\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430", + "Are you sure? Image will be deleted.": "\u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b? \u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043b\u0435\u043d\u043e.", + "Replace": "\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c", + "Uploading": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430", + "Loading image": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f", + "Display": "\u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435", + "Inline": "\u041e\u0431\u0442\u0435\u043a\u0430\u043d\u0438\u0435 \u0442\u0435\u043a\u0441\u0442\u043e\u043c", + "Break Text": "\u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0435 \u0432 \u0442\u0435\u043a\u0441\u0442", + "Alternative Text": "\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442", + "Change Size": "\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440", + "Width": "\u0428\u0438\u0440\u0438\u043d\u0430", + "Height": "\u0412\u044b\u0441\u043e\u0442\u0430", + "Something went wrong. Please try again.": "\u0427\u0442\u043e\u002d\u0442\u043e \u043f\u043e\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a\u002e \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430\u002c \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437\u002e", + "Image Caption": "Подпись к изображению", + "Advanced Edit": "Расширенное редактирование", + + // Video + "Insert Video": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u0438\u0434\u0435\u043e", + "Embedded Code": "\u0048\u0054\u004d\u004c\u002d\u043a\u043e\u0434 \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438", + "Paste in a video URL": "Вставить URL-адрес видео", + "Drop video": "Вставить видео", + "Your browser does not support HTML5 video.": "Ваш браузер не поддерживает html5 видео.", + "Upload Video": "Загрузить видео", + + // Tables + "Insert Table": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443", + "Table Header": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0442\u0430\u0431\u043b\u0438\u0446\u044b", + "Remove Table": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443", + "Table Style": "\u0421\u0442\u0438\u043b\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u044b", + "Horizontal Align": "\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435", + "Row": "\u0421\u0442\u0440\u043e\u043a\u0430", + "Insert row above": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u0432\u0435\u0440\u0445\u0443", + "Insert row below": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u043d\u0438\u0437\u0443", + "Delete row": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443", + "Column": "\u0421\u0442\u043e\u043b\u0431\u0435\u0446", + "Insert column before": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u0441\u043b\u0435\u0432\u0430", + "Insert column after": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u0441\u043f\u0440\u0430\u0432\u0430", + "Delete column": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446", + "Cell": "\u042f\u0447\u0435\u0439\u043a\u0430", + "Merge cells": "\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u044f\u0447\u0435\u0439\u043a\u0438", + "Horizontal split": "\u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e", + "Vertical split": "\u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u043e", + "Cell Background": "\u0424\u043e\u043d \u044f\u0447\u0435\u0439\u043a\u0438", + "Vertical Align": "\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435", + "Top": "\u041f\u043e \u0432\u0435\u0440\u0445\u043d\u0435\u043c\u0443 \u043a\u0440\u0430\u044e", + "Middle": "\u041f\u043e\u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435", + "Bottom": "\u041f\u043e \u043d\u0438\u0436\u043d\u0435\u043c\u0443 \u043a\u0440\u0430\u044e", + "Align Top": "\u0412\u044b\u0440\u043e\u0432\u043d\u044f\u0442\u044c \u043f\u043e \u0432\u0435\u0440\u0445\u043d\u0435\u043c\u0443 \u043a\u0440\u0430\u044e", + "Align Middle": "\u0412\u044b\u0440\u043e\u0432\u043d\u044f\u0442\u044c \u043f\u043e \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435", + "Align Bottom": "\u0412\u044b\u0440\u043e\u0432\u043d\u044f\u0442\u044c \u043f\u043e \u043d\u0438\u0436\u043d\u0435\u043c\u0443 \u043a\u0440\u0430\u044e", + "Cell Style": "\u0421\u0442\u0438\u043b\u044c \u044f\u0447\u0435\u0439\u043a\u0438", + + // Files + "Upload File": "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0444\u0430\u0439\u043b", + "Drop file": "\u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u0435 \u0441\u044e\u0434\u0430 \u0444\u0430\u0439\u043b", + + // Emoticons + "Emoticons": "\u0421\u043c\u0430\u0439\u043b\u0438\u043a\u0438", + "Grinning face": "\u0423\u0445\u043c\u044b\u043b\u043a\u0430 \u043d\u0430 \u043b\u0438\u0446\u0435", + "Grinning face with smiling eyes": "\u0423\u0441\u043c\u0435\u0445\u043d\u0443\u0432\u0448\u0435\u0435\u0441\u044f \u043b\u0438\u0446\u043e \u0441 \u0443\u043b\u044b\u0431\u0430\u044e\u0449\u0438\u043c\u0438\u0441\u044f \u0433\u043b\u0430\u0437\u0430\u043c\u0438", + "Face with tears of joy": "\u041b\u0438\u0446\u043e \u0441\u043e \u0441\u043b\u0435\u0437\u0430\u043c\u0438 \u0440\u0430\u0434\u043e\u0441\u0442\u0438", + "Smiling face with open mouth": "\u0423\u043b\u044b\u0431\u0430\u044e\u0449\u0435\u0435\u0441\u044f \u043b\u0438\u0446\u043e \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0440\u0442\u043e\u043c", + "Smiling face with open mouth and smiling eyes": "\u0423\u043b\u044b\u0431\u0430\u044f\u0441\u044c \u043b\u0438\u0446\u043e \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0440\u0442\u043e\u043c \u0438 \u0443\u043b\u044b\u0431\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u0433\u043b\u0430\u0437\u0430", + "Smiling face with open mouth and cold sweat": "\u0423\u043b\u044b\u0431\u0430\u044f\u0441\u044c \u043b\u0438\u0446\u043e \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0440\u0442\u043e\u043c \u0438 \u0445\u043e\u043b\u043e\u0434\u043d\u044b\u0439 \u043f\u043e\u0442", + "Smiling face with open mouth and tightly-closed eyes": "\u0423\u043b\u044b\u0431\u0430\u044f\u0441\u044c \u043b\u0438\u0446\u043e \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0440\u0442\u043e\u043c \u0438 \u043f\u043b\u043e\u0442\u043d\u043e \u0437\u0430\u043a\u0440\u044b\u0442\u044b\u043c\u0438 \u0433\u043b\u0430\u0437\u0430\u043c\u0438", + "Smiling face with halo": "\u0423\u043b\u044b\u0431\u0430\u044f\u0441\u044c \u043b\u0438\u0446\u043e \u0433\u0430\u043b\u043e", + "Smiling face with horns": "\u0423\u043b\u044b\u0431\u0430\u044f\u0441\u044c \u043b\u0438\u0446\u043e \u0441 \u0440\u043e\u0433\u0430\u043c\u0438", + "Winking face": "\u043f\u043e\u0434\u043c\u0438\u0433\u0438\u0432\u0430\u044f \u043b\u0438\u0446\u043e", + "Smiling face with smiling eyes": "\u0423\u043b\u044b\u0431\u0430\u044f\u0441\u044c \u043b\u0438\u0446\u043e \u0441 \u0443\u043b\u044b\u0431\u0430\u044e\u0449\u0438\u043c\u0438\u0441\u044f \u0433\u043b\u0430\u0437\u0430\u043c\u0438", + "Face savoring delicious food": "\u041b\u0438\u0446\u043e \u0441\u043c\u0430\u043a\u0443\u044e\u0449\u0435\u0435 \u0432\u043a\u0443\u0441\u043d\u0443\u044e \u0435\u0434\u0443", + "Relieved face": "\u041e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u044b \u043b\u0438\u0446\u043e", + "Smiling face with heart-shaped eyes": "\u0423\u043b\u044b\u0431\u0430\u044f\u0441\u044c \u043b\u0438\u0446\u043e \u0432 \u0444\u043e\u0440\u043c\u0435 \u0441\u0435\u0440\u0434\u0446\u0430 \u0433\u043b\u0430\u0437\u0430\u043c\u0438", + "Smiling face with sunglasses": "\u0423\u043b\u044b\u0431\u0430\u044f\u0441\u044c \u043b\u0438\u0446\u043e \u0441 \u043e\u0447\u043a\u0430\u043c\u0438", + "Smirking face": "\u0423\u0441\u043c\u0435\u0445\u043d\u0443\u0432\u0448\u0438\u0441\u044c \u043b\u0438\u0446\u043e", + "Neutral face": "\u041e\u0431\u044b\u0447\u043d\u044b\u0439 \u043b\u0438\u0446\u043e", + "Expressionless face": "\u041d\u0435\u0432\u044b\u0440\u0430\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043b\u0438\u0446\u043e", + "Unamused face": "\u041d\u0435 \u0441\u043c\u0435\u0448\u043d\u043e \u043b\u0438\u0446\u043e", + "Face with cold sweat": "\u041b\u0438\u0446\u043e \u0432 \u0445\u043e\u043b\u043e\u0434\u043d\u043e\u043c \u043f\u043e\u0442\u0443", + "Pensive face": "\u0417\u0430\u0434\u0443\u043c\u0447\u0438\u0432\u044b\u0439 \u043b\u0438\u0446\u043e", + "Confused face": "\u0421\u043c\u0443\u0449\u0435\u043d\u043d\u043e\u0435 \u043b\u0438\u0446\u043e", + "Confounded face": "\u041f\u043e\u0441\u0442\u044b\u0434\u043d\u043e\u0435 \u043b\u0438\u0446\u043e", + "Kissing face": "\u041f\u043e\u0446\u0435\u043b\u0443\u0438 \u043b\u0438\u0446\u043e", + "Face throwing a kiss": "\u041b\u0438\u0446\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0435 \u043f\u043e\u0446\u0435\u043b\u0443\u0439", + "Kissing face with smiling eyes": "\u041f\u043e\u0446\u0435\u043b\u0443\u0438 \u043b\u0438\u0446\u043e \u0441 \u0443\u043b\u044b\u0431\u0430\u044e\u0449\u0438\u043c\u0438\u0441\u044f \u0433\u043b\u0430\u0437\u0430\u043c\u0438", + "Kissing face with closed eyes": "\u041f\u043e\u0446\u0435\u043b\u0443\u0438 \u043b\u0438\u0446\u043e \u0441 \u0437\u0430\u043a\u0440\u044b\u0442\u044b\u043c\u0438 \u0433\u043b\u0430\u0437\u0430\u043c\u0438", + "Face with stuck out tongue": "\u041b\u0438\u0446\u043e \u0441 \u0442\u043e\u0440\u0447\u0430\u0449\u0438\u043c \u044f\u0437\u044b\u043a\u043e\u043c", + "Face with stuck out tongue and winking eye": "\u041b\u0438\u0446\u043e \u0441 \u0442\u043e\u0440\u0447\u0430\u0449\u0438\u043c \u044f\u0437\u044b\u043a\u043e\u043c \u0438 \u043f\u043e\u0434\u043c\u0438\u0433\u0438\u0432\u0430\u044e\u0449\u0438\u043c \u0433\u043b\u0430\u0437\u043e\u043c", + "Face with stuck out tongue and tightly-closed eyes": "\u041b\u0438\u0446\u043e \u0441 \u0442\u043e\u0440\u0447\u0430\u0449\u0438\u043c \u044f\u0437\u044b\u043a\u043e\u043c \u0438 \u043f\u043b\u043e\u0442\u043d\u043e \u0437\u0430\u043a\u0440\u044b\u0442\u044b\u043c\u0438 \u0433\u043b\u0430\u0437\u0430\u043c\u0438", + "Disappointed face": "\u0420\u0430\u0437\u043e\u0447\u0430\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u043b\u0438\u0446\u043e", + "Worried face": "\u041e\u0431\u0435\u0441\u043f\u043e\u043a\u043e\u0435\u043d\u043d\u044b\u0439 \u043b\u0438\u0446\u043e", + "Angry face": "\u0417\u043b\u043e\u0439 \u043b\u0438\u0446\u043e", + "Pouting face": "\u041f\u0443\u0445\u043b\u044b\u0435 \u043b\u0438\u0446\u043e", + "Crying face": "\u041f\u043b\u0430\u0447\u0443\u0449\u0435\u0435 \u043b\u0438\u0446\u043e", + "Persevering face": "\u041d\u0430\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u0430\u044f \u043b\u0438\u0446\u043e", + "Face with look of triumph": "\u041b\u0438\u0446\u043e \u0441 \u0432\u0438\u0434\u043e\u043c \u0442\u0440\u0438\u0443\u043c\u0444\u0430", + "Disappointed but relieved face": "\u0420\u0430\u0437\u043e\u0447\u0430\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435\u002c \u043d\u043e \u0441\u043f\u043e\u043a\u043e\u0439\u043d\u043e\u0435 \u043b\u0438\u0446\u043e", + "Frowning face with open mouth": "\u041d\u0430\u0445\u043c\u0443\u0440\u0435\u043d\u043d\u043e\u0435 \u043b\u0438\u0446\u043e \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0440\u0442\u043e\u043c", + "Anguished face": "\u043c\u0443\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043b\u0438\u0446\u043e", + "Fearful face": "\u041d\u0430\u043f\u0443\u0433\u0430\u043d\u043d\u043e\u0435 \u043b\u0438\u0446\u043e", + "Weary face": "\u0423\u0441\u0442\u0430\u043b\u044b\u0439 \u043b\u0438\u0446\u043e", + "Sleepy face": "\u0441\u043e\u043d\u043d\u043e\u0435 \u043b\u0438\u0446\u043e", + "Tired face": "\u0423\u0441\u0442\u0430\u043b\u0438 \u043b\u0438\u0446\u043e", + "Grimacing face": "\u0413\u0440\u0438\u043c\u0430\u0441\u0430 \u043d\u0430 \u043b\u0438\u0446\u0435", + "Loudly crying face": "\u0413\u0440\u043e\u043c\u043a\u043e \u043f\u043b\u0430\u0447\u0430 \u043b\u0438\u0446\u043e", + "Face with open mouth": "\u041b\u0438\u0446\u043e \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0440\u0442\u043e\u043c", + "Hushed face": "\u0417\u0430\u0442\u0438\u0445\u0448\u0438\u0439 \u043b\u0438\u0446\u043e", + "Face with open mouth and cold sweat": "\u041b\u0438\u0446\u043e \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0440\u0442\u043e\u043c \u0432 \u0445\u043e\u043b\u043e\u0434\u043d\u043e\u043c \u043f\u043e\u0442\u0443", + "Face screaming in fear": "\u041b\u0438\u0446\u043e \u043a\u0440\u0438\u0447\u0430\u0449\u0435\u0435 \u043e\u0442 \u0441\u0442\u0440\u0430\u0445\u0430", + "Astonished face": "\u0423\u0434\u0438\u0432\u043b\u0435\u043d\u043d\u043e\u0435 \u043b\u0438\u0446\u043e", + "Flushed face": "\u041f\u043e\u043a\u0440\u0430\u0441\u043d\u0435\u0432\u0448\u0435\u0435 \u043b\u0438\u0446\u043e", + "Sleeping face": "\u0421\u043f\u044f\u0449\u0430\u044f \u043b\u0438\u0446\u043e", + "Dizzy face": "\u0414\u0438\u0437\u0437\u0438 \u043b\u0438\u0446\u043e", + "Face without mouth": "\u041b\u0438\u0446\u043e \u0431\u0435\u0437 \u0440\u0442\u0430", + "Face with medical mask": "\u041b\u0438\u0446\u043e \u0441 \u043c\u0435\u0434\u0438\u0446\u0438\u043d\u0441\u043a\u043e\u0439 \u043c\u0430\u0441\u043a\u043e\u0439", + + // Line breaker + "Break": "\u041d\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430", + + // Math + "Subscript": "\u041d\u0438\u0436\u043d\u0438\u0439 \u0438\u043d\u0434\u0435\u043a\u0441", + "Superscript": "\u0412\u0435\u0440\u0445\u043d\u0438\u0439 \u0438\u043d\u0434\u0435\u043a\u0441", + + // Full screen + "Fullscreen": "\u041d\u0430 \u0432\u0435\u0441\u044c \u044d\u043a\u0440\u0430\u043d", + + // Horizontal line + "Insert Horizontal Line": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u043b\u0438\u043d\u0438\u044e", + + // Clear formatting + "Clear Formatting": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435", + + // Save + "Save": "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c", + + // Undo, redo + "Undo": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c", + "Redo": "\u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c", + + // Select all + "Select All": "\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0451", + + // Code view + "Code View": "\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u0048\u0054\u004d\u004c\u002d\u043a\u043e\u0434\u0430", + + // Quote + "Quote": "\u0426\u0438\u0442\u0430\u0442\u0430", + "Increase": "\u0423\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u0435", + "Decrease": "\u0421\u043d\u0438\u0436\u0435\u043d\u0438\u0435", + + // Quick Insert + "Quick Insert": "\u0411\u044b\u0441\u0442\u0440\u0430\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0430", + + // Spcial Characters + "Special Characters": "Специальные символы", + "Latin": "Латинский", + "Greek": "Греческий", + "Cyrillic": "Кириллица", + "Punctuation": "Пунктуация", + "Currency": "Валюта", + "Arrows": "Стрелки", + "Math": "Математический", + "Misc": "Разное", + + // Print. + "Print": "Распечатать", + + // Spell Checker. + "Spell Checker": "Программа проверки орфографии", + + // Help + "Help": "Помощь", + "Shortcuts": "Горячие клавищи", + "Inline Editor": "Встроенный редактор", + "Show the editor": "Показать редактор", + "Common actions": "Общие действия", + "Copy": "Копировать", + "Cut": "Вырезать", + "Paste": "Вставить", + "Basic Formatting": "Базовое форматирование", + "Increase quote level": "Увеличить уровень цитирования", + "Decrease quote level": "Уменьшить уровень цитирования", + "Image / Video": "Изображение / Видео", + "Resize larger": "Изменить размер", + "Resize smaller": "Уменьшить размер", + "Table": "Таблица", + "Select table cell": "Выбрать ячейку таблицы", + "Extend selection one cell": "Расширить выделение одной ячейки", + "Extend selection one row": "Расширить выделение на одну строку", + "Navigation": "Навигация", + "Focus popup / toolbar": "Сфокусировать всплывающее окно / панель инструментов", + "Return focus to previous position": "Вернуть фокус на предыдущую позицию", + + // Embed.ly + "Embed URL": "Вставить URL-адрес", + "Paste in a URL to embed": "Вставить URL-адрес для встраивания", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Вы пытаетесь вставить текст из документа Microsoft Word. Вы хотите сохранить или очистить формат?", + "Keep": "Оставить", + "Clean": "Очистить", + "Word Paste Detected": "Обнаружено копирование из Word" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sk.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sk.js new file mode 100644 index 0000000..03f3f56 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sk.js @@ -0,0 +1,338 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Slovak + */ + +$.FE.LANGUAGE['sk'] = { + translation: { + + // Place holder + "Type something": "Nap\u00ed\u0161te hoci\u010do", + + // Basic formatting + "Bold": "Tu\u010dn\u00e9", + "Italic": "Kurz\u00edva", + "Underline": "Pod\u010diarknut\u00e9", + "Strikethrough": "Pre\u0161krtnut\u00e9", + + // Main buttons + "Insert": "Vlo\u017ei\u0165", + "Delete": "Vymaza\u0165", + "Cancel": "Zru\u0161i\u0165", + "OK": "OK", + "Back": "Sp\u00e4\u0165", + "Remove": "Odstr\u00e1ni\u0165", + "More": "Viac", + "Update": "Aktualizova\u0165", + "Style": "\u0160t\u00fdl", + + // Font + "Font Family": "Typ p\u00edsma", + "Font Size": "Ve\u013ekos\u0165 p\u00edsma", + + // Colors + "Colors": "Farby", + "Background": "Pozadie", + "Text": "Text", + "HEX Color": "Hex Farby", + + // Paragraphs + "Paragraph Format": "Form\u00e1t odstavca", + "Normal": "Norm\u00e1lne", + "Code": "K\u00f3d", + "Heading 1": "Nadpis 1", + "Heading 2": "Nadpis 2", + "Heading 3": "Nadpis 3", + "Heading 4": "Nadpis 4", + + // Style + "Paragraph Style": "\u0160t\u00fdl odstavca", + "Inline Style": "Inline \u0161t\u00fdl", + + // Alignment + "Align": "Zarovnanie", + "Align Left": "Zarovna\u0165 v\u013eavo", + "Align Center": "Zarovna\u0165 na stred", + "Align Right": "Zarovna\u0165 vpravo", + "Align Justify": "Zarovna\u0165 do bloku", + "None": "\u017diadne", + + // Lists + "Ordered List": "\u010c\u00edslovan\u00fd zoznam", + "Default": "Štandardné", + "Lower Alpha": "Nižšia alfa", + "Lower Greek": "Nižšie grécke", + "Lower Roman": "Nižší roman", + "Upper Alpha": "Horná alfa", + "Upper Roman": "Horný román", + + "Unordered List": "Ne\u010d\u00edslovan\u00fd zoznam", + "Circle": "Kružnice", + "Disc": "Kotúč", + "Square": "Námestie", + + // Line height + "Line Height": "Výška riadku", + "Single": "Jednoposteľová", + "Double": "Dvojitý", + + // Indent + "Decrease Indent": "Zmen\u0161i\u0165 odsadenie", + "Increase Indent": "Zv\u00e4\u010d\u0161i\u0165 odsadenie", + + // Links + "Insert Link": "Vlo\u017ei\u0165 odkaz", + "Open in new tab": "Otvori\u0165 v novom okne", + "Open Link": "Otvori\u0165 odkaz", + "Edit Link": "Upravi\u0165 odkaz", + "Unlink": "Odstr\u00e1ni\u0165 odkaz", + "Choose Link": "Vyberte odkaz", + + // Images + "Insert Image": "Vlo\u017ei\u0165 obr\u00e1zok", + "Upload Image": "Nahra\u0165 obr\u00e1zok", + "By URL": "Z URL adresy", + "Browse": "Vybra\u0165", + "Drop image": "Pretiahnite obr\u00e1zok do tohto miesta", + "or click": "alebo kliknite a vlo\u017ete", + "Manage Images": "Spr\u00e1va obr\u00e1zkov", + "Loading": "Nahr\u00e1vam", + "Deleting": "Odstra\u0148ujem", + "Tags": "Zna\u010dky", + "Are you sure? Image will be deleted.": "Ste si ist\u00fd? Obr\u00e1zok bude odstranen\u00fd.", + "Replace": "Vymeni\u0165", + "Uploading": "Nahr\u00e1vam", + "Loading image": "Obr\u00e1zok se na\u010d\u00edtav\u00e1", + "Display": "Zobrazi\u0165", + "Inline": "Inline", + "Break Text": "Zalomenie textu", + "Alternative Text": "Alternat\u00edvny text", + "Change Size": "Zmeni\u0165 ve\u013ekos\u0165", + "Width": "\u0165\u00edrka", + "Height": "V\u00fd\u0161ka", + "Something went wrong. Please try again.": "Nie\u010do sa pokazilo. Pros\u00edm, sk\u00faste to znova.", + "Image Caption": "Titulok obrázka", + "Advanced Edit": "Pokročilá úprava", + + // Video + "Insert Video": "Vlo\u017ei\u0165 video", + "Embedded Code": "Vlo\u017een\u00fd k\u00f3d", + "Paste in a video URL": "Vložte do adresy URL videa", + "Drop video": "Drop video", + "Your browser does not support HTML5 video.": "Váš prehliadač nepodporuje video html5.", + "Upload Video": "Nahrať video", + + // Tables + "Insert Table": "Vlo\u017ei\u0165 tabu\u013eku", + "Table Header": "Hlavi\u010dka tabu\u013eky", + "Remove Table": "Odstrani\u0165 tabu\u013eku", + "Table Style": "\u0160t\u00fdl tabu\u013eky", + "Horizontal Align": "Horizont\u00e1lne zarovnanie", + "Row": "Riadok", + "Insert row above": "Vlo\u017ei\u0165 riadok nad", + "Insert row below": "Vlo\u017ei\u0165 riadok pod", + "Delete row": "Odstrani\u0165 riadok", + "Column": "St\u013apec", + "Insert column before": "Vlo\u017ei\u0165 st\u013apec v\u013eavo", + "Insert column after": "Vlo\u017ei\u0165 st\u013apec vpravo", + "Delete column": "Odstrani\u0165 st\u013apec", + "Cell": "Bunka", + "Merge cells": "Zl\u00fa\u010di\u0165 bunky", + "Horizontal split": "Horizont\u00e1lne rozdelenie", + "Vertical split": "Vertik\u00e1lne rozdelenie", + "Cell Background": "Bunka pozadia", + "Vertical Align": "Vertik\u00e1lne zarovn\u00e1n\u00ed", + "Top": "Vrch", + "Middle": "Stred", + "Bottom": "Spodok", + "Align Top": "Zarovnat na vrch", + "Align Middle": "Zarovnat na stred", + "Align Bottom": "Zarovnat na spodok", + "Cell Style": "\u0160t\u00fdl bunky", + + // Files + "Insert Audio": "Vlo\u017Ei\u0165 zvuk", + "Insert File": "Vlo\u017Ei\u0165 s\u00FAbor", + "Upload File": "Nahra\u0165 s\u00fabor", + "Drop file": "Vlo\u017ete s\u00fabor sem", + + // Emoticons + "Emoticons": "Emotikony", + "Grinning face": "Tv\u00e1r s \u00fasmevom", + "Grinning face with smiling eyes": "Tv\u00e1r s \u00fasmevom a o\u010dami", + "Face with tears of joy": "Tv\u00e1r so slzamy radosti", + "Smiling face with open mouth": "Usmievaj\u00faci sa tv\u00e1r s otvoren\u00fdmi \u00fastami", + "Smiling face with open mouth and smiling eyes": "Usmievaj\u00faci sa tv\u00e1r s otvoren\u00fdmi \u00fastami a o\u010dami", + "Smiling face with open mouth and cold sweat": "Usmievaj\u00faci sa tv\u00e1r s otvoren\u00fdmi \u00fastami a studen\u00fd pot", + "Smiling face with open mouth and tightly-closed eyes": "Usmievaj\u00faci sa tv\u00e1r s otvoren\u00fdmi \u00fastami a zavret\u00fdmi o\u010dami", + "Smiling face with halo": "Usmievaj\u00faci sa tv\u00e1r s halo", + "Smiling face with horns": "Usmievaj\u00faci sa tv\u00e1r s rohmi", + "Winking face": "Mrkaj\u00faca tv\u00e1r", + "Smiling face with smiling eyes": "Usmievaj\u00faci sa tv\u00e1r a o\u010dami", + "Face savoring delicious food": "Tv\u00e1r vychutn\u00e1vaj\u00faca si chutn\u00e9 jedlo", + "Relieved face": "Spokojn\u00e1 tv\u00e1r", + "Smiling face with heart-shaped eyes": "Usmievaj\u00faci sa tv\u00e1r s o\u010dami v tvare srdca", + "Smiling face with sunglasses": "Usmievaj\u00faci sa tv\u00e1r so slne\u010dn\u00fdmi okuliarmi", + "Smirking face": "U\u0161k\u0155\u0148aj\u00faca sa tv\u00e1r", + "Neutral face": "Neutr\u00e1lna tva\u0155", + "Expressionless face": "Bezv\u00fdrazn\u00e1 tv\u00e1r", + "Unamused face": "Nepobaven\u00e1 tv\u00e1r", + "Face with cold sweat": "Tv\u00e1r so studen\u00fdm potom", + "Pensive face": "Zamyslen\u00e1 tv\u00e1r", + "Confused face": "Zmeten\u00e1 tv\u00e1r", + "Confounded face": "Nahnevan\u00e1 tv\u00e1r", + "Kissing face": "Bozkavaj\u00faca tv\u00e1r", + "Face throwing a kiss": "Tv\u00e1r hadzaj\u00faca pusu", + "Kissing face with smiling eyes": "Bozk\u00e1vaj\u00faca tv\u00e1r s o\u010dami a \u00fasmevom", + "Kissing face with closed eyes": "Bozk\u00e1vaj\u00faca tv\u00e1r so zavret\u00fdmi o\u010dami", + "Face with stuck out tongue": "Tv\u00e1r s vyplazen\u00fdm jazykom", + "Face with stuck out tongue and winking eye": "Mrkaj\u00faca tv\u00e1r s vyplazen\u00fdm jazykom", + "Face with stuck out tongue and tightly-closed eyes": "Tv\u00e1r s vyplazen\u00fdm jazykom a privret\u00fdmi o\u010dami", + "Disappointed face": "Sklaman\u00e1 tv\u00e1r", + "Worried face": "Obavaj\u00faca se tv\u00e1r", + "Angry face": "Nahnevan\u00e1 tv\u00e1r", + "Pouting face": "Na\u0161pulen\u00e1 tv\u00e1r", + "Crying face": "Pla\u010d\u00faca tv\u00e1r", + "Persevering face": "H\u00fa\u017eevnat\u00e1 tv\u00e1r", + "Face with look of triumph": "Tv\u00e1r s v\u00fdrazom v\u00ed\u0165aza", + "Disappointed but relieved face": "Sklaman\u00e1 ale spokojn\u00e1 tv\u00e1r", + "Frowning face with open mouth": "Zamra\u010den\u00e1 tvar s otvoren\u00fdmi \u00fastami", + "Anguished face": "\u00dazkostn\u00e1 tv\u00e1r", + "Fearful face": "Strachuj\u00faca sa tv\u00e1r", + "Weary face": "Unaven\u00e1 tv\u00e1r", + "Sleepy face": "Ospal\u00e1 tv\u00e1r", + "Tired face": "Unaven\u00e1 tv\u00e1r", + "Grimacing face": "Sv\u00e1r s grimasou", + "Loudly crying face": "Nahlas pl\u00e1\u010d\u00faca tv\u00e1r", + "Face with open mouth": "Tv\u00e1r s otvoren\u00fdm \u00fastami", + "Hushed face": "Ml\u010diaca tv\u00e1r", + "Face with open mouth and cold sweat": "Tv\u00e1r s otvoren\u00fdmi \u00fastami a studen\u00fdm potom", + "Face screaming in fear": "Tv\u00e1r kri\u010diaca strachom", + "Astonished face": "Tv\u00e1r v \u00fa\u017ease", + "Flushed face": "S\u010dervenanie v tv\u00e1ri", + "Sleeping face": "Spiaca tv\u00e1r", + "Dizzy face": "Tv\u00e1r vyjadruj\u00faca z\u00e1vrat", + "Face without mouth": "Tv\u00e1r bez \u00fast", + "Face with medical mask": "Tv\u00e1r s lek\u00e1rskou maskou", + + // Line breaker + "Break": "Zalomenie", + + // Math + "Subscript": "Doln\u00fd index", + "Superscript": "Horn\u00fd index", + + // Full screen + "Fullscreen": "Cel\u00e1 obrazovka", + + // Horizontal line + "Insert Horizontal Line": "Vlo\u017ei\u0165 vodorovn\u00fa \u010diaru", + + // Clear formatting + "Clear Formatting": "Vymaza\u0165 formatovanie", + + // Save + "Save": "\u0055\u006c\u006f\u017e\u0069\u0165", + + // Undo, redo + "Undo": "Sp\u00e4\u0165", + "Redo": "Znova", + + // Select all + "Select All": "Vybra\u0165 v\u0161etko", + + // Code view + "Code View": "Zobrazi\u0165 html k\u00f3d", + + // Quote + "Quote": "Cit\u00e1t", + "Increase": "Nav\u00fd\u0161i\u0165", + "Decrease": "Zn\u00ed\u017ei\u0165", + + // Quick Insert + "Quick Insert": "Vlo\u017ei\u0165 zr\u00fdchlene", + + // Spcial Characters + "Special Characters": "Špeciálne znaky", + "Latin": "Latinčina", + "Greek": "Grécky", + "Cyrillic": "Cyriliky", + "Punctuation": "Interpunkcia", + "Currency": "Mena", + "Arrows": "Šípky", + "Math": "Matematika", + "Misc": "Misc", + + // Print. + "Print": "Vytlačiť", + + // Spell Checker. + "Spell Checker": "Kontrola pravopisu", + + // Help + "Help": "Pomoc", + "Shortcuts": "Skratky", + "Inline Editor": "Inline editor", + "Show the editor": "Zobraziť editor", + "Common actions": "Spoločné akcie", + "Copy": "Kópie", + "Cut": "Rez", + "Paste": "Pasta", + "Basic Formatting": "Základné formátovanie", + "Increase quote level": "Zvýšiť úroveň cenovej ponuky", + "Decrease quote level": "Znížiť úroveň cenovej ponuky", + "Image / Video": "Obrázok / video", + "Resize larger": "Zmena veľkosti", + "Resize smaller": "Meniť veľkosť", + "Table": "Stôl", + "Select table cell": "Vyberte bunku tabuľky", + "Extend selection one cell": "Rozšíriť výber jednej bunky", + "Extend selection one row": "Rozšíriť výber o jeden riadok", + "Navigation": "Navigácia", + "Focus popup / toolbar": "Zameranie / panel s nástrojmi", + "Return focus to previous position": "Vrátiť zaostrenie na predchádzajúcu pozíciu", + + // Embed.ly + "Embed URL": "Vložiť adresu URL", + "Paste in a URL to embed": "Vložte do adresy URL, ktorú chcete vložiť", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Vložený obsah vychádza z dokumentu Microsoft Word. chcete formát uchovať alebo ho vyčistiť?", + "Keep": "Zachovať", + "Clean": "Čistý", + "Word Paste Detected": "Slovná vložka bola zistená" + }, + direction: "ltr" +}; +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sl.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sl.js new file mode 100644 index 0000000..86da844 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sl.js @@ -0,0 +1,280 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Slovenian + */ + +$.FE.LANGUAGE['sl'] = { + translation: { + // Place holder + "Type something": "Nekaj vtipkajte", + + // Basic formatting + "Bold": "Krepko", + "Italic": "Poševno", + "Underline": "Podčrtano", + "Strikethrough": "Prečrtano", + + // Main buttons + "Insert": "Vstavi", + "Delete": "Izbriši", + "Cancel": "Prekliči", + "OK": "OK", + "Back": "Nazaj", + "Remove": "Odstrani", + "More": "Več", + "Update": "Posodobi", + "Style": "Slog", + + // Font + "Font Family": "Oblika pisave", + "Font Size": "Velikost pisave", + + // Colors + "Colors": "Barve", + "Background": "Ozadje", + "Text": "Besedilo", + "HEX Color": "HEX barva", + + // Paragraphs + "Paragraph Format": "Oblika odstavka", + "Normal": "Normalno", + "Code": "Koda", + "Heading 1": "Naslov 1", + "Heading 2": "Naslov 2", + "Heading 3": "Naslov 3", + "Heading 4": "Naslov 4", + + // Style + "Paragraph Style": "Slog odstavka", + "Inline Style": "Vrstični slog", + + // Alignment + "Align": "Poravnava", + "Align Left": "Leva poravnava", + "Align Center": "Sredinska poravnava", + "Align Right": "Desna poravnava", + "Align Justify": "Obojestranska poravnava", + "None": "Brez poravnave", + + // Lists + "Ordered List": "Številčni seznam", + "Default": "Privzeto", + "Lower Alpha": "Latinica male", + "Lower Greek": "Grške male", + "Lower Roman": "Rimske male", + "Upper Alpha": "Latinica velike", + "Upper Roman": "Rimske velike", + + "Unordered List": "Neštevilčni seznam", + "Circle": "Krog", + "Disc": "Disk", + "Square": "Kvadrat", + + // Line height + "Line Height": "Višina vrstice", + "Single": "Enojna", + "Double": "Dvojna", + + // Indent + "Decrease Indent": "Zmanjšaj zamik", + "Increase Indent": "Povečaj zamik", + + // Links + "Insert Link": "Vstavi povezavo", + "Open in new tab": "Odpri povezavo v novem zavihku", + "Open Link": "Odpri povezavo", + "Edit Link": "Uredi povezavo", + "Unlink": "Odstrani povezavo", + "Choose Link": "Izberi povezavo", + + // Images + "Insert Image": "Vstavi sliko", + "Upload Image": "Naloži sliko", + "By URL": "Iz URL povezave", + "Browse": "Prebrskaj", + "Drop image": "Spustite sliko sem", + "or click": "ali kliknite", + "Manage Images": "Urejaj slike", + "Loading": "Nalaganje", + "Deleting": "Brisanje", + "Tags": "Značke", + "Are you sure? Image will be deleted.": "Ali ste prepričani? Slika bo izbrisana.", + "Replace": "Zamenjaj", + "Uploading": "Nalaganje", + "Loading image": "Nalagam sliko", + "Display": "Prikaži", + "Inline": "Vrstično", + "Break Text": "Prelomi besedilo", + "Alternative Text": "Nadomestno besedilo", + "Change Size": "Spremeni velikost", + "Width": "Širina", + "Height": "Višina", + "Something went wrong. Please try again.": "Nekaj je šlo narobe. Prosimo, poskusite ponovno.", + "Image Caption": "Opis slike", + "Advanced Edit": "Napredno urejanje", + + // Video + "Insert Video": "Vstavi video posnetek", + "Embedded Code": "Vdelana koda", + "Paste in a video URL": "Prilepite URL video posnetka", + "Drop video": "Spustite video posnetek sem", + "Your browser does not support HTML5 video.": "Vaš brskalnik ne podpira HTML5 video funkcionalnosti.", + "Upload Video": "Naloži video posnetek", + + // Tables + "Insert Table": "Vstavi tabelo", + "Table Header": "Glava tabele", + "Remove Table": "Odstrani tabelo", + "Table Style": "Slog tabele", + "Horizontal Align": "Horizontalna poravnava", + "Row": "Vrstica", + "Insert row above": "Vstavi vrstico nad", + "Insert row below": "Vstavi vrstico pod", + "Delete row": "Izbriši vrstico", + "Column": "Stolpec", + "Insert column before": "Vstavi stolpec pred", + "Insert column after": "Vstavi stolpec po", + "Delete column": "Izbriši stolpec", + "Cell": "Celica", + "Merge cells": "Združi celice", + "Horizontal split": "Horizontalni razcep", + "Vertical split": "Vertikalni razcep", + "Cell Background": "Ozadje celice", + "Vertical Align": "Vertikalna poravnava", + "Top": "Vrh", + "Middle": "Sredina", + "Bottom": "Dno", + "Align Top": "Vrhnja poravnava", + "Align Middle": "Sredinska poravnava", + "Align Bottom": "Spodnja poravnava", + "Cell Style": "Slog celice", + + // Files + "Upload File": "Naloži datoteko", + "Drop file": "Spustite datoteko sem", + + // Emoticons + "Emoticons": "Emotikoni", + + // Line breaker + "Break": "Prelom", + + // Math + "Subscript": "Podpisano", + "Superscript": "Nadpisano", + + // Full screen + "Fullscreen": "Celozaslonski način", + + // Horizontal line + "Insert Horizontal Line": "Vstavi vodoravno črto", + + // Clear formatting + "Clear Formatting": "Počisti oblikovanje", + + // Save + "Save": "Shrani", + + // Undo, redo + "Undo": "Razveljavi", + "Redo": "Ponovno uveljavi", + + // Select all + "Select All": "Izberi vse", + + // Code view + "Code View": "Pogled kode", + + // Quote + "Quote": "Citat", + "Increase": "Povečaj", + "Decrease": "Zmanjšaj", + + // Quick Insert + "Quick Insert": "Hitro vstavljanje", + + // Special Characters + "Special Characters": "Posebni znaki", + "Latin": "Latinica", + "Greek": "Grščina", + "Cyrillic": "Cirilica", + "Punctuation": "Ločila", + "Currency": "Valute", + "Arrows": "Puščice", + "Math": "Matematika", + "Misc": "Razno", + + // Print. + "Print": "Natisni", + + // Spell Checker. + "Spell Checker": "Črkovalnik", + + // Help + "Help": "Pomoč", + "Shortcuts": "Bližnjice", + "Inline Editor": "Vdelani urejevalnik", + "Show the editor": "Pokaži urejevalnik", + "Common actions": "Skupna dejanja", + "Copy": "Kopiraj", + "Cut": "Izreži", + "Paste": "Prilepi", + "Basic Formatting": "Osnovno oblikovanje", + "Increase quote level": "Povečaj raven citata", + "Decrease quote level": "Zmanjšaj raven citata", + "Image / Video": "Slika / Video", + "Resize larger": "Povečaj", + "Resize smaller": "Pomanjšaj", + "Table": "Tabela", + "Select table cell": "Izberi celico tabele", + "Extend selection one cell": "Razširi izbor za eno celico", + "Extend selection one row": "Razširi izbor za eno vrstico", + "Navigation": "Navigacija", + "Focus popup / toolbar": "Fokusiraj pojavno okno / orodno vrstico", + "Return focus to previous position": "Vrni fokus v prejšnji položaj", + + // Embed.ly + "Embed URL": "Vdelaj URL", + "Paste in a URL to embed": "Prilepite URL za vdelavo", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Prilepljena vsebina prihaja iz dokumenta Microsoft Word. Ali želite obliko obdržati ali jo želite očistiti?", + "Keep": "Obdrži", + "Clean": "Počisti", + "Word Paste Detected": "Zaznano je lepljenje s programa Word" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sr.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sr.js new file mode 100644 index 0000000..575bd7d --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sr.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Serbian (Latin) + */ + +$.FE.LANGUAGE['sr'] = { + translation: { + // Place holder + "Type something": "Ukucajte ne\u0161tp", + + // Basic formatting + "Bold": "Podebljan", + "Italic": "Isko\u0161en", + "Underline": "Podvu\u010deno", + "Strikethrough": "Precrtan", + + // Main buttons + "Insert": "Umetanje", + "Delete": "Izbri\u0161i", + "Cancel": "Otkazivanje", + "OK": "Ok", + "Back": "Nazad", + "Remove": "Uklonite", + "More": "Vi\u0161e", + "Update": "A\u017euriranje", + "Style": "Stil", + + // Font + "Font Family": "Odaberi font", + "Font Size": "Veli\u010dina fontova", + + // Colors + "Colors": "Boje", + "Background": "Pozadina", + "Text": "Tekst", + "HEX Color": "HEX boje", + + // Paragraphs + "Paragraph Format": "Format pasusa", + "Normal": "Normalno", + "Code": "\u0160ifra", + "Heading 1": "Naslov 1", + "Heading 2": "Naslov 2", + "Heading 3": "Naslov 3", + "Heading 4": "Naslov 4", + + // Style + "Paragraph Style": "Stil pasusa", + "Inline Style": "Umetnutih stilova", + + // Alignment + "Align": "Poravnavanje", + "Align Left": "Poravnaj levo", + "Align Center": "Poravnaj u centru", + "Align Right": "Poravnaj desno", + "Align Justify": "Obostrano poravnavanje", + "None": "Niko nije", + + // Lists + "Ordered List": "Ure\u0111enih lista", + "Default": "Уобичајено", + "Lower Alpha": "Нижи алфа", + "Lower Greek": "Лов греек", + "Lower Roman": "Ловер роман", + "Upper Alpha": "Уппер алпха", + "Upper Roman": "Уппер роман", + + "Unordered List": "Neure\u0111enu lista", + "Circle": "Круг", + "Disc": "Диск", + "Square": "Квадрат", + + // Line height + "Line Height": "Висина линија", + "Single": "Једно", + "Double": "Доубле", + + // Indent + "Decrease Indent": "Smanjivanje uvla\u010denja", + "Increase Indent": "Pove\u0107avanje uvla\u010denja", + + // Links + "Insert Link": "Umetni vezu", + "Open in new tab": "Otvori na novoj kartici", + "Open Link": "Otvori vezu", + "Edit Link": "Ure\u0111ivanje veze", + "Unlink": "Ukloni vezu", + "Choose Link": "Odaberite vezu", + + // Images + "Insert Image": "Umetanje slike", + "Upload Image": "Otpremanje slika", + "By URL": "Po URL adresi", + "Browse": "Potra\u017ei", + "Drop image": "Baci sliku", + "or click": "ili kliknite na dugme", + "Manage Images": "Upravljanje slike", + "Loading": "U\u010ditavanje", + "Deleting": "Brisanje", + "Tags": "Oznake", + "Are you sure? Image will be deleted.": "Jesi siguran? Slika \u0107e biti izbrisana.", + "Replace": "Zameni", + "Uploading": "Otpremanje", + "Loading image": "U\u010ditavanje slika", + "Display": "Prikaz", + "Inline": "Pri upisivanju", + "Break Text": "Prelom teksta", + "Alternative Text": "Alternativni tekst", + "Change Size": "Promena veli\u010dine", + "Width": "\u0160irina", + "Height": "Visina", + "Something went wrong. Please try again.": "Ne\u0161to krenulo naopako. Poku\u0161ajte ponovo.", + "Image Caption": "Slika natpisa", + "Advanced Edit": "Napredno uređivanje", + + // Video + "Insert Video": "Umetanje video", + "Embedded Code": "Ugra\u0111eni k\u00f4d", + "Paste in a video URL": "Lepljenje u video URL", + "Drop video": "Baci snimak", + "Your browser does not support HTML5 video.": "Vaš pregledač ne podržava HTML5 video.", + "Upload Video": "Otpremanje video", + + // Tables + "Insert Table": "Umetni tabelu", + "Table Header": "Zaglavlje tabele", + "Remove Table": "Uklanjanje tabele", + "Table Style": "Stil tabele", + "Horizontal Align": "Horizontalno poravnavanje", + "Row": "Red", + "Insert row above": "Umetni red iznad", + "Insert row below": "Umetni red ispod", + "Delete row": "Izbri\u0161i red", + "Column": "Kolone", + "Insert column before": "Umetnite kolonu pre", + "Insert column after": "Umetnite kolonu nakon", + "Delete column": "Izbri\u0161i kolone", + "Cell": "Mobilni", + "Merge cells": "Objedinjavanje \u0107elija", + "Horizontal split": "Horizontalna split", + "Vertical split": "Vertikalno razdelite", + "Cell Background": "Mobilni pozadina", + "Vertical Align": "Vertikalno poravnavanje", + "Top": "Top", + "Middle": "Srednji", + "Bottom": "Dno", + "Align Top": "Poravnaj gore", + "Align Middle": "Poravnaj po sredini", + "Align Bottom": "Poravnaj dole", + "Cell Style": "Mobilni stil", + + // Files + "Upload File": "Otpremanje datoteke", + "Drop file": "Baci datoteku", + + // Emoticons + "Emoticons": "Emotikona", + "Grinning face": "Nasmejanoj lice", + "Grinning face with smiling eyes": "Nasmejanoj lice sa osmehom o\u010di", + "Face with tears of joy": "Suo\u010davaju sa suzama radosnicama", + "Smiling face with open mouth": "Nasmejano lice sa otvorenim ustima", + "Smiling face with open mouth and smiling eyes": "Lica sa otvorenim ustima i nasmejani o\u010di", + "Smiling face with open mouth and cold sweat": "Nasmejano lice sa otvorenih usta i hladan znoj", + "Smiling face with open mouth and tightly-closed eyes": "Nasmejano lice otvorenih usta i \u010dvrsto zatvorenih o\u010diju", + "Smiling face with halo": "Nasmejano lice sa oreolom", + "Smiling face with horns": "Nasmejano lice sa rogovima", + "Winking face": "Namigivanje lice", + "Smiling face with smiling eyes": "Lica sa osmehom o\u010di", + "Face savoring delicious food": "Lice u\u045bivaju\u0436i u ukusnu hranu", + "Relieved face": "Laknulo lice", + "Smiling face with heart-shaped eyes": "Nasmejano lice sa o\u010dima u obliku srca", + "Smiling face with sunglasses": "Nasmejano lice sa nao\u010dare", + "Smirking face": "Rugaju\u0436i lice", + "Neutral face": "Neutralno lice", + "Expressionless face": "Bez izraza lica.", + "Unamused face": "Nije zapaljen lice", + "Face with cold sweat": "Suo\u010davaju sa hladnim znojem", + "Pensive face": "Nevesela lica", + "Confused face": "Zbunjeno lice", + "Confounded face": "Dosadnih lice", + "Kissing face": "Ljubim lice", + "Face throwing a kiss": "Lice baca poljubac", + "Kissing face with smiling eyes": "Ljubi lice sa osmehom o\u010di", + "Kissing face with closed eyes": "Ljubi lice sa zatvorenim o\u010dima", + "Face with stuck out tongue": "Lice sa zaglavio jezik", + "Face with stuck out tongue and winking eye": "Lice sa zaglavljen jezik i namigivanje", + "Face with stuck out tongue and tightly-closed eyes": "Lice sa zaglavljen jezik i cvrsto zatvorene o\u010di", + "Disappointed face": "Razo\u010darani lice", + "Worried face": "Zabrinuto lice", + "Angry face": "Ljut lice", + "Pouting face": "Zlovoljan lice", + "Crying face": "Plakanje lice", + "Persevering face": "Istrajnog lice", + "Face with look of triumph": "Suo\u010davaju sa izgledom trijumfa", + "Disappointed but relieved face": "Razo\u010daran ali laknulo lice", + "Frowning face with open mouth": "Namršten lice sa otvorenim ustima", + "Anguished face": "Enih lica", + "Fearful face": "Strahu lice", + "Weary face": "Umorna lica", + "Sleepy face": "Spava mi se lice", + "Tired face": "Umorna lica", + "Grimacing face": "Klupi lice", + "Loudly crying face": "Glasno plakanje lice", + "Face with open mouth": "Suo\u010davaju sa otvorenim ustima", + "Hushed face": "Tihim lice", + "Face with open mouth and cold sweat": "Suo\u010davaju sa otvorenih usta i hladan znoj", + "Face screaming in fear": "Lice vrisak u strahu", + "Astonished face": "Zadivljeni lice", + "Flushed face": "Uplakanu lice", + "Sleeping face": "Pospanog lica", + "Dizzy face": "Lice mi se vrti", + "Face without mouth": "Lice bez jezika", + "Face with medical mask": "Suo\u010davaju sa medicinskim masku", + + // Line breaker + "Break": "Prelom", + + // Math + "Subscript": "Indeksni tekst", + "Superscript": "Eksponentni tekst", + + // Full screen + "Fullscreen": "Puni ekran", + + // Horizontal line + "Insert Horizontal Line": "Umetni horizontalnu liniju", + + // Clear formatting + "Clear Formatting": "Brisanje oblikovanja", + + // Save + "Save": "\u0441\u0430\u0447\u0443\u0432\u0430\u0442\u0438", + + // Undo, redo + "Undo": "Opozovi radnju", + "Redo": "Ponavljanje", + + // Select all + "Select All": "Izaberi sve", + + // Code view + "Code View": "Prikaz koda", + + // Quote + "Quote": "Ponude", + "Increase": "Pove\u0107anje", + "Decrease": "Smanjivanje", + + // Quick Insert + "Quick Insert": "Brzo umetanje", + + // Spcial Characters + "Special Characters": "Specijalni znakovi", + "Latin": "Latino", + "Greek": "Grk", + "Cyrillic": "Ćirilica", + "Punctuation": "Interpunkcije", + "Currency": "Valuta", + "Arrows": "Strelice", + "Math": "Matematika", + "Misc": "Misc", + + // Print. + "Print": "Odštampaj", + + // Spell Checker. + "Spell Checker": "Kontrolor pravopisa", + + // Help + "Help": "Pomoć", + "Shortcuts": "Prečice", + "Inline Editor": "Pri upisivanju Editor", + "Show the editor": "Prikaži urednik", + "Common actions": "Zajedničke akcije", + "Copy": "Kopija", + "Cut": "Rez", + "Paste": "Nalepi", + "Basic Formatting": "Osnovno oblikovanje", + "Increase quote level": "Povećati ponudu za nivo", + "Decrease quote level": "Smanjenje ponude nivo", + "Image / Video": "Slika / Video", + "Resize larger": "Veće veličine", + "Resize smaller": "Promena veličine manji", + "Table": "Sto", + "Select table cell": "Select ćelije", + "Extend selection one cell": "Proširite selekciju jednu ćeliju", + "Extend selection one row": "Proširite selekciju jedan red", + "Navigation": "Navigacija", + "Focus popup / toolbar": "Fokus Iskačući meni / traka sa alatkama", + "Return focus to previous position": "Vratiti fokus na prethodnu poziciju", + + // Embed.ly + "Embed URL": "Ugradite URL", + "Paste in a URL to embed": "Nalepite URL adresu da biste ugradili", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Nalepljeni sadržaj dolazi iz Microsoft Word dokument. Da li želite zadržati u formatu ili počistiti?", + "Keep": "Nastavi", + "Clean": "Oиisti", + "Word Paste Detected": "Word Nalepi otkriven" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sv.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sv.js new file mode 100644 index 0000000..70c1bec --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sv.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Swedish + */ + +$.FE.LANGUAGE['sv'] = { + translation: { + // Place holder + "Type something": "Ange n\u00e5got", + + // Basic formatting + "Bold": "Fetstil", + "Italic": "Kursiv stil", + "Underline": "Understruken", + "Strikethrough": "Genomstruken", + + // Main buttons + "Insert": "Infoga", + "Delete": "Radera", + "Cancel": "Avbryt", + "OK": "Ok", + "Back": "Tillbaka", + "Remove": "Ta bort", + "More": "Mer", + "Update": "Uppdatera", + "Style": "Stil", + + // Font + "Font Family": "Teckensnitt", + "Font Size": "Teckenstorlek", + + // Colors + "Colors": "F\u00e4rger", + "Background": "Bakgrund", + "Text": "Text", + "HEX Color": "Hex färg", + + // Paragraphs + "Paragraph Format": "Format", + "Normal": "Normal", + "Code": "Kod", + "Heading 1": "Rubrik 1", + "Heading 2": "Rubrik 2", + "Heading 3": "Rubrik 3", + "Heading 4": "Rubrik 4", + + // Style + "Paragraph Style": "Styckesformat", + "Inline Style": "Infogad stil", + + // Alignment + "Align": "Justera", + "Align Left": "Vänsterjustera", + "Align Center": "Centrera", + "Align Right": "Högerjustera", + "Align Justify": "Justera", + "None": "Inget", + + // Lists + "Ordered List": "Ordnad lista", + "Default": "Standard", + "Lower Alpha": "Lägre alfa", + "Lower Greek": "Lägre grekiska", + "Lower Roman": "Lägre roman", + "Upper Alpha": "Övre alfa", + "Upper Roman": "Övre roman", + + "Unordered List": "Oordnad lista", + "Circle": "Cirkel", + "Disc": "Skiva", + "Square": "Fyrkant", + + // Line height + "Line Height": "Radavstånd", + "Single": "Enda", + "Double": "Dubbel", + + // Indent + "Decrease Indent": "Minska indrag", + "Increase Indent": "\u00d6ka indrag", + + // Links + "Insert Link": "Infoga l\u00e4nk", + "Open in new tab": "\u00d6ppna i ny flik", + "Open Link": "\u00d6ppna l\u00e4nk", + "Edit Link": "Redigera l\u00e4nk", + "Unlink": "Ta bort l\u00e4nk", + "Choose Link": "V\u00e4lj l\u00e4nk", + + // Images + "Insert Image": "Infoga bild", + "Upload Image": "Ladda upp en bild", + "By URL": "Genom URL", + "Browse": "Bl\u00e4ddra", + "Drop image": "Sl\u00e4pp bild", + "or click": "eller klicka", + "Manage Images": "Hantera bilder", + "Loading": "Laddar", + "Deleting": "Raderar", + "Tags": "Etiketter", + "Are you sure? Image will be deleted.": "\u00c4r du s\u00e4ker? Bild kommer att raderas.", + "Replace": "Ers\u00e4tt", + "Uploading": "Laddar up", + "Loading image": "Laddar bild", + "Display": "Visa", + "Inline": "I linje", + "Break Text": "Bryt text", + "Alternative Text": "Alternativ text", + "Change Size": "\u00c4ndra storlek", + "Width": "Bredd", + "Height": "H\u00f6jd", + "Something went wrong. Please try again.": "N\u00e5got gick fel. Var god f\u00f6rs\u00f6k igen.", + "Image Caption": "Bildtext", + "Advanced Edit": "Avancerad redigering", + + // Video + "Insert Video": "Infoga video", + "Embedded Code": "Inb\u00e4ddad kod", + "Paste in a video URL": "Klistra in i en video url", + "Drop video": "Släpp video", + "Your browser does not support HTML5 video.": "Din webbläsare stöder inte html5-video.", + "Upload Video": "Ladda upp video", + + // Tables + "Insert Table": "Infoga tabell", + "Table Header": "Tabell huvud", + "Remove Table": "Ta bort tabellen", + "Table Style": "Tabellformat", + "Horizontal Align": "Horisontell justering", + "Row": "Rad", + "Insert row above": "Infoga rad f\u00f6re", + "Insert row below": "Infoga rad efter", + "Delete row": "Ta bort rad", + "Column": "Kolumn", + "Insert column before": "Infoga kollumn f\u00f6re", + "Insert column after": "Infoga kolumn efter", + "Delete column": "Ta bort kolumn", + "Cell": "Cell", + "Merge cells": "Sammanfoga celler", + "Horizontal split": "Dela horisontellt", + "Vertical split": "Dela vertikalt", + "Cell Background": "Cellbakgrund", + "Vertical Align": "Vertikal justering", + "Top": "Överst", + "Middle": "Mitten", + "Bottom": "Nederst", + "Align Top": "Justera överst", + "Align Middle": "Justera mitten", + "Align Bottom": "Justera nederst", + "Cell Style": "Cellformat", + + // Files + "Upload File": "Ladda upp fil", + "Drop file": "Sl\u00e4pp fil", + + // Emoticons + "Emoticons": "Uttryckssymboler", + "Grinning face": "Grina ansikte", + "Grinning face with smiling eyes": "Grina ansikte med leende \u00f6gon", + "Face with tears of joy": "Face med gl\u00e4djet\u00e5rar", + "Smiling face with open mouth": "Leende ansikte med \u00f6ppen mun", + "Smiling face with open mouth and smiling eyes": "Leende ansikte med \u00f6ppen mun och leende \u00f6gon", + "Smiling face with open mouth and cold sweat": "Leende ansikte med \u00f6ppen mun och kallsvett", + "Smiling face with open mouth and tightly-closed eyes": "Leende ansikte med \u00f6ppen mun och t\u00e4tt slutna \u00f6gon", + "Smiling face with halo": "Leende ansikte med halo", + "Smiling face with horns": "Leende ansikte med horn", + "Winking face": "Blinka ansikte", + "Smiling face with smiling eyes": "Leende ansikte med leende \u00f6gon", + "Face savoring delicious food": "Ansikte smaka uts\u00f6kt mat", + "Relieved face": "L\u00e4ttad ansikte", + "Smiling face with heart-shaped eyes": "Leende ansikte med hj\u00e4rtformade \u00f6gon", + "Smiling face with sunglasses": "Leende ansikte med solglas\u00f6gon", + "Smirking face": "Flinande ansikte", + "Neutral face": "Neutral ansikte", + "Expressionless face": "Uttryckslöst ansikte", + "Unamused face": "Inte roade ansikte", + "Face with cold sweat": "Ansikte med kallsvett", + "Pensive face": "Eftert\u00e4nksamt ansikte", + "Confused face": "F\u00f6rvirrad ansikte", + "Confounded face": "F\u00f6rbryllade ansikte", + "Kissing face": "Kyssande ansikte", + "Face throwing a kiss": "Ansikte kasta en kyss", + "Kissing face with smiling eyes": "Kyssa ansikte med leende \u00f6gon", + "Kissing face with closed eyes": "Kyssa ansikte med slutna \u00f6gon", + "Face with stuck out tongue": "Ansikte med stack ut tungan", + "Face with stuck out tongue and winking eye": "Ansikte med stack ut tungan och blinkande \u00f6ga", + "Face with stuck out tongue and tightly-closed eyes": "Ansikte med stack ut tungan och t\u00e4tt slutna \u00f6gon", + "Disappointed face": "Besviken ansikte", + "Worried face": "Orolig ansikte", + "Angry face": "Argt ansikte", + "Pouting face": "Sk\u00e4ggtorsk ansikte", + "Crying face": "Gr\u00e5tande ansikte", + "Persevering face": "Uth\u00e5llig ansikte", + "Face with look of triumph": "Ansikte med utseendet p\u00e5 triumf", + "Disappointed but relieved face": "Besviken men l\u00e4ttad ansikte", + "Frowning face with open mouth": "Rynkar pannan ansikte med \u00f6ppen mun", + "Anguished face": "\u00c5ngest ansikte", + "Fearful face": "R\u00e4dda ansikte", + "Weary face": "Tr\u00f6tta ansikte", + "Sleepy face": "S\u00f6mnig ansikte", + "Tired face": "Tr\u00f6tt ansikte", + "Grimacing face": "Grimaserande ansikte", + "Loudly crying face": "H\u00f6gt gr\u00e5tande ansikte", + "Face with open mouth": "Ansikte med \u00f6ppen mun", + "Hushed face": "D\u00e4mpade ansikte", + "Face with open mouth and cold sweat": "Ansikte med \u00f6ppen mun och kallsvett", + "Face screaming in fear": "Face skriker i skr\u00e4ck", + "Astonished face": "F\u00f6rv\u00e5nad ansikte", + "Flushed face": "Ansiktsrodnad", + "Sleeping face": "Sovande anskite", + "Dizzy face": "Yr ansikte", + "Face without mouth": "Ansikte utan mun", + "Face with medical mask": "Ansikte med medicinsk maskera", + + // Line breaker + "Break": "Ny rad", + + // Math + "Subscript": "Neds\u00e4nkt", + "Superscript": "Upph\u00f6jd", + + // Full screen + "Fullscreen": "Helsk\u00e4rm", + + // Horizontal line + "Insert Horizontal Line": "Infoga horisontell linje", + + // Clear formatting + "Clear Formatting": "Ta bort formatering", + + // Save + "Save": "Spara", + + // Undo, redo + "Undo": "\u00c5ngra", + "Redo": "G\u00f6r om", + + // Select all + "Select All": "Markera allt", + + // Code view + "Code View": "Kodvy", + + // Quote + "Quote": "Citat", + "Increase": "\u00d6ka", + "Decrease": "Minska", + + // Quick Insert + "Quick Insert": "Snabbinfoga", + + // Spcial Characters + "Special Characters": "Specialtecken", + "Latin": "Latin", + "Greek": "Grekisk", + "Cyrillic": "Cyrillic", + "Punctuation": "Skiljetecken", + "Currency": "Valuta", + "Arrows": "Pilar", + "Math": "Matematik", + "Misc": "Övrigt", + + // Print. + "Print": "Skriva ut", + + // Spell Checker. + "Spell Checker": "Stavningskontroll", + + // Help + "Help": "Hjälp", + "Shortcuts": "Genvägar", + "Inline Editor": "Inline editor", + "Show the editor": "Visa redigeraren", + "Common actions": "Vanliga kommandon", + "Copy": "Kopiera", + "Cut": "Klipp ut", + "Paste": "Klistra in", + "Basic Formatting": "Grundläggande formatering", + "Increase quote level": "Öka citatnivå", + "Decrease quote level": "Minska citatnivå", + "Image / Video": "Bild / video", + "Resize larger": "Öka storlek", + "Resize smaller": "Minska storlek", + "Table": "Tabell", + "Select table cell": "Markera tabellcell", + "Extend selection one cell": "Utöka markering en cell", + "Extend selection one row": "Utöka markering en rad", + "Navigation": "Navigering", + "Focus popup / toolbar": "Fokusera popup / verktygsfältet", + "Return focus to previous position": "Byt fokus till föregående plats", + + // Embed.ly + "Embed URL": "Bädda in url", + "Paste in a URL to embed": "Klistra in i en url för att bädda in", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Den inklippta texten kommer från ett Microsoft Word-dokument. Vill du behålla formateringen eller städa upp det?", + "Keep": "Behåll", + "Clean": "Städa upp", + "Word Paste Detected": "Urklipp från Word upptäckt" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/th.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/th.js new file mode 100644 index 0000000..5364885 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/th.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Thai + */ + +$.FE.LANGUAGE['th'] = { + translation: { + // Place holder + "Type something": "\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e1a\u0e32\u0e07\u0e2a\u0e34\u0e48\u0e07\u0e1a\u0e32\u0e07\u0e2d\u0e22\u0e48\u0e32\u0e07", + + // Basic formatting + "Bold": "\u0e15\u0e31\u0e27\u0e2b\u0e19\u0e32", + "Italic": "\u0e15\u0e31\u0e27\u0e40\u0e2d\u0e35\u0e22\u0e07", + "Underline": "\u0e02\u0e35\u0e14\u0e40\u0e2a\u0e49\u0e19\u0e43\u0e15\u0e49", + "Strikethrough": "\u0e02\u0e35\u0e14\u0e17\u0e31\u0e1a", + + // Main buttons + "Insert": "\u0e41\u0e17\u0e23\u0e01", + "Delete": "\u0e25\u0e1a", + "Cancel": "\u0e22\u0e01\u0e40\u0e25\u0e34\u0e01", + "OK": "\u0e15\u0e01\u0e25\u0e07", + "Back": "\u0e01\u0e25\u0e31\u0e1a", + "Remove": "\u0e40\u0e2d\u0e32\u0e2d\u0e2d\u0e01", + "More": "\u0e21\u0e32\u0e01\u0e01\u0e27\u0e48\u0e32", + "Update": "\u0e2d\u0e31\u0e1e\u0e40\u0e14\u0e17", + "Style": "\u0e2a\u0e44\u0e15\u0e25\u0e4c", + + // Font + "Font Family": "\u0e15\u0e23\u0e30\u0e01\u0e39\u0e25\u0e41\u0e1a\u0e1a\u0e2d\u0e31\u0e01\u0e29\u0e23", + "Font Size": "\u0e02\u0e19\u0e32\u0e14\u0e41\u0e1a\u0e1a\u0e2d\u0e31\u0e01\u0e29\u0e23", + + // Colors + "Colors": "\u0e2a\u0e35", + "Background": "\u0e1e\u0e37\u0e49\u0e19\u0e2b\u0e25\u0e31\u0e07", + "Text": "\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21", + "HEX Color": "สีฐานสิบหก", + + // Paragraphs + "Paragraph Format": "\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a", + "Normal": "\u0e1b\u0e01\u0e15\u0e34", + "Code": "\u0e42\u0e04\u0e49\u0e14", + "Heading 1": "\u0e2a\u0e48\u0e27\u0e19\u0e2b\u0e31\u0e27 1", + "Heading 2": "\u0e2a\u0e48\u0e27\u0e19\u0e2b\u0e31\u0e27 2", + "Heading 3": "\u0e2a\u0e48\u0e27\u0e19\u0e2b\u0e31\u0e27 3", + "Heading 4": "\u0e2a\u0e48\u0e27\u0e19\u0e2b\u0e31\u0e27 4", + + // Style + "Paragraph Style": "\u0e25\u0e31\u0e01\u0e29\u0e13\u0e30\u0e22\u0e48\u0e2d\u0e2b\u0e19\u0e49\u0e32", + "Inline Style": "\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a\u0e2d\u0e34\u0e19\u0e44\u0e25\u0e19\u0e4c", + + // Alignment + "Align": "\u0e01\u0e32\u0e23\u0e08\u0e31\u0e14\u0e41\u0e19\u0e27", + "Align Left": "\u0e08\u0e31\u0e14\u0e0a\u0e34\u0e14\u0e0b\u0e49\u0e32\u0e22", + "Align Center": "\u0e08\u0e31\u0e14\u0e01\u0e36\u0e48\u0e07\u0e01\u0e25\u0e32\u0e07", + "Align Right": "\u0e08\u0e31\u0e14\u0e0a\u0e34\u0e14\u0e02\u0e27\u0e32", + "Align Justify": "\u0e40\u0e15\u0e47\u0e21\u0e41\u0e19\u0e27", + "None": "\u0e44\u0e21\u0e48", + + // Lists + "Ordered List": "\u0e23\u0e32\u0e22\u0e01\u0e32\u0e23\u0e25\u0e33\u0e14\u0e31\u0e1a\u0e40\u0e25\u0e02", + "Default": "ค่าเริ่มต้น", + "Lower Alpha": "อัลฟาตอนล่าง", + "Lower Greek": "กรีกต่ำกว่า", + "Lower Roman": "โรมันล่าง", + "Upper Alpha": "อัลฟาตอนบน", + "Upper Roman": "โรมันตอนบน", + + "Unordered List": "\u0e23\u0e32\u0e22\u0e01\u0e32\u0e23\u0e2a\u0e31\u0e0d\u0e25\u0e31\u0e01\u0e29\u0e13\u0e4c\u0e2b\u0e31\u0e27\u0e02\u0e49\u0e2d\u0e22\u0e48\u0e2d\u0e22", + "Circle": "วงกลม", + "Disc": "จาน", + "Square": "สี่เหลี่ยม", + + // Line height + "Line Height": "ความสูงของบรรทัด", + "Single": "เดียว", + "Double": "สอง", + + // Indent + "Decrease Indent": "\u0e25\u0e14\u0e01\u0e32\u0e23\u0e40\u0e22\u0e37\u0e49\u0e2d\u0e07", + "Increase Indent": "\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e01\u0e32\u0e23\u0e40\u0e22\u0e37\u0e49\u0e2d\u0e07", + + // Links + "Insert Link": "\u0e41\u0e17\u0e23\u0e01\u0e25\u0e34\u0e07\u0e01\u0e4c", + "Open in new tab": "\u0e40\u0e1b\u0e34\u0e14\u0e43\u0e19\u0e41\u0e17\u0e47\u0e1a\u0e43\u0e2b\u0e21\u0e48", + "Open Link": "\u0e40\u0e1b\u0e34\u0e14\u0e25\u0e34\u0e49\u0e07\u0e04\u0e4c", + "Edit Link": "\u0e25\u0e34\u0e07\u0e04\u0e4c\u0e41\u0e01\u0e49\u0e44\u0e02", + "Unlink": "\u0e40\u0e2d\u0e32\u0e25\u0e34\u0e07\u0e01\u0e4c\u0e2d\u0e2d\u0e01", + "Choose Link": "\u0e40\u0e25\u0e37\u0e2d\u0e01\u0e01\u0e32\u0e23\u0e40\u0e0a\u0e37\u0e48\u0e2d\u0e21\u0e42\u0e22\u0e07", + + // Images + "Insert Image": "\u0e41\u0e17\u0e23\u0e01\u0e23\u0e39\u0e1b\u0e20\u0e32\u0e1e", + "Upload Image": "\u0e01\u0e32\u0e23\u0e2d\u0e31\u0e1b\u0e42\u0e2b\u0e25\u0e14\u0e20\u0e32\u0e1e", + "By URL": "\u0e15\u0e32\u0e21 URL", + "Browse": "\u0e40\u0e23\u0e35\u0e22\u0e01\u0e14\u0e39", + "Drop image": "\u0e27\u0e32\u0e07\u0e20\u0e32\u0e1e", + "or click": "\u0e2b\u0e23\u0e37\u0e2d\u0e04\u0e25\u0e34\u0e01\u0e17\u0e35\u0e48", + "Manage Images": "\u0e08\u0e31\u0e14\u0e01\u0e32\u0e23\u0e20\u0e32\u0e1e", + "Loading": "\u0e42\u0e2b\u0e25\u0e14", + "Deleting": "\u0e25\u0e1a", + "Tags": "\u0e41\u0e17\u0e47\u0e01", + "Are you sure? Image will be deleted.": "\u0e04\u0e38\u0e13\u0e41\u0e19\u0e48\u0e43\u0e08\u0e2b\u0e23\u0e37\u0e2d\u0e44\u0e21\u0e48 \u0e20\u0e32\u0e1e\u0e08\u0e30\u0e16\u0e39\u0e01\u0e25\u0e1a", + "Replace": "\u0e41\u0e17\u0e19\u0e17\u0e35\u0e48", + "Uploading": "\u0e2d\u0e31\u0e1e\u0e42\u0e2b\u0e25\u0e14", + "Loading image": "\u0e42\u0e2b\u0e25\u0e14\u0e20\u0e32\u0e1e", + "Display": "\u0e41\u0e2a\u0e14\u0e07", + "Inline": "\u0e41\u0e1a\u0e1a\u0e2d\u0e34\u0e19\u0e44\u0e25\u0e19\u0e4c", + "Break Text": "\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21\u0e2b\u0e22\u0e38\u0e14", + "Alternative Text": "\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21\u0e2d\u0e37\u0e48\u0e19", + "Change Size": "\u0e40\u0e1b\u0e25\u0e35\u0e48\u0e22\u0e19\u0e02\u0e19\u0e32\u0e14", + "Width": "\u0e04\u0e27\u0e32\u0e21\u0e01\u0e27\u0e49\u0e32\u0e07", + "Height": "\u0e04\u0e27\u0e32\u0e21\u0e2a\u0e39\u0e07", + "Something went wrong. Please try again.": "\u0e1a\u0e32\u0e07\u0e2d\u0e22\u0e48\u0e32\u0e07\u0e1c\u0e34\u0e14\u0e1b\u0e01\u0e15\u0e34. \u0e01\u0e23\u0e38\u0e13\u0e32\u0e25\u0e2d\u0e07\u0e2d\u0e35\u0e01\u0e04\u0e23\u0e31\u0e49\u0e07.", + "Image Caption": "คำบรรยายภาพ", + "Advanced Edit": "แก้ไขขั้นสูง", + + // Video + "Insert Video": "\u0e41\u0e17\u0e23\u0e01\u0e27\u0e34\u0e14\u0e35\u0e42\u0e2d", + "Embedded Code": "\u0e23\u0e2b\u0e31\u0e2a\u0e2a\u0e21\u0e2d\u0e07\u0e01\u0e25\u0e1d\u0e31\u0e07\u0e15\u0e31\u0e27", + "Paste in a video URL": "วางใน URL วิดีโอ", + "Drop video": "วางวิดีโอ", + "Your browser does not support HTML5 video.": "เบราเซอร์ของคุณไม่สนับสนุนวิดีโอ HTML5", + "Upload Video": "อัปโหลดวิดีโอ", + + // Tables + "Insert Table": "\u0e41\u0e17\u0e23\u0e01\u0e15\u0e32\u0e23\u0e32\u0e07", + "Table Header": "\u0e2a\u0e48\u0e27\u0e19\u0e2b\u0e31\u0e27\u0e02\u0e2d\u0e07\u0e15\u0e32\u0e23\u0e32\u0e07", + "Remove Table": "\u0e40\u0e2d\u0e32\u0e15\u0e32\u0e23\u0e32\u0e07\u0e2d\u0e2d\u0e01", + "Table Style": "\u0e25\u0e31\u0e01\u0e29\u0e13\u0e30\u0e15\u0e32\u0e23\u0e32\u0e07", + "Horizontal Align": "\u0e43\u0e19\u0e41\u0e19\u0e27\u0e19\u0e2d\u0e19", + "Row": "\u0e41\u0e16\u0e27", + "Insert row above": "\u0e41\u0e17\u0e23\u0e01\u0e41\u0e16\u0e27\u0e14\u0e49\u0e32\u0e19\u0e1a\u0e19", + "Insert row below": "\u0e41\u0e17\u0e23\u0e01\u0e41\u0e16\u0e27\u0e14\u0e49\u0e32\u0e19\u0e25\u0e48\u0e32\u0e07", + "Delete row": "\u0e25\u0e1a\u0e41\u0e16\u0e27", + "Column": "\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c", + "Insert column before": "\u0e41\u0e17\u0e23\u0e01\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c\u0e02\u0e49\u0e32\u0e07\u0e2b\u0e19\u0e49\u0e32", + "Insert column after": "\u0e41\u0e17\u0e23\u0e01\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c\u0e02\u0e49\u0e32\u0e07\u0e2b\u0e25\u0e31\u0e07", + "Delete column": "\u0e25\u0e1a\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c", + "Cell": "\u0e40\u0e0b\u0e25\u0e25\u0e4c", + "Merge cells": "\u0e1c\u0e2a\u0e32\u0e19\u0e40\u0e0b\u0e25\u0e25\u0e4c", + "Horizontal split": "\u0e41\u0e22\u0e01\u0e41\u0e19\u0e27\u0e19\u0e2d\u0e19", + "Vertical split": "\u0e41\u0e22\u0e01\u0e43\u0e19\u0e41\u0e19\u0e27\u0e15\u0e31\u0e49\u0e07", + "Cell Background": "\u0e1e\u0e37\u0e49\u0e19\u0e2b\u0e25\u0e31\u0e07\u0e02\u0e2d\u0e07\u0e40\u0e0b\u0e25\u0e25\u0e4c", + "Vertical Align": "\u0e08\u0e31\u0e14\u0e41\u0e19\u0e27\u0e15\u0e31\u0e49\u0e07", + "Top": "\u0e14\u0e49\u0e32\u0e19\u0e1a\u0e19", + "Middle": "\u0e01\u0e25\u0e32\u0e07", + "Bottom": "\u0e01\u0e49\u0e19", + "Align Top": "\u0e08\u0e31\u0e14\u0e14\u0e49\u0e32\u0e19\u0e1a\u0e19", + "Align Middle": "\u0e15\u0e4d\u0e32\u0e41\u0e2b\u0e19\u0e48\u0e07\u0e01\u0e25\u0e32\u0e07", + "Align Bottom": "\u0e15\u0e4d\u0e32\u0e41\u0e2b\u0e19\u0e48\u0e07\u0e14\u0e49\u0e32\u0e19\u0e25\u0e48\u0e32\u0e07", + "Cell Style": "\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a\u0e02\u0e2d\u0e07\u0e40\u0e0b\u0e25\u0e25\u0e4c", + + // Files + "Upload File": "\u0e2d\u0e31\u0e1b\u0e42\u0e2b\u0e25\u0e14\u0e44\u0e1f\u0e25\u0e4c", + "Drop file": "\u0e27\u0e32\u0e07\u0e44\u0e1f\u0e25\u0e4c", + + // Emoticons + "Emoticons": "\u0e2d\u0e35\u0e42\u0e21\u0e15\u0e34\u0e04\u0e2d\u0e19", + "Grinning face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e22\u0e34\u0e49\u0e21", + "Grinning face with smiling eyes": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e22\u0e34\u0e49\u0e21\u0e14\u0e49\u0e27\u0e22\u0e15\u0e32\u0e22\u0e34\u0e49\u0e21", + "Face with tears of joy": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e14\u0e49\u0e27\u0e22\u0e19\u0e49\u0e33\u0e15\u0e32\u0e41\u0e2b\u0e48\u0e07\u0e04\u0e27\u0e32\u0e21\u0e2a\u0e38\u0e02", + "Smiling face with open mouth": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e40\u0e1b\u0e37\u0e49\u0e2d\u0e19\u0e23\u0e2d\u0e22\u0e22\u0e34\u0e49\u0e21\u0e17\u0e35\u0e48\u0e21\u0e35\u0e1b\u0e32\u0e01\u0e40\u0e1b\u0e34\u0e14", + "Smiling face with open mouth and smiling eyes": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e22\u0e34\u0e49\u0e21\u0e01\u0e31\u0e1a\u0e40\u0e1b\u0e34\u0e14\u0e1b\u0e32\u0e01\u0e41\u0e25\u0e30\u0e15\u0e32\u0e22\u0e34\u0e49\u0e21", + "Smiling face with open mouth and cold sweat": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e22\u0e34\u0e49\u0e21\u0e14\u0e49\u0e27\u0e22\u0e1b\u0e32\u0e01\u0e40\u0e1b\u0e34\u0e14\u0e41\u0e25\u0e30\u0e40\u0e2b\u0e07\u0e37\u0e48\u0e2d\u0e40\u0e22\u0e47\u0e19", + "Smiling face with open mouth and tightly-closed eyes": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e22\u0e34\u0e49\u0e21\u0e01\u0e31\u0e1a\u0e40\u0e1b\u0e34\u0e14\u0e1b\u0e32\u0e01\u0e41\u0e25\u0e30\u0e15\u0e32\u0e41\u0e19\u0e48\u0e19\u0e1b\u0e34\u0e14", + "Smiling face with halo": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e22\u0e34\u0e49\u0e21\u0e17\u0e35\u0e48\u0e21\u0e35\u0e23\u0e31\u0e28\u0e21\u0e35", + "Smiling face with horns": "\u0e22\u0e34\u0e49\u0e21\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e21\u0e35\u0e40\u0e02\u0e32", + "Winking face": "\u0e01\u0e32\u0e23\u0e01\u0e23\u0e30\u0e1e\u0e23\u0e34\u0e1a\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32", + "Smiling face with smiling eyes": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e22\u0e34\u0e49\u0e21\u0e14\u0e49\u0e27\u0e22\u0e15\u0e32\u0e22\u0e34\u0e49\u0e21", + "Face savoring delicious food": "\u0e40\u0e1c\u0e0a\u0e34\u0e0d \u0073\u0061\u0076\u006f\u0072\u0069\u006e\u0067 \u0e2d\u0e32\u0e2b\u0e32\u0e23\u0e2d\u0e23\u0e48\u0e2d\u0e22", + "Relieved face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e42\u0e25\u0e48\u0e07\u0e43\u0e08", + "Smiling face with heart-shaped eyes": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e22\u0e34\u0e49\u0e21\u0e14\u0e49\u0e27\u0e22\u0e15\u0e32\u0e23\u0e39\u0e1b\u0e2b\u0e31\u0e27\u0e43\u0e08", + "Smiling face with sunglasses": "\u0e22\u0e34\u0e49\u0e21\u0e2b\u0e19\u0e49\u0e32\u0e14\u0e49\u0e27\u0e22\u0e41\u0e27\u0e48\u0e19\u0e15\u0e32\u0e01\u0e31\u0e19\u0e41\u0e14\u0e14", + "Smirking face": "\u0e2b\u0e19\u0e49\u0e32\u0e41\u0e2a\u0e22\u0e30\u0e22\u0e34\u0e49\u0e21\u0e17\u0e35\u0e48\u0e21\u0e38\u0e21", + "Neutral face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e17\u0e35\u0e48\u0e40\u0e1b\u0e47\u0e19\u0e01\u0e25\u0e32\u0e07", + "Expressionless face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e2d\u0e32\u0e23\u0e21\u0e13\u0e4c", + "Unamused face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32 \u0055\u006e\u0061\u006d\u0075\u0073\u0065\u0064", + "Face with cold sweat": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e17\u0e35\u0e48\u0e21\u0e35\u0e40\u0e2b\u0e07\u0e37\u0e48\u0e2d\u0e40\u0e22\u0e47\u0e19", + "Pensive face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e2b\u0e21\u0e48\u0e19", + "Confused face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e2a\u0e31\u0e1a\u0e2a\u0e19", + "Confounded face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e2a\u0e31\u0e1a\u0e2a\u0e19", + "Kissing face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e08\u0e39\u0e1a", + "Face throwing a kiss": "\u0e15\u0e49\u0e2d\u0e07\u0e40\u0e1c\u0e0a\u0e34\u0e0d\u0e01\u0e31\u0e1a\u0e01\u0e32\u0e23\u0e02\u0e27\u0e49\u0e32\u0e07\u0e1b\u0e32\u0e08\u0e39\u0e1a", + "Kissing face with smiling eyes": "\u0e08\u0e39\u0e1a\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e14\u0e49\u0e27\u0e22\u0e15\u0e32\u0e22\u0e34\u0e49\u0e21", + "Kissing face with closed eyes": "\u0e08\u0e39\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e14\u0e49\u0e27\u0e22\u0e14\u0e27\u0e07\u0e15\u0e32\u0e17\u0e35\u0e48\u0e1b\u0e34\u0e14\u0e2a\u0e19\u0e34\u0e17", + "Face with stuck out tongue": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e21\u0e35\u0e41\u0e1e\u0e25\u0e21\u0e2d\u0e2d\u0e01\u0e21\u0e32\u0e25\u0e34\u0e49\u0e19", + "Face with stuck out tongue and winking eye": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e21\u0e35\u0e15\u0e34\u0e14\u0e25\u0e34\u0e49\u0e19\u0e41\u0e25\u0e30\u0e15\u0e32\u0e02\u0e22\u0e34\u0e1a\u0e15\u0e32", + "Face with stuck out tongue and tightly-closed eyes": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e21\u0e35\u0e15\u0e34\u0e14\u0e25\u0e34\u0e49\u0e19\u0e41\u0e25\u0e30\u0e14\u0e27\u0e07\u0e15\u0e32\u0e17\u0e35\u0e48\u0e1b\u0e34\u0e14\u0e41\u0e19\u0e48\u0e19", + "Disappointed face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e1c\u0e34\u0e14\u0e2b\u0e27\u0e31\u0e07", + "Worried face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e01\u0e31\u0e07\u0e27\u0e25", + "Angry face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e42\u0e01\u0e23\u0e18", + "Pouting face": "\u0e2b\u0e19\u0e49\u0e32\u0e21\u0e38\u0e48\u0e22", + "Crying face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e23\u0e49\u0e2d\u0e07\u0e44\u0e2b\u0e49", + "Persevering face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e40\u0e2d\u0e32\u0e16\u0e48\u0e32\u0e19", + "Face with look of triumph": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e01\u0e31\u0e1a\u0e23\u0e39\u0e1b\u0e25\u0e31\u0e01\u0e29\u0e13\u0e4c\u0e02\u0e2d\u0e07\u0e0a\u0e31\u0e22\u0e0a\u0e19\u0e30", + "Disappointed but relieved face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e1c\u0e34\u0e14\u0e2b\u0e27\u0e31\u0e07 \u0e41\u0e15\u0e48\u0e42\u0e25\u0e48\u0e07\u0e43\u0e08", + "Frowning face with open mouth": "\u0e2b\u0e19\u0e49\u0e32\u0e21\u0e38\u0e48\u0e22\u0e17\u0e35\u0e48\u0e21\u0e35\u0e1b\u0e32\u0e01\u0e40\u0e1b\u0e34\u0e14", + "Anguished face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e01\u0e14\u0e02\u0e35\u0e48", + "Fearful face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e17\u0e35\u0e48\u0e19\u0e48\u0e32\u0e01\u0e25\u0e31\u0e27", + "Weary face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e17\u0e35\u0e48\u0e40\u0e2b\u0e19\u0e37\u0e48\u0e2d\u0e22\u0e25\u0e49\u0e32", + "Sleepy face": "\u0e2b\u0e19\u0e49\u0e32\u0e07\u0e48\u0e27\u0e07\u0e19\u0e2d\u0e19", + "Tired face": "\u0e2b\u0e19\u0e49\u0e32\u0e40\u0e1a\u0e37\u0e48\u0e2d", + "Grimacing face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32 \u0067\u0072\u0069\u006d\u0061\u0063\u0069\u006e\u0067", + "Loudly crying face": "\u0e23\u0e49\u0e2d\u0e07\u0e44\u0e2b\u0e49\u0e40\u0e2a\u0e35\u0e22\u0e07\u0e14\u0e31\u0e07\u0e2b\u0e19\u0e49\u0e32", + "Face with open mouth": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e17\u0e35\u0e48\u0e21\u0e35\u0e1b\u0e32\u0e01\u0e40\u0e1b\u0e34\u0e14", + "Hushed face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e40\u0e07\u0e35\u0e22\u0e1a", + "Face with open mouth and cold sweat": "หน้ากับปากเปิดและเหงื่อเย็น", + "Face screaming in fear": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e17\u0e35\u0e48\u0e21\u0e35\u0e1b\u0e32\u0e01\u0e40\u0e1b\u0e34\u0e14\u0e41\u0e25\u0e30\u0e40\u0e2b\u0e07\u0e37\u0e48\u0e2d\u0e40\u0e22\u0e47\u0e19", + "Astonished face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e1b\u0e23\u0e30\u0e2b\u0e25\u0e32\u0e14\u0e43\u0e08", + "Flushed face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e41\u0e14\u0e07", + "Sleeping face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e19\u0e2d\u0e19", + "Dizzy face": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e15\u0e32\u0e25\u0e32\u0e22", + "Face without mouth": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e42\u0e14\u0e22\u0e44\u0e21\u0e48\u0e15\u0e49\u0e2d\u0e07\u0e1b\u0e32\u0e01", + "Face with medical mask": "\u0e43\u0e1a\u0e2b\u0e19\u0e49\u0e32\u0e14\u0e49\u0e27\u0e22\u0e2b\u0e19\u0e49\u0e32\u0e01\u0e32\u0e01\u0e17\u0e32\u0e07\u0e01\u0e32\u0e23\u0e41\u0e1e\u0e17\u0e22\u0e4c", + + // Line breaker + "Break": "\u0e2b\u0e22\u0e38\u0e14", + + // Math + "Subscript": "\u0e15\u0e31\u0e27\u0e2b\u0e49\u0e2d\u0e22", + "Superscript": "\u0e15\u0e31\u0e27\u0e22\u0e01", + + // Full screen + "Fullscreen": "\u0e40\u0e15\u0e47\u0e21\u0e2b\u0e19\u0e49\u0e32\u0e08\u0e2d", + + // Horizontal line + "Insert Horizontal Line": "\u0e41\u0e17\u0e23\u0e01\u0e40\u0e2a\u0e49\u0e19\u0e41\u0e19\u0e27\u0e19\u0e2d\u0e19", + + // Clear formatting + "Clear Formatting": "\u0e19\u0e33\u0e01\u0e32\u0e23\u0e08\u0e31\u0e14\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a", + + // Save + "Save": "\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01", + + // Undo, redo + "Undo": "\u0e40\u0e25\u0e34\u0e01\u0e17\u0e33", + "Redo": "\u0e17\u0e4d\u0e32\u0e0b\u0e49\u0e33", + + // Select all + "Select All": "\u0e40\u0e25\u0e37\u0e2d\u0e01\u0e17\u0e31\u0e49\u0e07\u0e2b\u0e21\u0e14", + + // Code view + "Code View": "\u0e21\u0e38\u0e21\u0e21\u0e2d\u0e07\u0e23\u0e2b\u0e31\u0e2a", + + // Quote + "Quote": "\u0e2d\u0e49\u0e32\u0e07", + "Increase": "\u0e40\u0e1e\u0e34\u0e48\u0e21", + "Decrease": "\u0e25\u0e14\u0e25\u0e07", + + // Quick Insert + "Quick Insert": "\u0e41\u0e17\u0e23\u0e01\u0e14\u0e48\u0e27\u0e19", + + // Spcial Characters + "Special Characters": "อักขระพิเศษ", + "Latin": "ละติน", + "Greek": "กรีก", + "Cyrillic": "ริลลิก", + "Punctuation": "วรรคตอน", + "Currency": "เงินตรา", + "Arrows": "ลูกศร", + "Math": "คณิตศาสตร์", + "Misc": "อื่น ๆ", + + // Print. + "Print": "พิมพ์", + + // Spell Checker. + "Spell Checker": "ตัวตรวจสอบการสะกด", + + // Help + "Help": "ช่วยด้วย", + "Shortcuts": "ทางลัด", + "Inline Editor": "ตัวแก้ไขแบบอินไลน์", + "Show the editor": "แสดงตัวแก้ไข", + "Common actions": "การกระทำร่วมกัน", + "Copy": "สำเนา", + "Cut": "ตัด", + "Paste": "แปะ", + "Basic Formatting": "การจัดรูปแบบพื้นฐาน", + "Increase quote level": "ระดับราคาเพิ่มขึ้น", + "Decrease quote level": "ระดับราคาลดลง", + "Image / Video": "ภาพ / วิดีโอ", + "Resize larger": "ปรับขนาดใหญ่ขึ้น", + "Resize smaller": "ปรับขนาดเล็กลง", + "Table": "ตาราง", + "Select table cell": "เลือกเซลล์ตาราง", + "Extend selection one cell": "ขยายการเลือกหนึ่งเซลล์", + "Extend selection one row": "ขยายการเลือกหนึ่งแถว", + "Navigation": "การเดินเรือ", + "Focus popup / toolbar": "โฟกัสป๊อปอัพ / แถบเครื่องมือ", + "Return focus to previous position": "กลับไปยังตำแหน่งก่อนหน้า", + + // Embed.ly + "Embed URL": "ฝัง URL", + "Paste in a URL to embed": "วางใน url เพื่อฝัง", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "เนื้อหาที่วางจะมาจากเอกสารคำในแบบ microsoft คุณต้องการเก็บรูปแบบหรือทำความสะอาดหรือไม่?", + "Keep": "เก็บ", + "Clean": "สะอาด", + "Word Paste Detected": "ตรวจพบการวางคำ" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/tr.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/tr.js new file mode 100644 index 0000000..0fdf186 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/tr.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Turkish + */ + +$.FE.LANGUAGE['tr'] = { + translation: { + // Place holder + "Type something": "Bir \u015fey yaz\u0131n", + + // Basic formatting + "Bold": "Kal\u0131n", + "Italic": "\u0130talik", + "Underline": "Alt\u0131 \u00e7izili", + "Strikethrough": "\u00dcst\u00fc \u00e7izili", + + // Main buttons + "Insert": "Ekle", + "Delete": "Silmek", + "Cancel": "\u0130ptal", + "OK": "Tamam", + "Back": "Geri", + "Remove": "Kald\u0131r", + "More": "Daha", + "Update": "G\u00fcncelle\u015ftirme", + "Style": "Stil", + + // Font + "Font Family": "Yaz\u0131tipi Ailesi", + "Font Size": "Yaz\u0131tipi B\u00fcy\u00fckl\u00fc\u011f\u00fc", + + // Colors + "Colors": "Renkler", + "Background": "Arkaplan", + "Text": "Metin", + "HEX Color": "Altı renkli", + + // Paragraphs + "Paragraph Format": "Bi\u00e7imler", + "Normal": "Normal", + "Code": "Kod", + "Heading 1": "Ba\u015fl\u0131k 1", + "Heading 2": "Ba\u015fl\u0131k 2", + "Heading 3": "Ba\u015fl\u0131k 3", + "Heading 4": "Ba\u015fl\u0131k 4", + + // Style + "Paragraph Style": "Paragraf stili", + "Inline Style": "\u00c7izgide stili", + + // Alignment + "Align": "Hizalama", + "Align Left": "Sola hizala", + "Align Center": "Ortala", + "Align Right": "Sa\u011fa hizala", + "Align Justify": "\u0130ki yana yasla", + "None": "Hi\u00e7biri", + + // Lists + "Ordered List": "S\u0131ral\u0131 liste", + "Default": "Varsayılan", + "Lower Alpha": "Alt alfa", + "Lower Greek": "Alt yunan", + "Lower Roman": "Alt roma", + "Upper Alpha": "Üst alfa", + "Upper Roman": "Üst roma", + + "Unordered List": "S\u0131ras\u0131z liste", + "Circle": "Daire", + "Disc": "Disk", + "Square": "Kare", + + // Line height + "Line Height": "Satır yüksekliği", + "Single": "Tek", + "Double": "Çift", + + // Indent + "Decrease Indent": "Girintiyi azalt", + "Increase Indent": "Girintiyi art\u0131r", + + // Links + "Insert Link": "Ba\u011flant\u0131 ekle", + "Open in new tab": "Yeni sekmede a\u00e7", + "Open Link": "Linki a\u00e7", + "Edit Link": "D\u00fczenleme ba\u011flant\u0131s\u0131", + "Unlink": "Ba\u011flant\u0131y\u0131 kald\u0131r", + "Choose Link": "Ba\u011flant\u0131y\u0131 se\u00e7in", + + // Images + "Insert Image": "Resim ekle", + "Upload Image": "Y\u00fckleme g\u00f6r\u00fcnt\u00fcs\u00fc", + "By URL": "URL'ye g\u00f6re", + "Browse": "G\u00f6zat", + "Drop image": "B\u0131rak resim", + "or click": "ya da t\u0131klay\u0131n", + "Manage Images": "G\u00f6r\u00fcnt\u00fcleri y\u00f6netin", + "Loading": "Y\u00fckleniyor", + "Deleting": "Silme", + "Tags": "Etiketler", + "Are you sure? Image will be deleted.": "Emin misin? Resim silinecektir.", + "Replace": "De\u011fi\u015ftirmek", + "Uploading": "Y\u00fckleme", + "Loading image": "Y\u00fckleme g\u00f6r\u00fcnt\u00fcs\u00fc", + "Display": "G\u00f6stermek", + "Inline": "\u00c7izgide", + "Break Text": "K\u0131r\u0131lma metni", + "Alternative Text": "Alternatif metin", + "Change Size": "De\u011fi\u015fim boyutu", + "Width": "Geni\u015flik", + "Height": "Y\u00fckseklik", + "Something went wrong. Please try again.": "Bir \u015feyler yanl\u0131\u015f gitti. L\u00fctfen tekrar deneyin.", + "Image Caption": "Resim yazısı", + "Advanced Edit": "Ileri düzey düzenleme", + + // Video + "Insert Video": "Video ekle", + "Embedded Code": "G\u00f6m\u00fcl\u00fc kod", + "Paste in a video URL": "Bir video URL'sine yapıştırın", + "Drop video": "Video bırak", + "Your browser does not support HTML5 video.": "Tarayıcınız html5 videoyu desteklemez.", + "Upload Video": "Video yükle", + + // Tables + "Insert Table": "Tablo ekle", + "Table Header": "Tablo \u00fcstbilgisi", + "Remove Table": "Tablo kald\u0131rma", + "Table Style": "Tablo stili", + "Horizontal Align": "Yatay hizalama", + "Row": "Sat\u0131r", + "Insert row above": "\u00d6ncesine yeni sat\u0131r ekle", + "Insert row below": "Sonras\u0131na yeni sat\u0131r ekle", + "Delete row": "Sat\u0131r\u0131 sil", + "Column": "S\u00fctun", + "Insert column before": "\u00d6ncesine yeni s\u00fctun ekle", + "Insert column after": "Sonras\u0131na yeni s\u00fctun ekle", + "Delete column": "S\u00fctunu sil", + "Cell": "H\u00fccre", + "Merge cells": "H\u00fccreleri birle\u015ftir", + "Horizontal split": "Yatay b\u00f6l\u00fcnm\u00fc\u015f", + "Vertical split": "Dikey b\u00f6l\u00fcnm\u00fc\u015f", + "Cell Background": "H\u00fccre arka plan\u0131", + "Vertical Align": "Dikey hizalama", + "Top": "\u00dcst", + "Middle": "Orta", + "Bottom": "Alt", + "Align Top": "\u00dcst hizalama", + "Align Middle": "Orta hizalama", + "Align Bottom": "Dibe hizalama", + "Cell Style": "H\u00fccre stili", + + // Files + "Upload File": "Dosya Y\u00fckle", + "Drop file": "B\u0131rak dosya", + + // Emoticons + "Emoticons": "\u0130fadeler", + "Grinning face": "S\u0131r\u0131tan y\u00fcz", + "Grinning face with smiling eyes": "G\u00fclen g\u00f6zlerle y\u00fcz s\u0131r\u0131tarak", + "Face with tears of joy": "Sevin\u00e7 g\u00f6zya\u015flar\u0131yla Y\u00fcz", + "Smiling face with open mouth": "A\u00e7\u0131k a\u011fz\u0131 ile g\u00fcl\u00fcmseyen y\u00fcz\u00fc", + "Smiling face with open mouth and smiling eyes": "A\u00e7\u0131k a\u011fzı ve g\u00fcl\u00fcmseyen g\u00f6zlerle g\u00fcler y\u00fcz", + "Smiling face with open mouth and cold sweat": "A\u00e7\u0131k a\u011fz\u0131 ve so\u011fuk ter ile g\u00fclen y\u00fcz\u00fc", + "Smiling face with open mouth and tightly-closed eyes": "A\u00e7\u0131k a\u011fz\u0131 s\u0131k\u0131ca kapal\u0131 g\u00f6zlerle g\u00fclen y\u00fcz\u00fc", + "Smiling face with halo": "Halo ile y\u00fcz g\u00fclen", + "Smiling face with horns": "Boynuzlar\u0131 ile g\u00fcler y\u00fcz", + "Winking face": "G\u00f6z a\u00e7\u0131p kapay\u0131ncaya y\u00fcz\u00fc", + "Smiling face with smiling eyes": "G\u00fclen g\u00f6zlerle g\u00fcler Y\u00fcz", + "Face savoring delicious food": "Lezzetli yemekler tad\u0131n\u0131 Y\u00fcz", + "Relieved face": "Rahatlad\u0131m y\u00fcz\u00fc", + "Smiling face with heart-shaped eyes": "Kalp \u015feklinde g\u00f6zlerle g\u00fcler y\u00fcz", + "Smiling face with sunglasses": "Kalp \u015feklinde g\u00f6zlerle g\u00fcler y\u00fcz", + "Smirking face": "S\u0131r\u0131tan y\u00fcz", + "Neutral face": "N\u00f6tr y\u00fcz", + "Expressionless face": "Ifadesiz y\u00fcz\u00fc", + "Unamused face": "Kay\u0131ts\u0131z y\u00fcz\u00fc", + "Face with cold sweat": "So\u011fuk terler Y\u00fcz", + "Pensive face": "dalg\u0131n bir y\u00fcz", + "Confused face": "\u015fa\u015fk\u0131n bir y\u00fcz", + "Confounded face": "Ele\u015ftirilmi\u015ftir y\u00fcz\u00fc", + "Kissing face": "\u00f6p\u00fc\u015fme y\u00fcz\u00fc", + "Face throwing a kiss": "Bir \u00f6p\u00fcc\u00fck atma Y\u00fcz", + "Kissing face with smiling eyes": "G\u00fclen g\u00f6zlerle y\u00fcz \u00f6p\u00fc\u015fme", + "Kissing face with closed eyes": "Kapal\u0131 g\u00f6zlerle \u00f6p\u00f6\u015fme y\u00fcz", + "Face with stuck out tongue": "Dilini y\u00fcz ile s\u0131k\u0131\u015fm\u0131\u015f", + "Face with stuck out tongue and winking eye": "\u015ea\u015f\u0131r\u0131p kalm\u0131\u015f d\u0131\u015far\u0131 dil ve g\u00f6z k\u0131rpan y\u00fcz", + "Face with stuck out tongue and tightly-closed eyes": "Y\u00fcz ile dil ve s\u0131k\u0131ca kapal\u0131 g\u00f6zleri s\u0131k\u0131\u015fm\u0131\u015f", + "Disappointed face": "Hayal k\u0131r\u0131kl\u0131\u011f\u0131na y\u00fcz\u00fc", + "Worried face": "Endi\u015feli bir y\u00fcz", + "Angry face": "K\u0131zg\u0131n y\u00fcz", + "Pouting face": "Somurtarak y\u00fcz\u00fc", + "Crying face": "A\u011flayan y\u00fcz", + "Persevering face": "Azmeden y\u00fcz\u00fc", + "Face with look of triumph": "Zafer bak\u0131\u015fla Y\u00fcz", + "Disappointed but relieved face": "Hayal k\u0131r\u0131kl\u0131\u011f\u0131 ama rahatlad\u0131m y\u00fcz", + "Frowning face with open mouth": "A\u00e7\u0131k a\u011fz\u0131 ile \u00e7at\u0131k y\u00fcz\u00fc", + "Anguished face": "Kederli y\u00fcz", + "Fearful face": "Korkulu y\u00fcz\u00fc", + "Weary face": "Yorgun y\u00fcz\u00fc", + "Sleepy face": "Uykulu y\u00fcz\u00fc", + "Tired face": "Yorgun y\u00fcz\u00fc", + "Grimacing face": "Y\u00fcz\u00fcn\u00fc buru\u015fturarak y\u00fcz\u00fc", + "Loudly crying face": "Y\u00fcksek sesle y\u00fcz\u00fc a\u011fl\u0131yor", + "Face with open mouth": "A\u00e7\u0131k a\u011fz\u0131 ile Y\u00fcz", + "Hushed face": "Dingin y\u00fcz\u00fc", + "Face with open mouth and cold sweat": "A\u00e7\u0131k a\u011fz\u0131 ve so\u011fuk ter ile Y\u00fcz", + "Face screaming in fear": "Korku i\u00e7inde \u00e7ı\u011fl\u0131k Y\u00fcz", + "Astonished face": "\u015fa\u015fk\u0131n bir y\u00fcz", + "Flushed face": "K\u0131zarm\u0131\u015f y\u00fcz\u00fc", + "Sleeping face": "Uyuyan y\u00fcz\u00fc", + "Dizzy face": "Ba\u015f\u0131m d\u00f6nd\u00fc y\u00fcz", + "Face without mouth": "A\u011f\u0131z olmadan Y\u00fcz", + "Face with medical mask": "T\u0131bbi maske ile y\u00fcz", + + // Line breaker + "Break": "K\u0131r\u0131lma", + + // Math + "Subscript": "Alt simge", + "Superscript": "\u00dcst simge", + + // Full screen + "Fullscreen": "Tam ekran", + + // Horizontal line + "Insert Horizontal Line": "Yatay \u00e7izgi ekleme", + + // Clear formatting + "Clear Formatting": "Bi\u00e7imlendirme kald\u0131r", + + // Save + "Save": "Kayıt etmek", + + // Undo, redo + "Undo": "Geri Al", + "Redo": "Yinele", + + // Select all + "Select All": "T\u00fcm\u00fcn\u00fc se\u00e7", + + // Code view + "Code View": "Kod g\u00f6r\u00fcn\u00fcm\u00fc", + + // Quote + "Quote": "Al\u0131nt\u0131", + "Increase": "Art\u0131rmak", + "Decrease": "Azal\u0131\u015f", + + // Quick Insert + "Quick Insert": "H\u0131zl\u0131 insert", + + // Spcial Characters + "Special Characters": "Özel karakterler", + "Latin": "Latince", + "Greek": "Yunan", + "Cyrillic": "Kiril", + "Punctuation": "Noktalama", + "Currency": "Para birimi", + "Arrows": "Oklar", + "Math": "Matematik", + "Misc": "Misc", + + // Print. + "Print": "Baskı", + + // Spell Checker. + "Spell Checker": "Yazım denetleyicisi", + + // Help + "Help": "Yardım et", + "Shortcuts": "Kısayollar", + "Inline Editor": "Satır içi düzenleyici", + "Show the editor": "Editörü gösterin", + "Common actions": "Ortak eylemler", + "Copy": "Kopya", + "Cut": "Kesim", + "Paste": "Yapıştırmak", + "Basic Formatting": "Temel biçimlendirme", + "Increase quote level": "Teklif seviyesini yükselt", + "Decrease quote level": "Teklif seviyesini azalt", + "Image / Video": "Resim / video", + "Resize larger": "Daha büyük yeniden boyutlandır", + "Resize smaller": "Daha küçük boyuta getir", + "Table": "Tablo", + "Select table cell": "Tablo hücresi seç", + "Extend selection one cell": "Seçimi bir hücre genişlet", + "Extend selection one row": "Seçimi bir sıra genişlet", + "Navigation": "Navigasyon", + "Focus popup / toolbar": "Odaklanma açılır penceresi / araç çubuğu", + "Return focus to previous position": "Odaklamaya önceki konumuna geri dönün", + + // Embed.ly + "Embed URL": "URL göm", + "Paste in a URL to embed": "Yerleştirmek için bir URL'ye yapıştırın", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Yapıştırılan içerik bir Microsoft Word belgesinden geliyor. Biçimi saklamaya mı yoksa temizlemeyi mi istiyor musun?", + "Keep": "Tutmak", + "Clean": "Temiz", + "Word Paste Detected": "Kelime yapıştırması algılandı" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/uk.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/uk.js new file mode 100644 index 0000000..db36466 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/uk.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Ukrainian + */ + +$.FE.LANGUAGE['uk'] = { + translation: { + // Place holder + "Type something": "\u041d\u0430\u043f\u0438\u0448\u0456\u0442\u044c \u0431\u0443\u0434\u044c-\u0449\u043e", + + // Basic formatting + "Bold": "\u0416\u0438\u0440\u043d\u0438\u0439", + "Italic": "\u041a\u0443\u0440\u0441\u0438\u0432", + "Underline": "\u041f\u0456\u0434\u043a\u0440\u0435\u0441\u043b\u0435\u043d\u0438\u0439", + "Strikethrough": "\u0417\u0430\u043a\u0440\u0435\u0441\u043b\u0435\u043d\u0438\u0439", + + // Main buttons + "Insert": "\u0432\u0441\u0442\u0430\u0432\u0438\u0442\u0438", + "Delete": "\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438", + "Cancel": "\u0421\u043a\u0430\u0441\u0443\u0432\u0430\u0442\u0438", + "OK": "OK", + "Back": "\u043d\u0430\u0437\u0430\u0434", + "Remove": "\u0432\u0438\u0434\u0430\u043b\u0438\u0442\u0438", + "More": "\u0431\u0456\u043b\u044c\u0448\u0435", + "Update": "\u043e\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044f", + "Style": "\u0441\u0442\u0438\u043b\u044c", + + // Font + "Font Family": "\u0428\u0440\u0438\u0444\u0442", + "Font Size": "\u0420\u043e\u0437\u043c\u0456\u0440 \u0448\u0440\u0438\u0444\u0442\u0443", + + // Colors + "Colors": "\u043a\u043e\u043b\u044c\u043e\u0440\u0438", + "Background": "\u0424\u043e\u043d", + "Text": "\u0422\u0435\u043a\u0441\u0442", + "HEX Color": "Шістнадцятковий колір", + + // Paragraphs + "Paragraph Format": "\u0424\u043e\u0440\u043c\u0430\u0442", + "Normal": "\u041d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u0438\u0439", + "Code": "\u041a\u043e\u0434", + "Heading 1": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 1", + "Heading 2": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 2", + "Heading 3": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 3", + "Heading 4": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 4", + + // Style + "Paragraph Style": "\u043f\u0443\u043d\u043a\u0442 \u0441\u0442\u0438\u043b\u044c", + "Inline Style": "\u0432\u0431\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u0442\u0438\u043b\u044c", + + // Alignment + "Align": "\u0412\u0438\u0440\u0456\u0432\u043d\u044e\u0432\u0430\u043d\u043d\u044f", + "Align Left": "\u041f\u043e \u043b\u0456\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e", + "Align Center": "\u041f\u043e \u0446\u0435\u043d\u0442\u0440\u0443", + "Align Right": "\u041f\u043e \u043f\u0440\u0430\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e", + "Align Justify": "\u041f\u043e \u0448\u0438\u0440\u0438\u043d\u0456", + "None": "\u043d\u0456", + + // Lists + "Ordered List": "\u041d\u0443\u043c\u0435\u0440\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a", + "Default": "За замовчуванням", + "Lower Alpha": "Нижня альфа", + "Lower Greek": "Нижній грецький", + "Lower Roman": "Нижній римський", + "Upper Alpha": "Верхня альфа", + "Upper Roman": "Верхній римський", + + "Unordered List": "\u041c\u0430\u0440\u043a\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a", + "Circle": "Коло", + "Disc": "Диск", + "Square": "Площа", + + // Line height + "Line Height": "Висота рядка", + "Single": "Одномісний", + "Double": "Подвійний", + + // Indent + "Decrease Indent": "\u0417\u043c\u0435\u043d\u0448\u0438\u0442\u0438 \u0432\u0456\u0434\u0441\u0442\u0443\u043f", + "Increase Indent": "\u0417\u0431\u0456\u043b\u044c\u0448\u0438\u0442\u0438 \u0432\u0456\u0434\u0441\u0442\u0443\u043f", + + // Links + "Insert Link": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f", + "Open in new tab": "\u0412\u0456\u0434\u043a\u0440\u0438\u0442\u0438 \u0432 \u043d\u043e\u0432\u0456\u0439 \u0432\u043a\u043b\u0430\u0434\u0446\u0456", + "Open Link": "\u0432\u0456\u0434\u043a\u0440\u0438\u0442\u0438 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f", + "Edit Link": "\u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f", + "Unlink": "\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f", + "Choose Link": "\u0412\u0438\u0431\u0435\u0440\u0456\u0442\u044c \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f", + + // Images + "Insert Image": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f", + "Upload Image": "\u0417\u0430\u0432\u0430\u043d\u0442\u0430\u0436\u0438\u0442\u0438 \u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f", + "By URL": "\u0437\u0430 URL", + "Browse": "\u043f\u0435\u0440\u0435\u0433\u043b\u044f\u0434\u0430\u0442\u0438", + "Drop image": "\u041f\u0435\u0440\u0435\u043c\u0456\u0441\u0442\u0456\u0442\u044c \u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f \u0441\u044e\u0434\u0438", + "or click": "\u0430\u0431\u043e \u043d\u0430\u0442\u0438\u0441\u043d\u0456\u0442\u044c", + "Manage Images": "\u041a\u0435\u0440\u0443\u0432\u0430\u043d\u043d\u044f \u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f\u043c\u0438", + "Loading": "\u0417\u0430\u0432\u0430\u043d\u0442\u0430\u0436\u0435\u043d\u043d\u044f", + "Deleting": "\u0432\u0438\u0434\u0430\u043b\u0435\u043d\u043d\u044f", + "Tags": "\u043a\u043b\u044e\u0447\u043e\u0432\u0456 \u0441\u043b\u043e\u0432\u0430", + "Are you sure? Image will be deleted.": "\u0412\u0438 \u0432\u043f\u0435\u0432\u043d\u0435\u043d\u0456? \u0417\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f \u0431\u0443\u0434\u0435 \u0432\u0438\u0434\u0430\u043b\u0435\u043d\u043e.", + "Replace": "\u0437\u0430\u043c\u0456\u043d\u044e\u0432\u0430\u0442\u0438", + "Uploading": "\u0417\u0430\u0432\u0430\u043d\u0442\u0430\u0436\u0435\u043d\u043d\u044f", + "Loading image": "\u0417\u0430\u0432\u0430\u043d\u0442\u0430\u0436\u0435\u043d\u043d\u044f \u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u044c", + "Display": "\u0434\u0438\u0441\u043f\u043b\u0435\u0439", + "Inline": "\u0412 \u043b\u0456\u043d\u0456\u044e", + "Break Text": "\u043f\u0435\u0440\u0435\u0440\u0432\u0430 \u0442\u0435\u043a\u0441\u0442", + "Alternative Text": "\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u0438\u0439 \u0442\u0435\u043a\u0441\u0442", + "Change Size": "\u0437\u043c\u0456\u043d\u0438\u0442\u0438 \u0440\u043e\u0437\u043c\u0456\u0440", + "Width": "\u0428\u0438\u0440\u0438\u043d\u0430", + "Height": "\u0412\u0438\u0441\u043e\u0442\u0430", + "Something went wrong. Please try again.": "\u0429\u043e\u0441\u044c \u043f\u0456\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a. \u0411\u0443\u0434\u044c \u043b\u0430\u0441\u043a\u0430 \u0441\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0449\u0435 \u0440\u0430\u0437.", + "Image Caption": "Заголовок зображення", + "Advanced Edit": "Розширений редагування", + + // Video + "Insert Video": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0432\u0456\u0434\u0435\u043e", + "Embedded Code": "\u0432\u0431\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0439 \u043a\u043e\u0434", + "Paste in a video URL": "Вставте в відео-URL", + "Drop video": "Перетягніть відео", + "Your browser does not support HTML5 video.": "Ваш браузер не підтримує відео html5.", + "Upload Video": "Завантажити відео", + + // Tables + "Insert Table": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044e", + "Table Header": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0442\u0430\u0431\u043b\u0438\u0446\u0456", + "Remove Table": "\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0456", + "Table Style": "\u0421\u0442\u0438\u043b\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0456", + "Horizontal Align": "\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0435 \u0432\u0438\u0440\u0456\u0432\u043d\u044e\u0432\u0430\u043d\u043d\u044f", + "Row": "\u0420\u044f\u0434\u043e\u043a", + "Insert row above": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u043f\u043e\u0440\u043e\u0436\u043d\u0456\u0439 \u0440\u044f\u0434\u043e\u043a \u0437\u0432\u0435\u0440\u0445\u0443", + "Insert row below": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u043f\u043e\u0440\u043e\u0436\u043d\u0456\u0439 \u0440\u044f\u0434\u043e\u043a \u0437\u043d\u0438\u0437\u0443", + "Delete row": "\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0440\u044f\u0434\u043e\u043a", + "Column": "\u0421\u0442\u043e\u0432\u043f\u0435\u0446\u044c", + "Insert column before": "\u0414\u043e\u0434\u0430\u0442\u0438 \u0441\u0442\u043e\u0432\u043f\u0435\u0446\u044c \u043b\u0456\u0432\u043e\u0440\u0443\u0447", + "Insert column after": "\u0414\u043e\u0434\u0430\u0442\u0438 \u0441\u0442\u043e\u0432\u043f\u0435\u0446\u044c \u043f\u0440\u0430\u0432\u043e\u0440\u0443\u0447", + "Delete column": "\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0441\u0442\u043e\u0432\u043f\u0435\u0446\u044c", + "Cell": "\u041a\u043e\u043c\u0456\u0440\u043a\u0430", + "Merge cells": "\u041e\u0431'\u0454\u0434\u043d\u0430\u0442\u0438 \u043a\u043e\u043c\u0456\u0440\u043a\u0438", + "Horizontal split": "\u0420\u043e\u0437\u0434\u0456\u043b\u0438\u0442\u0438 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e", + "Vertical split": "\u0420\u043e\u0437\u0434\u0456\u043b\u0438\u0442\u0438 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u043e", + "Cell Background": "\u0441\u0442\u0456\u043b\u044c\u043d\u0438\u043a\u043e\u0432\u0438\u0439 \u0444\u043e\u043d", + "Vertical Align": "\u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u0430 \u0432\u0438\u0440\u0456\u0432\u043d\u044e\u0432\u0430\u043d\u043d\u044f", + "Top": "\u0422\u043e\u043f", + "Middle": "\u0441\u0435\u0440\u0435\u0434\u043d\u0456\u0439", + "Bottom": "\u0434\u043d\u043e", + "Align Top": "\u0417\u0456\u0441\u0442\u0430\u0432\u0442\u0435 \u0432\u0435\u0440\u0445\u043d\u044e", + "Align Middle": "\u0432\u0438\u0440\u0456\u0432\u043d\u044f\u0442\u0438 \u043f\u043e \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0456", + "Align Bottom": "\u0417\u0456\u0441\u0442\u0430\u0432\u0442\u0435 \u043d\u0438\u0436\u043d\u044e", + "Cell Style": "\u0441\u0442\u0438\u043b\u044c \u043a\u043e\u043c\u0456\u0440\u043a\u0438", + + // Files + "Upload File": "\u0417\u0430\u0432\u0430\u043d\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043b", + "Drop file": "\u041f\u0435\u0440\u0435\u043c\u0456\u0441\u0442\u0456\u0442\u044c \u0444\u0430\u0439\u043b \u0441\u044e\u0434\u0438", + + // Emoticons + "Emoticons": "\u0441\u043c\u0430\u0439\u043b\u0438", + "Grinning face": "\u043f\u043e\u0441\u043c\u0456\u0445\u043d\u0443\u0432\u0448\u0438\u0441\u044c \u043e\u0441\u043e\u0431\u0430", + "Grinning face with smiling eyes": "\u041f\u043e\u0441\u043c\u0456\u0445\u043d\u0443\u0432\u0448\u0438\u0441\u044c \u043e\u0441\u043e\u0431\u0430 \u0437 \u0443\u0441\u043c\u0456\u0445\u043d\u0435\u043d\u0438\u043c\u0438 \u043e\u0447\u0438\u043c\u0430", + "Face with tears of joy": "\u041e\u0431\u043b\u0438\u0447\u0447\u044f \u0437\u0456 \u0441\u043b\u044c\u043e\u0437\u0430\u043c\u0438 \u0440\u0430\u0434\u043e\u0441\u0442\u0456", + "Smiling face with open mouth": "\u0423\u0441\u043c\u0456\u0445\u043d\u0435\u043d\u0435 \u043e\u0431\u043b\u0438\u0447\u0447\u044f \u0437 \u0432\u0456\u0434\u043a\u0440\u0438\u0442\u0438\u043c \u0440\u043e\u0442\u043e\u043c", + "Smiling face with open mouth and smiling eyes": "\u041f\u043e\u0441\u043c\u0456\u0445\u0430\u044e\u0447\u0438\u0441\u044c \u043e\u0441\u043e\u0431\u0430 \u0437 \u0432\u0456\u0434\u043a\u0440\u0438\u0442\u0438\u043c \u0440\u043e\u0442\u043e\u043c \u0456 ", + "Smiling face with open mouth and cold sweat": "\u041f\u043e\u0441\u043c\u0456\u0445\u0430\u044e\u0447\u0438\u0441\u044c \u043e\u0441\u043e\u0431\u0430 \u0437 \u0432\u0456\u0434\u043a\u0440\u0438\u0442\u0438\u043c \u0440\u043e\u0442\u043e\u043c \u0456 ", + "Smiling face with open mouth and tightly-closed eyes": "\u041f\u043e\u0441\u043c\u0456\u0445\u0430\u044e\u0447\u0438\u0441\u044c \u043e\u0441\u043e\u0431\u0430 \u0437 \u0432\u0456\u0434\u043a\u0440\u0438\u0442\u0438\u043c \u0440\u043e\u0442\u043e\u043c \u0456 \u0449\u0456\u043b\u044c\u043d\u043e \u0437\u0430\u043a\u0440\u0438\u0442\u0438\u043c\u0438 \u043e\u0447\u0438\u043c\u0430", + "Smiling face with halo": "\u041f\u043e\u0441\u043c\u0456\u0445\u0430\u044e\u0447\u0438\u0441\u044c \u043e\u0441\u043e\u0431\u0430 \u0433\u0430\u043b\u043e", + "Smiling face with horns": "\u041f\u043e\u0441\u043c\u0456\u0445\u0430\u044e\u0447\u0438\u0441\u044c \u043e\u0441\u043e\u0431\u0430 \u0437 \u0440\u043e\u0433\u0430\u043c\u0438", + "Winking face": "\u043f\u0456\u0434\u043c\u043e\u0440\u0433\u0443\u044e\u0447\u0438 \u043e\u0441\u043e\u0431\u0430", + "Smiling face with smiling eyes": "\u041f\u043e\u0441\u043c\u0456\u0445\u0430\u044e\u0447\u0438\u0441\u044c \u043e\u0441\u043e\u0431\u0430 \u0437 \u0443\u0441\u043c\u0456\u0445\u043d\u0435\u043d\u0438\u043c\u0438 \u043e\u0447\u0438\u043c\u0430", + "Face savoring delicious food": "\u041e\u0441\u043e\u0431\u0430 \u0441\u043c\u0430\u043a\u0443\u044e\u0447\u0438 \u0441\u043c\u0430\u0447\u043d\u0443 \u0457\u0436\u0443", + "Relieved face": "\u0437\u0432\u0456\u043b\u044c\u043d\u0435\u043d\u043e \u043e\u0441\u043e\u0431\u0430", + "Smiling face with heart-shaped eyes": "\u041f\u043e\u0441\u043c\u0456\u0445\u0430\u044e\u0447\u0438\u0441\u044c \u043e\u0441\u043e\u0431\u0430 \u0443 \u0444\u043e\u0440\u043c\u0456 \u0441\u0435\u0440\u0446\u044f \u043e\u0447\u0438\u043c\u0430", + "Smiling face with sunglasses": "\u0053\u006d\u0069\u006c\u0069\u006e\u0067 \u0066\u0061\u0063\u0065 \u0077\u0069\u0074\u0068 \u0073\u0075\u006e\u0067\u006c\u0061\u0073\u0073\u0065\u0073", + "Smirking face": "\u043f\u043e\u0441\u043c\u0456\u0445\u043d\u0443\u0432\u0448\u0438\u0441\u044c \u043e\u0441\u043e\u0431\u0430", + "Neutral face": "\u0437\u0432\u0438\u0447\u0430\u0439\u043d\u0438\u0439 \u043e\u0441\u043e\u0431\u0430", + "Expressionless face": "\u043d\u0435\u0432\u0438\u0440\u0430\u0437\u043d\u0456 \u043e\u0431\u043b\u0438\u0447\u0447\u044f", + "Unamused face": "\u0055\u006e\u0061\u006d\u0075\u0073\u0065\u0064 \u043e\u0441\u043e\u0431\u0430", + "Face with cold sweat": "\u041e\u0441\u043e\u0431\u0430 \u0437 \u0445\u043e\u043b\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u0443", + "Pensive face": "\u0437\u0430\u043c\u0438\u0441\u043b\u0435\u043d\u0438\u0439 \u043e\u0441\u043e\u0431\u0430", + "Confused face": "\u043f\u043b\u0443\u0442\u0430\u0442\u0438 \u043e\u0441\u043e\u0431\u0430", + "Confounded face": "\u043d\u0435\u0445\u0430\u0439 \u043f\u043e\u0441\u043e\u0440\u043e\u043c\u043b\u044f\u0442\u044c\u0441\u044f \u043e\u0441\u043e\u0431\u0430", + "Kissing face": "\u043f\u043e\u0446\u0456\u043b\u0443\u043d\u043a\u0438 \u043e\u0441\u043e\u0431\u0430", + "Face throwing a kiss": "\u041e\u0441\u043e\u0431\u0430 \u043a\u0438\u0434\u0430\u043b\u0438 \u043f\u043e\u0446\u0456\u043b\u0443\u043d\u043e\u043a", + "Kissing face with smiling eyes": "\u041f\u043e\u0446\u0456\u043b\u0443\u043d\u043a\u0438 \u043e\u0441\u043e\u0431\u0430 \u0437 \u0443\u0441\u043c\u0456\u0445\u043d\u0435\u043d\u0438\u043c\u0438 \u043e\u0447\u0438\u043c\u0430", + "Kissing face with closed eyes": "\u041f\u043e\u0446\u0456\u043b\u0443\u043d\u043a\u0438 \u043e\u0431\u043b\u0438\u0447\u0447\u044f \u0437 \u0437\u0430\u043f\u043b\u044e\u0449\u0435\u043d\u0438\u043c\u0438 \u043e\u0447\u0438\u043c\u0430", + "Face with stuck out tongue": "\u041e\u0431\u043b\u0438\u0447\u0447\u044f \u0437 \u0441\u0442\u0438\u0440\u0447\u0430\u043b\u0438 \u044f\u0437\u0438\u043a", + "Face with stuck out tongue and winking eye": "\u041e\u0431\u043b\u0438\u0447\u0447\u044f \u0437 \u0441\u0442\u0438\u0440\u0447\u0430\u043b\u0438 \u044f\u0437\u0438\u043a\u0430 \u0456 \u0410\u043d\u0456\u043c\u043e\u0432\u0430\u043d\u0435 \u043e\u0447\u0435\u0439", + "Face with stuck out tongue and tightly-closed eyes": "\u041e\u0431\u043b\u0438\u0447\u0447\u044f \u0437 \u0441\u0442\u0438\u0440\u0447\u0430\u043b\u0438 \u044f\u0437\u0438\u043a\u0430 \u0456 \u0449\u0456\u043b\u044c\u043d\u043e \u0437\u0430\u043a\u0440\u0438\u0442\u0456 \u043e\u0447\u0456", + "Disappointed face": "\u0440\u043e\u0437\u0447\u0430\u0440\u043e\u0432\u0430\u043d\u0438\u0439 \u043e\u0441\u043e\u0431\u0430", + "Worried face": "\u0441\u0442\u0443\u0440\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043e\u0441\u043e\u0431\u0430", + "Angry face": "\u0437\u043b\u0438\u0439 \u043e\u0441\u043e\u0431\u0430", + "Pouting face": "\u043f\u0443\u0445\u043a\u0456 \u043e\u0441\u043e\u0431\u0430", + "Crying face": "\u043f\u043b\u0430\u0447 \u043e\u0441\u043e\u0431\u0430", + "Persevering face": "\u043d\u0430\u043f\u043e\u043b\u0435\u0433\u043b\u0438\u0432\u0430 \u043e\u0441\u043e\u0431\u0430", + "Face with look of triumph": "\u041e\u0441\u043e\u0431\u0430 \u0437 \u0432\u0438\u0434\u043e\u043c \u0442\u0440\u0456\u0443\u043c\u0444\u0443", + "Disappointed but relieved face": "\u0420\u043e\u0437\u0447\u0430\u0440\u043e\u0432\u0430\u043d\u0438\u0439\u002c \u0430\u043b\u0435 \u0437\u0432\u0456\u043b\u044c\u043d\u0435\u043d\u0438\u0439 \u043e\u0441\u043e\u0431\u0430", + "Frowning face with open mouth": "\u041d\u0430\u0441\u0443\u043f\u0438\u0432\u0448\u0438\u0441\u044c \u043e\u0441\u043e\u0431\u0430 \u0437 \u0432\u0456\u0434\u043a\u0440\u0438\u0442\u0438\u043c \u0440\u043e\u0442\u043e\u043c", + "Anguished face": "\u0431\u043e\u043b\u0456\u0441\u043d\u0438\u0439 \u043e\u0441\u043e\u0431\u0430", + "Fearful face": "\u043f\u043e\u0431\u043e\u044e\u044e\u0447\u0438\u0441\u044c \u043e\u0441\u043e\u0431\u0430", + "Weary face": "\u0432\u0442\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043e\u0441\u043e\u0431\u0430", + "Sleepy face": "сонне обличчя", + "Tired face": "\u0432\u0442\u043e\u043c\u0438\u043b\u0438\u0441\u044f \u043e\u0441\u043e\u0431\u0430", + "Grimacing face": "\u0433\u0440\u0438\u043c\u0430\u0441\u0443\u044e\u0447\u0438 \u043e\u0441\u043e\u0431\u0430", + "Loudly crying face": "\u004c\u006f\u0075\u0064\u006c\u0079 \u0063\u0072\u0079\u0069\u006e\u0067 \u0066\u0061\u0063\u0065", + "Face with open mouth": "\u041e\u0441\u043e\u0431\u0430 \u0437 \u0432\u0456\u0434\u043a\u0440\u0438\u0442\u0438\u043c \u0440\u043e\u0442\u043e\u043c", + "Hushed face": "\u0437\u0430\u0442\u0438\u0445 \u043e\u0441\u043e\u0431\u0430", + "Face with open mouth and cold sweat": "\u041e\u0441\u043e\u0431\u0430 \u0437 \u0432\u0456\u0434\u043a\u0440\u0438\u0442\u0438\u043c \u0440\u043e\u0442\u043e\u043c \u0456 \u0445\u043e\u043b\u043e\u0434\u043d\u0438\u0439 \u043f\u0456\u0442", + "Face screaming in fear": "\u041e\u0441\u043e\u0431\u0430 \u043a\u0440\u0438\u0447\u0430\u0442\u0438 \u0432 \u0441\u0442\u0440\u0430\u0445\u0443", + "Astonished face": "\u0437\u0434\u0438\u0432\u043e\u0432\u0430\u043d\u0438\u0439 \u043e\u0441\u043e\u0431\u0430", + "Flushed face": "\u043f\u0440\u0438\u043f\u043b\u0438\u0432 \u043a\u0440\u043e\u0432\u0456 \u0434\u043e \u043e\u0431\u043b\u0438\u0447\u0447\u044f", + "Sleeping face": "\u0421\u043f\u043b\u044f\u0447\u0430 \u043e\u0441\u043e\u0431\u0430", + "Dizzy face": "\u0414\u0456\u0437\u0437\u0456 \u043e\u0441\u043e\u0431\u0430", + "Face without mouth": "\u041e\u0441\u043e\u0431\u0430 \u0431\u0435\u0437 \u0440\u043e\u0442\u0430", + "Face with medical mask": "\u041e\u0441\u043e\u0431\u0430 \u0437 \u043c\u0435\u0434\u0438\u0447\u043d\u043e\u044e \u043c\u0430\u0441\u043a\u043e\u044e", + + // Line breaker + "Break": "\u0437\u043b\u043e\u043c\u0438\u0442\u0438", + + // Math + "Subscript": "\u043f\u0456\u0434\u0440\u044f\u0434\u043a\u043e\u0432\u0438\u0439", + "Superscript": "\u043d\u0430\u0434\u0440\u044f\u0434\u043a\u043e\u0432\u0438\u0439 \u0441\u0438\u043c\u0432\u043e\u043b", + + // Full screen + "Fullscreen": "\u043f\u043e\u0432\u043d\u043e\u0435\u043a\u0440\u0430\u043d\u043d\u0438\u0439 \u0440\u0435\u0436\u0438\u043c", + + // Horizontal line + "Insert Horizontal Line": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0443 \u043b\u0456\u043d\u0456\u044e", + + // Clear formatting + "Clear Formatting": "\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0443\u0432\u0430\u043d\u043d\u044f", + + // Save + "Save": "\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438", + + // Undo, redo + "Undo": "\u0421\u043a\u0430\u0441\u0443\u0432\u0430\u0442\u0438", + "Redo": "\u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0438", + + // Select all + "Select All": "\u0412\u0438\u0431\u0440\u0430\u0442\u0438 \u0432\u0441\u0435", + + // Code view + "Code View": "\u041f\u0435\u0440\u0435\u0433\u043b\u044f\u0434 \u043a\u043e\u0434\u0443", + + // Quote + "Quote": "\u0426\u0438\u0442\u0430\u0442\u0430", + "Increase": "\u0417\u0431\u0456\u043b\u044c\u0448\u0438\u0442\u0438", + "Decrease": "\u0437\u043d\u0438\u0436\u0435\u043d\u043d\u044f", + + // Quick Insert + "Quick Insert": "\u0428\u0432\u0438\u0434\u043a\u0438\u0439 \u0432\u0441\u0442\u0430\u0432\u043a\u0430", + + // Spcial Characters + "Special Characters": "Спеціальні символи", + "Latin": "Латинський", + "Greek": "Грецький", + "Cyrillic": "Кирилиця", + "Punctuation": "Пунктуація", + "Currency": "Валюта", + "Arrows": "Стріли", + "Math": "Математика", + "Misc": "Різне", + + // Print. + "Print": "Друкувати", + + // Spell Checker. + "Spell Checker": "Перевірка орфографії", + + // Help + "Help": "Допомогти", + "Shortcuts": "Ярлики", + "Inline Editor": "Вбудований редактор", + "Show the editor": "Показати редактору", + "Common actions": "Спільні дії", + "Copy": "Скопіювати", + "Cut": "Вирізати", + "Paste": "Вставити", + "Basic Formatting": "Основне форматування", + "Increase quote level": "Збільшити рівень цитування", + "Decrease quote level": "Знизити рівень цитування", + "Image / Video": "Зображення / відео", + "Resize larger": "Змінити розмір більше", + "Resize smaller": "Змінити розмір менше", + "Table": "Стіл", + "Select table cell": "Виберіть комірку таблиці", + "Extend selection one cell": "Продовжити виділення однієї комірки", + "Extend selection one row": "Продовжити виділення одного рядка", + "Navigation": "Навігація", + "Focus popup / toolbar": "Фокус спливаюче / панель інструментів", + "Return focus to previous position": "Поверніть фокус на попередню позицію", + + // Embed.ly + "Embed URL": "Вставити URL-адресу", + "Paste in a URL to embed": "Вставте в url, щоб вставити", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Вставлений вміст надходить з документу Microsoft Word. ви хочете зберегти формат чи очистити його?", + "Keep": "Тримати", + "Clean": "Чистий", + "Word Paste Detected": "Слово паста виявлено" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/vi.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/vi.js new file mode 100644 index 0000000..2f6dd11 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/vi.js @@ -0,0 +1,276 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +$.FE.LANGUAGE['vi'] = { + translation: { + // Place holder + "Type something": "Vi\u1EBFt \u0111i\u1EC1u g\u00EC \u0111\u00F3...", + + // Basic formatting + "Bold": "\u0110\u1EADm", + "Italic": "Nghi\u00EAng", + "Underline": "G\u1EA1ch ch\u00E2n", + "Strikethrough": "G\u1EA1ch ngang ch\u1EEF", + + // Main buttons + "Insert": "Ch\u00E8n", + "Delete": "X\u00F3a", + "Cancel": "H\u1EE7y", + "OK": "OK", + "Back": "Tr\u1EDF v\u1EC1", + "Remove": "X\u00F3a", + "More": "Th\u00EAm", + "Update": "C\u1EADp nh\u1EADt", + "Style": "Ki\u1EC3u", + + // Font + "Font Family": "Ph\u00F4ng ch\u1EEF", + "Font Size": "C\u1EE1 ch\u1EEF", + + // Colors + "Colors": "M\u00E0u s\u1EAFc", + "Background": "N\u1EC1n", + "Text": "Ch\u1EEF", + "HEX Color": "Màu hex", + + // Paragraphs + "Paragraph Format": "\u0110\u1ECBnh d\u1EA1ng \u0111o\u1EA1n v\u0103n b\u1EA3n", + "Normal": "Normal", + "Code": "Code", + "Heading 1": "Heading 1", + "Heading 2": "Heading 2", + "Heading 3": "Heading 3", + "Heading 4": "Heading 4", + + // Style + "Paragraph Style": "Ki\u1EC3u \u0111o\u1EA1n v\u0103n b\u1EA3n", + "Inline Style": "Ki\u1EC3u d\u00F2ng", + + // Alignment + "Align": "C\u0103n ch\u1EC9nh", + "Align Left": "C\u0103n tr\u00E1i", + "Align Center": "C\u0103n gi\u1EEFa", + "Align Right": "C\u0103n ph\u1EA3i", + "Align Justify": "C\u0103n \u0111\u1EC1u", + "None": "Kh\u00F4ng", + + // Lists + "Ordered List": "Danh s\u00E1ch theo th\u1EE9 t\u1EF1", + "Default": "Mặc định", + "Lower Alpha": "Hạ alpha", + "Lower Greek": "Hạ Hy Lạp", + "Lower Roman": "Hạ La Mã", + "Upper Alpha": "Alpha trên", + "Upper Roman": "Thượng lưu La Mã", + + "Unordered List": "Danh s\u00E1ch li\u1EC7t k\u00EA", + "Circle": "Vòng tròn", + "Disc": "Đĩa", + "Square": "Quảng trường", + + // Line height + "Line Height": "Chiều cao giữa các dòng", + "Single": "Độc thân", + "Double": "Gấp đôi", + + // Indent + "Decrease Indent": "Gi\u1EA3m c\u0103n l\u1EC1", + "Increase Indent": "T\u0103ng c\u0103n l\u1EC1", + + // Links + "Insert Link": "Ch\u00E8n link", + "Open in new tab": "M\u1EDF trong tab m\u1EDBi", + "Open Link": "M\u1EDF link", + "Edit Link": "S\u1EEDa link", + "Unlink": "B\u1ECF link", + "Choose Link": "Ch\u1ECDn link", + + // Images + "Insert Image": "Ch\u00E8n h\u00ECnh", + "Upload Image": "T\u1EA3i h\u00ECnh l\u00EAn", + "By URL": "B\u1EB1ng URL", + "Browse": "Duy\u1EC7t file", + "Drop image": "K\u00E9o th\u1EA3 h\u00ECnh", + "or click": "ho\u1EB7c ch\u1ECDn", + "Manage Images": "Qu\u1EA3n l\u00FD h\u00ECnh \u1EA3nh", + "Loading": "\u0110ang t\u1EA3i", + "Deleting": "\u0110ang x\u00F3a", + "Tags": "Tags", + "Are you sure? Image will be deleted.": "B\u1EA1n c\u00F3 ch\u1EAFc ch\u1EAFn? H\u00ECnh \u1EA3nh s\u1EBD b\u1ECB x\u00F3a.", + "Replace": "Thay th\u1EBF", + "Uploading": "\u0110ang t\u1EA3i l\u00EAn", + "Loading image": "\u0110ang t\u1EA3i h\u00ECnh \u1EA3nh", + "Display": "Hi\u1EC3n th\u1ECB", + "Inline": "C\u00F9ng d\u00F2ng v\u1EDBi ch\u1EEF", + "Break Text": "Kh\u00F4ng c\u00F9ng d\u00F2ng v\u1EDBi ch\u1EEF", + "Alternative Text": "Thay th\u1EBF ch\u1EEF", + "Change Size": "Thay \u0111\u1ED5i k\u00EDch c\u1EE1", + "Width": "Chi\u1EC1u r\u1ED9ng", + "Height": "Chi\u1EC1u cao", + "Something went wrong. Please try again.": "C\u00F3 l\u1ED7i x\u1EA3y ra. Vui l\u00F2ng th\u1EED l\u1EA1i sau.", + "Image Caption": "Chú thích hình ảnh", + "Advanced Edit": "Chỉnh sửa tiên tiến", + + // Video + "Insert Video": "Ch\u00E8n video", + "Embedded Code": "M\u00E3 nh\u00FAng", + "Paste in a video URL": "Dán vào một url video", + "Drop video": "Thả video", + "Your browser does not support HTML5 video.": "Trình duyệt của bạn không hỗ trợ video html5.", + "Upload Video": "Tải video lên", + + // Tables + "Insert Table": "Ch\u00E8n b\u1EA3ng", + "Table Header": "D\u00F2ng \u0111\u1EA7u b\u1EA3ng", + "Remove Table": "X\u00F3a b\u1EA3ng", + "Table Style": "Ki\u1EC3u b\u1EA3ng", + "Horizontal Align": "C\u0103n ch\u1EC9nh chi\u1EC1u ngang", + "Row": "D\u00F2ng", + "Insert row above": "Ch\u00E8n d\u00F2ng ph\u00EDa tr\u00EAn", + "Insert row below": "Ch\u00E8n d\u00F2ng ph\u00EDa d\u01B0\u1EDBi", + "Delete row": "X\u00F3a d\u00F2ng", + "Column": "C\u1ED9t", + "Insert column before": "Ch\u00E8n c\u1ED9t b\u00EAn tr\u00E1i", + "Insert column after": "Ch\u00E8n c\u1ED9t b\u00EAn ph\u1EA3i", + "Delete column": "X\u00F3a c\u1ED9t", + "Cell": "\u00D4 b\u1EA3ng", + "Merge cells": "G\u1ED9p \u00F4", + "Horizontal split": "Chia d\u00F2ng", + "Vertical split": "Chia c\u1ED9t", + "Cell Background": "M\u00E0u n\u1EC1n", + "Vertical Align": "C\u0103n ch\u1EC9nh chi\u1EC1u d\u1ECDc", + "Top": "Tr\u00EAn c\u00F9ng", + "Middle": "Gi\u1EEFa", + "Bottom": "D\u01B0\u1EDBi \u0111\u00E1y", + "Align Top": "C\u0103n tr\u00EAn", + "Align Middle": "C\u0103n gi\u1EEFa", + "Align Bottom": "C\u0103n d\u01B0\u1EDBi", + "Cell Style": "Ki\u1EC3u \u00F4", + + // Files + "Upload File": "T\u1EA3i file l\u00EAn", + "Drop file": "K\u00E9o th\u1EA3 file", + + // Emoticons + "Emoticons": "Bi\u1EC3u t\u01B0\u1EE3ng c\u1EA3m x\u00FAc", + + // Line breaker + "Break": "Ng\u1EAFt d\u00F2ng", + + // Math + "Subscript": "Subscript", + "Superscript": "Superscript", + + // Full screen + "Fullscreen": "To\u00E0n m\u00E0n h\u00ECnh", + + // Horizontal line + "Insert Horizontal Line": "Ch\u00E8n \u0111\u01B0\u1EDDng k\u1EBB ngang v\u0103n b\u1EA3n", + + // Clear formatting + "Clear Formatting": "X\u00F3a \u0111\u1ECBnh d\u1EA1ng", + + // Save + "Save": "Save", + + // Undo, redo + "Undo": "Undo", + "Redo": "Redo", + + // Select all + "Select All": "Ch\u1ECDn t\u1EA5t c\u1EA3", + + // Code view + "Code View": "Xem d\u1EA1ng code", + + // Quote + "Quote": "Tr\u00EDch d\u1EABn", + "Increase": "T\u0103ng", + "Decrease": "Gi\u1EA3m", + + // Quick Insert + "Quick Insert": "Ch\u00E8n nhanh", + + // Spcial Characters + "Special Characters": "Nhân vật đặc biệt", + "Latin": "Latin", + "Greek": "Người Hy Lạp", + "Cyrillic": "Chữ viết tay", + "Punctuation": "Chấm câu", + "Currency": "Tiền tệ", + "Arrows": "Mũi tên", + "Math": "Môn Toán", + "Misc": "Misc", + + // Print. + "Print": "In", + + // Spell Checker. + "Spell Checker": "Công cụ kiểm tra chính tả", + + // Help + "Help": "Cứu giúp", + "Shortcuts": "Phím tắt", + "Inline Editor": "Trình biên tập nội tuyến", + "Show the editor": "Hiển thị trình soạn thảo", + "Common actions": "Hành động thông thường", + "Copy": "Sao chép", + "Cut": "Cắt tỉa", + "Paste": "Dán", + "Basic Formatting": "Định dạng cơ bản", + "Increase quote level": "Tăng mức báo giá", + "Decrease quote level": "Giảm mức giá", + "Image / Video": "Hình ảnh / video", + "Resize larger": "Thay đổi kích thước lớn hơn", + "Resize smaller": "Thay đổi kích thước nhỏ hơn", + "Table": "Bàn", + "Select table cell": "Chọn ô trong bảng", + "Extend selection one cell": "Mở rộng lựa chọn một ô", + "Extend selection one row": "Mở rộng lựa chọn một hàng", + "Navigation": "Dẫn đường", + "Focus popup / toolbar": "Tập trung popup / thanh công cụ", + "Return focus to previous position": "Quay trở lại vị trí trước", + + // Embed.ly + "Embed URL": "Url nhúng", + "Paste in a URL to embed": "Dán vào một url để nhúng", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Nội dung dán là đến từ một tài liệu từ microsoft. bạn có muốn giữ định dạng hoặc làm sạch nó?", + "Keep": "Giữ", + "Clean": "Dọn dẹp", + "Word Paste Detected": "Dán từ được phát hiện" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/zh_cn.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/zh_cn.js new file mode 100644 index 0000000..f5fa605 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/zh_cn.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** +* Simplified Chinese spoken in China. +*/ + +$.FE.LANGUAGE['zh_cn'] = { + translation: { + // Place holder + "Type something": "输入内容", + + // Basic formatting + "Bold": "粗体", + "Italic": "斜体", + "Underline": "下划线", + "Strikethrough": "删除线", + + // Main buttons + "Insert": "插入", + "Delete": "删除", + "Cancel": "取消", + "OK": "确定", + "Back": "后退", + "Remove": "删除", + "More": "更多", + "Update": "更新", + "Style": "样式", + + // Font + "Font Family": "字体", + "Font Size": "字号", + + // Colors + "Colors": "颜色", + "Background": "背景", + "Text": "字体", + "HEX Color": "十六进制颜色", + + // Paragraphs + "Paragraph Format": "段落格式", + "Normal": "正文", + "Code": "代码", + "Heading 1": "标题1", + "Heading 2": "标题2", + "Heading 3": "标题3", + "Heading 4": "标题4", + + // Style + "Paragraph Style": "段落样式", + "Inline Style": "内联样式", + + // Alignment + "Align": "对齐方式", + "Align Left": "左对齐", + "Align Center": "居中", + "Align Right": "右对齐", + "Align Justify": "两端对齐", + "None": "无", + + // Lists + "Ordered List": "编号", + "Default": "默认", + "Lower Alpha": "低α", + "Lower Greek": "下希腊", + "Lower Roman": "较低的罗马", + "Upper Alpha": "上阿尔法", + "Upper Roman": "上罗马", + + "Unordered List": "项目符号", + "Circle": "圈", + "Disc": "圆盘", + "Square": "广场", + + // Line height + "Line Height": "线高", + "Single": "单", + "Double": "双", + + // Indent + "Decrease Indent": "减少缩进量", + "Increase Indent": "增加缩进量", + + // Links + "Insert Link": "插入超链接", + "Open in new tab": "在新标签页中打开", + "Open Link": "打开超链接", + "Edit Link": "编辑超链接", + "Unlink": "删除超链接", + "Choose Link": "选择超链接", + + // Images + "Insert Image": "插入图片", + "Upload Image": "上传图片", + "By URL": "通过 URL", + "Browse": "浏览", + "Drop image": "拖入图片", + "or click": "或点击", + "Manage Images": "管理图片", + "Loading": "加载中", + "Deleting": "删除中", + "Tags": "标签", + "Are you sure? Image will be deleted.": "图片将会被删除,是否确认?", + "Replace": "替换", + "Uploading": "上传中", + "Loading image": "图片加载中", + "Display": "显示", + "Inline": "嵌入型", + "Break Text": "上下型环绕", + "Alternative Text": "替换文字", + "Change Size": "改变大小", + "Width": "宽度", + "Height": "高度", + "Something went wrong. Please try again.": "发生错误,请重试。", + "Image Caption": "图片标题", + "Advanced Edit": "高级编辑", + + // Video + "Insert Video": "插入视频", + "Embedded Code": "嵌入代码", + "Paste in a video URL": "粘贴视频网址", + "Drop video": "拖入视频", + "Your browser does not support HTML5 video.": "您的浏览器不支持 HTML5 视频。", + "Upload Video": "上传视频", + + // Tables + "Insert Table": "插入表格", + "Table Header": "表头", + "Remove Table": "删除表格", + "Table Style": "表格样式", + "Horizontal Align": "水平对齐方式", + "Row": "行", + "Insert row above": "在上方插入", + "Insert row below": "在下方插入", + "Delete row": "删除行", + "Column": "列", + "Insert column before": "在左侧插入", + "Insert column after": "在右侧插入", + "Delete column": "删除列", + "Cell": "单元格", + "Merge cells": "合并单元格", + "Horizontal split": "水平分割", + "Vertical split": "垂直分割", + "Cell Background": "单元格背景", + "Vertical Align": "垂直对齐方式", + "Top": "靠上", + "Middle": "居中", + "Bottom": "靠下", + "Align Top": "靠上对齐", + "Align Middle": "居中对齐", + "Align Bottom": "靠下对齐", + "Cell Style": "单元格样式", + + // Files + "Upload File": "上传文件", + "Drop file": "拖入文件", + + // Emoticons + "Emoticons": "表情符号", + "Grinning face": "露齿笑脸", + "Grinning face with smiling eyes": "露齿笑到眯起眼", + "Face with tears of joy": "笑哭", + "Smiling face with open mouth": "张嘴微笑", + "Smiling face with open mouth and smiling eyes": "眯眼张嘴微笑", + "Smiling face with open mouth and cold sweat": "带冷汗的张嘴微笑", + "Smiling face with open mouth and tightly-closed eyes": "紧闭双眼张嘴微笑", + "Smiling face with halo": "带光环微笑", + "Smiling face with horns": "带牛角的微笑", + "Winking face": "眨眼", + "Smiling face with smiling eyes": "眯眼微笑", + "Face savoring delicious food": "馋", + "Relieved face": "如释重负", + "Smiling face with heart-shaped eyes": "桃心眼微笑", + "Smiling face with sunglasses": "戴太阳镜微笑", + "Smirking face": "得意地笑", + "Neutral face": "中性脸", + "Expressionless face": "面无表情", + "Unamused face": "不高兴", + "Face with cold sweat": "冷汗", + "Pensive face": "沉思", + "Confused face": "迷惑", + "Confounded face": "困惑", + "Kissing face": "嘴巴嘟嘟", + "Face throwing a kiss": "飞吻", + "Kissing face with smiling eyes": "眯眼接吻", + "Kissing face with closed eyes": "闭眼接吻", + "Face with stuck out tongue": "吐舌", + "Face with stuck out tongue and winking eye": "眨眼吐舌", + "Face with stuck out tongue and tightly-closed eyes": "眯眼吐舌", + "Disappointed face": "失望", + "Worried face": "担心", + "Angry face": "生气", + "Pouting face": "撅嘴", + "Crying face": "大哭", + "Persevering face": "坚强", + "Face with look of triumph": "扬眉吐气", + "Disappointed but relieved face": "失望", + "Frowning face with open mouth": "皱眉", + "Anguished face": "痛苦", + "Fearful face": "害怕", + "Weary face": "疲惫", + "Sleepy face": "困了", + "Tired face": "累了", + "Grimacing face": "扭曲脸", + "Loudly crying face": "大哭", + "Face with open mouth": "张开嘴", + "Hushed face": "安静", + "Face with open mouth and cold sweat": "冷汗", + "Face screaming in fear": "害怕尖叫", + "Astonished face": "惊讶", + "Flushed face": "脸红", + "Sleeping face": "熟睡", + "Dizzy face": "眩晕", + "Face without mouth": "没有嘴的脸", + "Face with medical mask": "口罩脸", + + // Line breaker + "Break": "换行", + + // Math + "Subscript": "下标", + "Superscript": "上标", + + // Full screen + "Fullscreen": "全屏", + + // Horizontal line + "Insert Horizontal Line": "插入水平线", + + // Clear formatting + "Clear Formatting": "清除格式", + + // Save + "Save": "保存", + + // Undo, redo + "Undo": "撤消", + "Redo": "恢复", + + // Select all + "Select All": "全选", + + // Code view + "Code View": "代码视图", + + // Quote + "Quote": "引用", + "Increase": "增加引用级别", + "Decrease": "减少引用级别", + + // Quick Insert + "Quick Insert": "快速插入", + + // Spcial Characters + "Special Characters": "特殊字符", + "Latin": "拉丁字母", + "Greek": "希腊字母", + "Cyrillic": "西里尔字母", + "Punctuation": "标点", + "Currency": "货币", + "Arrows": "箭头", + "Math": "数学", + "Misc": "杂项", + + // Print. + "Print": "打印", + + // Spell Checker. + "Spell Checker": "拼写检查器", + + // Help + "Help": "帮助", + "Shortcuts": "快捷键", + "Inline Editor": "内联编辑器", + "Show the editor": "显示编辑器", + "Common actions": "常用操作", + "Copy": "复制", + "Cut": "剪切", + "Paste": "粘贴", + "Basic Formatting": "基本格式", + "Increase quote level": "增加引用级别", + "Decrease quote level": "减少引用级别", + "Image / Video": "图像/视频", + "Resize larger": "放大", + "Resize smaller": "缩小", + "Table": "表格", + "Select table cell": "选择单元格", + "Extend selection one cell": "增加选中的单元格", + "Extend selection one row": "增加选中的行", + "Navigation": "导航", + "Focus popup / toolbar": "焦点弹出/工具栏", + "Return focus to previous position": "将焦点返回到上一个位置", + + // Embed.ly + "Embed URL": "嵌入网址", + "Paste in a URL to embed": "粘贴要嵌入的网址", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "粘贴的内容来自微软 Word 文档。你想保留还是清除格式?", + "Keep": "保留", + "Clean": "清除", + "Word Paste Detected": "检测到粘贴自 Word 的内容" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/zh_tw.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/zh_tw.js new file mode 100644 index 0000000..b554fee --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/zh_tw.js @@ -0,0 +1,336 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Traditional Chinese spoken in Taiwan. + */ + +$.FE.LANGUAGE['zh_tw'] = { + translation: { + // Place holder + "Type something": "\u8f38\u5165\u4e00\u4e9b\u5167\u5bb9", + + // Basic formatting + "Bold": "\u7c97\u9ad4", + "Italic": "\u659c\u9ad4", + "Underline": "\u5e95\u7dda", + "Strikethrough": "\u522a\u9664\u7dda", + + // Main buttons + "Insert": "\u63d2\u5165", + "Delete": "\u522a\u9664", + "Cancel": "\u53d6\u6d88", + "OK": "\u78ba\u5b9a", + "Back": "\u5f8c", + "Remove": "\u79fb\u9664", + "More": "\u66f4\u591a", + "Update": "\u66f4\u65b0", + "Style": "\u6a23\u5f0f", + + // Font + "Font Family": "\u5b57\u9ad4", + "Font Size": "\u5b57\u578b\u5927\u5c0f", + + // Colors + "Colors": "\u984f\u8272", + "Background": "\u80cc\u666f", + "Text": "\u6587\u5b57", + "HEX Color": "十六進制顏色", + + // Paragraphs + "Paragraph Format": "\u683c\u5f0f", + "Normal": "\u6b63\u5e38", + "Code": "\u7a0b\u5f0f\u78bc", + "Heading 1": "\u6a19\u984c 1", + "Heading 2": "\u6a19\u984c 2", + "Heading 3": "\u6a19\u984c 3", + "Heading 4": "\u6a19\u984c 4", + + // Style + "Paragraph Style": "\u6bb5\u843d\u6a23\u5f0f", + "Inline Style": "\u5167\u806f\u6a23\u5f0f", + + // Alignment + "Align": "\u5c0d\u9f4a", + "Align Left": "\u7f6e\u5de6\u5c0d\u9f4a", + "Align Center": "\u7f6e\u4e2d\u5c0d\u9f4a", + "Align Right": "\u7f6e\u53f3\u5c0d\u9f4a", + "Align Justify": "\u5de6\u53f3\u5c0d\u9f4a", + "None": "\u7121", + + // Lists + "Ordered List": "\u6578\u5b57\u6e05\u55ae", + "Default": "默認", + "Lower Alpha": "低α", + "Lower Greek": "下希臘", + "Lower Roman": "較低的羅馬", + "Upper Alpha": "上阿爾法", + "Upper Roman": "上羅馬", + + "Unordered List": "\u9805\u76ee\u6e05\u55ae", + "Circle": "圈", + "Disc": "圓盤", + "Square": "廣場", + + // Line height + "Line Height": "線高", + "Single": "單", + "Double": "雙", + + // Indent + "Decrease Indent": "\u6e1b\u5c11\u7e2e\u6392", + "Increase Indent": "\u589e\u52a0\u7e2e\u6392", + + // Links + "Insert Link": "\u63d2\u5165\u9023\u7d50", + "Open in new tab": "\u5728\u65b0\u5206\u9801\u958b\u555f", + "Open Link": "\u958b\u555f\u9023\u7d50", + "Edit Link": "\u7de8\u8f2f\u9023\u7d50", + "Unlink": "\u79fb\u9664\u9023\u7d50", + "Choose Link": "\u9078\u64c7\u9023\u7d50", + + // Images + "Insert Image": "\u63d2\u5165\u5716\u7247", + "Upload Image": "\u4e0a\u50b3\u5716\u7247", + "By URL": "\u7db2\u5740\u4e0a\u50b3", + "Browse": "\u700f\u89bd", + "Drop image": "\u5716\u7247\u62d6\u66f3", + "or click": "\u6216\u9ede\u64ca", + "Manage Images": "\u7ba1\u7406\u5716\u7247", + "Loading": "\u8f09\u5165\u4e2d", + "Deleting": "\u522a\u9664", + "Tags": "\u6a19\u7c64", + "Are you sure? Image will be deleted.": "\u78ba\u5b9a\u522a\u9664\u5716\u7247\uff1f", + "Replace": "\u66f4\u63db", + "Uploading": "\u4e0a\u50b3", + "Loading image": "\u4e0a\u50b3\u4e2d", + "Display": "\u986f\u793a", + "Inline": "\u5d4c\u5165", + "Break Text": "\u8207\u6587\u5b57\u5206\u96e2", + "Alternative Text": "\u6587\u5b57\u74b0\u7e5e", + "Change Size": "\u8abf\u6574\u5927\u5c0f", + "Width": "\u5bec\u5ea6", + "Height": "\u9ad8\u5ea6", + "Something went wrong. Please try again.": "\u932f\u8aa4\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002", + "Image Caption": "圖片說明", + "Advanced Edit": "高級編輯", + + // Video + "Insert Video": "\u63d2\u5165\u5f71\u7247", + "Embedded Code": "\u5d4c\u5165\u7a0b\u5f0f\u78bc", + "Paste in a video URL": "粘貼在視頻網址", + "Drop video": "放下視頻", + "Your browser does not support HTML5 video.": "您的瀏覽器不支持html5視頻。", + "Upload Video": "上傳視頻", + + // Tables + "Insert Table": "\u63d2\u5165\u8868\u683c", + "Table Header": "\u8868\u982d", + "Remove Table": "\u522a\u9664\u8868", + "Table Style": "\u8868\u6a23\u5f0f", + "Horizontal Align": "\u6c34\u6e96\u5c0d\u9f4a\u65b9\u5f0f", + "Row": "\u884c", + "Insert row above": "\u5411\u4e0a\u63d2\u5165\u4e00\u884c", + "Insert row below": "\u5411\u4e0b\u63d2\u5165\u4e00\u884c", + "Delete row": "\u522a\u9664\u884c", + "Column": "\u5217", + "Insert column before": "\u5411\u5de6\u63d2\u5165\u4e00\u5217", + "Insert column after": "\u5411\u53f3\u63d2\u5165\u4e00\u5217", + "Delete column": "\u522a\u9664\u884c", + "Cell": "\u5132\u5b58\u683c", + "Merge cells": "\u5408\u4f75\u5132\u5b58\u683c", + "Horizontal split": "\u6c34\u5e73\u5206\u5272", + "Vertical split": "\u5782\u76f4\u5206\u5272", + "Cell Background": "\u5132\u5b58\u683c\u80cc\u666f", + "Vertical Align": "\u5782\u76f4\u5c0d\u9f4a\u65b9\u5f0f", + "Top": "\u4e0a", + "Middle": "\u4e2d", + "Bottom": "\u4e0b", + "Align Top": "\u5411\u4e0a\u5c0d\u9f4a", + "Align Middle": "\u4e2d\u9593\u5c0d\u9f4a", + "Align Bottom": "\u5e95\u90e8\u5c0d\u9f4a", + "Cell Style": "\u5132\u5b58\u683c\u6a23\u5f0f", + + // Files + "Upload File": "\u4e0a\u50b3\u6587\u4ef6", + "Drop file": "\u6587\u4ef6\u62d6\u66f3", + + // Emoticons + "Emoticons": "\u8868\u60c5", + "Grinning face": "\u81c9\u4e0a\u7b11\u563b\u563b", + "Grinning face with smiling eyes": "\u7b11\u563b\u563b\u7684\u81c9\uff0c\u542b\u7b11\u7684\u773c\u775b", + "Face with tears of joy": "\u81c9\u4e0a\u5e36\u8457\u559c\u6085\u7684\u6dda\u6c34", + "Smiling face with open mouth": "\u7b11\u81c9\u5f35\u958b\u5634", + "Smiling face with open mouth and smiling eyes": "\u7b11\u81c9\u5f35\u958b\u5634\u5fae\u7b11\u7684\u773c\u775b", + "Smiling face with open mouth and cold sweat": "\u7b11\u81c9\u5f35\u958b\u5634\uff0c\u4e00\u8eab\u51b7\u6c57", + "Smiling face with open mouth and tightly-closed eyes": "\u7b11\u81c9\u5f35\u958b\u5634\uff0c\u7dca\u7dca\u9589\u8457\u773c\u775b", + "Smiling face with halo": "\u7b11\u81c9\u6688", + "Smiling face with horns": "\u5fae\u7b11\u7684\u81c9\u89d2", + "Winking face": "\u7728\u773c\u8868\u60c5", + "Smiling face with smiling eyes": "\u9762\u5e36\u5fae\u7b11\u7684\u773c\u775b", + "Face savoring delicious food": "\u9762\u5c0d\u54c1\u5690\u7f8e\u5473\u7684\u98df\u7269", + "Relieved face": "\u9762\u5c0d\u5982\u91cb\u91cd\u8ca0", + "Smiling face with heart-shaped eyes": "\u5fae\u7b11\u7684\u81c9\uff0c\u5fc3\u81df\u5f62\u7684\u773c\u775b", + "Smiling face with sunglasses": "\u7b11\u81c9\u592a\u967d\u93e1", + "Smirking face": "\u9762\u5c0d\u9762\u5e36\u7b11\u5bb9", + "Neutral face": "\u4e2d\u6027\u9762", + "Expressionless face": "\u9762\u7121\u8868\u60c5", + "Unamused face": "\u4e00\u81c9\u4e0d\u5feb\u7684\u81c9", + "Face with cold sweat": "\u9762\u5c0d\u51b7\u6c57", + "Pensive face": "\u6c89\u601d\u7684\u81c9", + "Confused face": "\u9762\u5c0d\u56f0\u60d1", + "Confounded face": "\u8a72\u6b7b\u7684\u81c9", + "Kissing face": "\u9762\u5c0d\u63a5\u543b", + "Face throwing a kiss": "\u9762\u5c0d\u6295\u64f2\u4e00\u500b\u543b", + "Kissing face with smiling eyes": "\u63a5\u543b\u81c9\uff0c\u542b\u7b11\u7684\u773c\u775b", + "Kissing face with closed eyes": "\u63a5\u543b\u7684\u81c9\u9589\u8457\u773c\u775b", + "Face with stuck out tongue": "\u9762\u5c0d\u4f38\u51fa\u820c\u982d", + "Face with stuck out tongue and winking eye": "\u9762\u5c0d\u4f38\u51fa\u820c\u982d\u548c\u7728\u52d5\u7684\u773c\u775b", + "Face with stuck out tongue and tightly-closed eyes": "\u9762\u5c0d\u4f38\u51fa\u820c\u982d\u548c\u7dca\u9589\u7684\u773c\u775b", + "Disappointed face": "\u9762\u5c0d\u5931\u671b", + "Worried face": "\u9762\u5c0d\u64d4\u5fc3", + "Angry face": "\u61a4\u6012\u7684\u81c9", + "Pouting face": "\u9762\u5c0d\u5658\u5634", + "Crying face": "\u54ed\u6ce3\u7684\u81c9", + "Persevering face": "\u600e\u5948\u81c9", + "Face with look of triumph": "\u9762\u5e36\u770b\u7684\u52dd\u5229", + "Disappointed but relieved face": "\u5931\u671b\uff0c\u4f46\u81c9\u4e0a\u91cb\u7136", + "Frowning face with open mouth": "\u9762\u5c0d\u76ba\u8457\u7709\u982d\u5f35\u53e3", + "Anguished face": "\u9762\u5c0d\u75db\u82e6", + "Fearful face": "\u53ef\u6015\u7684\u81c9", + "Weary face": "\u9762\u5c0d\u53ad\u5026", + "Sleepy face": "\u9762\u5c0d\u56f0", + "Tired face": "\u75b2\u618a\u7684\u81c9", + "Grimacing face": "\u7319\u7370\u7684\u81c9", + "Loudly crying face": "\u5927\u8072\u54ed\u81c9", + "Face with open mouth": "\u9762\u5c0d\u5f35\u958b\u5634", + "Hushed face": "\u5b89\u975c\u7684\u81c9", + "Face with open mouth and cold sweat": "\u9762\u5c0d\u5f35\u958b\u5634\uff0c\u4e00\u8eab\u51b7\u6c57", + "Face screaming in fear": "\u9762\u5c0d\u5c16\u53eb\u5728\u6050\u61fc\u4e2d", + "Astonished face": "\u9762\u5c0d\u9a5a\u8a1d", + "Flushed face": "\u7d05\u64b2\u64b2\u7684\u81c9\u86cb", + "Sleeping face": "\u719f\u7761\u7684\u81c9", + "Dizzy face": "\u9762\u5c0d\u7729", + "Face without mouth": "\u81c9\u4e0a\u6c92\u6709\u5634", + "Face with medical mask": "\u9762\u5c0d\u91ab\u7642\u53e3\u7f69", + + // Line breaker + "Break": "\u63db\u884c", + + // Math + "Subscript": "\u4e0b\u6a19", + "Superscript": "\u4e0a\u6a19", + + // Full screen + "Fullscreen": "\u5168\u87a2\u5e55", + + // Horizontal line + "Insert Horizontal Line": "\u63d2\u5165\u6c34\u5e73\u7dda", + + // Clear formatting + "Clear Formatting": "\u6e05\u9664\u683c\u5f0f", + + // Save + "Save": "保存", + + // Undo, redo + "Undo": "\u5fa9\u539f", + "Redo": "\u53d6\u6d88\u5fa9\u539f", + + // Select all + "Select All": "\u5168\u9078", + + // Code view + "Code View": "\u539f\u59cb\u78bc", + + // Quote + "Quote": "\u5f15\u6587", + "Increase": "\u7e2e\u6392", + "Decrease": "\u53bb\u9664\u7e2e\u6392", + + // Quick Insert + "Quick Insert": "\u5feb\u63d2", + + // Spcial Characters + "Special Characters": "特殊字符", + "Latin": "拉丁", + "Greek": "希臘語", + "Cyrillic": "西里爾", + "Punctuation": "標點", + "Currency": "貨幣", + "Arrows": "箭頭", + "Math": "數學", + "Misc": "雜項", + + // Print. + "Print": "打印", + + // Spell Checker. + "Spell Checker": "拼寫檢查器", + + // Help + "Help": "幫幫我", + "Shortcuts": "快捷鍵", + "Inline Editor": "內聯編輯器", + "Show the editor": "顯示編輯", + "Common actions": "共同行動", + "Copy": "複製", + "Cut": "切", + "Paste": "糊", + "Basic Formatting": "基本格式", + "Increase quote level": "提高報價水平", + "Decrease quote level": "降低報價水平", + "Image / Video": "圖像/視頻", + "Resize larger": "調整大小更大", + "Resize smaller": "調整大小更小", + "Table": "表", + "Select table cell": "選擇表單元格", + "Extend selection one cell": "擴展選擇一個單元格", + "Extend selection one row": "擴展選擇一行", + "Navigation": "導航", + "Focus popup / toolbar": "焦點彈出/工具欄", + "Return focus to previous position": "將焦點返回到上一個位置", + + // Embed.ly + "Embed URL": "嵌入網址", + "Paste in a URL to embed": "粘貼在一個網址中嵌入", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "粘貼的內容來自微軟Word文檔。你想保留格式還是清理它?", + "Keep": "保持", + "Clean": "清潔", + "Word Paste Detected": "檢測到字貼" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/formwidgets/richeditor/partials/_page_links_form.htm b/modules/backend/formwidgets/richeditor/partials/_page_links_form.htm new file mode 100644 index 0000000..3a61b9a --- /dev/null +++ b/modules/backend/formwidgets/richeditor/partials/_page_links_form.htm @@ -0,0 +1,33 @@ + 'pageLinksForm']) ?> + + + + + diff --git a/modules/backend/formwidgets/richeditor/partials/_richeditor.htm b/modules/backend/formwidgets/richeditor/partials/_richeditor.htm new file mode 100755 index 0000000..3457a34 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/partials/_richeditor.htm @@ -0,0 +1,38 @@ + +previewMode): ?> +
    + +
    data-fullpage="true" + data-read-only="true" + data-use-media-manager="true" + data-editor-lang="" + data-toolbar-buttons="" + data-toolbar-buttons="" + data-allow-empty-tags="" + data-allow-tags="" + data-no-wrap-tags="" + data-remove-tags="" + data-line-breaker-tags="" + data-image-styles="" + data-link-styles="" + data-paragraph-styles="" + data-paragraph-format="" + data-table-styles="" + data-table-cell-styles="" + data-links-handler="getEventHandler('onLoadPageLinksForm') ?>" + data-upload-handler="getEventHandler('onUpload') ?>" + data-ace-vendor-path="" + data-control="richeditor" + getAttributes() ?> + > + +
    +
    + diff --git a/modules/backend/formwidgets/sensitive/assets/css/sensitive.css b/modules/backend/formwidgets/sensitive/assets/css/sensitive.css new file mode 100644 index 0000000..c8ac937 --- /dev/null +++ b/modules/backend/formwidgets/sensitive/assets/css/sensitive.css @@ -0,0 +1,2 @@ +div[data-control="sensitive"] a[data-toggle], +div[data-control="sensitive"] a[data-copy] {box-shadow:none;border:1px solid #d1d6d9;border-left:0} \ No newline at end of file diff --git a/modules/backend/formwidgets/sensitive/assets/js/sensitive.js b/modules/backend/formwidgets/sensitive/assets/js/sensitive.js new file mode 100644 index 0000000..6925130 --- /dev/null +++ b/modules/backend/formwidgets/sensitive/assets/js/sensitive.js @@ -0,0 +1,192 @@ +/* + * Sensitive field widget plugin. + * + * Data attributes: + * - data-control="sensitive" - enables the plugin on an element + * + * JavaScript API: + * $('div#someElement').sensitive({...}) + */ ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var Sensitive = function(element, options) { + this.$el = $(element) + this.options = options + this.clean = Boolean(this.$el.data('clean')) + this.hidden = true + + this.$input = this.$el.find('[data-input]').first() + this.$toggle = this.$el.find('[data-toggle]').first() + this.$icon = this.$el.find('[data-icon]').first() + this.$loader = this.$el.find('[data-loader]').first() + this.$copy = this.$el.find('[data-copy]').first() + + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + this.init() + } + + Sensitive.DEFAULTS = { + readOnly: false, + disabled: false, + eventHandler: null, + hideOnTabChange: false, + } + + Sensitive.prototype = Object.create(BaseProto) + Sensitive.prototype.constructor = Sensitive + + Sensitive.prototype.init = function() { + this.$input.on('keydown', this.proxy(this.onInput)) + this.$toggle.on('click', this.proxy(this.onToggle)) + + if (this.options.hideOnTabChange) { + // Watch for tab change or minimise + document.addEventListener('visibilitychange', this.proxy(this.onTabChange)) + } + + if (this.$copy.length) { + this.$copy.on('click', this.proxy(this.onCopy)) + } + } + + Sensitive.prototype.dispose = function () { + this.$input.off('keydown', this.proxy(this.onInput)) + this.$toggle.off('click', this.proxy(this.onToggle)) + + if (this.options.hideOnTabChange) { + document.removeEventListener('visibilitychange', this.proxy(this.onTabChange)) + } + + if (this.$copy.length) { + this.$copy.off('click', this.proxy(this.onCopy)) + } + + this.$input = this.$toggle = this.$icon = this.$loader = null + this.$el = null + + BaseProto.dispose.call(this) + } + + Sensitive.prototype.onInput = function() { + if (this.clean) { + this.clean = false + this.$input.val('') + } + + return true + } + + Sensitive.prototype.onToggle = function() { + if (this.$input.val() !== '' && this.clean) { + this.reveal() + } else { + this.toggleVisibility() + } + + return true + } + + Sensitive.prototype.onTabChange = function() { + if (document.hidden && !this.hidden) { + this.toggleVisibility() + } + } + + Sensitive.prototype.onCopy = function() { + var that = this, + deferred = $.Deferred(), + isHidden = this.hidden + + deferred.then(function () { + if (that.hidden) { + that.toggleVisibility() + } + + that.$input.focus() + that.$input.select() + + try { + document.execCommand('copy') + } catch (err) { + } + + that.$input.blur() + if (isHidden) { + that.toggleVisibility() + } + }) + + if (this.$input.val() !== '' && this.clean) { + this.reveal(deferred) + } else { + deferred.resolve() + } + } + + Sensitive.prototype.toggleVisibility = function() { + if (this.hidden) { + this.$input.attr('type', 'text') + } else { + this.$input.attr('type', 'password') + } + + this.$icon.toggleClass('icon-eye icon-eye-slash') + + this.hidden = !this.hidden + } + + Sensitive.prototype.reveal = function(deferred) { + var that = this + this.$icon.css({ + visibility: 'hidden' + }) + this.$loader.removeClass('hide') + + this.$input.request(this.options.eventHandler, { + success: function (data) { + that.$input.val(data.value) + that.clean = false + + that.$icon.css({ + visibility: 'visible' + }) + that.$loader.addClass('hide') + + that.toggleVisibility() + + if (deferred) { + deferred.resolve() + } + } + }) + } + + var old = $.fn.sensitive + + $.fn.sensitive = function (option) { + var args = Array.prototype.slice.call(arguments, 1), result + this.each(function () { + var $this = $(this) + var data = $this.data('oc.sensitive') + var options = $.extend({}, Sensitive.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.sensitive', (data = new Sensitive(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : this + } + + $.fn.sensitive.noConflict = function () { + $.fn.sensitive = old + return this + } + + $(document).render(function () { + $('[data-control="sensitive"]').sensitive() + }); + +}(window.jQuery); diff --git a/modules/backend/formwidgets/sensitive/assets/less/sensitive.less b/modules/backend/formwidgets/sensitive/assets/less/sensitive.less new file mode 100644 index 0000000..5717658 --- /dev/null +++ b/modules/backend/formwidgets/sensitive/assets/less/sensitive.less @@ -0,0 +1,10 @@ +@import "../../../../assets/less/core/boot.less"; + +div[data-control="sensitive"] { + a[data-toggle], + a[data-copy] { + box-shadow: none; + border: 1px solid @input-group-addon-border-color; + border-left: 0; + } +} diff --git a/modules/backend/formwidgets/sensitive/partials/_sensitive.htm b/modules/backend/formwidgets/sensitive/partials/_sensitive.htm new file mode 100644 index 0000000..b913070 --- /dev/null +++ b/modules/backend/formwidgets/sensitive/partials/_sensitive.htm @@ -0,0 +1,41 @@ +
    data-hide-on-tab-change="true" +> +
    +
    + previewMode): ?>disabled="disabled" + autocomplete="off" + data-input + /> + + + + + + + + +
    +
    + +
    +
    +
    diff --git a/modules/backend/formwidgets/taglist/partials/_taglist.htm b/modules/backend/formwidgets/taglist/partials/_taglist.htm new file mode 100644 index 0000000..ad375d4 --- /dev/null +++ b/modules/backend/formwidgets/taglist/partials/_taglist.htm @@ -0,0 +1,53 @@ + $option) { + if (!strlen($option)) { + continue; + } + if (($useKey && in_array($key, $selectedValues)) || (!$useKey && in_array($option, $selectedValues))) { + $displayOnlyOptions[] = $option; + } + } +?> + +previewMode || $field->readOnly || $field->disabled): ?> +
      readOnly || $field->disabled ? 'disabled="disabled"' : ''; ?>> + +
    • + +
    + value)): ?> + + + + + + + + + diff --git a/modules/backend/helpers/Backend.php b/modules/backend/helpers/Backend.php new file mode 100644 index 0000000..67c02e1 --- /dev/null +++ b/modules/backend/helpers/Backend.php @@ -0,0 +1,256 @@ +uri() . '/' . $path, $parameters, $secure); + } + + /** + * Returns the base backend URL + */ + public function baseUrl($path = null) + { + $backendUri = $this->uri(); + $baseUrl = Request::getBaseUrl(); + + if ($path === null) { + return $baseUrl . '/' . $backendUri; + } + + $path = RouterHelper::normalizeUrl($path); + return $baseUrl . '/' . $backendUri . $path; + } + + /** + * Returns a URL in context of the active Backend skin + */ + public function skinAsset($path = null) + { + $skinPath = Skin::getActive()->getPath($path, true); + return Url::asset($skinPath); + } + + /** + * Create a new redirect response to a given backend path. + */ + public function redirect($path, $status = 302, $headers = [], $secure = null) + { + return Redirect::to($this->uri() . '/' . $path, $status, $headers, $secure); + } + + /** + * Create a new backend redirect response, while putting the current URL in the session. + */ + public function redirectGuest($path, $status = 302, $headers = [], $secure = null) + { + return Redirect::guest($this->uri() . '/' . $path, $status, $headers, $secure); + } + + /** + * Create a new redirect response to the previously intended backend location. + */ + public function redirectIntended($path, $status = 302, $headers = [], $secure = null) + { + return Redirect::intended($this->uri() . '/' . $path, $status, $headers, $secure); + } + + /** + * makeCarbon converts mixed inputs to a Carbon object and sets the backend timezone + * @return \Carbon\Carbon + */ + public static function makeCarbon($value, $throwException = true) + { + $carbon = DateTimeHelper::makeCarbon($value, $throwException); + + try { + // Find user preference + $carbon->setTimezone(\Backend\Models\Preference::get('timezone')); + } + catch (Exception $ex) { + // Use system default + $carbon->setTimezone(Config::get('backend.timezone', Config::get('app.timezone'))); + } + + return $carbon; + } + + /** + * Proxy method for dateTime() using "date" format alias. + * @return string + */ + public function date($dateTime, $options = []) + { + return $this->dateTime($dateTime, $options + ['formatAlias' => 'date']); + } + + /** + * Returns the HTML for a date formatted in the backend. + * Supported for formatAlias: + * time -> 6:28 AM + * timeLong -> 6:28:01 AM + * date -> 04/23/2016 + * dateMin -> 4/23/2016 + * dateLong -> April 23, 2016 + * dateLongMin -> Apr 23, 2016 + * dateTime -> April 23, 2016 6:28 AM + * dateTimeMin -> Apr 23, 2016 6:28 AM + * dateTimeLong -> Saturday, April 23, 2016 6:28 AM + * dateTimeLongMin -> Sat, Apr 23, 2016 6:29 AM + * @return string + */ + public function dateTime($dateTime, $options = []) + { + extract(array_merge([ + 'defaultValue' => '', + 'format' => null, + 'formatAlias' => null, + 'jsFormat' => null, + 'timeTense' => false, + 'timeSince' => false, + 'ignoreTimezone' => false, + ], $options)); + + if (!$dateTime) { + return ''; + } + + $carbon = DateTimeHelper::makeCarbon($dateTime); + + if ($jsFormat !== null) { + $format = $jsFormat; + } + else { + $format = DateTimeHelper::momentFormat($format); + } + + $attributes = [ + 'datetime' => $carbon, + 'data-datetime-control' => 1, + ]; + + if ($ignoreTimezone) { + $attributes['data-ignore-timezone'] = true; + } + + if ($timeTense) { + $attributes['data-time-tense'] = 1; + } + elseif ($timeSince) { + $attributes['data-time-since'] = 1; + } + elseif ($format) { + $attributes['data-format'] = $format; + } + elseif ($formatAlias) { + $attributes['data-format-alias'] = $formatAlias; + } + + return ''.e($defaultValue).''.PHP_EOL; + } + + /** + * Decompiles the compilation asset files + * + * This is used to load each individual asset file, as opposed to using the compilation assets. This is useful only + * for development, to allow developers to test changes without having to re-compile assets. + * + * @param string $file The compilation asset file to decompile + * @param boolean $skinAsset If true, will load decompiled assets from the "skins" directory. + * @throws DecompileException If the compilation file cannot be decompiled + * @return array + */ + public function decompileAsset(string $file, bool $skinAsset = false) + { + $assets = $this->parseAsset($file, $skinAsset); + + return array_map(function ($asset) use ($skinAsset) { + // Resolve relative asset paths + if ($skinAsset) { + $assetPath = base_path(substr(Skin::getActive()->getPath($asset, true), 1)); + } else { + $assetPath = base_path($asset); + } + $relativePath = File::localToPublic(realpath($assetPath)); + + return Url::asset($relativePath); + }, $assets); + } + + /** + * Parse the provided asset file to get the files that it includes + * + * @param string $file The compilation asset file to parse + * @param boolean $skinAsset If true, will load decompiled assets from the "skins" directory. + * @return array + */ + protected function parseAsset($file, $skinAsset) + { + if ($skinAsset) { + $assetFile = base_path(substr(Skin::getActive()->getPath($file, true), 1)); + } else { + $assetFile = base_path($file); + } + + $results = [$file]; + + if (!file_exists($assetFile)) { + throw new DecompileException('File ' . $file . ' does not exist to be decompiled.'); + } + if (!is_readable($assetFile)) { + throw new DecompileException('File ' . $file . ' cannot be decompiled. Please allow read access to the file.'); + } + + $contents = file_get_contents($assetFile); + + // Find all assets that are compiled in this file + preg_match_all('/^=require\s+([A-z0-9-_+\.\/]+)[\n|\r\n|$]/m', $contents, $matches, PREG_SET_ORDER); + + // Determine correct asset path + $directory = str_replace(basename($file), '', $file); + + if (count($matches)) { + $results = array_map(function ($match) use ($directory) { + return str_replace('/', DIRECTORY_SEPARATOR, $directory . $match[1]); + }, $matches); + + foreach ($results as $i => $result) { + $nested = $this->parseAsset($result, $skinAsset); + array_splice($results, $i, 1, $nested); + } + } + + return $results; + } +} diff --git a/modules/backend/helpers/exception/DecompileException.php b/modules/backend/helpers/exception/DecompileException.php new file mode 100644 index 0000000..08e620c --- /dev/null +++ b/modules/backend/helpers/exception/DecompileException.php @@ -0,0 +1,7 @@ + [ + 'title' => 'لوحة الإدارة' + ], + 'page' => [ + 'access_denied' => [ + 'label' => 'ممنوع الوصول', + 'help' => "ليس لديك الصلاحيات لعرض هذه الصفحة.", + 'cms_link' => 'عودة للوحة الإدارة' + ], + ], + 'account' => [ + 'sign_out' => 'تسجيل خروج', + 'login' => 'تسجيل دخول', + 'reset' => 'استعادة', + 'restore' => 'استرجاع', + 'login_placeholder' => 'اسم المستخدم', + 'password_placeholder' => 'كلمة المرور', + 'forgot_password' => 'نسيت كلمة المرور؟', + 'enter_login' => 'أدخل اسم المستخدم', + ], + 'dashboard' => [ + 'menu_label' => 'لوحة الإدارة', + 'widget_width' => 'العرض', + 'full_width' => 'عرض كامل', + 'manage_widgets' => 'إدارة التطبيقات', + 'status' => [ + 'widget_title_default' => 'حالة النظام', + 'update_available' => '{0} تحديث متاح!|{1} تحديث متاح!|[2,Inf] تحديثات متاحة!', + 'updates_pending' => 'تحديثات في الانتظار', + 'updates_nil' => 'النظام محدث', + 'updates_link' => 'تحديث', + 'warnings_pending' => 'بعض الملاحظات تحتاج تأكيدك', + 'warnings_nil' => 'ليس هناك تحذيرات', + 'warnings_link' => 'عرض', + 'core_build' => 'نسخة النظام', + 'event_log' => 'سجل الأحداث', + 'request_log' => 'سجل الطلبات', + 'app_birthday' => 'أونلاين منذ', + ], + 'welcome' => [ + 'widget_title_default' => 'مرحباً', + 'welcome_back_name' => 'مرحباً بك في :app, :name.', + 'welcome_to_name' => 'مرحباً بك في :app, :name.', + 'first_sign_in' => 'هذا هو أول تسجيل دخول لك.', + 'last_sign_in' => 'آخر تسجيل دخول لك كان في', + 'view_access_logs' => 'عرض سجلات الدخول', + 'nice_message' => 'نتمنى لك يوماً سعيداً!', + ] + ], + 'list' => [ + 'default_title' => 'القائمة', + 'search_prompt' => 'بحث...', + 'no_records' => 'لا توجد سجلات.', + 'pagination' => 'السجلات المعروضة: :from-:to من :total', + 'delete_selected' => 'حذف المحدد', + 'delete_selected_empty' => 'ليس هناك سجلات محددة لحذفها.', + 'delete_selected_confirm' => 'هل أنت متأكد من حذف السجلات المحددة؟', + 'delete_selected_success' => 'حذف السجلات المحددة.', + 'column_switch_true' => 'نعم', + 'column_switch_false' => 'لا' + ], + 'form' => [ + 'action_confirm' => 'هل أنت متأكد؟', + 'create' => 'إضافة', + 'create_and_close' => 'إضافة وإغلاق', + 'creating' => 'جاري الإضافة...', + 'save' => 'حفظ', + 'save_and_close' => 'حفظ وإغلاق', + 'saving' => 'جاري الحفظ...', + 'delete' => 'حذف', + 'deleting' => 'جاري الحذف...', + 'confirm_delete_multiple' => 'هل أنت متأكد من حذف ما تم تحديده؟', + 'cancel' => 'إلغاء الأمر', + 'close' => 'إغلاق', + 'confirm' => 'تأكيد', + 'ok' => 'موافقة', + 'or' => 'أو', + 'create_title' => 'إضافة :name', + 'update_title' => 'تعديل :name', + 'preview_title' => 'عرض :name', + 'create_success' => 'تم إنشاء :name بنجاح', + 'update_success' => 'تم تعديل :name بنجاح', + 'delete_success' => 'تم حذف :name بنجاح', + 'restore_success' => 'تم استعادة :name بنجاح', + 'reset_success' => 'تمت الاستعادة', + 'missing_id' => 'لا يمكن العثور على هذا السجل.', + 'not_found' => 'السجل رقم :id غير موجود.', + 'creating_name' => 'إضافة :name...', + 'saving_name' => 'حفظ :name...', + 'confirm_delete' => 'هل أنت متأكد من الحذف?', + 'confirm_delete_multiple' => 'هل أنت متأكد من حذف السجلات المحددة?', + 'deleting_name' => 'جاري حذف :name...', + 'restore' => 'استعادة', + 'restoring' => 'استعادة', + 'confirm_restore' => 'هل أنت متأكد من استعادة هذا السجل?', + 'add' => 'إضافة', + 'apply' => 'تطبيق', + 'reload' => 'إعادة تحميل', + 'complete' => 'تم', + 'select' => 'تحديد', + 'select_all' => 'اختر الكل', + 'select_none' => 'لا تختر شيء', + 'select_placeholder' => 'من فضلك اختار', + 'insert_row' => 'إضافة سجل', + 'return_to_list' => 'عودة للقائمة', + ], + 'relation' => [ + 'help' => 'اضغط على عنصر لإضافته', + 'related_data' => 'بيانات :name المرتبطة', + 'add' => 'إضافة', + 'add_selected' => 'إضافة المحدد', + 'add_a_new' => 'أضف :name', + 'link_selected' => 'ربط المحدد', + 'link_a_new' => 'ربط :name', + 'cancel' => 'إلغاء الأمر', + 'close' => 'إغلاق', + 'add_name' => 'أضف :name', + 'create' => 'إنشاء', + 'create_name' => 'إنشاء :name', + 'update' => 'تحديث', + 'update_name' => 'تحديث :name', + 'preview' => 'استعراض', + 'preview_name' => 'استعراض :name', + 'remove' => 'إزالة', + 'remove_name' => 'إزالة :name', + 'delete' => 'حذف', + 'delete_name' => 'حذف :name', + 'delete_confirm' => 'هل أنت متأكد؟', + 'link' => 'ربط', + 'link_name' => 'ربط :name', + 'unlink' => 'إلغاء ربط', + 'unlink_name' => 'إلغاء ربط :name', + 'unlink_confirm' => 'هل أنت متأكد؟' + ], + 'reorder' => [ + 'default_title' => 'إعادة الترتيب', + 'no_records' => 'ليس هناك سجلات لإعادة ترتيبها.' + ], + 'myaccount' => [ + 'menu_label' => 'حسابي', + ], + 'backend_preferences' => [ + 'menu_label' => 'تفضيلات لوحة الإدارة', + ], + 'filter' => [ + 'all' => 'الكل', + 'date_all' => 'كل الفترات', + 'number_all' => 'كل الأرقام', + ], + 'import_export' => [ + 'created' => 'تمت الإضافة', + 'updated' => 'تم التعديل', + 'skipped' => 'تم تجاهله', + 'warnings' => 'تحذيرات', + 'errors' => 'أخطاء', + 'processing' => 'معالجة', + 'file_not_found_error' => 'الملف غير موجود', + ], + 'media' => [ + 'menu_label' => 'الوسائط', + 'delete_confirm' => 'هل أنت متأكد من حذف العناصر المحددة؟', + ], +]; diff --git a/modules/backend/lang/be/lang.php b/modules/backend/lang/be/lang.php new file mode 100644 index 0000000..7122157 --- /dev/null +++ b/modules/backend/lang/be/lang.php @@ -0,0 +1,534 @@ + [ + 'title' => "Панэль кіравання" + ], + 'field' => [ + 'invalid_type' => "Выкарыстаны няправільны тып поля: \":type\"", + 'options_method_invalid_model' => "Для атрыбуту \":field\" не была знойздена адпаведная мадэль. Паспрабуйце яўна вызначыць метад опцый для мадэлі \":model\"", + 'options_method_not_exists' => "Клас мадэлі \":model\" павінен мець метад \":method()\", які вяртае опцыі для поля формы \":field\"" + ], + 'widget' => [ + 'not_registered' => "Віджэт з імем класа \":name\" не быў зарэгістрыраваны", + 'not_bound' => "Віджэт з імем класа \":name\" не быў злучаны з кантролерам" + ], + 'page' => [ + 'untitled' => "Без назвы", + 'access_denied' => [ + 'label' => "Доступ забаронены", + 'help' => "У вас няма патрэбных праў для прагляду гэтай старонкі", + 'cms_link' => 'Вярнуцца у панэль кіравання' + ], + 'no_database' => [ + 'label' => "Няма базы дадзеных", + 'help' => "Неабходна база дадзеных мець доступ у панэль кіравання. Праверце, што база дадзеных правільна наладжаная, а міграцыі выкананыя, перад тым, як пасправаць зноў", + 'cms_link' => "Вярнуцца на хатнюю старонку" + ], + ], + 'partial' => [ + 'not_found_name' => "Частковы шаблон \":name\" не знойдзены." + ], + 'account' => [ + 'sign_out' => "Выйсці", + 'login' => "Увайсці", + 'reset' => "Скасаваць", + 'restore' => "Аднавіць", + 'login_placeholder' => "Карыстальнік", + 'password_placeholder' => "Пароль", + 'forgot_password' => "Забыліся пароль?", + 'enter_email' => "Увядзіце электронную пошту", + 'enter_login' => "Увядзіце імя карыстальніка", + 'email_placeholder' => "Электронная пошта", + 'enter_new_password' => "Увядзіце новы пароль", + 'password_reset' => "Скасаванне паролю", + 'restore_success' => "На Вашу электронную пошту было адпраўлена паведамленне з інструкцыямі", + 'restore_error' => "Імя карыстальніка \":login\" не было знойдзена", + 'reset_success' => "Пароль быў зменены, цяпер Вы можаце ўвайсці", + 'reset_error' => "Няправільныя дадзеныя для змены пароля. Паспрабуйце яшчэ!", + 'reset_fail' => "Немагчыма змяніць пароль!", + 'apply' => "Ужыць", + 'cancel' => "Адмяніць", + 'delete' => "Выдаліць", + 'ok' => "Добра" + ], + 'dashboard' => [ + 'menu_label' => "Панэль кіравання", + 'widget_label' => "Віджэт", + 'widget_width' => "Шырыня віджэта", + 'full_width' => "Поўная шырыня", + 'manage_widgets' => "Кіраванне віджэтамі", + 'add_widget' => "Дадаць віджэт", + 'widget_inspector_title' => "Канфігурацыя віджэта", + 'widget_inspector_description' => "Налада адлюстравання віджэта", + 'widget_columns_label' => "Шырыня :columns", + 'widget_columns_description' => "Шырыня віджэта, лічба паміж 1 і 10", + 'widget_columns_error' => "Калі ласка, ужывайце лічбы ад 1 да 10 у якасці шырыні віджэта", + 'columns' => "{1} слупок|[2,4] слупкі|[5,Inf] слупкоў", + 'widget_new_row_label' => "Новы радок", + 'widget_new_row_description' => "Размясціць віджэт на новым радку", + 'widget_title_label' => "Назва віджэта", + 'widget_title_error' => "Віджэт павінен мець назву", + 'reset_layout' => "Скасаваць макет", + 'reset_layout_confirm' => "Скасаваць макет да зыходных наладаў", + 'reset_layout_success' => "Макет быў скасаваны", + 'make_default' => "Зрабіць зыходным", + 'make_default_confirm' => "Зрабіць дадзены макет заходным?", + 'make_default_success' => "Гэты макет цяпер зыходны", + 'status' => [ + 'widget_title_default' => "Статус сістэмы", + 'update_available' => "{0} абнаўленняў!|{1} абнаўленне!|[2,4] абнаўленні!|[5,Inf] абнаўленняў", + 'updates_pending' => "Абнаўленні праграмнага забеспячэння ў чаканні", + 'updates_nil' => "Праграмнае забеспячэнне ў актуальным стане", + 'updates_link' => "Абнавіць", + 'warnings_pending' => "Што патрабуе ўвагі", + 'warnings_nil' => "Няма папярэджанняў", + 'warnings_link' => "Прагледзець", + 'core_build' => "Зборка сістэмы", + 'event_log' => "Журнал падзей", + 'request_log' => "Спіс запытаў", + 'app_birthday' => "Анлайн з", + ], + 'welcome' => [ + 'widget_title_default' => "Сардэчна запрашаем", + 'welcome_back_name' => "Сардэчна запрашаем назад да :app, :name.", + 'welcome_to_name' => "Сардэчна запрашаем да :app, :name.", + 'first_sign_in' => "Гэта першы раз, калі Вы ўвайшлі", + 'last_sign_in' => "Ваш апошні ўваход быў", + 'view_access_logs' => "Прагледзець журнал доступу", + 'nice_message' => "Добрага дню!", + ] + ], + 'user' => [ + 'name' => "Адміністратар", + 'menu_label' => "Адміністратары", + 'menu_description' => "Кіраванне карыстальнікамі панэлі кіравання, групамі і дазволамі", + 'list_title' => "Кіраванне адміністратарамі", + 'new' => "Новы адміністратар", + 'login' => "Лагін", + 'first_name' => "Імя", + 'last_name' => "Прозвішча", + 'full_name' => "Поўнае імя", + 'email' => "Электронная пошта", + 'groups' => "Групы", + 'groups_comment' => "Укажыце, да якіх груп павінен належаць профіль. Для карыстальнікаў групы вызначаюць дазволы, якія для кожнага карыстальніка могуць быць перапісаны на яго ўзроўні на вокладцы \"Дазволы\"", + 'avatar' => "Аватар", + 'password' => "Пароль", + 'password_confirmation' => "Пацвердзіце пароль", + 'permissions' => "Дазволы", + 'account' => "Профіль", + 'superuser' => "Супер карыстальнік", + 'superuser_comment' => "Надзяляе гэтага карыстальніка неабмежаванымі магчымасцямі ва ўсіх абласцях сістэмы. Супер карыстальнікі могуць дадаваць і змяняць іншых карыстальнікаў", + 'send_invite' => "Выслаць запрашэнне па электроннай пошце", + 'send_invite_comment' => "Дасылае вітальнае паведамленне з лагінам і паролем", + 'delete_confirm' => "Выдаліць гэтага адміністратара?", + 'return' => "Вярнуцца да спісу адміністратараў", + 'allow' => "Дазволіць", + 'inherit' => "Успадкаваць", + 'deny' => "Забараніць", + 'activated' => "Актываваны", + 'last_login' => "Апошні ўваход", + 'created_at' => "Створаны", + 'updated_at' => "Абноўлены", + 'group' => [ + 'name' => "Група", + 'name_comment' => "Імя адлюстроўваецца ў спісе груп на форме стварэння і рэдагавання адміністратараў", + 'name_field' => "Назва", + 'description_field' => "Апісанне", + 'is_new_user_default_field_label' => "Група па змаўчанні", + 'is_new_user_default_field_comment' => "Дадаваць новых адміністратараў у гэтую групу па змаўчанні", + 'code_field' => "Код", + 'code_comment' => "Увядзіце унікальны код, калі Вы жадаеце мець доступ да групы скрозь API", + 'menu_label' => "Кіраванне групамі", + 'list_title' => "Кіраванне групамі", + 'new' => "Новая група", + 'delete_confirm' => "Выдаліць гэтую адміністратарскую групу?", + 'return' => "Вярнуцца да спісу груп", + 'users_count' => "Карыстальнікі" + ], + 'preferences' => [ + 'not_authenticated' => "Немагчыма загрузіць ці захаваць налады для невядомага карыстальніка" + ] + ], + 'list' => [ + 'default_title' => "Спіс", + 'search_prompt' => "Пошук...", + 'no_records' => "Няма запісаў для прагляду", + 'missing_model' => "Для спіса, які выкарыстоўваецца ў класе \":class\", не знойдзена мадэль", + 'missing_column' => "Няма ніводных вызначэнняў слупкоў для \":columns\"", + 'missing_columns' => "Спіс, ужыты ў класе \":class\", не мае пэўных слупкоў", + 'missing_definition' => "Вызначаны спіс не мае слупка для поля \":field\"", + 'missing_parent_definition' => "Налады спіса не маюць вызначэнняў для \":definition\"", + 'behavior_not_ready' => "Паводзіны спіса не былі вызначаны, праверце, што Вы вызвалі makeLists() у кантролеры", + 'invalid_column_datetime' => "Значэнне слупку \":column\" не з'яўляецца аб'ектам тыпу DateTime, можа ў Вас адсутнічае спасылка на \$dates у мадэлі?", + 'pagination' => "Паказаныя запісы: :from-:to з :total", + 'prev_page' => "Папярэдняя старонка", + 'next_page' => "Наступная старонка", + 'refresh' => "Абнавіць", + 'updating' => 'Абнаўленне...', + 'loading' => 'Загрузка...', + 'setup_title' => "Налады лісту", + 'setup_help' => "З дапамогай сцяжкоў вызначце слупкі для лісту. Вы можаце змяніць пазіцыю слупкоў, перацягваючы іх уверх і ўніз", + 'records_per_page' => "Запісаў на старонку", + 'records_per_page_help' => "Вызначце, колькі запісаў павінна быць на адной старонцы. Памятайце, што вялікая колькасць запісаў можа паменьшыць прадукцыйнасць", + 'check' => "Праверыць", + 'delete_selected' => "Выдаліць абраныя", + 'delete_selected_empty' => "Няма абраных запісаў для выдалення", + 'delete_selected_confirm' => "Выдяліць абраныя запісы?", + 'delete_selected_success' => "Абраныя запісы былі выдаленыя", + 'column_switch_true' => "Так", + 'column_switch_false' => "Не" + ], + 'fileupload' => [ + 'attachment' => "Прымацаванне", + 'help' => "Дадайце назву і апісанне для гэтага прымацавання", + 'title_label' => "Назва", + 'description_label' => "Апісанне", + 'default_prompt' => "Націсніце %s альбо перацягніце файл сюды, каб загрузіць", + 'attachment_url' => "URL прымацавання", + 'upload_file' => "Загрузіць файл", + 'upload_error' => "Памылка загрузкі", + 'remove_confirm' => "Вы ўпэўнены?", + 'remove_file' => "Выдаліць файл" + ], + 'form' => [ + 'create_title' => "Новая :name", + 'update_title' => "Рэдагаваць :name", + 'preview_title' => "Папярэдні прагляд :name", + 'create_success' => ":name была створаная", + 'update_success' => ":name абноўленая", + 'delete_success' => ":name выдаленая", + 'reset_success' => "Скід зроблены", + 'missing_id' => "Ідентыфікатар запісу формы не быў указаны", + 'missing_model' => "Для паводзінаў форму ў класе \":class\" няма вызначанай мадэлі", + 'missing_definition' => "Паводзіны формы не маюць поля для \":field\"", + 'not_found' => "Немагчыма знайсці запіс формы з ідэнтыфікатарам :id", + 'action_confirm' => "Вы ўпэўнены?", + 'create' => "Стварыць", + 'create_and_close' => "Стварыць і зачыніць", + 'creating' => "Стварэнне...", + 'creating_name' => "Стварэнне :name...", + 'save' => "Захаваць", + 'save_and_close' => "Захаваць і зачыніць", + 'saving' => "Захаванне...", + 'saving_name' => "Захаванне :name...", + 'delete' => "Выдаліць", + 'deleting' => "Выдаленне...", + 'confirm_delete' => "Выдаліць запіс?", + 'confirm_delete_multiple' => "Выдаліць абраныя запісы?", + 'deleting_name' => "Выдаленне :name...", + 'reset_default' => "Скінуць да стану па змаўчанні", + 'resetting' => "Скіданне", + 'resetting_name' => "Скіданне :name", + 'undefined_tab' => "Рознае", + 'field_off' => "Выкл", + 'field_on' => "Укл", + 'add' => "Дадаць", + 'apply' => "Ужыць", + 'cancel' => "Адмяніць", + 'close' => "Зачыніць", + 'confirm' => "Пацвердзіць", + 'reload' => "Перазагрузіць", + 'complete' => "Завяршыць", + 'ok' => "Добра", + 'or' => "ці", + 'confirm_tab_close' => "Зачыніць вокладку? Незахаваныя змяненні будуць згубленыя", + 'behavior_not_ready' => "Паводзіны формы пакуль не былі ініцыялізаваныя, упэўніцеся, што Вы выканалі initForm() у сваім кантролеры", + 'preview_no_files_message' => "Няма загружаных файлаў", + 'preview_no_record_message' => "Няма выбраных запісаў", + 'select' => "Выбраць", + 'select_all' => "абраць усё", + 'select_none' => "выбраць няма", + 'select_placeholder' => "Калі ласка, выберыце", + 'insert_row' => "Уставіць радок", + 'insert_row_below' => "Уставіць радок ніжэй", + 'delete_row' => "Выдаліць радок", + 'concurrency_file_changed_title' => "Файл быў зменены", + 'concurrency_file_changed_description' => "Файл які вы рэдагуеце быў зменены на діску іншым карыстальнікам. Вы можаце альбо перазагрузіць файл і згубіць сваі змяненні, альбо перазапісаць файл на діску", + 'return_to_list' => "Вярнуцца да спісу" + ], + 'recordfinder' => [ + 'find_record' => "Знайсці запіс" + ], + 'pagelist' => [ + 'page_link' => "Спасылка на староку", + 'select_page' => "Выберыце старонку..." + ], + 'relation' => [ + 'missing_config' => "Паводзіны стаўлення не маюць ніводнай канфігурацыі для \":config\"", + 'missing_definition' => "Паводзіны стаўлення не маюць вызначэнняў для поля \":field\"", + 'missing_model' => "Паводзіны стаўлення ў :class не маюць вызначанай мадэлі", + 'invalid_action_single' => "Гэтае дзеянне немагчыма выканаць на адзіночным стаўленні", + 'invalid_action_multi' => "Гэтае дзеянне немагчыма выканаць на множным стаўленні", + 'help' => "Націсніце на пункт, каб дадаць", + 'related_data' => "Роднасныя :name дадзеныя", + 'add' => "Дадаць", + 'add_selected' => "Дадаць выбраныя", + 'add_a_new' => "Дадаць новае :name", + 'link_selected' => "Звязаць выбраныя", + 'link_a_new' => "Звязаць з новым :name", + 'cancel' => "Адмяніць", + 'close' => "Зачыніць", + 'add_name' => "Дадаць :name", + 'create' => "Стварыць", + 'create_name' => "Стварыць :name", + 'update' => "Абнавіць", + 'update_name' => "Абнавіць :name", + 'preview' => "Папярэдні прагляд", + 'preview_name' => "Прагледзець :name", + 'remove' => "Выдаліць", + 'remove_name' => "Выдаліць :name", + 'delete' => "Выдаліць", + 'delete_name' => "Выдаліць :name", + 'delete_confirm' => "Вы ўпэўнены?", + 'link' => "Звязаць", + 'link_name' => "Звязаць :name", + 'unlink' => "Раз'яднаць", + 'unlink_name' => "Раз'яднаць :name", + 'unlink_confirm' => "Вы ўпэўнены?" + ], + 'reorder' => [ + 'default_title' => "Змяніць парадак запісаў", + 'no_records' => "Няма запісаў для сартавання" + ], + 'model' => [ + 'name' => 'Мадэль', + 'not_found' => "Немагчыма знайсці мадэль \":class\" з ідэнтыфікатарам \":id\"", + 'missing_id' => "Не вызначаны ідэнтыфікатар для пошуку запісу мадэлі", + 'missing_relation' => "Мадэль \":class\" не мае вызначэнняў для \":relation\"", + 'missing_method' => "Мадэль \":class\" не мае метаду \":method\"", + 'invalid_class' => "Мадэль \":model\" выкарыстаная ў класе \":class\" неправільная, яна павінна ўспадкоўваць клас \\Model", + 'mass_assignment_failed' => "Памылковае масавае прызначэнне для атрыбуту \":attribute\"" + ], + 'warnings' => [ + 'tips' => "Парады па канфігурацыі сістэмы", + 'tips_description' => "Ёсць пытанні, на якія Вам неабходна звярнуць увагу, каб наладзіць сістэму належным чынам", + 'permissions' => "PHP не можа пісаць у каталог \":name\" альбо ў яго падкаталогі. Калі ласка, вызначце патрэбныя дазволы ў наладах сервера для гэтага каталога", + 'extension' => "Пашыранне PHP \":name\" не ўсталявана. Калі ласка, ўсталюце пашырэнне і актывуйце яго" + ], + 'editor' => [ + 'menu_label' => "Налады рэдактара", + 'menu_description' => "Налада глабальных наладаў рэдактара, такіх як памер шрыфта і каляровая схема", + 'font_size' => "Памер шрыфта", + 'tab_size' => "Памер табуляцыі", + 'use_hard_tabs' => "Водступ з дапамогай табуляцыі", + 'code_folding' => "Складванне коду", + 'code_folding_begin' => "Пазначыць пачатак", + 'code_folding_begin_end' => "Пазначыць пачатак і канец", + 'autocompletion' => "Аўтазавяршэнне", + 'word_wrap' => "Перанос слоў", + 'highlight_active_line' => "Вылучыць актыўную лінію", + 'auto_closing' => "Аўтаматычна зачыняць тэгі", + 'show_invisibles' => "Паказваць нябачныя сімвалы", + 'show_gutter' => "Паказваць нумерацыю радкоў", + 'basic_autocompletion'=> "Простае аўтазавяршэнне (Ctrl + Space)", + 'live_autocompletion'=> "Жывое аўтазавяршэнне", + 'enable_snippets'=> "Уключыць фрагменты кода (Tab)", + 'display_indent_guides'=> "Паказываць водступы", + 'show_print_margin'=> "Паказываць палі для друку", + 'mode_off' => "Выкл", + 'mode_fluid' => "Вадкі", + '40_characters' => "40 сімвалаў", + '80_characters' => "80 сімвалаў", + 'theme' => "Каляровая схема", + 'markup_styles' => "Стылі макету", + 'custom_styles' => "Прыстасаваныя табліцы стыляў", + 'custom styles_comment' => "Прыстасаваныя стылі якія патрэбна дадаць у рэдактар", + 'markup_classes' => "Класы макету", + 'paragraph' => "Параграф", + 'link' => "Спасылка", + 'table' => "Табліца", + 'table_cell' => "Клетка табліцы", + 'image' => "Карцінка", + 'label' => "Назва", + 'class_name' => "Імя класу", + 'markup_tags' => "Тэгі макету", + 'allowed_empty_tags' => "Дазволеныя пустыя тэгі", + 'allowed_empty_tags_comment' => "Ліст тэгаў, якія не выдаляюцца нават без зместу", + 'allowed_tags' => "Дазволеныя тэгі", + 'allowed_tags_comment' => "Ліст дазволеных тэгаў", + 'no_wrap' => "Не абгортваць тэгі", + 'no_wrap_comment' => "Ліст тэгаў, якія не абгортваюцца блокавымі тэгамі", + 'remove_tags' => "Выдаліць тэгі", + 'remove_tags_comment' => "Ліст тэгаў, якія выдаляюцца разам са зместам" + ], + 'tooltips' => [ + 'preview_website' => "Праглядзець сайт" + ], + 'mysettings' => [ + 'menu_label' => "Маі налады", + 'menu_description' => "Налады для Вашага акаунту" + ], + 'myaccount' => [ + 'menu_label' => "Мой акаунт", + 'menu_description' => "Абнавіць прыватныя налады (імя, электронную пошту, пароль)", + 'menu_keywords' => "бяспека лагін" + ], + 'branding' => [ + 'menu_label' => "Налады адлюстравання панэлі кіравання", + 'menu_description' => "Налады панэлі кіравання, такія як колер фона, лагатып, апісанні", + 'brand' => "Брэнд", + 'logo' => "Лагатып", + 'logo_description' => "Загрузіце лагатып для ўжывання ў панэлі кіравання", + 'app_name' => "Назва прыкладання", + 'app_name_description' => "Гэта імя паказваецца ў загалоўку панэлі кіравання", + 'app_tagline' => "Слоган прыкладання", + 'app_tagline_description' => "Гэты слоган паказваецца на старонцы ўваходу", + 'colors' => "Колеры", + 'primary_color' => "Галоўны колер", + 'secondary_color' => "Дадатковы колер", + 'accent_color' => "Акцэнтавы колер", + 'styles' => "Стылі", + 'custom_stylesheet' => "Карыстацкія табліцы стыляў", + 'navigation' => "Навігацыя", + 'menu_mode' => "Стыль меню", + 'menu_mode_inline' => "Строкавы", + 'menu_mode_tile' => "Плітка", + 'menu_mode_collapsed' => "Выпадаючы" + ], + 'backend_preferences' => [ + 'menu_label' => "Сістэмныя налады панэлі кіравання", + 'menu_description' => "Кіруйце такімі наладамі, як, напрыклад, мовай прыкладання", + 'region' => "Рэгіён", + 'code_editor' => "Рэдактар коду", + 'timezone' => "Часавая зона", + 'timezone_comment' => "Настройка адлюстравання дат у гэтым часавым поясе", + 'locale' => "Лакалізацыя", + 'locale_comment' => "Выберыце жаданую лакалізацыю, каб змяніць мову" + ], + 'access_log' => [ + 'hint' => "Гэты ліст паказвае паспяховыя спробы ўваходу адміністратараў. Запісы захоўваюцца на працягу :days д", + 'menu_label' => "Дзеннік доступаў", + 'menu_description' => "Прагледзець ліст паспяховых уваходаў у панэль кіравання", + 'created_at' => "Дата і час", + 'login' => "Лагін", + 'ip_address' => "IP адрас", + 'first_name' => "Імя", + 'last_name' => "Прозвішча", + 'email' => "Электронная пошта" + ], + 'filter' => [ + 'all' => 'all', + 'options_method_not_exists' => "The model class :model must define a method :method() returning options for the ':filter' filter.", + 'date_all' => 'all period' + ], + 'import_export' => [ + 'upload_csv_file' => "1. Загрузіць CSV файл", + 'import_file' => "Імпартаваць файл", + 'first_row_contains_titles' => "Першы радок утрымлівае назвы слупкоў", + 'first_row_contains_titles_desc' => "Пакіньце гэтую пазнаку, калі першы радок утрымлівае назвы слупкоў", + 'match_columns' => "2. Суаднесці слупкі з палямі ў табліцы базы дадзеных", + 'file_columns' => "Слупкі файла", + 'database_fields' => "Палі базы дадзеных", + 'set_import_options' => "3. Налады імпарту", + 'export_output_format' => "1. Фармат выходнага файлу экспарту", + 'file_format' => "Фармат файлу", + 'standard_format' => "Стандартны фармат", + 'custom_format' => "Фармат карыстальніка", + 'delimiter_char' => "Сімвал для абмежавання", + 'enclosure_char' => "Сімвал для абгароджвання", + 'escape_char' => "Сімвал для экранавання", + 'select_columns' => "2. Выберыце слупкі для экспарту", + 'column' => "Слупок", + 'columns' => "Слупкі", + 'set_export_options' => "3. Налады экспарту", + 'show_ignored_columns' => "Паказаць слупкі якія ігнаруюцца", + 'auto_match_columns' => "Аўтаматычныя суадносіны слупкоў", + 'created' => "Створана", + 'updated' => "Абноўлена", + 'skipped' => "Прапушчана", + 'warnings' => "Папярэджанні", + 'errors' => "Памылкі", + 'skipped_rows' => "Прапушчаныя радкі", + 'import_progress' => "Прагрэс імпарту", + 'processing' => "Абработка", + 'import_error' => "Памылка імпарту", + 'upload_valid_csv' => "Калі ласка, загрузіце правільны CSV файл", + 'drop_column_here' => "Скінуць слупок сюды...", + 'ignore_this_column' => "Ігнараваць гэты слупок", + 'processing_successful_line1' => "Экспарт завершаны!", + 'processing_successful_line2' => "Браўзер зараз пяройдзе да пампавання файла", + 'export_progress' => "Прагрэс экспарту", + 'export_error' => "Памылка экспарту", + 'column_preview' => "Прагляд слупкоў", + 'file_not_found_error' => "Файл не знойдзены", + 'empty_error' => "Няма дадзеных для экспарту", + 'empty_import_columns_error' => "Калі ласка, укажыце слупкі для імпарту", + 'match_some_column_error' => "Калі ласка, спачатку суаднясіце некалькі слупкоў", + 'required_match_column_error' => "Калі ласка, вызначце суадносіны для патрэбнага слупка \":label\"", + 'empty_export_columns_error' => "Калі ласка, вызначце слупкі для экспарту", + 'behavior_missing_uselist_error' => "Вы павінны вызначыць паводзіны кантролера ListController з уключанай наладай \"useList\"", + 'missing_model_class_error' => "Калі ласка вызначце modelClass уласцівасць для \":type\"", + 'missing_column_id_error' => "Прапушчаны ідэнтыфікатар слупка", + 'unknown_column_error' => "Невядомы слупок", + 'encoding_not_supported_error' => "Не атрымалася вызначыць кадзіроўку файла. Калі ласка, выберыце правільны фармат самастойна", + 'encoding_format' => "Кадзіроўка файла" + ], + 'permissions' => [ + 'manage_media' => "Загрузка і кіраванне медыя зместам - выявы, відэа, гукі, дакументы" + ], + 'mediafinder' => [ + 'label' => "Медыя каталог", + 'default_prompt' => "Націсніце %s кнопку, каб адшукаць медыя файлы" + ], + 'media' => [ + 'menu_label' => "Медыя", + 'upload' => "Загрузіць", + 'move' => "Перамясціць", + 'delete' => "Выдаліць", + 'add_folder' => "Дадаць каталог", + 'search' => "Пошук", + 'display' => "Паказаць", + 'filter_everything' => "Усё", + 'filter_images' => "Выявы", + 'filter_video' => "Відэа", + 'filter_audio' => "Аўдыё", + 'filter_documents' => "Дакументы", + 'library' => "Бібліятэка", + 'size' => "Памер", + 'title' => "Назва", + 'last_modified' => "Час апошняй мадыфікацыі", + 'public_url' => "Публічны URL", + 'click_here' => "Націсніце сюды", + 'thumbnail_error' => "Памылка падчас генерацыі мініяцюры", + 'return_to_parent' => "Вярнуцца да бацькоўскага каталогу", + 'return_to_parent_label' => "Падняцца ..", + 'nothing_selected' => "Нічога не выбрана", + 'multiple_selected' => "Шматлікія аб'екты выбраны", + 'uploading_file_num' => "Загрузка :number файла(аў)...", + 'uploading_complete' => "Загрузка скончаная", + 'uploading_error' => "Не атымалася загрузіць", + 'type_blocked' => "Гэты тып файлу заблакіраваны з-за небяспекі", + 'order_by' => "Сартаваць па", + 'folder' => "Каталог", + 'no_files_found' => "Не знойдзена файлаў па Вашым запыце", + 'delete_empty' => "Калі ласка, вызначце файлы для выдалення", + 'delete_confirm' => "Выдаліць абраныя аб'екты?", + 'error_renaming_file' => "Памылка падчас пераіменавання аб'екту", + 'new_folder_title' => "Новы каталог", + 'folder_name' => "Імя каталогу", + 'error_creating_folder' => "Памылка падчас стварэння каталогу", + 'folder_or_file_exist' => "Каталог альбо файл з такім імем ужо існуе", + 'move_empty' => "Калі ласка, выберыце аб'екты для перамяшчэння", + 'move_popup_title' => "Перамясціць файлы альбо каталогі", + 'move_destination' => "Каталог прызначэння", + 'please_select_move_dest' => "Калі ласка, выберыце каталог прызначэння", + 'move_dest_src_match' => "Калі ласка, выберыце іншы каталог прызначэння", + 'empty_library' => "Медыя бібліятэка пустая. Загрузіце файлы альбо стварыце каталогі, каб пачаць", + 'insert' => "Уставіць", + 'crop_and_insert' => "Абрэзаць і ўставіць", + 'select_single_image' => "Калі ласка, выберыце адну выяву", + 'selection_not_image' => "Абраны аб'ект не з'яўляецца файлам", + 'restore' => "Адмяніць усе змяненні", + 'resize' => "Змяніць памер...", + 'selection_mode_normal' => "Нармальны", + 'selection_mode_fixed_ratio' => "Фіксіраваныя суадносіны старонак", + 'selection_mode_fixed_size' => "Фіксіраваны памер", + 'height' => "Вышыня", + 'width' => "Шырыня", + 'selection_mode' => "Рэжым выбару", + 'resize_image' => "Змяніць памер", + 'image_size' => "Памер выявы:", + 'selected_size' => "Выбрана:" + ] +]; diff --git a/modules/backend/lang/bg/lang.php b/modules/backend/lang/bg/lang.php new file mode 100644 index 0000000..31f924e --- /dev/null +++ b/modules/backend/lang/bg/lang.php @@ -0,0 +1,438 @@ + [ + 'title' => 'Администраторски Панел' + ], + 'field' => [ + 'invalid_type' => 'Използвано невалиден тип поле :type.', + 'options_method_not_exists' => "Моделът клас :model трябва да се определя метод :method() връщайки настройки за ':field' поле." + ], + 'widget' => [ + 'not_registered' => "Името на класът за джаджата ':name' не е било регистрирано", + 'not_bound' => "Джаджата с име на класът ':name' не е бил свързан към контролера" + ], + 'page' => [ + 'untitled' => 'Неозаглавен', + 'access_denied' => [ + 'label' => 'Отказан достъп', + 'help' => "Вие нямате нужните права за да видите тази страница.", + 'cms_link' => 'Върни се към администраторския-панел' + ], + ], + 'partial' => [ + 'not_found_name' => "Частичната страница ':name' не е намерена." + ], + 'account' => [ + 'sign_out' => 'Изход', + 'login' => 'Вход', + 'reset' => 'Нулиране', + 'restore' => 'Възстановяване', + 'login_placeholder' => 'вход', + 'password_placeholder' => 'парола', + 'forgot_password' => 'Забравена парола?', + 'enter_email' => 'Напиши своя имейл', + 'enter_login' => 'Напиши своя акаунт', + 'email_placeholder' => 'имейл', + 'enter_new_password' => 'Въведи нова парола', + 'password_reset' => 'Смяна на паролата', + 'restore_success' => 'Беше изпратен имейл до вашата поща със инструкций за въстановяване на паролата.', + 'restore_error' => "Не е намерен акаунт със име ':login'", + 'reset_success' => 'Вашата парола е успешно нулирана. Сега може да се логнете.', + 'reset_error' => 'Невалиден данни за нулиране на паролата. Моля, опитайте отново!', + 'reset_fail' => 'Неуспешно нулиране на паролата!', + 'apply' => 'Приложи', + 'cancel' => 'Отказ', + 'delete' => 'Изтрии', + 'ok' => 'Потвърди' + ], + 'dashboard' => [ + 'menu_label' => 'Табло', + 'widget_label' => 'Джаджа', + 'widget_width' => 'Широчина', + 'full_width' => 'Пълна ширина', + 'add_widget' => 'Добави джаджа', + 'widget_inspector_title' => 'Настойка на джаджи', + 'widget_inspector_description' => 'Конфигуриране на джаджите за доклад', + 'widget_columns_label' => 'Ширина :columns', + 'widget_columns_description' => 'Ширина на джаджата, число между 1 и 10.', + 'widget_columns_error' => 'Моля, въведете ширината на джаджа като число между 1 и 10.', + 'columns' => '{1} column|[2,Inf] columns', + 'widget_new_row_label' => 'Принудително добави нов ред', + 'widget_new_row_description' => 'Поставете джаджа в нов ред.', + 'widget_title_label' => 'Заглавие на джаджа', + 'widget_title_error' => 'Заглавие на джаджа се изисква.', + 'status' => [ + 'widget_title_default' => 'Състояние на системата', + 'online' => 'на линия', + 'maintenance' => 'в поддръжка', + 'update_available' => '{0} актуализации налични!|{1} актуализация налична!|[2,Inf] актуализации налични!' + ] + ], + 'user' => [ + 'name' => 'Администратор', + 'menu_label' => 'Администратори', + 'menu_description' => 'Управление на админ-панелана: администратори, групи и разрешения.', + 'list_title' => 'Управление на администратори', + 'new' => 'Нов администратор', + 'login' => 'Вход', + 'first_name' => 'Име', + 'last_name' => 'Фамилия', + 'full_name' => 'Пълно име', + 'email' => 'Имейл', + 'groups' => 'Група', + 'groups_comment' => 'Укажете към коя група принадлежи този акаунт.', + 'avatar' => 'Картинка на профила', + 'password' => 'Парола', + 'password_confirmation' => 'Потвърди паролата', + 'permissions' => 'Разрешения', + 'account' => 'Потребителски профил', + 'superuser' => 'Супер Потребител', + 'superuser_comment' => 'Даване на този профил на неограничен достъп (права) до всички райони. ', + 'send_invite' => 'Изпрати покана по имейл', + 'send_invite_comment' => 'Изпраща приветствено съобщение, съдържащо информация за име и парола за вход.', + 'delete_confirm' => 'Наистина ли искате да изтриете този администратор?', + 'return' => 'Назад към списъка с администратори', + 'allow' => 'Позволи', + 'inherit' => 'Наследи', + 'deny' => 'Откажи', + 'group' => [ + 'name' => 'Група', + 'name_field' => 'Име', + 'description_field' => 'Описание', + 'is_new_user_default_field' => 'Добавяне на нови администратори към тази група по подразбиране.', + 'code_field' => 'Код', + 'code_comment' => 'Въведете уникален код, ако искате да получите достъп до него с API.', + 'menu_label' => 'Групи', + 'list_title' => 'Управление на групи', + 'new' => 'Нова група', + 'delete_confirm' => 'Наистина ли искате да изтриете тази администраторска група?', + 'return' => 'Назад към списъка с групи', + 'users_count' => 'Потребители' + ], + 'preferences' => [ + 'not_authenticated' => 'Няма удостоверен потребител, за да се зареди или запишат предпочитанията му.' + ] + ], + 'list' => [ + 'default_title' => 'Списък', + 'search_prompt' => 'Търсене...', + 'no_records' => 'Не са открити записи в тази гледка.', + 'missing_model' => 'Режим на работа на списък в :class не разполага с дефиниран модел.', + 'missing_column' => 'Все още няма дефиниции на колони за :columns.', + 'missing_columns' => 'Списък използван в :class все още няма дефиниран списък колони', + 'missing_definition' => "Режим на работа на списък не съдържа колони за ':field'.", + 'behavior_not_ready' => 'Режим на работа на списък не беше зареден, проверете дали викате makeLists() във вашия контролер.', + 'invalid_column_datetime' => "Стойността на колона ':column' не е дата/тайм обект, да не би да пропускате \$dates препратка в Модела?", + 'pagination' => 'Показаните записи: :from-:to от :total', + 'prev_page' => 'Предишна страница', + 'next_page' => 'Следваща страница', + 'refresh' => 'Обнови', + 'updating' => 'Обновяване...', + 'loading' => 'Зареждане...', + 'setup_title' => 'Настройка на списък', + 'setup_help' => 'Използвайте тикчетата, за да изберете колони, които искате да видите в списъка. Можете да промените позицията на колони, като ги плъзнете нагоре или надолу.', + 'records_per_page' => 'Записи на страница', + 'records_per_page_help' => 'Изберете брой на записи за показване на страница. Моля, имайте предвид, че голям брой записи на една страница може да забави работата на страницата.', + 'delete_selected' => 'Изтрии избраните', + 'delete_selected_empty' => 'Не са избрани записи за изтриване.', + 'delete_selected_confirm' => 'Изтриване на избраните записи?', + 'delete_selected_success' => 'Успешно изтрити избраните записи.', + 'column_switch_true' => 'Да', + 'column_switch_false' => 'Не' + ], + 'fileupload' => [ + 'attachment' => 'Прикачен файл', + 'help' => 'Добавете заглавие и описание за този прикачен файл.', + 'title_label' => 'Заглавие', + 'description_label' => 'Описание', + 'default_prompt' => 'Кликнете на %s или плъзнете файла тук, за да го качите', + 'attachment_url' => 'Адрес на прикачен файл', + 'upload_file' => 'Качи файл', + 'upload_error' => 'Грешка при качване', + 'remove_confirm' => 'Сигурни ли сте?', + 'remove_file' => 'Премахни файл' + ], + 'form' => [ + 'create_title' => 'Ново :name', + 'update_title' => 'Промени :name', + 'preview_title' => 'Прегледай :name', + 'create_success' => 'Това :name беше създадено успешно.', + 'update_success' => 'Това :name беше актуализирано успешно.', + 'delete_success' => 'Това :name беше изтрито успешно.', + 'missing_id' => 'Форма ID на запис не е посочено.', + 'missing_model' => 'Режим на работа на форма в :class не разполага с дефиниран модел.', + 'missing_definition' => "Режим на работа на форма не съдържа поле за ':field'.", + 'not_found' => 'Форма запис с ID на :id не може да бъде намерен.', + 'action_confirm' => 'Сигурни ли сте?', + 'create' => 'Създай', + 'create_and_close' => 'Създай и затвори', + 'creating' => 'Създаване...', + 'creating_name' => 'Създаване :name...', + 'save' => 'Запази', + 'save_and_close' => 'Запази и затвори', + 'saving' => 'Запазване...', + 'saving_name' => 'Запазване :name...', + 'delete' => 'Изтрии', + 'deleting' => 'Изтриване...', + 'confirm_delete' => 'Наистина ли искате да изтриете този запис?', + 'confirm_delete_multiple' => 'Наистина ли искате да изтриете избраните записи?', + 'deleting_name' => 'Изтриване :name...', + 'reset_default' => 'Възстанови по подразбиране', + 'resetting' => 'Възстановяване', + 'resetting_name' => 'Възстановяване :name', + 'undefined_tab' => 'Разни', + 'field_off' => 'Изключен', + 'field_on' => 'Включен', + 'add' => 'Добави', + 'apply' => 'Приложи', + 'cancel' => 'Отказ', + 'close' => 'Затвори', + 'confirm' => 'Потвърди', + 'reload' => 'Презареди', + 'complete' => 'Завърши', + 'ok' => 'ОК', + 'or' => 'или', + 'confirm_tab_close' => 'Наистина ли искате да затворите раздела? Незапазените промени ще бъдат загубени.', + 'behavior_not_ready' => 'Режим на работа на форма не беше зареден, проверете дали викате initForm() във вашия контролер.', + 'preview_no_files_message' => 'Все още няма качени файлове.', + 'preview_no_record_message' => 'Не е избран запис.', + 'select' => 'Избери', + 'select_all' => 'Избери всички', + 'select_none' => 'изберете никой', + 'select_placeholder' => 'моля изберете', + 'insert_row' => 'Вмъкни ред', + 'insert_row_below' => 'Вмъкни ред По-долу', + 'delete_row' => 'Изтрии ред', + 'concurrency_file_changed_title' => 'Файлът беше променен', + 'concurrency_file_changed_description' => "Файлът, който редактирате е бил променен на диска от друг потребител. Можете да презаредите файла и да загубите вашите промени или замени файла на диска.", + 'return_to_list' => 'Назад към списъка' + ], + 'recordfinder' => [ + 'find_record' => 'Намери запис' + ], + 'relation' => [ + 'missing_config' => "Режим на работа на връзки няма никакви настройки за ':config'.", + 'missing_definition' => "Режим на работа на връзки няма дефиниция за ':field'.", + 'missing_model' => 'Режим на работа на връзки използван в :class не разполага с дефиниран модел.', + 'invalid_action_single' => 'Това действие не може да се извърши на единствена връзка', + 'invalid_action_multi' => 'Това действие не може да се извърши на множество връзки.', + 'help' => 'Щракнете върху елемент за добавяне', + 'related_data' => 'Свързани :name данни', + 'add' => 'Добави', + 'add_selected' => 'Добави избрани', + 'add_a_new' => 'Добави ново :name', + 'link_selected' => 'Вържи избрани', + 'link_a_new' => 'Вържи ново :name', + 'cancel' => 'Отказ', + 'close' => 'Затвори', + 'add_name' => 'Добави :name', + 'create' => 'Създай', + 'create_name' => 'Създай :name', + 'update' => 'Актуализация', + 'update_name' => 'Актуализация :name', + 'preview' => 'Предварителен преглед', + 'preview_name' => 'Предварителен преглед :name', + 'remove' => 'Премахване', + 'remove_name' => 'Премахване :name', + 'delete' => 'Изтривам', + 'delete_name' => 'Изтривам :name', + 'delete_confirm' => 'Сигурни ли сте?', + 'link' => 'Вържи', + 'link_name' => 'Вържи :name', + 'unlink' => 'Прекратяване на връзката', + 'unlink_name' => 'Прекратяване на връзката :name', + 'unlink_confirm' => 'Сигурни ли сте?' + ], + 'reorder' => [ + 'default_title' => 'Пренареждане на записи', + 'no_records' => 'Не са налични записи, за да сортирате.', + ], + 'model' => [ + 'name' => 'Модел', + 'not_found' => "Модел ':class' със ИД :id не може д абъде намерено.", + 'missing_id' => 'Не е посочено ИД за търсене на записи в Модел ID.', + 'missing_relation' => "Модел ':class' не съдържа определение за ':relation'.", + 'missing_method' => "Модел ':class'не съдържа метод ':method'.", + 'invalid_class' => "Модел :model използван в :class не е валиден, той трябва да наследи \Model клас.", + 'mass_assignment_failed' => "Масовото назначаване Mass assignment се провали за Модела атрибут ':attribute'." + ], + 'warnings' => [ + 'tips' => 'Съвети за конфигурацията на системата', + 'tips_description' => 'Има проблематични въпроси, на които трябва да се обърне внимание, за да конфигурирате системата правилно.', + 'permissions' => 'Директория :name или нейните поддиректории не е достъпна за писане от PHP (Няма права). Моля, задайте съответните разрешения за уеб сървъра на тази директория (папка).', + 'extension' => 'Разширението на PHP :name не е инсталирано. Моля инсталирайте тази библиотека и активирайте разширението.' + ], + 'editor' => [ + 'menu_label' => 'Редактор Код предпочитания и настройки', + 'menu_description' => 'Персонализирайте вашите предпочитания на редактора на код, като например размера на шрифта и цветова схема.', + 'font_size' => 'Размер шрифт', + 'tab_size' => 'Размер на табулацията', + 'use_hard_tabs' => 'Отстъпи използващи раздели', + 'code_folding' => 'Код сгъване', + 'word_wrap' => 'Събиране (разгъване) на текста', + 'highlight_active_line' => 'Маркирайте активната линия', + 'auto_closing' => 'Автоматично затваряне на тагове и специални символи', + 'show_invisibles' => 'Покажи невидими знаци', + 'show_gutter' => 'Покажи gutter', + 'theme' => 'Цветова схема' + ], + 'tooltips' => [ + 'preview_website' => 'Преглед на сайта' + ], + 'mysettings' => [ + 'menu_label' => 'Моите Настройки', + 'menu_description' => 'Настройки свързани с вашия администраторски профил' + ], + 'myaccount' => [ + 'menu_label' => 'Моят профил', + 'menu_description' => 'Обнови данните на профила ви, като име, имейл адрес и парола.', + 'menu_keywords' => 'вход за сигурност' + ], + 'branding' => [ + 'menu_label' => 'Персонализирайте администраторския-панел', + 'menu_description' => 'Персонализирайте администраторския-панел, като име, цветове и лого.', + 'brand' => 'Марка', + 'logo' => 'Лого', + 'logo_description' => 'Качете ваше лого което да използвате за администраторския-панел.', + 'app_name' => 'Име', + 'app_name_description' => 'Това име се показва в областта за заглавието на администраторския-панел.', + 'app_tagline' => 'Лозунг', + 'app_tagline_description' => 'Това име се показва на екрана за вход в администраторския-панел.', + 'colors' => 'Цветове', + 'primary_light' => 'Първичен (Светъл)', + 'primary_dark' => 'Първичен (Тъмен)', + 'secondary_light' => 'Вторичен (Светъл)', + 'secondary_dark' => 'Вторичен (Тъмен)', + 'styles' => 'Стилове', + 'custom_stylesheet' => 'Персонализиран стилове' + ], + 'backend_preferences' => [ + 'menu_label' => 'Администраторски-панел предпочитания', + 'menu_description' => 'Управлявайте предпочитанията на профила си като например желания език.', + 'locale' => 'Език', + 'locale_comment' => 'Изберете желаното местоположение за използване на език.' + ], + 'access_log' => [ + 'hint' => 'Този дневник показва списък на успешните опити за влизане от администраторите. Записите се съхраняват в продължение на общо :days дни.', + 'menu_label' => 'Дневник (регистър) на влизанията', + 'menu_description' => 'Преглед на списък с успешни влизания на потребители в администраторския-панел.', + 'created_at' => 'Дата и Час', + 'login' => 'Влизане', + 'ip_address' => 'ИП адрес', + 'first_name' => 'Име', + 'last_name' => 'Фамилия name', + 'email' => 'Имейл' + ], + 'filter' => [ + 'all' => 'всичко' + ], + 'import_export' => [ + 'upload_csv_file' => '1. Качи CSV файл', + 'import_file' => 'Внеси файл', + 'first_row_contains_titles' => 'Първия ред съдържа заглавията на колините ', + 'first_row_contains_titles_desc' => 'Оставете това тикче ако на първия ред в CSV се използват като заглавията на колоните.', + 'match_columns' => '2. Съчетайте колоните от файла с полетата на базата', + 'file_columns' => 'Колони от файла', + 'database_fields' => 'Полета на базата', + 'set_import_options' => '3. Задаване на опции за внасяне', + 'export_output_format' => '1. Изнесете изходен формат', + 'file_format' => 'Формат за файла', + 'standard_format' => 'Стандартен формат', + 'custom_format' => 'Персонализиран формат', + 'delimiter_char' => 'Разделителeн знак', + 'enclosure_char' => 'Затварящ знак', + 'escape_char' => 'Специален знак за избягване', + 'select_columns' => '2. Изберете колони за изнасяне', + 'column' => 'Колона', + 'columns' => 'Колони', + 'set_export_options' => '3. Задайте опций за изнасяне', + 'show_ignored_columns' => 'Покажи игнорираните колони', + 'auto_match_columns' => 'Автоматично обединяване на колони', + 'created' => 'Създаден', + 'updated' => 'Обновен', + 'skipped' => 'Пропуснат', + 'warnings' => 'Предупреждения', + 'errors' => 'Грешки', + 'skipped_rows' => 'Пропуснати редове', + 'import_progress' => 'Прогрес на внасянето', + 'processing' => 'Обработване', + 'import_error' => 'Грешка при внасяне', + 'upload_valid_csv' => 'Моля, качете валиден CSV файл', + 'drop_column_here' => 'Пуснете колоната тук...', + 'ignore_this_column' => 'Игнорирай тази колона', + 'processing_successful_line1' => 'Процес при износ на файла завърши успешно!', + 'processing_successful_line2' => 'Браузърът трябва да ви пренасочи автоматично за да свалите файла.', + 'export_progress' => 'Прогрес на изнасянето', + 'export_error' => 'Грешка при изнасяне', + 'column_preview' => 'Преглед колона', + 'file_not_found_error' => 'Файлът не е намерен', + 'empty_error' => 'Няма предоставени данни за изнасяне', + ], + 'permissions' => [ + 'manage_media' => 'Управление на медия' + ], + 'mediafinder' => [ + 'label' => 'Медия', + 'default_prompt' => 'Кликнете върху %s бутон за да намерите медия' + ], + 'media' => [ + 'menu_label' => 'Медия', + 'upload' => 'Качи', + 'move' => 'Премести', + 'delete' => 'Изтрии', + 'add_folder' => 'Добави папка', + 'search' => 'Търсене', + 'display' => 'Показване', + 'filter_everything' => 'Всичко', + 'filter_images' => 'Изображения', + 'filter_video' => 'Видео', + 'filter_audio' => 'Аудио', + 'filter_documents' => 'Документи', + 'library' => 'Библиотека', + 'size' => 'Размер', + 'title' => 'Заглавие', + 'last_modified' => 'Последно модифициран', + 'public_url' => 'Обществен URL', + 'click_here' => 'Натисни тук', + 'thumbnail_error' => 'Грешка при генериране на умалено изображение.', + 'return_to_parent' => 'Върнете се към основната папка', + 'return_to_parent_label' => 'Нагоре ..', + 'nothing_selected' => 'Нищо не е избрано.', + 'multiple_selected' => 'Множество предмети избрани.', + 'uploading_file_num' => 'Качване: брой на файл(ове)...', + 'uploading_complete' => 'Качването завършено', + 'uploading_error' => 'Качването неуспешно', + 'order_by' => 'Подредени по', + 'folder' => 'Папка', + 'no_files_found' => 'Не са намерени файлове по заявката ви.', + 'delete_empty' => 'Моля изберете елементи, за които да бъдат изтрити.', + 'delete_confirm' => 'Наистина ли искате да изтриете избрания елемент(и)?', + 'error_renaming_file' => 'Грешка при преименуването на елемента.', + 'new_folder_title' => 'Нова папка', + 'folder_name' => 'Име на папка', + 'error_creating_folder' => 'Грешка при създаване на папка', + 'folder_or_file_exist' => 'Папка или файл с посоченото име вече съществува.', + 'move_empty' => 'Моля изберете елементи които да бъдат преместени.', + 'move_popup_title' => 'Преместване на файлове или папки', + 'move_destination' => 'Дестинационна папка', + 'please_select_move_dest' => 'Моля изберете папка за дестинация.', + 'move_dest_src_match' => 'Моля, изберете друга папка за дестинация.', + 'empty_library' => 'Медийната библиотека е празна. Качете файлове, или създайте папки, за да започнете.', + 'insert' => 'Вмъквам', + 'crop_and_insert' => 'Отрежи и вмъкни', + 'select_single_image' => 'Моля, изберете едно изображение.', + 'selection_not_image' => 'Избраният елемент не е изображение.', + 'restore' => 'Отмяна на всички промени', + 'resize' => 'Преоразмеряване...', + 'selection_mode_normal' => 'Normal', + 'selection_mode_fixed_ratio' => 'Фиксиран съотношение', + 'selection_mode_fixed_size' => 'Фиксиран размер', + 'height' => 'Височина', + 'width' => 'Широчина', + 'selection_mode' => 'Режимът на избиране (селекция)', + 'resize_image' => 'Преоразмеряване изображение', + 'image_size' => 'Размер на изображение:', + 'selected_size' => 'Избран:' + ] +]; diff --git a/modules/backend/lang/ca/lang.php b/modules/backend/lang/ca/lang.php new file mode 100644 index 0000000..7b470b4 --- /dev/null +++ b/modules/backend/lang/ca/lang.php @@ -0,0 +1,596 @@ + [ + 'title' => "Àrea d'Administració", + 'invalid_login' => "Els detalls que has introduït no corresponen als nostres registres. Si us plau revisa'ls i torna-ho a intentar." + ], + 'field' => [ + 'invalid_type' => 'El tipus de camp :type utilitzat és invàlid.', + 'options_method_invalid_model' => "L'atribut ':field' no resol a un model vàlid. Intenta especificar explícitament el mètode d'opcions per la classe de model :model.", + 'options_method_not_exists' => "La classe de model :model ha de definir un mètode :method() que retorni opcions pel camp de formulari ':field'." + ], + 'widget' => [ + 'not_registered' => "No s'ha registrat un widget amb el nom de classe ':name'", + 'not_bound' => "No s'ha vinculat al controlador un widget amb el nom de classe ':name'" + ], + 'page' => [ + 'untitled' => 'Sense títol', + 'access_denied' => [ + 'label' => 'Accés denegat', + 'help' => "No tens els permisos necessaris per veure aquesta pàgina.", + 'cms_link' => "Tornar al panell d'administració" + ], + 'no_database' => [ + 'label' => 'No es troba la base de dades', + 'help' => "Es requereix una base de dades per accedir al panell d'administració. Comprova que la base de dades estigui configurada i migrada abans de tornar-ho a intentar.", + 'cms_link' => 'Tornar a la pàgina principal' + ], + 'invalid_token' => [ + 'label' => 'Token de seguretat invàlid' + ] + ], + 'partial' => [ + 'not_found_name' => "El parcial ':name' no s'ha trobat." + ], + 'account' => [ + 'signed_in_as' => 'Connectat com :full_name', + 'sign_out' => 'Sortir', + 'login' => 'Accedir', + 'reset' => 'Reiniciar', + 'restore' => 'Restaurar', + 'login_placeholder' => 'usuari', + 'password_placeholder' => 'contrasenya', + 'remember_me' => 'Recordar-me', + 'forgot_password' => 'Has oblidat la teva contrasenya?', + 'enter_email' => 'Introdueix el teu email', + 'enter_login' => 'Introdueix el teu usuari', + 'email_placeholder' => 'email', + 'enter_new_password' => 'Introdueix una nova contrasenya', + 'password_reset' => 'Reiniciar contrasenya', + 'restore_success' => 'Hem enviat un missatge al teu correu amb instruccions.', + 'restore_error' => "No es pot trobar l'usuari ':login'", + 'reset_success' => "La contrasenya s'ha reiniciat. Ara pots accedir.", + 'reset_error' => 'Dades per restablir contrasenya incorrectes. Si us plau intenta-ho de nou!', + 'reset_fail' => "No s'ha pogut restablir la contrasenya!", + 'apply' => 'Aplicar', + 'cancel' => 'Cancel·lar', + 'delete' => 'Eliminar', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Escriptori', + 'widget_label' => 'Widget', + 'widget_width' => 'Ample', + 'full_width' => 'ample complet', + 'manage_widgets' => 'Gestionar widgets', + 'add_widget' => 'Afegir widget', + 'widget_inspector_title' => 'Configuració de widget', + 'widget_inspector_description' => 'Configurar el widget', + 'widget_columns_label' => 'Ample :columns', + 'widget_columns_description' => "L'ample del widget, un número entre 1 i 10.", + 'widget_columns_error' => "Si us plau introdueix l'ample del widget amb un número entre 1 i 10.", + 'columns' => '{1} columna|[2,Inf] columnes', + 'widget_new_row_label' => 'Forçar nova fila', + 'widget_new_row_description' => 'Posar el widget en una nova fila.', + 'widget_title_label' => 'Títol del widget', + 'widget_title_error' => 'El títol del widget és obligatori.', + 'reset_layout' => 'Reiniciar disposició', + 'reset_layout_confirm' => 'Reiniciar la disposició als valors per defecte?', + 'reset_layout_success' => "La disposició s'ha reiniciat", + 'make_default' => 'Desar per defecte', + 'make_default_confirm' => 'Convertir la disposició actual en els valors per defecte?', + 'make_default_success' => 'La disposició actual és ara la disposició per defecte.', + 'collapse_all' => 'Contraure tots', + 'expand_all' => 'Expandir tots', + 'status' => [ + 'widget_title_default' => 'Estat del sistema', + 'update_available' => '{0} actualitzacions disponibles!|{1} actualització disponible!|[2,Inf] actualitzacions disponibles!', + 'updates_pending' => 'Actualitzacions de software pendents', + 'updates_nil' => 'El software està actualitzat', + 'updates_link' => 'Actualitzar', + 'warnings_pending' => 'Alguns problemes requereixen atenció', + 'warnings_nil' => 'No hi ha avisos per mostrar', + 'warnings_link' => 'Veure', + 'core_build' => 'Versió del sistema', + 'event_log' => "Registre d'esdeveniments", + 'request_log' => 'Registre de peticions', + 'app_birthday' => 'En línia des de', + ], + 'welcome' => [ + 'widget_title_default' => 'Benvingut', + 'welcome_back_name' => 'Benvingut de nou a :app, :name.', + 'welcome_to_name' => 'Benvingut a :app, :name.', + 'first_sign_in' => 'Aquest és el primer cop que accedeixes.', + 'last_sign_in' => "L'últim cop que vas accedir va ser", + 'view_access_logs' => "Veure els registres d'accés", + 'nice_message' => 'Que tinguis un gran dia!', + ] + ], + 'user' => [ + 'name' => 'Administrador', + 'menu_label' => 'Administradors', + 'menu_description' => 'Gestionar els usuaris administradors del panell, grups i permisos.', + 'list_title' => 'Gestionar Administradors', + 'new' => 'Nou Administrador', + 'login' => 'Login', + 'first_name' => 'Nom', + 'last_name' => 'Cognom', + 'full_name' => 'Nom complet', + 'email' => 'Email', + 'role_field' => 'Rol', + 'role_comment' => "Els rols defineixen els permisos d'usuari, que poden ser invalidats a nivell d'usuari, a la pestanya de permisos.", + 'groups' => 'Grups', + 'groups_comment' => 'Especificar a quins grups pertany aquest compte.', + 'avatar' => 'Avatar', + 'password' => 'Contrasenya', + 'password_confirmation' => 'Confirmar contrasenya', + 'permissions' => 'Permisos', + 'account' => 'Compte', + 'superuser' => 'Super Usuari', + 'superuser_comment' => 'Concedeix a aquest compte accés il·limitat a totes les àrees del sistema. Els superusuaris poden afegir i gestionar altres usuaris.', + 'send_invite' => 'Enviar invitació per email', + 'send_invite_comment' => "Envia un missatge de benvinguda que conté la informació d'usuari i contrasenya.", + 'delete_confirm' => 'Eliminar aquest administrador?', + 'return' => "Tornar a la llista d'administradors", + 'allow' => 'Permetre', + 'inherit' => 'Heretar', + 'deny' => 'Denegar', + 'activated' => 'Activat', + 'last_login' => 'Últim accés', + 'created_at' => 'Creat el', + 'updated_at' => 'Actualitzat el', + 'group' => [ + 'name' => 'Grup', + 'name_field' => 'Nom', + 'name_comment' => "El nom es mostra a la llista de grups del formulari d'administrador.", + 'description_field' => 'Descripció', + 'is_new_user_default_field_label' => 'Grup per defecte', + 'is_new_user_default_field_comment' => 'Afegir nous administradors a aquest grup per defecte', + 'code_field' => 'Codi', + 'code_comment' => "Introdueix un codi únic si vols accedir a l'objecte de grup amb l'API.", + 'menu_label' => 'Gestionar grups', + 'list_title' => 'Gestionar grups', + 'new' => 'Nou grup', + 'delete_confirm' => "Eliminar aquest grup d'administració?", + 'return' => 'Tornar a la llista de grups', + 'users_count' => 'Usuaris' + ], + 'role' => [ + 'name' => 'Rol', + 'name_field' => 'Nom', + 'name_comment' => "El nom es mostra a la llista de rols del formulari d'administrador.", + 'description_field' => 'Descripció', + 'code_field' => 'Codi', + 'code_comment' => "Introdueix un codi únic si vols accedir a l'objecte de rol amb l'API.", + 'menu_label' => 'Gestionar rols', + 'list_title' => 'Gestionar rols', + 'new' => 'Nou rol', + 'delete_confirm' => "Eliminar aquest rol d'administració?", + 'return' => 'Tornar a la llista de rols', + 'users_count' => 'Usuaris' + ], + 'preferences' => [ + 'not_authenticated' => 'No hi ha un usuari autenticat per a qui carregar o guardar les preferències.' + ] + ], + 'list' => [ + 'default_title' => 'Llista', + 'search_prompt' => 'Cercar...', + 'no_records' => 'No hi ha registres en aquesta vista.', + 'missing_model' => 'El comportament List utilitzat a :class no té un model definit.', + 'missing_column' => 'No hi ha definicions de columna per :columns.', + 'missing_columns' => 'La llista utilitzada a :class no té columnes de llista definides.', + 'missing_definition' => "El comportament List no té una columna per ':field'.", + 'missing_parent_definition' => "El comportament de llista no conté una definició per ':definition'.", + 'behavior_not_ready' => "El comportament List no s'ha inicialitzat, comprova que has cridat makeLists() al controlador.", + 'invalid_column_datetime' => "El valor de columna ':column' no és un objecte DateTime, et falta una referència a \$dates al model?", + 'pagination' => 'Mostrant registres: :from-:to de :total', + 'first_page' => 'Primera pàgina', + 'last_page' => 'Última pàgina', + 'prev_page' => 'Pàgina anterior', + 'next_page' => 'Pàgina següent', + 'refresh' => 'Refrescar', + 'updating' => 'Actualitzant...', + 'loading' => 'Carregant...', + 'setup_title' => 'Configuració de llista', + 'setup_help' => 'Marca les caselles per seleccionar les columnes que vols veure a la llista. Pots canviar la posiciói de les columnes arrossegant-les amunt o avall.', + 'records_per_page' => 'Registres per pàgina', + 'records_per_page_help' => 'Selecciona el número de registres per pàgina per mostrar. Si us plau tinguis en compte que un gran número de registres en una sola pàgina pot reduir el rendiment.', + 'check' => 'Marcar', + 'delete_selected' => 'Eliminar els seleccionats', + 'delete_selected_empty' => 'No hi ha registres seleccionats per eliminar.', + 'delete_selected_confirm' => 'Eliminar els registres seleccionats?', + 'delete_selected_success' => 'Registres eliminats.', + 'column_switch_true' => 'Sí', + 'column_switch_false' => 'No' + ], + 'fileupload' => [ + 'attachment' => 'Adjunt', + 'help' => 'Afegeix un títol i descripció per aquest adjunt.', + 'title_label' => 'Títol', + 'description_label' => 'Descripció', + 'default_prompt' => 'Clica el %s o arrossega un arxiu aquí per pujar', + 'attachment_url' => "URL de l'adjunt", + 'upload_file' => 'Pujar arxiu', + 'upload_error' => 'Error de pujada', + 'remove_confirm' => 'Segur que ho vols eliminar?', + 'remove_file' => 'Elminar arxiu' + ], + 'repeater' => [ + 'min_items_failed' => ":name requereix un mínim de :min elements, només n'hi ha :items", + 'max_items_failed' => ":name només permet fins a :max elements, n'hi ha :items", + ], + 'form' => [ + 'create_title' => 'Nou :name', + 'update_title' => 'Editar :name', + 'preview_title' => 'Previsualitzar :name', + 'create_success' => ':name creat', + 'update_success' => ':name actualitzat', + 'delete_success' => ':name eliminat', + 'reset_success' => 'Reinici completat', + 'missing_id' => "La ID del registre del formulari no s'ha especificat.", + 'missing_model' => 'El comportament Form utilitzat a :class no té un model definit.', + 'missing_definition' => "El comportament Form no té un camp per ':field'.", + 'not_found' => "El registre de formulari amb la ID :id no s'ha trobat.", + 'action_confirm' => "N'estàs segur?", + 'create' => 'Crear', + 'create_and_close' => 'Crear i tancar', + 'creating' => 'Creant...', + 'creating_name' => 'Creant :name...', + 'save' => 'Guardar', + 'save_and_close' => 'Guardar i tancar', + 'saving' => 'Guardant...', + 'saving_name' => 'Guardant :name...', + 'delete' => 'Eliminar', + 'deleting' => 'Eliminant...', + 'confirm_delete' => 'Eliminar registre?', + 'confirm_delete_multiple' => 'Eliminar els registres seleccionats?', + 'deleting_name' => 'Eliminant :name...', + 'reset_default' => 'Reiniciar als valors per defecte', + 'resetting' => 'Reiniciant', + 'resetting_name' => 'Reiniciant :name', + 'undefined_tab' => 'Misc', + 'field_off' => 'Off', + 'field_on' => 'On', + 'add' => 'Afegir', + 'apply' => 'Aplicar', + 'cancel' => 'Cancel·lar', + 'close' => 'Tancar', + 'confirm' => 'Confirmar', + 'reload' => 'Recarregar', + 'complete' => 'Completat', + 'ok' => 'OK', + 'or' => 'o', + 'confirm_tab_close' => 'Tancar la pestanya? Els canvis no guardats es perdran.', + 'behavior_not_ready' => "El comportament Form no s'ha inicialitzat, comprova que has cridat initForm() al controlador.", + 'preview_no_files_message' => 'No hi ha arxius pujats.', + 'preview_no_media_message' => 'No hi ha medis seleccionats.', + 'preview_no_record_message' => 'No hi ha cap registre seleccionat.', + 'select' => 'Seleccionar', + 'select_all' => 'seleccionar tot', + 'select_none' => 'no selecciona cap', + 'select_placeholder' => 'si us plau selecciona', + 'insert_row' => 'Inserir fila', + 'insert_row_below' => 'Inserir fila a sota', + 'delete_row' => 'Eliminar fila', + 'concurrency_file_changed_title' => "L'arxiu ha canviat", + 'concurrency_file_changed_description' => "L'arxiu que estàs editant ha estat canviat al disc per un altre usuari. Pots o bé recarregar l'arxiu i perdre els teus canvis, o bé sobreescriure l'arxiu al disc.", + 'return_to_list' => 'Tornar a la llista' + ], + 'recordfinder' => [ + 'find_record' => 'Trobar registre', + 'cancel' => 'Cancel·lar', + ], + 'pagelist' => [ + 'page_link' => 'Enllaç a pàgina', + 'select_page' => 'Selecciona una pàgina...' + ], + 'relation' => [ + 'missing_config' => "El comportament Relation no té una configuració per ':config'.", + 'missing_definition' => "El comportament Relation no té una definició per ':field'.", + 'missing_model' => 'El comportament Relation utilitzat a :class no té un model definit.', + 'invalid_action_single' => 'Aquesta acció no pot ser realitzada en una relació singular.', + 'invalid_action_multi' => 'Aquesta acció no pot ser realitzada en una relació múltiple.', + 'help' => 'Clica en un element per afegir-lo', + 'related_data' => 'Dada :name relacionada', + 'add' => 'Afegir', + 'add_selected' => 'Afegir seleccionats', + 'add_a_new' => 'Afegir un nou :name', + 'link_selected' => 'Vincular seleccionats', + 'link_a_new' => 'Vincular un nou :name', + 'cancel' => 'Cancel·lar', + 'close' => 'Tancar', + 'add_name' => 'Afegir :name', + 'create' => 'Crear', + 'create_name' => 'Crear :name', + 'update' => 'Actualitzar', + 'update_name' => 'Actualitzar :name', + 'preview' => 'Previsualitzar', + 'preview_name' => 'Previsualitzar :name', + 'remove' => 'Treure', + 'remove_name' => 'Treure :name', + 'delete' => 'Eliminar', + 'delete_name' => 'Eliminar :name', + 'delete_confirm' => "N'estàs segur?", + 'link' => 'Vincular', + 'link_name' => 'Vincular :name', + 'unlink' => 'Desvincular', + 'unlink_name' => 'Desvincular :name', + 'unlink_confirm' => "N'estàs segur?" + ], + 'reorder' => [ + 'default_title' => 'Reordenar registres', + 'no_records' => 'No hi ha registres disponibles per reordenar.' + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => "El model ':class' amb l'ID :id no s'ha trobat.", + 'missing_id' => "No s'ha especificat ID per trobar el registre de model.", + 'missing_relation' => "El model ':class' no té una definició per ':relation'.", + 'missing_method' => "El model ':class' no té un mètode ':method'.", + 'invalid_class' => "El model :model utilitzat a :class no és vàlid, ha d'heretar la classe \Model.", + 'mass_assignment_failed' => "L'assignació massiva ha fallat per l'atribut ':attribute' del model." + ], + 'warnings' => [ + 'tips' => 'Consells de configuració del sistema', + 'tips_description' => "Hi ha problemes que has d'atendre per configurar el sistema correctament.", + 'permissions' => 'El directori :name o un dels seus subdirectoris no pot ser escrit per PHP. Si us plau assigna els permisos corresponents pel servidor web en aquest directori.', + 'extension' => "L'extensió :name no està instal·lada. Si us plau instal·la aquesta llibreria i activa l'extensió.", + 'plugin_missing' => 'El plugin :name és una dependència però no està instal·lat. Si us plau instal·la aquest plugin.', + ], + 'editor' => [ + 'menu_label' => "Opcions de l'editor", + 'menu_description' => "Personalitza les preferències globals de l'editor, com ara el mida de la font i l'esquema de colors.", + 'font_size' => 'Mida de la font', + 'tab_size' => 'Mida de la tabulació', + 'use_hard_tabs' => 'Indentar utilitzant tabulacions', + 'code_folding' => 'Plegat de codi', + 'code_folding_begin' => "Marca d'inici", + 'code_folding_begin_end' => "Marca d'inici i final", + 'autocompletion' => 'Autocompletat', + 'word_wrap' => 'Ajust de línia', + 'highlight_active_line' => 'Destacar la línia activa', + 'auto_closing' => 'Tancar les etiquetes automàticament', + 'show_invisibles' => 'Mostrar els caràcters invisibles', + 'show_gutter' => 'Mostrar números de línia', + 'basic_autocompletion'=> 'Autompletat bàsic (Ctrl + Espai)', + 'live_autocompletion'=> 'Autompletat en viu', + 'enable_snippets'=> 'Activar snippets de codi (Tab)', + 'display_indent_guides'=> "Mostrar guies d'indentació", + 'show_print_margin'=> "Mostrar marge d'impressió", + 'mode_off' => 'Off', + 'mode_fluid' => 'Fluit', + '40_characters' => '40 caràcters', + '80_characters' => '80 caràcters', + 'theme' => 'Esquema de color', + 'markup_styles' => 'Estils de marcat', + 'custom_styles' => "Full d'estils personalitzat", + 'custom styles_comment' => "Estils personalitzats per incloure a l'editor HTML.", + 'markup_classes' => 'Classes de marcat', + 'paragraph' => 'Paràgraf', + 'link' => 'Enllaç', + 'table' => 'Taula', + 'table_cell' => 'Cel·la', + 'image' => 'Imatge', + 'label' => 'Etiqueta', + 'class_name' => 'Nom de classe', + 'markup_tags' => 'Etiquetes de marcat', + 'allowed_empty_tags' => 'Etiquetes buides permeses', + 'allowed_empty_tags_comment' => "La llista d'etiquetes que no s'eliminen quan no tenen contingut.", + 'allowed_tags' => 'Etiquetes permeses', + 'allowed_tags_comment' => "La llista d'etiquetes permeses.", + 'no_wrap' => 'No envoltar etiquetes', + 'no_wrap_comment' => "La llista d'etiquetes que no s'han d'envoltar dins d'etiquetes de bloc.", + 'remove_tags' => 'Eliminar etiquetes', + 'remove_tags_comment' => "La llista d'etiquetes que s'eliminen junt amb el seu contingut.", + 'line_breaker_tags' => 'Etiquetes de canvi de línia', + 'line_breaker_tags_comment' => "La llista d'etiquetes que s'utilitzen per introduir un canvi de línia.", + 'toolbar_buttons' => "Botons de la barra d'eines", + 'toolbar_buttons_comment' => "Els botons de la barra d'eines que es mostraran en l'editor de text enriquit per defecte.", + ], + 'tooltips' => [ + 'preview_website' => 'Previsualitzar el lloc web' + ], + 'mysettings' => [ + 'menu_label' => 'Les meves opcions', + 'menu_description' => "Les opcions de configuració relacionades amb el teu compte d'administració" + ], + 'myaccount' => [ + 'menu_label' => 'El meu compte', + 'menu_description' => "Actualitza els teus detalls de compte com ara el nom, adreça d'email i contrasenya.", + 'menu_keywords' => 'seguretat acces security login' + ], + 'branding' => [ + 'menu_label' => "Personalitzar el panell d'administració", + 'menu_description' => "Personalitzar l'aspecte de l'àrea d'administració, com ara el nom, els colors o el logo.", + 'brand' => 'Marca', + 'logo' => 'Logo', + 'logo_description' => 'Pujar un logo personalitzat per utilitzar al panell.', + 'app_name' => "Nom de l'aplicació", + 'app_name_description' => "Aquest nom es mostra a l'àrea del títol del panell.", + 'app_tagline' => "Tagline de l'aplicació", + 'app_tagline_description' => "Aquest text es mostra a la finestra d'accés al panell.", + 'colors' => 'Colors', + 'primary_color' => 'Color primari', + 'secondary_color' => 'Color secundari', + 'accent_color' => "Color d'accent", + 'styles' => 'Estils', + 'custom_stylesheet' => "Full d'estils personalitzat", + 'navigation' => 'Navegació', + 'menu_mode' => 'Estil del menú', + 'menu_mode_inline' => 'En línia', + 'menu_mode_tile' => 'Rajoles', + 'menu_mode_collapsed' => 'Comprimit' + ], + 'backend_preferences' => [ + 'menu_label' => 'Preferències del panell', + 'menu_description' => 'Gestiona les preferències del teu compte, com ara el teu idioma preferit.', + 'region' => 'Regió', + 'code_editor' => 'Editor de codi', + 'timezone' => 'Zona horària', + 'timezone_comment' => 'Ajustar les dates mostrades a aquesta zona horària.', + 'locale' => 'Idioma', + 'locale_comment' => 'Selecciona el teu idioma preferit.' + ], + 'access_log' => [ + 'hint' => "Aquest registre mostra una llista dels accessos d'administradors. Els registres es guarden durant :days dies.", + 'menu_label' => "Registre d'accés", + 'menu_description' => "Veure una llista d'accessos correctes al panell.", + 'created_at' => 'Data i Hora', + 'login' => 'Login', + 'ip_address' => 'Adreça IP', + 'first_name' => 'Nom', + 'last_name' => 'Cognom', + 'email' => 'Email' + ], + 'filter' => [ + 'all' => 'tots', + 'options_method_not_exists' => "La classe de model :model ha de definir un mètode :method() que retorni opcions pel filtre ':filter'.", + 'date_all' => 'tots els períodes', + 'number_all' => 'tots els números', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Pujar un arxiu CSV', + 'import_file' => 'Importar arxiu', + 'row' => 'Fila :row', + 'first_row_contains_titles' => 'La primera fila conté els títols de columnes', + 'first_row_contains_titles_desc' => "Deixa això marcat si la primera fila del CSV s'utilitza pels títols de les columnes.", + 'match_columns' => "2. Emparellar les columnes de l'arxiu amb camps de la base de dades", + 'file_columns' => "Columnes de l'arxiu", + 'database_fields' => 'Camps de la base de dades', + 'set_import_options' => "3. Establir les opcions d'importació", + 'export_output_format' => "1. Format de sortida de l'exportació", + 'file_format' => "Format de l'arxiu", + 'standard_format' => 'Estàndard', + 'custom_format' => 'Personalitzat', + 'delimiter_char' => 'Caràcter delimitador', + 'enclosure_char' => 'Caràcter de tancament de cadena', + 'escape_char' => "Caràcter d'escapament", + 'select_columns' => '2. Seleccionar columnes per exportar', + 'column' => 'Columna', + 'columns' => 'Columnes', + 'set_export_options' => "3. Establir les opcions d'exportació", + 'show_ignored_columns' => 'Mostrar columnes ignorades', + 'auto_match_columns' => 'Emparellar columnes automàticament', + 'created' => 'Creat', + 'updated' => 'Actualitzat', + 'skipped' => 'Omesos', + 'warnings' => 'Avisos', + 'errors' => 'Errors', + 'skipped_rows' => 'Files omeses', + 'import_progress' => "Progrés d'importació", + 'processing' => 'Processant', + 'import_error' => "Error en la importació", + 'upload_valid_csv' => 'Si us plau puja un arxiu CSV vàlid.', + 'drop_column_here' => 'Arrossega una columna aquí...', + 'ignore_this_column' => 'Ignora aquesta columna', + 'processing_successful_line1' => "Procès d'exportació d'arxiu completat!", + 'processing_successful_line2' => "El navegador et redigirirà aviat a la descàrrega de l'arxiu.", + 'export_progress' => "Progrès d'exportació", + 'export_error' => "Error en l'exportació", + 'column_preview' => 'Previsualitzar columna', + 'file_not_found_error' => 'Arxiu no trobat', + 'empty_error' => 'No hi ha dades per exportar', + 'empty_import_columns_error' => 'Si us plau indica alguna columna per importar.', + 'match_some_column_error' => 'Si us plau emparella algunes columnes primer.', + 'required_match_column_error' => 'Si us plau indica un emparellament pel camp requerit :label.', + 'empty_export_columns_error' => 'Si us plau indica alguna columna per exportar.', + 'behavior_missing_uselist_error' => "Has d'implementar el comportament de controlador ListController amb l'opció d'exportació useList activada.", + 'missing_model_class_error' => 'Si us plau especifica la propietat modelClass per :type', + 'missing_column_id_error' => "Falta l'identificador de columna", + 'unknown_column_error' => 'Columna desconeguda', + 'encoding_not_supported_error' => "La codificació de l'arxiu font no es reconeix. Si us plau selecciona l'opció de format d'arxiu personalitzat amb la codificació correcta per importar el teu arxiu.", + 'encoding_format' => "Codificació d'arxiu", + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Europa Occidental)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Europa Central)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, Europa del Sud)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, Europa del Nord)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Ciríl·lic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Aràbic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Grec)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebreu)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turc)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Regió Bàltica)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celta)', + 'iso_8859_15' => "ISO-8859-15 (Latin-9, Europa Occidental - revisió amb signe de l'euro)", + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Puja i gestiona continguts multimèdia - imatges, vídeos, sons, documents' + ], + 'mediafinder' => [ + 'label' => 'Cercador multimèdia', + 'default_prompt' => 'Clica el botó %s per cercar un element multimèdia' + ], + 'media' => [ + 'menu_label' => 'Mèdia', + 'upload' => 'Pujar', + 'move' => 'Moure', + 'delete' => 'Eliminar', + 'add_folder' => 'Afegir carpeta', + 'search' => 'Cercar', + 'display' => 'Mostrar', + 'filter_everything' => 'Tot', + 'filter_images' => 'Imatges', + 'filter_video' => 'Vídeo', + 'filter_audio' => 'Àudio', + 'filter_documents' => 'Documents', + 'library' => 'Biblioteca', + 'size' => 'Mida', + 'title' => 'Títol', + 'last_modified' => 'Modificat per últim cop', + 'public_url' => 'URL', + 'click_here' => 'Clica aquí', + 'thumbnail_error' => 'Error generant miniatura.', + 'return_to_parent' => 'Tornar a la carpeta pare', + 'return_to_parent_label' => 'Ves amunt ..', + 'nothing_selected' => 'No hi ha res seleccionat.', + 'multiple_selected' => 'Múltiples elements seleccionats.', + 'uploading_file_num' => 'Pujant :number arxiu(s)...', + 'uploading_complete' => 'Pujada completa', + 'uploading_error' => 'Pujada fallida', + 'type_blocked' => "Aquest tipus d'arxiu està bloquejat per raons de seguretat.", + 'order_by' => 'Ordenar per', + 'direction' => 'Direcció', + 'direction_asc' => 'Ascendent', + 'direction_desc' => 'Descendent', + 'folder' => 'Carpeta', + 'no_files_found' => "No s'han trobat arxius amb aquests paràmetres de cerca.", + 'delete_empty' => 'Si us plau selecciona elements per eliminar.', + 'delete_confirm' => 'Eliminar els elements seleccionats?', + 'error_renaming_file' => "Error reanomenant l'element.", + 'new_folder_title' => 'Nova carpeta', + 'folder_name' => 'Nom de carpeta', + 'error_creating_folder' => 'Error creant carpeta', + 'folder_or_file_exist' => 'Ja existeix una carpeta o arxiu amb aquest nom', + 'move_empty' => 'Si us plau selecciona elements per moure.', + 'move_popup_title' => 'Moure arxius o carpetes', + 'move_destination' => 'Carpeta de destí', + 'please_select_move_dest' => 'Si us plau selecciona una carpeta de destí.', + 'move_dest_src_match' => 'Si us plau selecciona una altra carpeta de destí.', + 'empty_library' => 'Això sembla una mica buit. Puja arxius o crea carpetes per començar.', + 'insert' => 'Insertar', + 'crop_and_insert' => 'Retallar i inserir', + 'select_single_image' => 'Si us plau selecciona una única imatge.', + 'selection_not_image' => "L'element seleccionat no és una imatge.", + 'restore' => 'Desfès tots els canvis', + 'resize' => 'Redimensionar...', + 'selection_mode_normal' => 'Normal', + 'selection_mode_fixed_ratio' => 'Ràtio fixa', + 'selection_mode_fixed_size' => 'Mida fixa', + 'height' => 'Alçada', + 'width' => 'Amplada', + 'selection_mode' => 'Selecciona mode', + 'resize_image' => 'Redimensionar imatge', + 'image_size' => "Mida d'imatge:", + 'selected_size' => 'Seleccionat:' + ], +]; diff --git a/modules/backend/lang/cs/lang.php b/modules/backend/lang/cs/lang.php new file mode 100644 index 0000000..277e59a --- /dev/null +++ b/modules/backend/lang/cs/lang.php @@ -0,0 +1,560 @@ + [ + 'title' => 'Administrace' + ], + 'field' => [ + 'invalid_type' => 'Byl použitý špatný typ :type.', + 'options_method_invalid_model' => "Vlastnost ':field' neodpovídá platnému modelu. Zkuste specifikovat metodu voleb pro modelovou třídu :model explicitně.", + 'options_method_not_exists' => "Modelová třída :model musí implementovat metodu :method(), která vrací volby pro formulářové pole ':field'" + ], + 'widget' => [ + 'not_registered' => "Třída widgetu se jménem ':name' není zaregistrovaná.", + 'not_bound' => "Widget s názvem třídy ':name' není navázaná na kontroler." + ], + 'page' => [ + 'untitled' => 'Bez názvu', + 'access_denied' => [ + 'label' => 'Přístup odmítnut', + 'help' => 'Nemáte potřebná oprávnění k prohlížení této stránky.', + 'cms_link' => 'Zpět do administrace' + ], + 'no_database' => [ + 'label' => 'Chybí databáze', + 'help' => "K přístupu do administrace je zapotřebí databáze. Zkontrolujte, zda je databáze nakonfigurována a migrována a zkuste to znovu.", + 'cms_link' => 'Zpět na úvodní stránku' + ], + ], + 'partial' => [ + 'not_found_name' => "Dílčí šablona ':name' nebyla nalezena." + ], + 'account' => [ + 'sign_out' => 'Odhlásit', + 'login' => 'Přihlásit se', + 'reset' => 'Resetovat', + 'restore' => 'Obnovit', + 'login_placeholder' => 'Přihlašovací jméno', + 'password_placeholder' => 'Heslo', + 'remember_me' => 'Zůstat přihlášený', + 'forgot_password' => 'Zapomněli jste heslo?', + 'enter_email' => 'Zadejte váš e-mail', + 'enter_login' => 'Zadejte váš login', + 'email_placeholder' => 'E-mail', + 'enter_new_password' => 'Zadejte nové heslo', + 'password_reset' => 'Obnova hesla', + 'restore_success' => 'E-mail byl zaslán na vaší e-mailovou adresu s heslem a instrukcemi k obnově.', + 'restore_error' => "Uživatel s přihlašovacím jménem ':login' nebyl nalezen", + 'reset_success' => 'Vaše heslo bylo úspěšně obnoveno. Nyní se můžete přihlásit.', + 'reset_error' => 'Data pro obnovu hesla nejsou správná. Prosím zkuste to znovu!', + 'reset_fail' => 'Obnova hesla selhala!', + 'apply' => 'Použít', + 'cancel' => 'Zrušit', + 'delete' => 'Smazat', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Plocha', + 'widget_label' => 'Widget', + 'widget_width' => 'Šířka', + 'full_width' => 'Plná šířka', + 'manage_widgets' => 'Správa widgetů', + 'add_widget' => 'Přidat widget', + 'widget_inspector_title' => 'Nastavení widgetu', + 'widget_inspector_description' => 'Zde si upravte všechna nastavení widgetu', + 'widget_columns_label' => 'Šířka :columns', + 'widget_columns_description' => 'Šířka widgetu, zadejte číslo mezi 1 a 10.', + 'widget_columns_error' => 'Zadejte prosím šířku widgetu jako číslo mezi 1 a 10.', + 'columns' => '{1} sloupec|[2,Inf] sloupce', + 'widget_new_row_label' => 'Vždy na novém řádku', + 'widget_new_row_description' => 'Vloží widget do nového řádku', + 'widget_title_label' => 'Název widgetu', + 'widget_title_error' => 'Musíte zadat název widgetu', + 'reset_layout' => 'Obnovit výchozí uspořádání', + 'reset_layout_confirm' => 'Skutečně obnovit výchozí uspořádání?', + 'reset_layout_success' => 'Výchozí uspořádání bylo obnoveno', + 'make_default' => 'Nastavit jako výchozí', + 'make_default_confirm' => 'Nastavit aktuální uspořádání jako výchozí?', + 'make_default_success' => 'Aktuální uspořádání je nyní nastaveno jako výchozí', + 'collapse_all' => 'Vše sbalit', + 'expand_all' => 'Vše rozbalit', + 'status' => [ + 'widget_title_default' => 'Stav systému', + 'update_available' => '{0} dostupných aktualizací!|{1} dostupná aktualizace!|[2,Inf] dostupných aktualizací!', + 'updates_pending' => 'Jsou dostupné aktualizace softwaru', + 'updates_nil' => 'Software je aktuální', + 'updates_link' => 'Aktualizovat', + 'warnings_pending' => 'Některé problémy vyžadují pozornost', + 'warnings_nil' => 'Žádné varování k zobrazení', + 'warnings_link' => 'Zobrazit', + 'core_build' => 'Verze systému', + 'event_log' => 'Protokol událostí', + 'request_log' => 'Protokol požadavků', + 'app_birthday' => 'Online od', + ], + 'welcome' => [ + 'widget_title_default' => 'Vítejte', + 'welcome_back_name' => 'Vítejte zpět do :app, :name.', + 'welcome_to_name' => 'Vítejte do :app, :name.', + 'first_sign_in' => 'Toto je vaše první přihlášení.', + 'last_sign_in' => 'Vaše poslední přihlášení bylo', + 'view_access_logs' => 'Zobrazit protokol přihlášení', + 'nice_message' => 'Hezký den!', + ] + ], + 'user' => [ + 'name' => 'Administrátor', + 'menu_label' => 'Administrátoři', + 'menu_description' => 'Správa uživatelů administrace, jejich skupin a opravnění.', + 'list_title' => 'Správa administrátorů', + 'new' => 'Nový administrátor', + 'login' => 'Přihlašovací jméno', + 'first_name' => 'Křestní jméno', + 'last_name' => 'Příjmení', + 'full_name' => 'Celé jméno', + 'email' => 'E-mail', + 'role_field' => 'Role', + 'role_comment' => 'Role definují uživatelská oprávnění, která mohou být přepsána na uživatelské úrovni, na kartě Oprávnění.', + 'groups' => 'Skupiny', + 'groups_comment' => 'Vyberte do jakých skupin uživatel patří.', + 'avatar' => 'Avatar', + 'password' => 'Heslo', + 'password_confirmation' => 'Potvrzení hesla', + 'permissions' => 'Oprávnění', + 'account' => 'Účet', + 'superuser' => 'Super uživatel', + 'superuser_comment' => 'Má neomezený přístup do všech stránek administrace.', + 'send_invite' => 'Zaslat pozvánku e-mailem', + 'send_invite_comment' => 'Odešle uvítací e-mail s údaji pro přihlášení.', + 'delete_confirm' => 'Opravdu chcete smazat tohoto administrátora?', + 'return' => 'Zpět na seznam administrátorů', + 'allow' => 'Povolit', + 'inherit' => 'Podědit', + 'deny' => 'Odmítnout', + 'activated' => 'Aktivován', + 'last_login' => 'Poslední přihlášení', + 'created_at' => 'Vytvořen', + 'updated_at' => 'Aktualizován', + 'group' => [ + 'name' => 'Skupina', + 'name_field' => 'Jméno', + 'name_comment' => 'Toto jméno je zobrazeno v seznamu skupin na formuláři správce.', + 'description_field' => 'Popis', + 'is_new_user_default_field_label' => 'Výchozí skupina', + 'is_new_user_default_field_comment' => 'Zařadit nové administrátory automaticky do této skupiny', + 'code_field' => 'Kód', + 'code_comment' => 'Zadejte unikátní kód pro přístup přes API.', + 'menu_label' => 'Skupiny', + 'list_title' => 'Správa skupin', + 'new' => 'Nová skupina', + 'delete_confirm' => 'Opravdu chcete smazat tuto skupinu administrátorů?', + 'return' => 'Zpět na seznam skupin', + 'users_count' => 'Uživatelů' + ], + 'role' => [ + 'name' => 'Role', + 'name_field' => 'Jméno', + 'name_comment' => 'Toto jméno je zobrazeno v seznamu skupin na formuláři správce.', + 'description_field' => 'Popis', + 'code_field' => 'Kód', + 'code_comment' => 'Zadejte unikátní kód pro přístup přes API.', + 'menu_label' => 'Role', + 'list_title' => 'Správa rolí', + 'new' => 'Nová role', + 'delete_confirm' => 'Opravdu chcete smazat tuto roli?', + 'return' => 'Zpět na seznam rolí', + 'users_count' => 'Uživatelů' + ], + 'preferences' => [ + 'not_authenticated' => 'Nebyl nalezen žádný přihlášený uživatel pro načtení, nebo uložení nastavení.' + ] + ], + 'list' => [ + 'default_title' => 'Seznam', + 'search_prompt' => 'Hledat...', + 'no_records' => 'Žádné záznamy v tomto pohledu.', + 'missing_model' => 'Chování seznamu použité v :class nemá definovaný model.', + 'missing_column' => 'Neexistují žádné definice sloupců pro :columns.', + 'missing_columns' => 'Seznam použitý v :class nemá defonované žádné sloupce.', + 'missing_definition' => "Chování seznamu neobsahuje sloupec pro ':field'.", + 'missing_parent_definition' => "Chování seznamu neobsahuje definici ':definition'.", + 'behavior_not_ready' => 'Chování seznamu nebylo inicializováno. Zkontrolujte, zda jste ve svém controlleru zavolali makeLists().', + 'invalid_column_datetime' => "Hodnota sloupce ':column' není objekt typu DateTime. Nechybí vám odkaz \$dates ve vašem Modelu?", + 'pagination' => 'Zobrazuji záznamy: :from-:to z :total', + 'first_page' => 'První stránka', + 'last_page' => 'Poslední stránka', + 'prev_page' => 'Předchozí stránka', + 'next_page' => 'Další stránka', + 'refresh' => 'Obnovit', + 'updating' => 'Aktualizuji...', + 'loading' => 'Načítám...', + 'setup_title' => 'Nastavení výpisu', + 'setup_help' => 'Pomocí checkboxů si vyberte, které sloupce chcete ve výpisu vidět. Pozici změníte chytnutím a posunem nahorů, nebo dolů.', + 'records_per_page' => 'Záznamů na stránku', + 'records_per_page_help' => 'Vyberte kolik chcete vidět záznamů na jedné stránce. Vysoký počet záznamů může negativně ovlivnit rychlost stránek.', + 'check' => 'Zaškrtnout', + 'delete_selected' => 'Smazat vybrané záznamy', + 'delete_selected_empty' => 'Nebyly vybrány žádné záznamy ke smazání.', + 'delete_selected_confirm' => 'Opravdu chcete smazat vybrané záznamy?', + 'delete_selected_success' => 'Vybrané záznamy byly smazány.', + 'column_switch_true' => 'Ano', + 'column_switch_false' => 'Ne' + ], + 'fileupload' => [ + 'attachment' => 'Příloha', + 'help' => 'Přidat název a popisek k příloze.', + 'title_label' => 'Název', + 'description_label' => 'Popis', + 'default_prompt' => 'Kliknutím na %s nebo přetažením na toto místo můžete soubor nahrát', + 'attachment_url' => 'URL přílohy', + 'upload_file' => 'Nahrát soubor', + 'upload_error' => 'Chyba nahrávání', + 'remove_confirm' => 'Jste si jistí?', + 'remove_file' => 'Odstranit soubor' + ], + 'form' => [ + 'create_title' => 'Nový :name', + 'update_title' => 'Upravit :name', + 'preview_title' => 'Náhled :name', + 'create_success' => ':name byl úspěšně vytvořen', + 'update_success' => ':name byl úspěšně upraven', + 'delete_success' => ':name byl úspěšně smazán', + 'reset_success' => 'Úspěšně obnoveno', + 'missing_id' => 'Musíte uvést ID záznamu.', + 'missing_model' => 'Chování formuláře použité v :class nemá definovaný model.', + 'missing_definition' => "Chování formuláře neobsahuje pole pro ':field'.", + 'not_found' => 'Záznam formuláře s ID :id nebyl nalezen.', + 'action_confirm' => 'Jste si jistí?', + 'create' => 'Vytvořit', + 'create_and_close' => 'Vytvořit a zavřít', + 'creating' => 'Vytváření...', + 'creating_name' => 'Vytváření :name...', + 'save' => 'Uložit', + 'save_and_close' => 'Uložit a zavřít', + 'saving' => 'Ukládání...', + 'saving_name' => 'Ukládání :name...', + 'delete' => 'Smazat', + 'deleting' => 'Mazání...', + 'confirm_delete' => 'Opravdu chcete smazat záznam?', + 'confirm_delete_multiple' => 'Opravdu chcete smazat vybrané záznamy?', + 'deleting_name' => 'Mazání :name...', + 'reset_default' => 'Obnovit výchozí', + 'resetting' => 'Obnovování', + 'resetting_name' => 'Obnovování :name', + 'undefined_tab' => 'Ostatní', + 'field_off' => 'Vyp', + 'field_on' => 'Zap', + 'add' => 'Přidat', + 'apply' => 'Použít', + 'cancel' => 'Zrušit', + 'close' => 'Zavřít', + 'confirm' => 'Potvrdit', + 'reload' => 'Znovu načíst', + 'complete' => 'Kompletní', + 'ok' => 'OK', + 'or' => 'nebo', + 'confirm_tab_close' => 'Opravdu chcete zavřít záložku? Neuložené změny budou ztraceny.', + 'behavior_not_ready' => 'Chování formuláře není inicializováno, zkontrolujte jestli voláte metodu initForm() ve vašem kontroléru.', + 'preview_no_files_message' => 'Žádný soubor nebyl nahrán.', + 'preview_no_media_message' => 'Žádné médium nebylo vybráno.', + 'preview_no_record_message' => 'Žádný záznam není vybraný.', + 'select' => 'Vybrat', + 'select_all' => 'vybrat vše', + 'select_none' => 'vyberte žádný', + 'select_placeholder' => 'Prosím vyberte', + 'insert_row' => 'Vložit řádek', + 'insert_row_below' => 'Vložit řádek pod', + 'delete_row' => 'Smazat řádek', + 'concurrency_file_changed_title' => 'Soubor byl změněn', + 'concurrency_file_changed_description' => "Soubor, který upravujete, byl na disku změněn jiným uživatelem. Můžete buď znovu načíst soubor a ztratit změny, nebo přepsat soubor na disku.", + 'return_to_list' => 'Zpět na seznam' + ], + 'recordfinder' => [ + 'find_record' => 'Najít záznam', + 'cancel' => 'Zrušit', + ], + 'pagelist' => [ + 'page_link' => 'Odkaz na stránku', + 'select_page' => 'vyberte stránku...' + ], + 'relation' => [ + 'missing_config' => "Chování relace nemá žádné nastavení pro ':config'.", + 'missing_definition' => "Chování relace neobsahuje definici pro ':field'.", + 'missing_model' => 'Chování relace použité v :class nemá definovaný žádný model.', + 'invalid_action_single' => 'Tato akce nemůže být provedena na jednoduché relaci (singular relationship).', + 'invalid_action_multi' => 'Tato akce nemůže být provedena na vícenásobné relaci (multiple relationship).', + 'help' => 'Pro přidání klikněte na položku', + 'related_data' => 'Související data pro :name', + 'add' => 'Přidat', + 'add_selected' => 'Přidat vybrané', + 'add_a_new' => 'Přidat nový :name', + 'link_selected' => 'Vytvořit vazbu na vybrané', + 'link_a_new' => 'Vytvořit novou vazbu na :name', + 'cancel' => 'Zrušit', + 'close' => 'Zavřít', + 'add_name' => 'Přidat :name', + 'create' => 'Vytvořit', + 'create_name' => 'Vytvořit :name', + 'update' => 'Upravit', + 'update_name' => 'Upravit :name', + 'preview' => 'Náhled', + 'preview_name' => 'Náhled :name', + 'remove' => 'Odstranit', + 'remove_name' => 'Odstranit :name', + 'delete' => 'Smazat', + 'delete_name' => 'Smazat :name', + 'delete_confirm' => 'Jste si jistí?', + 'link' => 'Vazba', + 'link_name' => 'Vazba :name', + 'unlink' => 'Zrušit vazbu', + 'unlink_name' => 'Zrušit vazbu :name', + 'unlink_confirm' => 'Jste si jistí?' + ], + 'reorder' => [ + 'default_title' => 'Seřadit záznamy', + 'no_records' => 'Nenašli jsme žádné záznamy k seřazení.', + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => "Model ':class' s ID :id nebyl nalezen", + 'missing_id' => 'Není specifikované ID pro hledání záznamu v modelu.', + 'missing_relation' => "Model ':class' neobsahuje definici pro ':relation'.", + 'missing_method' => "Model ':class' nemá implementovanou metodu ':method'.", + 'invalid_class' => "Model :model použitý ve třídě :class není validní, musí dědit ze třídy Model.", + 'mass_assignment_failed' => "Hromadné přiřazení selhalo pro vlastnost ':attribute'." + ], + 'warnings' => [ + 'tips' => 'Tipy pro konfiguraci systému', + 'tips_description' => 'Existují problémy, které vyžadují vaši pozornost, aby byl systém správně nakonfigurován.', + 'permissions' => 'Do adresáře :name nebo jeho podadresářů nelze zapisovat z PHP. Prosím nastavte správná oprávnění.', + 'extension' => 'PHP rozšíření :name není nainstalováno. Prosím nainstalujte toto rozšíření a aktivujte ho.', + 'plugin_missing' => 'Plugin :name je vyžadován, ale není nainstalovaný. Prosím nainstalujte tento plugin.', + ], + 'editor' => [ + 'menu_label' => 'Nastavení editoru kódu', + 'menu_description' => 'Nastavení editoru kódu, velikosti písma a barevného schématu.', + 'font_size' => 'Velikost písma', + 'tab_size' => 'Počet znaků odsazení', + 'use_hard_tabs' => 'Odsazení tabulátory', + 'code_folding' => 'Skládání kódu', + 'code_folding_begin' => 'Označit začátek', + 'code_folding_begin_end' => 'Označit začátek a konec', + 'autocompletion' => 'Automatické doplňování', + 'word_wrap' => 'Zalamování slov', + 'highlight_active_line' => 'Zvýraznit aktivní řádel', + 'auto_closing' => 'Automaticky uzavírat značky', + 'show_invisibles' => 'Zobrazit neviditelné znaky', + 'show_gutter' => 'Zobrazit kurzor', + 'basic_autocompletion'=> 'Základní automatické doplňování (Ctrl + Space)', + 'live_autocompletion'=> 'Živé automatické doplňování', + 'enable_snippets'=> 'Povolte úryvky (snippets) kódu (Tab)', + 'display_indent_guides'=> 'Zobrazit vodítka odsazení', + 'show_print_margin'=> 'Zobrazit okraje tisku', + 'mode_off' => 'Vypnout', + 'mode_fluid' => 'Plynulý (fluid)', + '40_characters' => '40 znaků', + '80_characters' => '80 znaků', + 'theme' => 'Barevné schéma', + 'markup_styles' => 'Styly', + 'custom_styles' => 'Vlastní styly', + 'custom styles_comment' => 'Vlastní styly, které chcete zahrnout do editoru HTML.', + 'markup_classes' => 'Třídy stylů', + 'paragraph' => 'Odstavec', + 'link' => 'Odkaz', + 'table' => 'Tabulka', + 'table_cell' => 'Buňka tabulky', + 'image' => 'Obrázek', + 'label' => 'Popisek', + 'class_name' => 'Název třídy', + 'markup_tags' => 'Značky', + 'allowed_empty_tags' => 'Povolené prázdné značky', + 'allowed_empty_tags_comment' => 'Seznam značek, které nejsou odstraněny, pokud neobsahují žádný obsah.', + 'allowed_tags' => 'Povolené značky', + 'allowed_tags_comment' => 'Seznam povolených značek.', + 'no_wrap' => 'Nezabalovat tyto značky', + 'no_wrap_comment' => 'Seznam značek, které by neměly být zabaleny uvnitř blokových značek.', + 'remove_tags' => 'Odstranit značky', + 'remove_tags_comment' => 'Seznam značek, které jsou odstraněny spolu s jejich obsahem.', + 'toolbar_buttons' => 'Tlačítka na panelu nástrojů', + 'toolbar_buttons_comment' => 'Seznam výchozích tlačítek na panelů nástrojů textového editoru.', + ], + 'tooltips' => [ + 'preview_website' => 'Náhled stránek' + ], + 'mysettings' => [ + 'menu_label' => 'Moje nastavení', + 'menu_description' => 'Nastavení vašeho administrátorského účtu' + ], + 'myaccount' => [ + 'menu_label' => 'Můj účet', + 'menu_description' => 'Nastavte si svoje jméno, e-mailovou adresu a heslo.', + 'menu_keywords' => 'bezpečnost login' + ], + 'branding' => [ + 'menu_label' => 'Nastavení administrace', + 'menu_description' => 'Nastavte si název, logo a barvy použité v administraci.', + 'brand' => 'Značka', + 'logo' => 'Logo', + 'logo_description' => 'Nahrajte vlastní logo, které bude použité v administraci.', + 'app_name' => 'Jméno aplikace', + 'app_name_description' => 'Toto jméno se zobrazí v titulní liště stránek.', + 'app_tagline' => 'Motto aplikace', + 'app_tagline_description' => 'Toto motto se zobrazí na přihlašovací stránce administrace.', + 'colors' => 'Barvy', + 'primary_color' => 'Primární barva', + 'secondary_color' => 'Sekundární barva', + 'accent_color' => 'Barva pro zvýraznění', + 'styles' => 'Styly', + 'custom_stylesheet' => 'Vlastní kaskádové styly', + 'navigation' => 'Navigace', + 'menu_mode' => 'Styl menu', + 'menu_mode_inline' => 'V řádku', + 'menu_mode_tile' => 'V dlaždicích', + 'menu_mode_collapsed' => 'Sbalené', + ], + 'backend_preferences' => [ + 'menu_label' => 'Nastavení administrace', + 'menu_description' => 'Spravujte nastavení svého uživatelského účtu, jako je například jazyk apod.', + 'region' => 'Oblast', + 'code_editor' => 'Editor kódu', + 'timezone' => 'Časová zóna', + 'timezone_comment' => 'Upraví zobrazení času a data podle této časové zóny.', + 'locale' => 'Jazyk', + 'locale_comment' => 'Vyberte jazyk administrace.' + ], + 'access_log' => [ + 'hint' => 'Tento záznam zobrazuje seznam úspěšných přihlášení do administrace. Záznamy jsou uchovávány :days dní.', + 'menu_label' => 'Protokol přístupů', + 'menu_description' => 'Zobrazit seznam úspěšných přihlášení do administrace.', + 'created_at' => 'Datum & čas', + 'login' => 'Login', + 'ip_address' => 'IP adresa', + 'first_name' => 'Jméno', + 'last_name' => 'Příjmení', + 'email' => 'E-mail' + ], + 'filter' => [ + 'all' => 'Vše', + 'options_method_not_exists' => "Třída modelu :model musí definovat metodu :method(), která vrací položky filtru ':filter'.", + 'date_all' => 'Všechna období' + ], + 'import_export' => [ + 'upload_csv_file' => '1. Nahrajte CSV soubor', + 'import_file' => 'Soubor pro import', + 'first_row_contains_titles' => 'První řádek obsahuje názvy sloupců', + 'first_row_contains_titles_desc' => 'Nechte zaškrtnuto, pokud první řádek obsahuje názvy sloupců.', + 'match_columns' => '2. Vytvořit vazbu mezi sloupci v souboru a v databázi', + 'file_columns' => 'Sloupce souboru', + 'database_fields' => 'Sloupce v databázi', + 'set_import_options' => '3. Nastavit vlastnosti importu', + 'export_output_format' => '1. Nastavit formát exportu', + 'file_format' => 'Formát souboru', + 'standard_format' => 'Standardní', + 'custom_format' => 'Vlastní', + 'delimiter_char' => ' Oddělovací znak', + 'enclosure_char' => 'Znak pro ohraničení (enclosure character)', + 'escape_char' => 'Uvozovací znak (escape character)', + 'select_columns' => '2. Vybrat exportované sloupce', + 'column' => 'Sloupec', + 'columns' => 'Sloupce', + 'set_export_options' => '3. Nastavit vlastnosti importu', + 'show_ignored_columns' => 'Zobrazit ignorované sloupce', + 'auto_match_columns' => 'Vytvořit vazby automaticky', + 'created' => 'Vytvořeno', + 'updated' => 'Aktualizováno', + 'skipped' => 'Přeskočeno', + 'warnings' => 'Upozornění', + 'errors' => 'S chybou', + 'skipped_rows' => 'Přeskočené řádky', + 'import_progress' => 'Průběh importu', + 'processing' => 'Zpracovávám', + 'import_error' => 'Chyba importu', + 'upload_valid_csv' => 'Nahrajte prosím platný soubor CSV.', + 'drop_column_here' => 'Sem přetáhněte sloupec...', + 'ignore_this_column' => 'Ignorovat tento sloupec', + 'processing_successful_line1' => 'Export byl dokončen!', + 'processing_successful_line2' => 'Prohlížeč vás nyní přesměruje na stránku pro stažení souboru.', + 'export_progress' => 'Průběh exportu', + 'export_error' => 'Chyba exportu', + 'column_preview' => 'Náhled sloupce', + 'file_not_found_error' => 'Soubor nebyl nalezen', + 'empty_error' => 'Nebyly nalezeny žádné záznamy pro export', + 'empty_import_columns_error' => 'Prosím vyberte sloupce pro import.', + 'match_some_column_error' => 'Prosím vytvořte vazbu mezi sloupci.', + 'required_match_column_error' => 'Prosím vytvořte vazbu pro vyžadovaný sloupec :label.', + 'empty_export_columns_error' => 'Prosím vyberte sloupce pro export.', + 'behavior_missing_uselist_error' => 'Musíte implementovat chování controlleru ListController s povolenou vlastností "useList".', + 'missing_model_class_error' => 'Prosím specifikujte vlastnost třídy pro :type', + 'missing_column_id_error' => 'Chybí identifikátor sloupce', + 'unknown_column_error' => 'neznámý sloupec', + 'encoding_not_supported_error' => 'Kódování zdrojového souboru není rozpoznáno. Zvolte volbu formátu souboru s vlastním kódováním pro import souboru.', + 'encoding_format' => 'Kódování souboru', + ], + 'permissions' => [ + 'manage_media' => 'Správa médií' + ], + 'mediafinder' => [ + 'label' => 'Vyhledávač médií', + 'default_prompt' => 'Klikněte na tlačítko %s pro hledání souboru' + ], + 'media' => [ + 'menu_label' => 'Média', + 'upload' => 'Nahrát', + 'move' => 'Přesunout', + 'delete' => 'Smazat', + 'add_folder' => 'Přidat složku', + 'search' => 'Vyhledat', + 'display' => 'Zobrazit', + 'filter_everything' => 'Vše', + 'filter_images' => 'Obrázky', + 'filter_video' => 'Video', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Dokumenty', + 'library' => 'Knihovna', + 'size' => 'Velikost', + 'title' => 'Název', + 'last_modified' => 'Naposledy upraveno', + 'public_url' => 'Veřejná URL', + 'click_here' => 'Klikněte zde', + 'thumbnail_error' => 'Chyba generování náhledu.', + 'return_to_parent' => 'Zpět do nadřazené složky', + 'return_to_parent_label' => 'Nahoru ..', + 'nothing_selected' => 'Nic nevybráno.', + 'multiple_selected' => 'Vybráno více položek.', + 'uploading_file_num' => 'Nahrávám :number soubor(y)...', + 'uploading_complete' => 'Nahrávání kompletní', + 'uploading_error' => 'Nahrávání se nezdařilo', + 'type_blocked' => 'Kvůli bezpečnosti je tento typ souborů zablokován.', + 'order_by' => 'Seřadit dle', + 'folder' => 'Složka', + 'no_files_found' => 'Pro tento požadavek nebyly nalezeny žádné soubory.', + 'delete_empty' => 'Vyberte položky ke smazání.', + 'delete_confirm' => 'Opravu chcete smazat vybrané položky?', + 'error_renaming_file' => 'Přejmenování se nezdařilo.', + 'new_folder_title' => 'Nová složka', + 'folder_name' => 'Název složky', + 'error_creating_folder' => 'Chyba vytváření složky', + 'folder_or_file_exist' => 'Adresář nebo soubor se zadaným názvem již existuje.', + 'move_empty' => 'Vyberte položky k přesunutí.', + 'move_popup_title' => 'Přesun souborů nebo složek', + 'move_destination' => 'Cílová složka', + 'please_select_move_dest' => 'Prosím vyberte cílovou složku.', + 'move_dest_src_match' => 'Prosím vyberte jinou cílovou složku.', + 'empty_library' => 'Knihovna médií je prázdná. Nahrajte prosím soubory, nebo vytvořte složky.', + 'insert' => 'Vložit', + 'crop_and_insert' => 'Oříznout & vložit', + 'select_single_image' => 'Prosím vyberte pouze jeden obrázek.', + 'selection_not_image' => 'Vybraná položka není obrázek.', + 'restore' => 'Zpět všechny změny', + 'resize' => 'Změnit velikost...', + 'selection_mode_normal' => 'Normální', + 'selection_mode_fixed_ratio' => 'Pevný poměr stran', + 'selection_mode_fixed_size' => 'Pevná velikost', + 'height' => 'Výška', + 'width' => 'Šířka', + 'selection_mode' => 'Způsob označování (selection mode)', + 'resize_image' => 'Změnit velikost obrázku', + 'image_size' => 'Velikost obrázku:', + 'selected_size' => 'Vybráno:' + ], +]; diff --git a/modules/backend/lang/da/lang.php b/modules/backend/lang/da/lang.php new file mode 100644 index 0000000..0374767 --- /dev/null +++ b/modules/backend/lang/da/lang.php @@ -0,0 +1,545 @@ + [ + 'title' => 'Administrationsområde' + ], + 'field' => [ + 'invalid_type' => 'Ugyldig felttype :type.', + 'options_method_not_exists' => "Model klassen :model skal implementere :method() som returnerer valgmuligheder for feltet ':field'." + ], + 'widget' => [ + 'not_registered' => "En widget klasse med navnet ':name' er ikke registreret", + 'not_bound' => "En widget klasse med navnet ':name' er ikke blevet bundet til controlleren" + ], + 'page' => [ + 'untitled' => 'Unavngivet', + 'access_denied' => [ + 'label' => 'Adgang nægtet', + 'help' => "Du har ikke de fornødne rettigheder til at se denne side.", + 'cms_link' => 'Tilbage til backenden' + ], + 'no_database' => [ + 'label' => 'Databasen kan ikke findes', + 'help' => "En database er påkrævet for at kunne tilgå backenden. Kontroller om databasen er konfigureret og migreret, inden du prøver igen.", + 'cms_link' => 'Tilbage til hjemmesiden' + ], + ], + 'partial' => [ + 'not_found_name' => "Partialen ':name' kunne ikke findes." + ], + 'account' => [ + 'sign_out' => 'Log ud', + 'login' => 'Log ind', + 'reset' => 'Reset', + 'restore' => 'Genopret', + 'login_placeholder' => 'Log ind', + 'password_placeholder' => 'adgangskode', + 'forgot_password' => 'Glemt din adgangskode?', + 'enter_email' => 'Indtast din email', + 'enter_login' => 'Indtast din login-info', + 'email_placeholder' => 'email', + 'enter_new_password' => 'Skriv en ny adgangskode', + 'password_reset' => 'Nulstil adgangskode', + 'restore_success' => 'En besked med instruktioner, er blevet sendt til din email adresse.', + 'restore_error' => "En bruger med login-infoen ':login', kunne ikke findes", + 'reset_success' => 'Adgangskoden er blevet nulstillet. Du kan nu logge ind.', + 'reset_error' => 'Ugyldig adgangskode-nulstillings-data angivet. Prøv venligst igen!', + 'reset_fail' => 'Kunne ikke nulstille din adgangskode!', + 'apply' => 'Accepter', + 'cancel' => 'Fortryd', + 'delete' => 'Slet', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Dashboard', + 'widget_label' => 'Widget', + 'widget_width' => 'Bredde', + 'full_width' => 'Fuld bredde', + 'manage_widgets' => 'Administrer widgets', + 'add_widget' => 'Tilføj widget', + 'widget_inspector_title' => 'Widget konfiguration', + 'widget_inspector_description' => 'Konfigurer widgeten', + 'widget_columns_label' => 'Bredde :columns', + 'widget_columns_description' => 'Widget bredden, et nummer mellem 1 og 10.', + 'widget_columns_error' => 'Indtast venligst widget bredden som et nummer mellem 1 og 10.', + 'columns' => '{1} kollone|[2,Inf] kolonner', + 'widget_new_row_label' => 'Tving ny række', + 'widget_new_row_description' => 'Læg widget på ny række.', + 'widget_title_label' => 'Widget titel', + 'widget_title_error' => 'Widget titlen er påkrævet.', + 'reset_layout' => 'Nulstil layout', + 'reset_layout_confirm' => 'Nulstil layout?', + 'reset_layout_success' => 'Layoutet er blevet nulstillet', + 'make_default' => 'Gør til standard', + 'make_default_confirm' => 'Sæt det nuværende layout som standardlayout', + 'make_default_success' => 'Nuværende layout er standardlayoutet', + 'status' => [ + 'widget_title_default' => 'System status', + 'update_available' => '{0} opdateringer!|{1} opdatering!|[2,Inf] opdateringer!', + 'updates_pending' => 'Afventende softwareopdateringer', + 'updates_nil' => 'Softwaren er up-to-date', + 'updates_link' => 'Opdater', + 'warnings_pending' => 'Nogle problemer har brug for din opmærksomhed', + 'warnings_nil' => 'Ingen advarsler at vise', + 'warnings_link' => 'Vis', + 'core_build' => 'System build', + 'event_log' => 'Event log', + 'request_log' => 'Request log', + 'app_birthday' => 'Online siden', + ], + 'welcome' => [ + 'widget_title_default' => 'Velkommen', + 'welcome_back_name' => 'Velkommen tilbage til :app, :name.', + 'welcome_to_name' => 'Velkommen til :app, :name.', + 'first_sign_in' => 'Dette er første gang du er logget ind.', + 'last_sign_in' => 'Du var sidst logget ind', + 'view_access_logs' => 'Vis access logs', + 'nice_message' => 'Hav en god dag!', + ] + ], + 'user' => [ + 'name' => 'Administrator', + 'menu_label' => 'Administratorer', + 'menu_description' => 'Administrer back-end administratorbrugere, grupper og rettigheder.', + 'list_title' => 'Administrer Administrators', + 'new' => 'Ny Administrator', + 'login' => 'Log ind', + 'first_name' => 'Fornavn', + 'last_name' => 'Efternavn', + 'full_name' => 'Fulde navn', + 'email' => 'Email', + 'groups' => 'Grupper', + 'groups_comment' => 'Vælg hvilke grupper kontoen skal tilhøre. Grupper definerer brugerrettigheder, som kan overskrives på den enkelte bruger..', + 'avatar' => 'Avatar', + 'password' => 'Adgangskode', + 'password_confirmation' => 'Bekræft Adgangskode', + 'permissions' => 'Rettigheder', + 'account' => 'Konto', + 'superuser' => 'Superbruger', + 'superuser_comment' => 'Giver kontoen fuld adgang til hele systemet.', + 'send_invite' => 'Send invitation på email', + 'send_invite_comment' => 'Sender en velkomstbesked med login informationer.', + 'delete_confirm' => 'Slet denne administrator?', + 'return' => 'Tilbage til administrator liste', + 'allow' => 'Tillad', + 'inherit' => 'Nedarv', + 'deny' => 'Tillad ikke', + 'group' => [ + 'name' => 'Gruppe', + 'name_comment' => 'Navnet vises i gruppelisten på Opret/rediger Administrator formularen.', + 'name_field' => 'Navn', + 'description_field' => 'Beskrivelse', + 'is_new_user_default_field_label' => 'Standardgruppe', + 'is_new_user_default_field_comment' => 'Tilføj automatisk nye administratorer til denne gruppe', + 'code_field' => 'Kode', + 'code_comment' => 'Skriv en unik kode hvis du vil tilgå gruppe objektet, via API\'et.', + 'menu_label' => 'Administrer Grupper', + 'list_title' => 'Administrer Grupper', + 'new' => 'Ny Gruppe', + 'delete_confirm' => 'Slet denne administratorgruppe??', + 'return' => 'Tilbage til gruppelisten', + 'users_count' => 'Brugere' + ], + 'preferences' => [ + 'not_authenticated' => 'Der er ingen bruger at loade eller save preferencer for.' + ] + ], + 'list' => [ + 'default_title' => 'Liste', + 'search_prompt' => 'Søg...', + 'no_records' => 'Der er ingen records i dette view.', + 'missing_model' => 'List behavioren brugt i :class har ikke defineret en model.', + 'missing_column' => 'Der er ingen kolonnedefinition for :columns.', + 'missing_columns' => 'Liste brugt i :class har ikke nogle listekolonner defineret.', + 'missing_definition' => "List behavioren har ikke en kolonne for ':field'.", + 'missing_parent_definition' => "List behavioren har ingen definition for ':definition'.", + 'behavior_not_ready' => 'List behavioren er ikke blevet initialiseret. Kontroller om du har kaldt makeLists() i controlleren.', + 'invalid_column_datetime' => "Kolonneværdien ':column' er ikke et DateTime objekt: Mangler du en \$dates reference i Modellen?", + 'pagination' => 'Viste records: :from-:to af :total', + 'prev_page' => 'Forrige side', + 'next_page' => 'Næste side', + 'refresh' => 'Opdater', + 'updating' => 'Opdaterer...', + 'loading' => 'Loader...', + 'setup_title' => 'Listeopsætning', + 'setup_help' => 'Brug afkrydsningsfelterne til at vælge de kolonner du vil se i listen. Du kan lndre position for kolonnerne ved at trække dem op og ned.', + 'records_per_page' => 'Records pr. side', + 'records_per_page_help' => 'Vælg det antal records der skal vises pr. side. Vær opmærksom på at et stort antal records på en enkelt side, kan gøre siden langsom.', + 'check' => 'Check', + 'delete_selected' => 'Slet valgte', + 'delete_selected_empty' => 'Der er ingen valgte records at slette.', + 'delete_selected_confirm' => 'Slet de valgte records?', + 'delete_selected_success' => 'Slet valgte records.', + 'column_switch_true' => 'Ja', + 'column_switch_false' => 'Nej' + ], + 'fileupload' => [ + 'attachment' => 'Vedhæftning', + 'help' => 'Tilføj en titel og beskrivelse til denne vedhæftning.', + 'title_label' => 'Titel', + 'description_label' => 'Beskrivelse', + 'default_prompt' => 'Tryk på %s eller træk en fil hertil, for at uploade', + 'attachment_url' => 'Vedhæftnings URL', + 'upload_file' => 'Upload fil', + 'upload_error' => 'Upload fejl', + 'remove_confirm' => 'Er du sikker?', + 'remove_file' => 'Fjern fil' + ], + 'form' => [ + 'create_title' => 'Ny :name', + 'update_title' => 'Rediger :name', + 'preview_title' => 'Forhåndsvisning :name', + 'create_success' => ':name oprettet', + 'update_success' => ':name opdateret', + 'delete_success' => ':name slettet', + 'reset_success' => 'Nulstilning færdig', + 'missing_id' => 'Formular record ID er ikke blevet angivet.', + 'missing_model' => 'Form behavior used in :class does not have a model defined.', + 'missing_definition' => "Form behavioren indeholder ikke et felt for ':field'.", + 'not_found' => 'Formular record med et ID\'et :id kunne ikke findes.', + 'action_confirm' => 'Er du sikker?', + 'create' => 'Opret', + 'create_and_close' => 'Opret og luk', + 'creating' => 'Opretter...', + 'creating_name' => 'Opretter :name...', + 'save' => 'Gem', + 'save_and_close' => 'Gem og luk', + 'saving' => 'Gem...', + 'saving_name' => 'Gemmer :name...', + 'delete' => 'Slet', + 'deleting' => 'Sletter...', + 'confirm_delete' => 'Slet record?', + 'confirm_delete_multiple' => 'Slet valgte records?', + 'deleting_name' => 'Sletter :name...', + 'reset_default' => 'Nulstil til standard', + 'resetting' => 'Nulstiller', + 'resetting_name' => 'Nulstiller :name', + 'undefined_tab' => 'Andet', + 'field_off' => 'Fra', + 'field_on' => 'Til', + 'add' => 'Tilføj', + 'apply' => 'Slå til', + 'cancel' => 'Fortryd', + 'close' => 'Luk', + 'confirm' => 'Bekræft', + 'reload' => 'Reload', + 'complete' => 'Færdig', + 'ok' => 'OK', + 'or' => 'eller', + 'confirm_tab_close' => 'Luk tab? Ændringer der ikke er gemt vil blive tabt.', + 'behavior_not_ready' => 'Form behavioren er ikke blevet initialiseret. Kontroller at du har kaldt initForm() in controlleren.', + 'preview_no_files_message' => 'Der er ikke uploadet nogle filer.', + 'preview_no_record_message' => 'Der er ikke valgt nogen record.', + 'select' => 'Vælg', + 'select_all' => 'Vælg alle', + 'select_none' => 'vælg ingen', + 'select_placeholder' => 'Vælg venligst', + 'insert_row' => 'Indsæt Række', + 'insert_row_below' => 'Indsæt Række Nedeunder', + 'delete_row' => 'Slet Række', + 'concurrency_file_changed_title' => 'Fil er blevet ændret', + 'concurrency_file_changed_description' => "Den fil du redigerer er blevet ændret på disken, af en anden bruger. Du kan enten reloade filen og miste ændringer eller overskrive filen på disken.", + 'return_to_list' => 'Tilbage til listen' + ], + 'recordfinder' => [ + 'find_record' => 'Find Record' + ], + 'relation' => [ + 'missing_config' => "Relation behavioren har ingen konfiguration for ':config'.", + 'missing_definition' => "Relation behavioren har ingen definition for ':field'.", + 'missing_model' => 'Relation behavioren brugt :class har ikke defineret en model.', + 'invalid_action_single' => 'Denne handling kan ikke udføres på et "enligt" relationship.', + 'invalid_action_multi' => 'Denne handling kan ikke udføres på et "flere" relationship.', + 'help' => 'Tryk på en ting for at tilføje', + 'related_data' => 'Relateret :name data', + 'add' => 'Tilføj', + 'add_selected' => 'Tilføj valgte', + 'add_a_new' => 'Tilføj en ny :name', + 'link_selected' => 'Link valgte', + 'link_a_new' => 'Link en ny :name', + 'cancel' => 'Fortryd', + 'close' => 'Luk', + 'add_name' => 'Tilføj :name', + 'create' => 'Opret', + 'create_name' => 'Opret :name', + 'update' => 'Opdater', + 'update_name' => 'Opdater :name', + 'preview' => 'Forhåndsvisning', + 'preview_name' => 'Forhåndsvis :name', + 'remove' => 'Fjern', + 'remove_name' => 'Fjern :name', + 'delete' => 'Slet', + 'delete_name' => 'Slet :name', + 'delete_confirm' => 'Er du sikker?', + 'link' => 'Link', + 'link_name' => 'Link :name', + 'unlink' => 'Fjern link', + 'unlink_name' => 'Fjern link til :name', + 'unlink_confirm' => 'Er du sikker?' + ], + 'reorder' => [ + 'default_title' => 'Sorter records', + 'no_records' => 'Der er ikke nogle records at sortere.' + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => "Model ':class' with an ID of :id could not be found", + 'missing_id' => 'Der er ikke angivet noget ID til model recorden.', + 'missing_relation' => "Model ':class' har ingen definition af ':relation'.", + 'missing_method' => "Model ':class' har ikke metoden ':method'.", + 'invalid_class' => "Model :model brugt i :class er ikke gyldig. Den skal nedarve fra \\Model Klassen.", + 'mass_assignment_failed' => "Mass assignment fejlede for Model attributen ':attribute'." + ], + 'warnings' => [ + 'tips' => 'Systemkonfigurations-tips', + 'tips_description' => 'Der er problemer du skal være opmærksom på for at konfigurre systemet ordenligt.', + 'permissions' => 'Mappe :name eller dens undermapper, er ikke skrivbare for PHP. Konfigurer venligst webserverens rettigheder for denne mappe.', + 'extension' => 'PHP extensionen :name er ikke installeret. Installer og aktiver venligst denne extension.' + ], + 'editor' => [ + 'menu_label' => 'Indstillinger for redigeringsværktøj', + 'menu_description' => 'Tilpas de globale indstllinger for redigeringsværktøjet, som eksempelvis skriftstørrelse og farver.', + 'font_size' => 'Skriftstørrelse', + 'tab_size' => 'Tab størrelse', + 'use_hard_tabs' => 'Indryk med tabs', + 'code_folding' => 'Kode foldning', + 'code_folding_begin' => 'Marker begyndelse', + 'code_folding_begin_end' => 'Marker begyndelse og endelse', + 'autocompletion' => 'Autocompletion', + 'word_wrap' => 'Word wrap', + 'highlight_active_line' => 'Highlight den aktive linie', + 'auto_closing' => 'Luk automatisk tags', + 'show_invisibles' => 'Vis usynlige karakterer', + 'show_gutter' => 'Vis gutter', + 'basic_autocompletion'=> 'Basic Autocompletion (Ctrl + Space)', + 'live_autocompletion'=> 'Live Autocompletion', + 'enable_snippets'=> 'Aktiver kode snippets (Tab)', + 'display_indent_guides'=> 'Vis indrykningsguides', + 'show_print_margin'=> 'Vis print margin', + 'mode_off' => 'Fra', + 'mode_fluid' => 'Fluid', + '40_characters' => '40 Karakterer', + '80_characters' => '80 Karakterer', + 'theme' => 'Farveskema', + 'markup_styles' => 'Markup Styles', + 'custom_styles' => 'Custom stylesheet', + 'custom styles_comment' => 'Custom styles som skal inkluderes i HTML editoren.', + 'markup_classes' => 'Markup Classes', + 'paragraph' => 'Afsnit', + 'link' => 'Link', + 'table' => 'Tabel', + 'table_cell' => 'Tabel Celle', + 'image' => 'Billede', + 'label' => 'Label', + 'class_name' => 'Class navn', + 'markup_tags' => 'Markup Tags', + 'allowed_empty_tags' => 'Tilladte tomme tags', + 'allowed_empty_tags_comment' => 'Liste af tags der ikke bliver fjernet, når de ikke har noget indhold.', + 'allowed_tags' => 'Tilladte tags', + 'allowed_tags_comment' => 'Liste af tilladte tags.', + 'no_wrap' => 'Omgiv ikke tags', + 'no_wrap_comment' => 'Liste af tags der ikke skal omgives af block tags.', + 'remove_tags' => 'Fjern tags', + 'remove_tags_comment' => 'Liste af tags der bliver fjernet, inklusiv deres indhold.' + ], + 'tooltips' => [ + 'preview_website' => 'Forhåndsvis hjemmesiden' + ], + 'mysettings' => [ + 'menu_label' => 'Mine indstillinger', + 'menu_description' => 'Indstilling til din administrationsbruger' + ], + 'myaccount' => [ + 'menu_label' => 'Min konto', + 'menu_description' => 'Opdater dine kontodetaljer som eksempelvis navn, email-adresse og adgangskode.', + 'menu_keywords' => 'Sikkerhedslogin' + ], + 'branding' => [ + 'menu_label' => 'Tilpas back-end', + 'menu_description' => 'Tilpas backendområdet med eksempelvis navn, farver og logo.', + 'brand' => 'Brand', + 'logo' => 'Logo', + 'logo_description' => 'Upload et custom logo, der skal bruges i backenden.', + 'app_name' => 'App Navn', + 'app_name_description' => 'Dette navn vises i titlen i backenden.', + 'app_tagline' => 'App Tagline', + 'app_tagline_description' => 'Dette bliver vist ved backendlogin-siden.', + 'colors' => 'Farver', + 'primary_color' => 'Primær farve', + 'secondary_color' => 'Sekundær farve', + 'accent_color' => 'Accent color', + 'styles' => 'Styles', + 'custom_stylesheet' => 'Custom stylesheet', + 'navigation' => 'Navigation', + 'menu_mode' => 'Menu style', + 'menu_mode_inline' => 'På linie', + 'menu_mode_tile' => 'Stablet', + 'menu_mode_collapsed' => 'Kollapset' + ], + 'backend_preferences' => [ + 'menu_label' => 'Backend indstillinger', + 'menu_description' => 'Administrer dine backend indstillinger som eksempelvis dit ønskede sprog.', + 'region' => 'Region', + 'code_editor' => 'Kode editor', + 'timezone' => 'Tidszone', + 'timezone_comment' => 'Juster viste datoer til denne tidszone.', + 'locale' => 'Locale', + 'locale_comment' => 'Vælg din ønskede locale.' + ], + 'access_log' => [ + 'hint' => 'Denne log viser en liste af successfulde administratorlogins. Records bliver gemt i :days dage.', + 'menu_label' => 'Access log', + 'menu_description' => 'Se en liste af successfulde backendbruger logins.', + 'created_at' => 'Dato & Tid', + 'login' => 'Login', + 'ip_address' => 'IP addresse', + 'first_name' => 'Fornavn', + 'last_name' => 'Efternavn', + 'email' => 'Email' + ], + 'filter' => [ + 'all' => 'alle', + 'options_method_not_exists' => "Model klassen :model skal implementere metoden :method() som returnerer muligheder til ':filter' filteret.", + 'date_all' => 'altid' + ], + 'import_export' => [ + 'upload_csv_file' => '1. Upload en CSV fil', + 'import_file' => 'Importer fil', + 'first_row_contains_titles' => 'Første række indeholder kolonnetitler', + 'first_row_contains_titles_desc' => 'Lad denne være krydset hvis første række i CSV filen er brugt til kolonnetitler.', + 'match_columns' => '2. Match the filkolonnerne til databasekolonner', + 'file_columns' => 'Filkolonner', + 'database_fields' => 'Databasekolonner', + 'set_import_options' => '3. Sæt import indstillinger', + 'export_output_format' => '1. Eksporter output format', + 'file_format' => 'Filformat', + 'standard_format' => 'Standard format', + 'custom_format' => 'Custom format', + 'delimiter_char' => 'Adskillelseskarakter', + 'enclosure_char' => 'Indramningskarakter', + 'escape_char' => 'Escapekarakter', + 'select_columns' => '2. Vælg kolonner der skal eksporteres', + 'column' => 'Kolonne', + 'columns' => 'Kolonner', + 'set_export_options' => '3. Sæt eksport indstillinger', + 'show_ignored_columns' => 'Vis ignorerede kolonner', + 'auto_match_columns' => 'Automatch kolonner', + 'created' => 'Oprettet', + 'updated' => 'Opdateret', + 'skipped' => 'Skipped', + 'warnings' => 'Advarsler', + 'errors' => 'Fejl', + 'skipped_rows' => 'Skipped Rækker', + 'import_progress' => 'Import progress', + 'processing' => 'Arbejder', + 'import_error' => 'Import fejl', + 'upload_valid_csv' => 'Upload venligst en gyldig CSV fil.', + 'drop_column_here' => 'Slip kolonne her...', + 'ignore_this_column' => 'Ignorer denne kolonne', + 'processing_successful_line1' => 'Fileksportprocess færdig!', + 'processing_successful_line2' => 'Browseren vil nu viderestille dig til fildownload.', + 'export_progress' => 'Eksporteringprocess', + 'export_error' => 'Eksporteringsfejl', + 'column_preview' => 'Kolonne forhåndsvisning', + 'file_not_found_error' => 'Fil blev ikke fundet', + 'empty_error' => 'Der blev ikke leveret noget data til eksportering', + 'empty_import_columns_error' => 'Vælg venligst nogle kolonner at importere.', + 'match_some_column_error' => 'Match venligst nogle kolonner først.', + 'required_match_column_error' => 'Vælg venligst et match til det påkrævede felt :label.', + 'empty_export_columns_error' => 'Vælg venligst nogle kolonner at eksportere.', + 'behavior_missing_uselist_error' => 'Du skal implementere controller behavioren ListController med eksport "useList" mulighed aktiveret.', + 'missing_model_class_error' => 'Agiv venligst modelklasse muligheden for :type', + 'missing_column_id_error' => 'Mangler kolonne identifier', + 'unknown_column_error' => 'Ukendt kolonne', + 'encoding_not_supported_error' => 'Fil indkodning kan ikke genkendes. Vælg venligst filformat med den korrekte indkodning for at importere filen.', + 'encoding_format' => 'Filindkodning', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Vesteuropæisk)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Centralauropæisk)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, Sydeuropæisk)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, Nordeuropæisk)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabisk)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Græsk)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebraisk)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Tyrkisk)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordisk)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Keltisk)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Vesteuropæisk med eurotegn)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Upload og administrer media indhold - billeder, video, lyd, dokumenter' + ], + 'mediafinder' => [ + 'label' => 'Media Finder', + 'default_prompt' => 'Tryk på %s knappen for at finde et mediaobjekt' + ], + 'media' => [ + 'menu_label' => 'Media', + 'upload' => 'Upload', + 'move' => 'Flyt', + 'delete' => 'Slet', + 'add_folder' => 'Tilføj mappe', + 'search' => 'Søg', + 'display' => 'Vis', + 'filter_everything' => 'Alt', + 'filter_images' => 'Billeder', + 'filter_video' => 'Video', + 'filter_audio' => 'Lyd', + 'filter_documents' => 'Dokumenter', + 'library' => 'Bibliotek', + 'size' => 'Størrelse', + 'title' => 'Titel', + 'last_modified' => 'Sidst redigeret', + 'public_url' => 'Offentlig URL', + 'click_here' => 'Tryk her', + 'thumbnail_error' => 'Fejl ved generering af thumbnail.', + 'return_to_parent' => 'Gå en mappe tilbage', + 'return_to_parent_label' => 'Gå op ..', + 'nothing_selected' => 'Intet er valgt.', + 'multiple_selected' => 'Flere ting valgt.', + 'uploading_file_num' => 'Uploader :number fil(er)...', + 'uploading_complete' => 'Upload færdig', + 'uploading_error' => 'Upload fejlede', + 'type_blocked' => 'Filtypen er blokeret af sikkerhedshensyn.', + 'order_by' => 'Sorter efter', + 'folder' => 'Mappe', + 'no_files_found' => 'Ingen filer fundet fra din forespørgsel.', + 'delete_empty' => 'Vælg venligst filer at slette.', + 'delete_confirm' => 'Slet de valgte ting?', + 'error_renaming_file' => 'Fejl ved omdøbning.', + 'new_folder_title' => 'Ny mappe', + 'folder_name' => 'Mappenavn', + 'error_creating_folder' => 'Fejl ved opretning af mappe', + 'folder_or_file_exist' => 'En mappe eller fil med det angivede navn, findes allerede.', + 'move_empty' => 'Vælg venligst nogle ting du vil flytte.', + 'move_popup_title' => 'Flyt filer eller mapper', + 'move_destination' => 'Destinationmappe', + 'please_select_move_dest' => 'Vælg venligst en destinationsmappe.', + 'move_dest_src_match' => 'Vælg venligst en anden destinationsmappe.', + 'empty_library' => 'Media biblioteket er tomt. Upload filer eller mapper for at starte.', + 'insert' => 'Indsæt', + 'crop_and_insert' => 'Beskær & Indsæt', + 'select_single_image' => 'Vælg venligst et enkelt billede.', + 'selection_not_image' => 'Det valgte objekt er ikke et billede.', + 'restore' => 'Fortryd alle ændringer', + 'resize' => 'Skaler...', + 'selection_mode_normal' => 'Normal', + 'selection_mode_fixed_ratio' => 'Fast størrelsesforhold', + 'selection_mode_fixed_size' => 'Fast størrelse', + 'height' => 'Højde', + 'width' => 'Bredde', + 'selection_mode' => 'Udvælgelsesmetode', + 'resize_image' => 'Skaler billede', + 'image_size' => 'Billedstørrelse:', + 'selected_size' => 'Valgt:' + ] +]; diff --git a/modules/backend/lang/de/lang.php b/modules/backend/lang/de/lang.php new file mode 100644 index 0000000..e765f39 --- /dev/null +++ b/modules/backend/lang/de/lang.php @@ -0,0 +1,622 @@ + [ + 'title' => 'Admin-Bereich', + 'invalid_login' => 'Die Angaben stimmen nicht mit unseren Aufzeichnungen überein. Überprüfen Sie diese und versuchen Sie es noch einmal.', + ], + 'field' => [ + 'invalid_type' => 'Ungültiger Feldtyp :type.', + 'options_method_invalid_model' => 'Das Attribut ":field" löst sich nicht zu einen gültigen Model auf. Probiere die options Methode der Model-Klasse :model explicit zu definieren.', + 'options_method_not_exists' => 'Die Modell-Klasse :model muss eine Methode :method() mit Rückgabe der Werte von ":field" besitzen.', + 'options_static_method_invalid_value' => "Die statische Methode ':method()' in der Klasse :class hat kein valides Optionsarray zurückgegeben.", + 'colors_method_not_exists' => "Die Modellklasse :model muss eine Methode :method() definieren, welche html color (HEX) codes für das ':field' Formularfeld zurückgibt.", + ], + 'widget' => [ + 'not_registered' => "Ein Widget namens ':name' wurde nicht registriert", + 'not_bound' => "Ein Widget mit dem Klassennamen ':name' wurde nicht mit dem Controller verbunden", + ], + 'page' => [ + 'untitled' => "Unbenannt", + '404' => [ + 'label' => 'Seite nicht gefunden', + 'help' => "Die von Ihnen angeforderte Seite konnte nicht gefunden werden.", + 'back_link' => 'Zurück zur vorigen Seite', + ], + 'access_denied' => [ + 'label' => "Zugriff verweigert", + 'help' => "Sie haben nicht die erforderlichen Berechtigungen, um diese Seite zu sehen.", + 'cms_link' => "Zum CMS-Backend", + ], + 'no_database' => [ + 'label' => 'Datenbank fehlt', + 'help' => "Eine Datenbank wird benötigt um Zugriff auf das Backend zu haben. Überprüfe die Datenbankkonfiguration und migriere die Datenbank bevor du es noch einmal probierst.", + 'cms_link' => 'Zurück zur Homepage' + ], + ], + 'partial' => [ + 'not_found_name' => "Das Partial ':name' wurde nicht gefunden.", + 'invalid_name' => 'Ungültiger Partial: :name.', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Ungültiger AJAX handler: :name.', + 'not_found' => "AJAX handler ':name' wurde nicht gefunden.", + ], + 'account' => [ + 'impersonate_confirm' => 'Sind Sie sicher, dass Sie sich als dieser Benutzer anmelden wollen? Sie können zu Ihrem ursprünglichen Zustand zurückkehren, indem Sie sich abmelden.', + 'impersonate_success' => 'Sie sind jetzt als dieser Benutzer angemeldet', + 'signed_in_as' => 'Angemeldet als :full_name', + 'sign_out' => 'Abmelden', + 'login' => 'Anmelden', + 'reset' => 'Zurücksetzen', + 'restore' => 'Wiederherstellen', + 'login_placeholder' => 'Benutzername', + 'password_placeholder' => 'Passwort', + 'remember_me' => 'Angemeldet bleiben', + 'forgot_password' => "Passwort vergessen?", + 'enter_email' => "Bitte E-Mail-Adresse eingeben", + 'enter_login' => "Bitte Benutzernamen eingeben", + 'email_placeholder' => "E-Mail", + 'enter_new_password' => "Bitte ein neues Passwort eingeben", + 'password_reset' => "Passwort zurücksetzen", + 'restore_success' => "Eine E-Mail mit weiteren Anweisungen zum Zurücksetzen Ihres Passworts wurde an Sie versandt", + 'restore_error' => "Ein Benutzer mit dem Namen ':login' wurde nicht gefunden", + 'reset_success' => "Ihr Passwort wurde erfolgreich zurückgesetzt. Sie können sich jetzt anmelden.", + 'reset_error' => "Konnte Passwort nicht zurücksetzen. Bitte erneut versuchen!", + 'reset_fail' => "Passwort-Zurücksetzung nicht möglich!", + 'apply' => 'Anwenden', + 'cancel' => 'Abbrechen', + 'delete' => 'Löschen', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => 'Dashboard', + 'widget_label' => 'Widget', + 'widget_width' => 'Breite', + 'full_width' => 'ganze Breite', + 'manage_widgets' => 'Widgets verwalten', + 'add_widget' => 'Neues Widget', + 'widget_inspector_title' => 'Widget Konfiguration', + 'widget_inspector_description' => 'Dieses Widget konfigurieren', + 'widget_columns_label' => 'Breite :columns', + 'widget_columns_description' => 'Die Breite de Widgets, eine Zahl zwischen 1 und 10.', + 'widget_columns_error' => 'Bitte geben sie als Breite des Widgets eine Zahl zwischen 1 und 10 ein.', + 'columns' => '{1} Spalte|[2,Inf] Spalten', + 'widget_new_row_label' => 'Neue Reihe erzwingen', + 'widget_new_row_description' => 'Setzt das Widget in eine neue Reihe', + 'widget_title_label' => 'Titel des Widgets', + 'widget_title_error' => 'Ein Titel des Widgets wird benötigt.', + 'reset_layout' => 'Layout zurücksetzen', + 'reset_layout_confirm' => 'Layout auf Ursprungszustand zurücksetzen', + 'reset_layout_success' => 'Layout wurde zurückgesetzt', + 'make_default' => 'Setze Standard', + 'make_default_confirm' => 'Das aktuelle Layout and Standard setzen', + 'make_default_success' => 'Das aktuelle Layout ist nun das Standardlayout', + 'collapse_all' => 'Alles zusammenklappen', + 'expand_all' => 'Alles ausklappen', + 'status' => [ + 'widget_title_default' => 'System Status', + 'update_available' => '{0} Updates verfügbar!|{1} Update verfügbar!|[2,Inf] Updates verfügbar!', + 'updates_pending' => 'Software ', + 'updates_nil' => 'Software ist auf dem neuesten Stand', + 'updates_link' => 'Update', + 'warnings_pending' => 'Es sind Probleme aufgetreten', + 'warnings_nil' => 'Keine Probleme', + 'warnings_link' => 'Untersuchen', + 'core_build' => 'System Build', + 'event_log' => 'Event Log', + 'request_log' => 'Request Log', + 'app_birthday' => 'Online seit', + ], + 'welcome' => [ + 'widget_title_default' => 'Willkommen', + 'welcome_back_name' => 'Willkommen zurück zu :app, :name.', + 'welcome_to_name' => 'Willkommen zu :app, :name.', + 'first_sign_in' => 'Das ist das erste mal, dass Sie sich eingeloggt haben.', + 'last_sign_in' => 'Ihr letzter Login war', + 'view_access_logs' => 'Zugriffsprotokoll betrachten', + 'nice_message' => 'Wir wünschen einen schönen Tag!', + ] + ], + 'user' => [ + 'name' => 'Administrator', + 'menu_label' => 'Administratoren', + 'menu_description' => 'Backend-Benutzer, Administratoren, Gruppen und Zugriffsrechte verwalten.', + 'list_title' => 'Administratoren verwalten', + 'new' => 'Neuer Administrator', + 'login' => 'Benutzername', + 'first_name' => 'Vorname', + 'last_name' => 'Nachname', + 'full_name' => 'Kompletter Name', + 'email' => 'E-Mail', + 'role_field' => 'Rolle', + 'role_comment' => 'Rollen definieren Benutzerberechtigungen, die auf Benutzerebene auf der Registerkarte Berechtigungen überschrieben werden können.', + 'groups' => 'Gruppen', + 'groups_comment' => 'Geben Sie hier die Gruppenzugehörigkeit an', + 'avatar' => 'Avatar', + 'password' => 'Passwort', + 'password_confirmation' => 'Passwort bestätigen', + 'permissions' => 'Rechte', + 'account' => 'Account', + 'superuser' => 'Super-User', + 'superuser_comment' => 'Bestätigen Sie hier, um dem Nutzer Vollzugriff zu geben', + 'send_invite' => 'Einladung per E-Mail versenden', + 'send_invite_comment' => 'Hier bestätigen, dass eine Einladung per E-Mail erfolgt', + 'delete_confirm' => 'Möchten Sie diesen Administrator-Account wirklich löschen?', + 'return' => 'Zurück zur Administratoren Übersicht', + 'allow' => 'Zulassen', + 'inherit' => 'Vererben', + 'deny' => 'Verbieten', + 'activated' => 'Aktiviert', + 'last_login' => 'Letzer login', + 'created_at' => 'Erstellt am', + 'updated_at' => 'Aktualisiert am', + 'group' => [ + 'name' => 'Gruppe', + 'name_comment' => 'Der Name, der angezeigt wird wenn name is displayed in the group list on the Create/Edit Administrator form.', + 'name_field' => 'Name', + 'description_field' => 'Beschreibung', + 'is_new_user_default_field_label' => 'Standard Gruppe', + 'is_new_user_default_field_comment' => 'Fügt neue Administratoren zu dieser Gruppe standardmäßig hinzu.', + 'code_field' => 'Code', + 'code_comment' => 'Eindeutigen Code hinzufügen, wenn dies über die API bearbeitet werden soll.', + 'menu_label' => 'Gruppen', + 'list_title' => 'Gruppen verwalten', + 'new' => 'Neue Administratoren Gruppe', + 'delete_confirm' => 'Möchten Sie diesen Administratoren-Gruppe wirklich löschen?', + 'return' => 'Zurück zur Gruppen-Übersicht', + 'users_count' => 'Benutzer', + ], + 'role' => [ + 'name' => 'Rolle', + 'name_field' => 'Name', + 'name_comment' => 'Der Name wird in der Rollenliste auf dem Administratorformular angezeigt.', + 'description_field' => 'Beschreibung', + 'code_field' => 'Code', + 'code_comment' => 'Geben Sie einen eindeutigen Code an, wenn Sie mit der API auf das Rollenobjekt zugreifen möchten.', + 'menu_label' => 'Rollen verwalten', + 'list_title' => 'Rollen verwalten', + 'new' => 'Neue Rolle', + 'delete_confirm' => 'Diese Administratorrolle löschen?', + 'return' => 'Zurück zur Rollenliste', + 'users_count' => 'Benutzer', + ], + 'preferences' => [ + 'not_authenticated' => 'Zum Speichern oder Anzeigen dieser Einstellungen liegt kein Nutzerkonto vor' + ], + 'trashed_hint_title' => 'Dieses Konto wurde gelöscht.', + 'trashed_hint_desc' => 'Dieses Konto wurde gelöscht und kann nicht mehr angemeldet werden. Um es wiederherzustellen, klicken Sie auf das Symbol "Benutzer wiederherstellen" unten rechts', + ], + 'list' => [ + 'default_title' => 'Auflisten', + 'search_prompt' => 'Suchen...', + 'no_records' => 'Keine Ergebnisse für diese Ansicht gefunden', + 'missing_model' => 'In :class benutztes Lisstenverhalten hat kein Model definiert.', + 'missing_column' => 'Keine Spaltendefinition für :columns.', + 'missing_columns' => 'In :class benutzte Liste behinhaltet keine Spalten', + 'missing_definition' => "Der Liste fehlt eine Spalte für ':field'.", + 'missing_parent_definition' => "Listenverhalten beinhaltet keine Definition von ':definition'.", + 'behavior_not_ready' => 'Listenverhalten kann nicht initialisiert werden, überprüfen Sie den Aufruf von makeLists() in Ihrem Controller.', + 'invalid_column_datetime' => "Spaltenwert ':column' ist kein gültiges DateTime Objekt, haben Sie eine \$dates Referenz in dem Model vergessen?", + 'pagination' => 'Angezeigte Aufzeichnungen: :from-:to von :total', + 'first_page' => 'Erste Seite', + 'last_page' => 'Letzte Seite', + 'prev_page' => 'Vorherige Seite', + 'next_page' => 'Nächste Seite', + 'refresh' => 'Erneuern', + 'updating' => 'Aktualisiere...', + 'loading' => 'Laden...', + 'setup_title' => 'Listen Setup', + 'setup_help' => 'Benutzen Sie Checkboxen, um Spalten auszuwählen, welche Sie in den Listen sehen möchten. Sie können die Position der Spalten ändern, indem Sie diese hinauf oder hinunter ziehen.', + 'records_per_page' => 'Aufzeichnungen pro Seite', + 'records_per_page_help' => 'Wählen Sie, wieviele Aufzeichnungen pro Seite dargestellt werden sollen. Bitte beachten Sie, dass eine hohe Anzahl pro Seite die Performance negativ beeinflussen kann.', + 'check' => 'Gesetzt', + 'delete_selected' => 'Markierte löschen', + 'delete_selected_empty' => 'Keine Einträge zum Löschen markiert.', + 'delete_selected_confirm' => 'Markierte Einträge löschen?', + 'delete_selected_success' => 'Markierte Einträge erfolgreich gelöscht.', + 'column_switch_true' => 'Ja', + 'column_switch_false' => 'Nein' + ], + 'fileupload' => [ + 'attachment' => 'Anhang', + 'help' => 'Fügen Sie dem Anhang einen Titel und eine Beschreibung hinzu.', + 'title_label' => 'Titel', + 'description_label' => 'Beschreibung', + 'default_prompt' => 'Auf %s klicken oder eine Datei hierhin ziehen, um sie hochzuladen', + 'attachment_url' => 'Originaldatei-URL', + 'upload_file' => 'Datei hochladen', + 'upload_error' => 'Fehler beim hochladen', + 'remove_confirm' => 'Sind Sie sicher?', + 'remove_file' => 'Datei entfernen', + ], + 'repeater' => [ + 'add_new_item' => 'Neues Element hinzufügen', + 'min_items_failed' => ':name erfordert ein Minimum an :min Elementen, aber es wurden nur :items bereitgestellt', + 'max_items_failed' => ':name lässt nur bis zu :max Elemente zu, :items wurden bereitgestellt', + ], + 'form' => [ + 'create_title' => "Neuer :name", + 'update_title' => "Bearbeite :name", + 'preview_title' => "Vorschau für :name", + 'create_success' => ':name wurde erfolgreich erzeugt', + 'update_success' => ':name wurde erfolgreich aktualisiert', + 'delete_success' => ':name wurde erfolgreich gelöscht', + 'reset_success' => 'Zurücksetzung abgeschlossen', + 'missing_id' => "Formulardatensatz-ID (Form record ID) fehlt.", + 'missing_model' => 'In :class genutztes Formularverhalten (behaviour) hat kein definiertes Model', + 'missing_definition' => "Formverhalten fehlt ein Feld für ':field'.", + 'not_found' => 'Formulareintrag mit der ID :id kann nicht gefunden werden.', + 'action_confirm' => 'Sind Sie sich sicher?', + 'create' => 'Erstellen', + 'create_and_close' => 'Erstellen und schließen', + 'creating' => 'Erstellen...', + 'creating_name' => 'Erstelle :name...', + 'save' => 'Speichern', + 'save_and_close' => 'Speichern und schließen', + 'saving' => 'Wird gespeichert...', + 'saving_name' => ':name wird gespeichert...', + 'delete' => 'Löschen', + 'deleting' => 'Löschen...', + 'confirm_delete' => 'Wollen Sie diesen Eintrag wirklich löschen?', + 'confirm_delete_multiple' => 'Wollen Sie diese Einträge wirklich löschen?', + 'deleting_name' => 'Deleting :name...', + 'reset_default' => 'Zurücksetzen', + 'resetting' => 'Setze zurück...', + 'resetting_name' => 'Setze :name zurück...', + 'undefined_tab' => 'Verschiedenes', + 'field_off' => 'Aus', + 'field_on' => 'An', + 'add' => 'Hinzufügen', + 'apply' => 'Anwenden', + 'cancel' => 'Abbrechen', + 'close' => 'Schließen', + 'confirm' => 'Bestätigen', + 'reload' => 'Erneut laden', + 'complete' => 'Abgeschlossen', + 'ok' => 'OK', + 'or' => 'oder', + 'confirm_tab_close' => 'Wollen Sie den Tab wirklich schließen? Ungespeicherte Änderungen gehen verloren.', + 'behavior_not_ready' => 'Formularverhalten kann nicht initialisiert werden, überprüfen Sie den Aufruf von makeLists() in Ihrem Controller.', + 'preview_no_files_message' => 'Es wurden keine Dateien hochgeladen', + 'preview_no_media_message' => 'Es wurde keine Media-Datei ausgewählt.', + 'preview_no_record_message' => 'Es ist kein Eintrag ausgewählt.', + 'select' => 'Auswählen', + 'select_all' => 'Wählen Sie Alle', + 'select_none' => 'nichts ausgewählt', + 'select_placeholder' => 'Bitte auswählen', + 'insert_row' => 'Reihe einfügen', + 'insert_row_below' => 'Neue Reihe darunter einfügen', + 'delete_row' => 'Reihe löschen', + 'concurrency_file_changed_title' => 'Datei wurde geändert', + 'concurrency_file_changed_description' => 'Die Datei, welche Sie bearbeiten, wurde auf von einem anderen Benutzer geändert. Sie können die Datei entweder erneut laden, wodurch Ihre Änderungen verloren gehen oder Sie überschreiben die Datei auf dem Server', + 'return_to_list' => 'Zurück zur Liste' + ], + 'recordfinder' => [ + 'find_record' => 'Finde Eintrag', + 'cancel' => 'Abbrechen', + ], + 'pagelist' => [ + 'page_link' => 'Seitenlink', + 'select_page' => 'Wähle eine Seite...' + ], + 'relation' => [ + 'missing_config' => "Verhalten (behaviour) der Verbindung hat keine Konfiguration für ':config'.", + 'missing_definition' => "Verhalten (behaviour) der Verbindung umfasst keine Definition für ':field'.", + 'missing_model' => "Verhalten (behaviour) der Verbindung, die in :class benutzt wird, hat kein definiertes Model", + 'invalid_action_single' => "Dieser Vorgang kann nicht auf eine Einwege-Verbindung (singular) angewendet werden.", + 'invalid_action_multi' => "Dieser Vorgang kann nicht auf eine Mehrwege-Verbindung (multiple) angewendet werden.", + 'help' => "Zum Hinzufügen auf ein Item klicken", + 'related_data' => "Verwandte :name Daten", + 'add' => "Hinzufügen", + 'add_selected' => 'Auswahl hinzufügen', + 'add_a_new' => ':name hinzufügen', + 'link_selected' => 'Auswahl verlinken', + 'link_a_new' => ':name verlinken', + 'cancel' => 'Abbrechen', + 'close' => 'Schließen', + 'add_name' => ":name hinzufügen", + 'create' => "Erstellen", + 'create_name' => "Erstelle :name", + 'update' => "Update", + 'update_name' => "Update :name", + 'preview' => 'Vorschaue', + 'preview_name' => 'Vorschau :name', + 'remove' => "Entfernen", + 'remove_name' => ":name entfernen", + 'delete' => "Löschen", + 'delete_name' => ":name löschen", + 'delete_confirm' => "Sind Sie sicher?", + 'link' => 'Link', + 'link_name' => 'Link :name', + 'unlink' => 'Link entfernen', + 'unlink_name' => 'Link von :name entfernen', + 'unlink_confirm' => 'Sind Sie sicher?' + ], + 'reorder' => [ + 'default_title' => 'Einträge sortieren', + 'no_records' => 'Es gibt keine Einträge zum sortieren.' + ], + 'model' => [ + 'name' => "Model", + 'not_found' => "Model ':class' mit ID :id konnte nicht gefunden werden", + 'missing_id' => "Für diesen Model-Datensatz ist keine ID angegeben", + 'missing_relation' => "Model ':class' hat keine definierte Verbindung ':relation'.", + 'missing_method' => "Model ':class' besitzt keine Methode ':method'.", + 'invalid_class' => "In :class benutztes Model :model ist ungültig, da es von der Klasse \Model abgeleitet sein muss (inherit).", + 'mass_assignment_failed' => "Mass assignment failed for Model attribute ':attribute'.", + ], + 'warnings' => [ + 'tips' => 'System Konfigurations Tips', + 'tips_description' => 'Es gibt Probleme, welche Sie beachten müssen, um das System korrekt zu konfigurieren.', + 'permissions' => 'Verzeichnis :name oder ein Unterverzeichnis kann nicht von PHP beschrieben werden. Bitte setzen Sie die korrekten Rechte für den Webserver in diesem Verzeichnis.', + 'extension' => 'Die PHP Erweiterung :name ist nicht installiert. Bitte installieren Sie diese Library und aktivieren Sie die Erweiterung.', + 'plugin_missing' => 'Das Plugin :name hat eine Abhängigkeit die nicht installiert ist. Bitte installieren Sie alle benötigten Plugins.', + 'debug' => 'Der Debug-Modus ist aktiviert. Dies wird für Produktionsinstallationen nicht empfohlen.', + 'decompileBackendAssets' => 'Assets im Backend sind derzeit dekompiliert. Dies wird für Produktionsinstallationen nicht empfohlen.', + ], + 'editor' => [ + 'menu_label' => 'Editor Einstellungen', + 'menu_description' => 'Verwalten der Code-Editor Einstellungen.', + 'font_size' => 'Schriftgrösse', + 'tab_size' => 'Tabgrösse', + 'use_hard_tabs' => 'Gedankenstrich bei Tabs', + 'code_folding' => 'Code-Folding', + 'code_folding_begin' => 'Markierungsbeginn', + 'code_folding_begin_end' => 'Markierungsbeginn und Ende', + 'autocompletion' => 'Autovervollständigung', + 'word_wrap' => 'Word Wrap', + 'highlight_active_line' => 'Aktive Zeile hervorheben', + 'auto_closing' => 'Automatisch Tags schließen', + 'show_invisibles' => 'Unsichtbare Zeichen anzeigen', + 'show_gutter' => 'Gutter anzeigen', + 'live_autocompletion'=> 'Live Autovervollständigung', + 'enable_snippets'=> 'Aktiviere Code-snippets (Tab)', + 'display_indent_guides'=> 'Zeige Einrückungshilfen', + 'show_print_margin'=> 'Zeige Druckabstand', + 'mode_off' => 'Aus', + 'mode_fluid' => 'Fluid', + '40_characters' => '40 Zeichen', + '80_characters' => '80 Zeichen', + 'theme' => 'Farbschema', + 'markup_styles' => 'Markup Styles', + 'custom_styles' => 'Custom stylesheet', + 'custom styles_comment' => 'Custom styles im HTML editor einbinden.', + 'markup_classes' => 'Markup Classes', + 'paragraph' => 'Paragraph', + 'link' => 'Link', + 'table' => 'Tabelle', + 'table_cell' => 'Tabellenzelle', + 'image' => 'Bild', + 'label' => 'Beschriftung', + 'class_name' => 'Class name', + 'markup_tags' => 'Markup Tags', + 'allowed_empty_tags' => 'Erlaube leere Tags', + 'allowed_empty_tags_comment' => 'Die Liste von Tags welche nicht entfernt werden wenn sie keinen Inhalt haben (leer sind).', + 'allowed_tags' => 'Erlaubte tags', + 'allowed_tags_comment' => 'Die Liste von erlaubten Tags.', + 'no_wrap' => 'Tags nicht wrappen', + 'no_wrap_comment' => 'Die Liste von Tags welche nicht in Block-Tags gepackt werden sollen.', + 'remove_tags' => 'Entferne Tags', + 'remove_tags_comment' => 'Die Liste an Tags welche nicht zusammen entfernt werden mit ihrem Inhalt.', + 'line_breaker_tags' => 'Zeilenumbruch Tags', + 'line_breaker_tags_comment' => 'Die Liste von Tags, zwischen die ein Zeilenumbruch-Element eingefügt wird.', + 'toolbar_buttons' => 'Toolbar-Buttons', + 'toolbar_buttons_comment' => 'Die Toolbar-Buttons, die im Rich Editor standardmässig angezeigt werden sollen.', + 'toolbar_buttons_preset' => 'Standard-Vorlage für Toolbars übernehmen:', + 'toolbar_buttons_presets' => [ + 'default' => 'Standard', + 'minimal' => 'Minimal', + 'full' => 'Vollständig', + ], + 'paragraph_formats' => 'Absatzformatierungen', + 'paragraph_formats_comment' => 'Die Optionen, welche in der Dropdown-Liste für Absatzformatierungen angezeigt werden.', + ], + 'tooltips' => [ + 'preview_website' => 'Vorschau der Webseite' + ], + 'mysettings' => [ + 'menu_label' => 'Meine Einstellungen', + 'menu_description' => 'Einstellungen beziehen sich auf Ihren Administratoren Account', + ], + 'myaccount' => [ + 'menu_label' => 'Mein Account', + 'menu_description' => 'Updaten Sie Ihre Account-Details wie z.B. den Namen, die E-Mail-Adresse und das Passwort.', + 'menu_keywords' => 'Sicheres Anmelden' + ], + 'branding' => [ + 'menu_label' => 'Backend anpassen', + 'menu_description' => 'Passe den Admin-Bereich an - z.B. Name, Farben und Logo.', + 'brand' => 'Brand', + 'logo' => 'Logo', + 'logo_description' => 'Lade ein eigenes Logo hoch, das im Backend verwendet werden soll.', + 'favicon' => 'Favicon', + 'favicon_description' => 'Laden Sie ein benutzerdefiniertes Favicon zur Verwendung im Back-End hoch', + 'app_name' => 'App-Name', + 'app_name_description' => 'Dieser Name wird als Titel des Backends angezeigt.', + 'app_tagline' => 'App-Tagline', + 'app_tagline_description' => 'Die Tagline wird im Log-In-Bereich des Backends angezeigt.', + 'colors' => 'Farben', + 'primary_color' => 'Primärfarbe', + 'secondary_color' => 'Zweitfarbe', + 'accent_color' => 'Akzentfarbe', + 'styles' => 'Styles', + 'custom_stylesheet' => 'Benutzerdefiniertes Stylesheet', + 'navigation' => 'Navigation', + 'menu_mode' => 'Menustyles', + 'menu_mode_inline' => 'Inline', + 'menu_mode_inline_no_icons' => 'Inline (ohne Icons)', + 'menu_mode_tile' => 'Tiles', + 'menu_mode_collapsed' => 'Collapsed' + ], + 'backend_preferences' => [ + 'menu_label' => 'Backend Einstellungen', + 'menu_description' => 'Verwalten der Spracheinstellungen und der Backenddarstellung.', + 'region' => 'Region', + 'code_editor' => 'Code editor', + 'timezone' => 'Zeitzone', + 'timezone_comment' => 'Passt die angzeigten Daten an diese Zeitzone an.', + 'locale' => 'Sprache', + 'locale_comment' => 'Wählen Sie Ihre gewünschte Sprache für das Backend.', + ], + 'access_log' => [ + 'hint' => 'Dieser Log zeigt eine Liste mit erfolgreichen Anmelde-Versuchen von Administratoren. Die Aufzeichnungen bleiben erhalten für :days Tage.', + 'menu_label' => 'Zugriffslog', + 'menu_description' => 'Sehen Sie sich eine Liste mit erfolgreichen Backend Benutzeranmeldungen an.', + 'created_at' => 'Datum & Uhrzeit', + 'login' => 'Anmeldung', + 'ip_address' => 'IP Adresse', + 'first_name' => 'Vorname', + 'last_name' => 'Nachname', + 'email' => 'E-Mail', + ], + 'filter' => [ + 'all' => 'Alle', + 'options_method_not_exists' => "Die Modelklasse :model muss eine methode :method() definiert haben und returning options for the ':filter' filter.", + 'date_all' => 'Ganzen Zeitraum' + ], + 'import_export' => [ + 'upload_csv_file' => '1. CSV-Datei hochladen', + 'import_file' => 'Datei importieren', + 'row' => 'Zeile :row', + 'first_row_contains_titles' => 'Erste Zeile enthält Spaltentitel', + 'first_row_contains_titles_desc' => 'Aktiviert lassen, falls erste Zeile Spaltentitel enthält.', + 'match_columns' => '2. Spalten der Datei den Datenbankfeldern zuordnen', + 'file_columns' => 'Spalten der Datei', + 'database_fields' => 'Datenbankfelder', + 'set_import_options' => '3. Importoptionen festlegen', + 'export_output_format' => '1. Exportformat wählen', + 'file_format' => 'Dateiformat', + 'standard_format' => 'Standardformat', + 'custom_format' => 'Benutzerdefiniertes Format', + 'delimiter_char' => 'Trennzeichen', + 'enclosure_char' => 'Textqualifizierer', + 'escape_char' => 'Escape-Zeichen', + 'select_columns' => '2. Spalten für den Export auswählen', + 'column' => 'Spalte', + 'columns' => 'Spalten', + 'set_export_options' => '3. Exportoptionen festlegen', + 'show_ignored_columns' => 'Ignorierte Spalten anzeigen', + 'auto_match_columns' => 'Spalten automatisch zuordnen', + 'created' => 'Erstellt', + 'updated' => 'Geändert', + 'skipped' => 'Übersprungen', + 'warnings' => 'Warnungen', + 'errors' => 'Fehler', + 'skipped_rows' => 'Übersprungene Zeilen', + 'import_progress' => 'Import-Fortschritt', + 'processing' => 'Verarbeite', + 'import_error' => 'Import-Fehler', + 'upload_valid_csv' => 'Bitte eine gültige CSV-Datei hochladen.', + 'drop_column_here' => 'Spalte hier ablegen...', + 'ignore_this_column' => 'Diese Spalte ignorieren', + 'processing_successful_line1' => 'Datei-Exportvorgang erfolgreich abgeschlossen!', + 'processing_successful_line2' => 'Ihr Browser sollte Sie nun automatisch zum Download weiterleiten.', + 'export_progress' => 'Export-Fortschritt', + 'export_error' => 'Export-Fehler', + 'column_preview' => 'Spaltenvorschau', + 'file_not_found_error' => 'Datei nicht gefunden', + 'empty_error' => 'Es wurden keine Daten geliefert die exportiert werden können.', + 'empty_import_columns_error' => 'Bitte geben Sie einige Reihen zum importieren an.', + 'match_some_column_error' => 'Bitte Verbinden Sie erst ein paar Reihen.', + 'required_match_column_error' => 'Bitte stellen Sie eine Verbindung zwischen den benötigten Feldern :label her.', + 'empty_export_columns_error' => 'Bitte geben Sie einige Reihen zum exportieren an.', + 'behavior_missing_uselist_error' => 'Sie müssen das Controller-Verhalten "ListController" implementieren und "useList" Option aktivieren.', + 'missing_model_class_error' => 'Bitte geben Sie die spezifische "modelClass" Eigenschaft für :type an.', + 'missing_column_id_error' => 'Fehleneder Reihen Identifier', + 'unknown_column_error' => 'Unbekannte Reihe', + 'encoding_not_supported_error' => 'Qulldatei Encoding wurde nicht bekannt oder ist nicht bekannt. Bitte wählen Sie ein Dateiformat mit ein entsprechendes Encoding um es zu importieren.', + 'encoding_format' => 'Datei encoding', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Medien verwalten', + 'allow_unsafe_markdown' => 'Unsicheres Markdown verwenden (kann Javascript enthalten)', + ], + 'mediafinder' => [ + 'label' => 'Media Finder', + 'default_prompt' => 'Klicke auf %s um eine Mediendatei auszuwählen' + ], + 'media' => [ + 'menu_label' => 'Medien', + 'upload' => 'Hochladen', + 'move' => 'Verschieben', + 'delete' => 'Löschen', + 'add_folder' => 'Ordner erstellen', + 'search' => 'Suchen', + 'display' => 'Anzeigen', + 'filter_everything' => 'Alles', + 'filter_images' => 'Bilder', + 'filter_video' => 'Video', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Dokumente', + 'library' => 'Sammlung', + 'size' => 'Größe', + 'title' => 'Titel', + 'last_modified' => 'Zuletzt bearbeitet', + 'public_url' => 'Öffentliche URL', + 'click_here' => 'Hier drücken', + 'thumbnail_error' => 'Fehler beim Erstellen des Thumbnails.', + 'return_to_parent' => 'Zu oberem Ordner zurückkehren', + 'return_to_parent_label' => 'Stufe hoch ..', + 'nothing_selected' => 'Nichts ausgewählt.', + 'multiple_selected' => 'Mehrere Dateien ausgewählt.', + 'uploading_file_num' => 'Lade :number Datei(en)...', + 'uploading_complete' => 'Upload vollständig', + 'uploading_error' => 'Upload fehlgeschlagen', + 'type_blocked' => 'Der verwendete Dateityp ist aus Sicherheitsgründen gesperrt.', + 'order_by' => 'Sortieren nach', + 'direction' => 'Direction', + 'direction_asc' => 'Aufsteigend', + 'direction_desc' => 'Absteigend', + 'folder' => 'Ordner', + 'no_files_found' => 'Keine entsprechenden Dateien gefunden.', + 'delete_empty' => 'Bitte Wählen Sie Dateien zum Löschen aus.', + 'delete_confirm' => 'Wollen Sie wirklich die gewählte(n) Datei(en) löschen?', + 'error_renaming_file' => 'Fehler beim Umbenennen.', + 'new_folder_title' => 'Neuer Ordner', + 'folder_name' => 'Ordnername', + 'error_creating_folder' => 'Fehler beim Erstellen des Ordners', + 'folder_or_file_exist' => 'Ein Ordner oder eine Datei mit dem gewählten Namen existiert bereits.', + 'move_empty' => 'Bitte wählen Sie Dateien zum Verschieben aus', + 'move_popup_title' => 'Verschiebe Dateien oder Ordner', + 'move_destination' => 'Zielordner', + 'please_select_move_dest' => 'Bitte wählen Sie einen Zielordner.', + 'move_dest_src_match' => 'Bitte wählen Sie einen anderen Zielordner.', + 'empty_library' => 'Diese Medienbibliothek ist leer. Laden Sie Dateien hoch oder erstellen Sie Ordner!', + 'insert' => 'Einfügen', + 'crop_and_insert' => 'Zuschneiden und Einfügen', + 'select_single_image' => 'Bitte wählen Sie ein einzelnes Bild.', + 'selection_not_image' => 'Die gewählte Datei ist kein Bild.', + 'restore' => 'Alle Änderungen rückgängig machen', + 'resize' => 'Größe anpassen...', + 'selection_mode_normal' => 'Normal', + 'selection_mode_fixed_ratio' => 'Festes Verhältnis', + 'selection_mode_fixed_size' => 'Feste Größe', + 'height' => 'Höhe', + 'width' => 'Breite', + 'selection_mode' => 'Auswahlmodus', + 'resize_image' => 'Bildgröße anpassen', + 'image_size' => 'Dimensionen:', + 'selected_size' => 'Ausgewählt:' + ] +]; diff --git a/modules/backend/lang/el/lang.php b/modules/backend/lang/el/lang.php new file mode 100644 index 0000000..71163c2 --- /dev/null +++ b/modules/backend/lang/el/lang.php @@ -0,0 +1,551 @@ + [ + 'title' => 'Περιοχή Διαχείρισης', + ], + 'field' => [ + 'invalid_type' => 'Χρησιμοποιήθηκε μη έγκυρος τύπος πεδίου :type.', + 'options_method_not_exists' => "H κλάση του μοντέλου πρέπει να καθορίζει μια μέθοδο :method() επιστροφής επίλογων για το πεδίο ':field'", + ], + 'widget' => [ + 'not_registered' => "Δεν έχει καθοριστεί το όνομα ':name' της κλάσης του Widget", + 'not_bound' => "Το Widget με το όνομα της κλάσης ':name' δεν έχει βρεθεί στον χειριστή.", + ], + 'page' => [ + 'untitled' => 'Χωρίς Τίτλο', + 'access_denied' => [ + 'label' => 'Απαγορεύεται η πρόσβαση', + 'help' => "Δεν έχεις τα απαραίτητα δικαιώματα για να δεις αυτήν την σελίδα.", + 'cms_link' => 'Επιστροφή στό back-end.', + ], + 'no_database' => [ + 'label' => 'Δεν βρέθηκε η βάση δεδομένων', + 'help' => "Η βάση δεδομένων είναι απαραίτητη για να έχετε πρόσβαση στο back-end. Ελέγξτε εάν η βάση δεδομένων είναι ρυθμισμένη και συνδεδεμένη πριν προσπαθήσετε ξανά.", + 'cms_link' => 'Επιστροφή στην αρχική', + ], + ], + 'partial' => [ + 'not_found_name' => "Το μερικό ':name' δεν βρέθηκε.", + ], + 'account' => [ + 'sign_out' => 'Αποσύνδεση', + 'login' => 'Σύνδεση', + 'reset' => 'Επαναφορά', + 'restore' => 'Αποκατάσταση', + 'login_placeholder' => 'σύνδεση', + 'password_placeholder' => 'κωδικός', + 'forgot_password' => 'Ξεχάσατε τον κωδικό σας;', + 'enter_email' => 'Συμπληρώστε το email σας', + 'enter_login' => 'Συμπληρώστε τον λογαριασμό σας', + 'email_placeholder' => 'email', + 'enter_new_password' => 'Πληκτρολογήστε νέο κωδικό.', + 'password_reset' => 'Επαναφορά Κωδικού', + 'restore_success' => 'Ένα μήνυμα έχει σταλεί στην διεύθυνση ηλεκτρονικού ταχυδρομείου σου με οδηγίες.', + 'restore_error' => "Δεν βρέθηκε χρήστης με τα στοιχεία ':login'", + 'reset_success' => 'Ο κωδικός σας έχει επαναφερθεί. Μπορείτε τώρα να συνδεθείτε.', + 'reset_error' => 'Τα στοιχεία που έχουν δοθεί για την επαναφορά του κωδικού είναι μη έγκυρα. Παρακαλούμε δοκιμάστε ξανά!', + 'reset_fail' => 'Δεν κατέστη δυνατό να επαναφερθεί ο κωδικός σας!', + 'apply' => 'Εφαρμογή', + 'cancel' => 'Άκυρο', + 'delete' => 'Διαγραφή', + 'ok' => 'Εντάξει', + ], + 'dashboard' => [ + 'menu_label' => 'Κέντρο Ελένχου', + 'widget_label' => 'Widget', + 'widget_width' => 'Πλάτος', + 'full_width' => 'πλήρες πλάτος', + 'manage_widgets' => 'Διαχείριση Widgets', + 'add_widget' => 'Προσθήκη Widget', + 'widget_inspector_title' => 'Ρύθμιση Widget', + 'widget_inspector_description' => 'Ρύθμιση του widget αναφορών', + 'widget_columns_label' => 'Πλάτος :columns', + 'widget_columns_description' => 'Το πλάτος του widget, ένας αριθμός μεταξύ του 1 και του 10.', + 'widget_columns_error' => 'Παρακαλούμε εισάγετε το πλάτος του widget σαν ένα αριθμό μεταξύ του 1 και του 10.', + 'columns' => '{1} στηλη|[2,Inf] στήλες', + 'widget_new_row_label' => 'Έναρξη νέας σειράς', + 'widget_new_row_description' => 'Τοποθετείστε το widget σε νέα σειρά.', + 'widget_title_label' => 'Τίτλος Widget', + 'widget_title_error' => 'O τίτλος του Widget είναι απαραίτητος.', + 'reset_layout' => 'Επαναφορά διάταξης', + 'reset_layout_confirm' => 'Επαναφορά της διάταξης στο προκαθορισμένο;', + 'reset_layout_success' => 'Η διάταξη επαναφέρθηκε', + 'make_default' => 'Ορισμός προκαθορισμένης', + 'make_default_confirm' => 'Να οριστεί η τρέχουσα διάταξη ως προκαθορισμένη;', + 'make_default_success' => 'Η τρέχουσα διάταξη είναι τώρα η προκαθορισμένη.', + 'status' => [ + 'widget_title_default' => 'Κατάσταση συστήματος', + 'update_available' => '{0} διαθέσιμες ενημερώσεις!|{1} διαθέσιμη ενημέρωση!|[2,Inf] διαθέσιμες ενημερώσεις!', + 'updates_pending' => 'Εκκρεμούν ενημερώσεις λογισμικού', + 'updates_nil' => 'Το λογισμικό είναι ενημερωμένο', + 'updates_link' => 'Ενημέρωση', + 'warnings_pending' => 'Κάποια ζητήματα θέλουν προσοχή', + 'warnings_nil' => 'Δεν υπάρχουν προειδοποιήσεις', + 'warnings_link' => 'Εμφάνιση', + 'core_build' => 'Έκδοση συστήματος', + 'event_log' => 'Καταγραφή συμβάντων', + 'request_log' => 'Καταγραφή αιτήσεων', + 'app_birthday' => 'Σε λειτουργία από', + ], + 'welcome' => [ + 'widget_title_default' => 'Καλώς ορίσατε', + 'welcome_back_name' => 'Καλώς ορίσατε ξανά στο :app, :name.', + 'welcome_to_name' => 'Καλώς ορίσατε στο :app, :name.', + 'first_sign_in' => 'Αυτή είναι η πρώτη φορά που συνδεεστε.', + 'last_sign_in' => 'Η τελευταία σύνδεση σας ήταν', + 'view_access_logs' => 'Προβολή του αρχείου καταγραφής προσβάσεων', + 'nice_message' => 'Να έχετε μια υπέροχη ημέρα!', + ] + ], + 'user' => [ + 'name' => 'Διαχειριστής', + 'menu_label' => 'Διαχειριστές', + 'menu_description' => 'Διευθέτηση των διαχειριστών, των ομάδων και των δικαιωμάτων του back-end', + 'list_title' => 'Διαχείριση Διαχειριστών', + 'new' => 'Νέος Διαχειριστής', + 'login' => 'Λογαριασμός', + 'first_name' => 'Όνομα', + 'last_name' => 'Επώνυμο', + 'full_name' => 'Ονοματεπώνυμο', + 'email' => 'e-Mail', + 'groups' => 'Ομάδες', + 'groups_comment' => 'Καθορίστε σε ποιες ομάδες ανήκει αυτός ο λογαριασμός. Οι ομαδες καθορισουν τα δικαώματα του χρηστη, τα οποια μπορουν να παρακαμφθουν στο επιπεδο του χρηστη, στην καρτελα Δικαιωματων.', + 'avatar' => 'Avatar', + 'password' => 'Κωδικός', + 'password_confirmation' => 'Επιβεβαίωση Κωδικού', + 'permissions' => 'Δικαιώματα', + 'account' => 'Λογαριασμός', + 'superuser' => 'Υπέρ-Χρήστης', + 'superuser_comment' => 'Εκχώρηση σε αυτόν τον λογαριασμό απεριόριστη πρόσβαση σε όλες τις περιοχές του συστήματος. Οι υπερ-χρήστες μπορούν να προσθέσουν και να διαχειριστούν άλλους χρήστες.', + 'send_invite' => 'Αποστολή πρόσκλησης μέσω email', + 'send_invite_comment' => 'Αποστέλλει ένα μήνυμα καλωσορίσματος το οποίο περιέχει τις πληροφορίες σύνδεσης και του κωδικού.', + 'delete_confirm' => 'Διαγράφη αυτού του διαχειριστή;', + 'return' => 'Επιστροφή στην λίστα των διαχειριστών', + 'allow' => 'Επέτρεψε', + 'inherit' => 'Κληρονόμησε', + 'deny' => 'Απαγόρευσε', + 'group' => [ + 'name' => 'Ομάδες', + 'name_comment' => 'Το όνομα εμφανίζεται στην λίστα των ομάδων κατά την Προσθήκη/Επεξεργασία της φόρμας των Διαχειριστών.', + 'name_field' => 'Όνομα', + 'description_field' => 'Περιγραφή', + 'is_new_user_default_field_label' => 'Προεπιλεγμένη ομάδα', + 'is_new_user_default_field_comment' => 'Προεπιλεγμένη προσθήκη νέων διαχειριστών σε αυτήν την ομάδα.', + 'code_field' => 'Κώδικας', + 'code_comment' => 'Συμπληρώστε ένα μοναδικό κωδικό αν θέλετε να έχετε πρόσβαση στο αντικείμενο της ομάδας μέσω του API.', + 'menu_label' => 'Διαχείρηση Ομάδων', + 'list_title' => 'Διαχείριση Ομάδων', + 'new' => 'Νέα Ομάδα', + 'delete_confirm' => 'Διαγραφή αυτής της ομάδας διαχειριστών;', + 'return' => 'Επιστροφή στην λίστα των ομάδων', + 'users_count' => 'Χρήστες', + ], + 'preferences' => [ + 'not_authenticated' => 'Δεν υπάρχει κανένας πιστοποιημένος χρήστης για να φορτωθούν ή να σωθούν οι ρυθμίσεις του.' , + ] + ], + 'list' => [ + 'default_title' => 'Λίστα', + 'search_prompt' => 'Αναζήτηση...', + 'no_records' => 'Δεν υπάρχουν εγγραφές σε αυτήν την προβολή.', + 'missing_model' => 'Η συμπεριφορά της λίστας χρησιμοποιήθηκε στην :class δεν έχει κάποιο καθορισμένο μοντέλο.', + 'missing_column' => 'Δεν υπάρχει ορισμός στηλών για τα :columns.', + 'missing_columns' => 'Η λίστα χρησιμοποιήθηκε στη :class δεν έχει ορισμένες στήλες λίστας.', + 'missing_definition' => "Η συμπεριφορά της λίστας δεν περιέχει μια στήλη για το ':field'.", + 'missing_parent_definition' => "Λίστα με τις συμπεριφορές οι οποίες δεν περιλαμβάνουν έναν ορισμό για ':definition'.", + 'behavior_not_ready' => 'Η συμπεριφορά της λίστας δεν έχει αρχικοποιηθεί, ελέγξτε ότι έχετε καλέσει την makeLists() στον χειριστή.', + 'invalid_column_datetime' => "Η τιμή της στήλης ':column' δεν είναι ένα αντικείμενο DateTime, μήπως διαφεύγει μια \$dates αναφορά στο μοντέλο?", + 'pagination' => 'Εμφάνιση εγγραφών: :from-:to απο :total', + 'prev_page' => 'Προηγούμενη σελίδα', + 'next_page' => 'Επόμενη σελίδα', + 'refresh' => 'Ανανέωση', + 'updating' => 'Αναβάθμιση...', + 'loading' => 'Φόρτωμα...', + 'setup_title' => 'Ρύθμιση λίστας', + 'setup_help' => 'Χρησιμοποιήστε το πλαίσιο ελέγχου για να επιλέξετε τις στήλες που θέλετε να δείτε στην λίστα. Μπορείτε να αλλάξετε την θέση των στηλών με το σύρσιμο πάνω και κάτω.', + 'records_per_page' => 'Εγγραφές ανά σελίδα', + 'records_per_page_help' => 'Επιλέξτε τον αριθμό των εγγραφών ανά σελίδα για εμφάνιση. Παρακαλούμε σημειώστε ότι ένας υψηλός αριθμός εγγραφών σε μια και μόνο σελίδα μπορεί να μειώσει την απόδοση.', + 'check' => 'Έλεγχος', + 'delete_selected' => 'Διαγραφή επιλεγμένου', + 'delete_selected_empty' => 'Δεν υπάρχουν επιλεγμένες εγγραφές για να διαγράψετε.', + 'delete_selected_confirm' => 'Να διαγραφούν οι επιλεγμένες εγγραφές;', + 'delete_selected_success' => 'Διαγραφή επιλεγμένων εγγραφών.', + 'column_switch_true' => 'Ναι', + 'column_switch_false' => 'Όχι' + ], + 'fileupload' => [ + 'attachment' => 'Επισύναψη', + 'help' => 'Προσθέστε τίτλο και περιγραφή για αυτήν την επισύναψη.', + 'title_label' => 'Τίτλος', + 'description_label' => 'Περιγραφή', + 'default_prompt' => 'Κάντε κλικ στο %s ή σύρετε ένα αρχείο εδώ για να το ανεβάσετε', + 'attachment_url' => 'URL Συνημμένου', + 'upload_file' => 'Ανέβασμα αρχείου', + 'upload_error' => 'Σφάλμα ανεβάσματος', + 'remove_confirm' => 'Είστε σίγουροι;', + 'remove_file' => 'Διαγραφή αρχείου', + ], + 'form' => [ + 'create_title' => 'Νέο :name', + 'update_title' => 'Επεξεργασία :name', + 'preview_title' => 'Προεπισκόπηση :name', + 'create_success' => ':name δημιουργήθηκε', + 'update_success' => ':name ενημερώθηκε', + 'delete_success' => ':name διαγράφηκε', + 'reset_success' => 'Η επαναφορά ολοκληρώθηκε', + 'missing_id' => 'Το ID της εγγραφής στην φόρμα δεν έχει οριστεί.', + 'missing_model' => 'Η συμπεριφορά της φόρμας που χρησιμοποιήθηκε στην :class δεν έχει καθορισμένο μοντέλο.', + 'missing_definition' => "Η συμπεριφορά της φόρμας δεν περιέχει ένα πεδίο για το ':field'.", + 'not_found' => 'Η εγγραφή της φόρμας με ID :id δεν βρέθηκε.', + 'action_confirm' => 'Είστε σίγουροι;', + 'create' => 'Δημιουργία', + 'create_and_close' => 'Δημιουργία και κλείσιμο', + 'creating' => 'Δημιουργία...', + 'creating_name' => 'Δημιουργία :name...', + 'save' => 'Αποθήκευση', + 'save_and_close' => 'Αποθήκευση και κλείσιμο', + 'saving' => 'Αποθήκευση...', + 'saving_name' => 'Αποθήκευση :name...', + 'delete' => 'Διαγραφή', + 'deleting' => 'Διαγραφή...', + 'confirm_delete' => 'Διαγραφή εγγραφής', + 'confirm_delete_multiple' => 'Διαγραφή επιλεγμένων εγγραφών;', + 'deleting_name' => 'Διαγραφή :name...', + 'reset_default' => 'Επαναφορά στο προκαθορισμένο', + 'resetting' => 'Επαναφορά', + 'resetting_name' => 'Επαναφορά :name', + 'undefined_tab' => 'Διάφορα', + 'field_off' => 'Όχι', + 'field_on' => 'Ναι', + 'add' => 'Προσθήκη', + 'apply' => 'Εφαρμογή', + 'cancel' => 'Άκυρο', + 'close' => 'Κλείσιμο', + 'confirm' => 'Επιβεβαίωση', + 'reload' => 'Επαναφόρτιση', + 'complete' => 'Ολοκλήρωση', + 'ok' => 'Εντάξει', + 'or' => 'ή', + 'confirm_tab_close' => 'Κλείσιμο της καρτέλας; Οι μη αποθηκευμένες αλλαγές θα χαθούν.', + 'behavior_not_ready' => 'Η συμπεριφορά δεν έχει αρχικοποιήσεις, ελέγξτε εάν έχετε καλέσει το initForm() στον χειριστή.', + 'preview_no_files_message' => 'Δεν υπάρχουν αρχεία που ανέβηκαν.', + 'preview_no_record_message' => 'Δεν είναι επιλεγμένη καμία εγγραφή.', + 'select' => 'Επιλογή', + 'select_all' => 'επιλογή όλων', + 'select_none' => 'επιλέξτε κανένα', + 'select_placeholder' => 'παρακαλούμε επιλέξτε', + 'insert_row' => 'Προσθήκη Σειράς', + 'insert_row_below' => 'Προσθήκη Σειράς από Κάτω', + 'delete_row' => 'Διαγραφή Σειράς', + 'concurrency_file_changed_title' => 'Το αρχείο έχει αλλάξει', + 'concurrency_file_changed_description' => "Το αρχείο το οποίο επεξεργάζεστε έχει αλλάξει στον δίσκο από έναν άλλο χρήστη. Μπορείτε είτε να επαναφορτώσετε το αρχείο και να χάσετε τις αλλαγές σας είτε να παρακάμψετε το αρχείο στον δίσκο.", + 'return_to_list' => 'Επιστροφή στην λίστα', + ], + 'recordfinder' => [ + 'find_record' => 'Ανεύρεση Εγγραφής', + ], + 'relation' => [ + 'missing_config' => "Η συμπεριφορά της σχέσης δεν έχει καμία ρύθμιση για το ':config'.", + 'missing_definition' => "Η συμπεριφορά της σχέσης δεν περιέχει ορισμό για το ':field'.", + 'missing_model' => 'Η συμπεριφορά της σχέσης που χρησιμοποιήθηκε στην :class δεν έχει καθορισμένο μοντέλο.', + 'invalid_action_single' => 'Αυτή η ενεργεία δεν μπορεί να εκτελεστεί σε μια μοναδική σχέση.', + 'invalid_action_multi' => 'Αυτή η ενέργεια δεν μπορεί να εκτελεστεί σε μια πολλαπλή σχέση.', + 'help' => 'Κάντε κλικ πάνω σε ένα αντικείμενο για να προσθέσετε', + 'related_data' => 'Σχετικά :name δεδομένα' , + 'add' => 'Προσθήκη', + 'add_selected' => 'Προσθήκη επιλεγμένου', + 'add_a_new' => 'Προσθήκη νέου :name', + 'link_selected' => 'Σύνδεση του επιλεγμένου', + 'link_a_new' => 'Σύνδεση ενός νέου :name ', + 'cancel' => 'Άκυρο', + 'close' => 'Κλείσιμο', + 'add_name' => 'Προσθήκη :name', + 'create' => 'Δημιουργία', + 'create_name' => 'Δημιουργία :name', + 'update' => 'Ενημέρωση', + 'update_name' => 'Ενημέρωση :name', + 'preview' => 'Προεπισκόπηση', + 'preview_name' => 'Προεπισκόπηση :name', + 'remove' => 'Αφαίρεση', + 'remove_name' => 'Αφαίρεση :name', + 'delete' => 'Διαγραφή', + 'delete_name' => 'Διαγραφή :name', + 'delete_confirm' => 'Είστε σίγουροι;', + 'link' => 'Σύνδεση', + 'link_name' => 'Σύνδεση :name', + 'unlink' => 'Αποσύνδεση', + 'unlink_name' => 'Αποσύνδεση :name', + 'unlink_confirm' => 'Είστε σίγουροι;', + ], + 'reorder' => [ + 'default_title' => 'Αναδιάταξη εγγραφών', + 'no_records' => 'Δεν υπάρχουν διαθέσιμες εγγραφές για ταξινόμηση.', + ], + 'model' => [ + 'name' => 'Μοντέλο', + 'not_found' => "Η κλάση ':class' του μοντέλου με ID :id δεν μπόρεσε να βρεθεί", + 'missing_id' => 'Δεν έχει οριστεί το ID για να αναζητηθεί η εγγραφή του μοντέλου.', + 'missing_relation' => "Η κλάση ':class' του μοντέλου δεν περιέχει ένα ορισμό για την ':relation'.", + 'missing_method' => "Η κλάση ':class' του μοντέλου δεν περιέχει την μέθοδο ':method'.", + 'invalid_class' => "Το μοντέλο ':model' που χρησιμοποιήθηκε στην :class δεν είναι έγκυρο, πρέπει να κληρονομεί την κλάση του \Model.", + 'mass_assignment_failed' => "Η μαζική εκχώρηση για την ιδιότητα ':attribute' του μοντέλου απέτυχε.", + ], + 'warnings' => [ + 'tips' => 'Συμβουλές ρύθμισης του συστήματος', + 'tips_description' => 'Υπάρχουν ζητήματα για τα οποία πρέπει να δώσετε προσοχή με σκοπό να ρυθμιστεί το σύστημα ορθά.', + 'permissions' => 'Ο φάκελος :name ή οι υποφάκελοι του δεν έχουν δικαίωμα εγγραφής για την PHP. Παρακαλούμε ρυθμίστε τα κατάλληλα δικαιώματα στον webserver για αυτό τον καταλογο.', + 'extension' => 'Η επέκταση :name της PHP δεν έχει εγκατασταθεί. Παρακαλούμε εγκαταστήστε την βιβλιοθήκη και ενεργοποιήστε την επέκταση.', + ], + 'editor' => [ + + + + + 'menu_label' => 'Editor settings', + 'menu_description' => 'Customize the global editor preferences, such as font size and color scheme.', + 'font_size' => 'Font size', + 'tab_size' => 'Tab size', + 'use_hard_tabs' => 'Indent using tabs', + 'code_folding' => 'Code folding', + 'code_folding_begin' => 'Mark begin', + 'code_folding_begin_end' => 'Mark begin and end', + 'autocompletion' => 'Autocompletion', + 'word_wrap' => 'Word wrap', + 'highlight_active_line' => 'Highlight active line', + 'auto_closing' => 'Automatically close tags', + 'show_invisibles' => 'Show invisible characters', + 'show_gutter' => 'Show gutter', + 'basic_autocompletion'=> 'Basic Autocompletion (Ctrl + Space)', + 'live_autocompletion'=> 'Live Autocompletion', + 'enable_snippets'=> 'Enable code snippets (Tab)', + 'display_indent_guides'=> 'Show indent guides', + 'show_print_margin'=> 'Show print margin', + 'mode_off' => 'Off', + 'mode_fluid' => 'Fluid', + '40_characters' => '40 Characters', + '80_characters' => '80 Characters', + 'theme' => 'Color scheme', + 'markup_styles' => 'Markup Styles', + 'custom_styles' => 'Custom stylesheet', + 'custom styles_comment' => 'Custom styles to include in the HTML editor.', + 'markup_classes' => 'Markup Classes', + 'paragraph' => 'Paragraph', + 'link' => 'Link', + 'table' => 'Table', + 'table_cell' => 'Table Cell', + 'image' => 'Image', + 'label' => 'Label', + 'class_name' => 'Class name', + 'markup_tags' => 'Markup Tags', + 'allowed_empty_tags' => 'Allowed empty tags', + 'allowed_empty_tags_comment' => 'The list of tags that are not removed when they have no content inside.', + 'allowed_tags' => 'Allowed tags', + 'allowed_tags_comment' => 'The list of allowed tags.', + 'no_wrap' => 'Do not wrap tags', + 'no_wrap_comment' => 'The list of tags that should not be wrapped inside block tags.', + 'remove_tags' => 'Remove tags', + 'remove_tags_comment' => 'The list of tags that are removed together with their content.' + + + ], + 'tooltips' => [ + 'preview_website' => 'Προεπισκόπηση ιστοσελίδας', + ], + 'mysettings' => [ + 'menu_label' => 'Οι ρυθμίσεις μου', + 'menu_description' => 'Ρυθμίσεις σχετικές με τον λογαριασμό διαχειριστή σας', + ], + 'myaccount' => [ + 'menu_label' => 'Ο λογαριασμός μου', + 'menu_description' => 'Ενημερώστε τις λεπτομερείς του λογαριασμού σας όπως το όνομα, την διεύθυνση email και τον κωδικού.', + 'menu_keywords' => 'ασφαλής σύνδεση', + ], + 'branding' => [ + 'menu_label' => 'Προσαρμογή του back-end', + 'menu_description' => 'Προσαρμόστε την περιοχή διαχείρισης όπως το όνομα, τα χρώματα και το λογότυπο.', + 'brand' => 'Διακριτικός Τίτλος', + 'logo' => 'Λογότυπο', + 'logo_description' => 'Ανεβάστε ένα προσαρμοσμένο λογότυπο για την χρήση στο back-end.', + 'app_name' => 'Όνομα Εφαρμογής', + 'app_name_description' => 'Το όνομα αυτό εμφανίζεται στην περιοχή τίλιου του back-end.', + 'app_tagline' => 'Ετικέτα Εφαρμογής', + 'app_tagline_description' => 'Αυτό το όνομα εμφανίζεται στην οθόνη σύνδεσης στο back-end.', + 'colors' => 'Χρώματα', + 'primary_color' => 'Πρωτεύων χρώμα', + 'secondary_color' => 'Δευτερεύων χρώμα', + 'accent_color' => 'Τονισμένο χρώμα', + 'styles' => 'Στυλ', + 'custom_stylesheet' => 'Προσαρμοσμένο stylesheet', + 'navigation' => 'Πλοήγηση', + 'menu_mode' => 'Στυλ μενού', + 'menu_mode_inline' => 'Ενσωματωμένο', + 'menu_mode_tile' => 'Πλακίδια', + 'menu_mode_collapsed' => 'Συμπτυγμένο', + ], + 'backend_preferences' => [ + 'menu_label' => 'Προτιμήσεις Back-End', + 'menu_description' => 'Διαχειριστείτε τις ρυθμίσεις του λογαριασμού σας όπως την επιθυμητή γλώσσα.', + 'region' => 'Περιοχή', + 'code_editor' => 'Επεξεργαστής κώδικα', + 'timezone' => 'Ζώνη ώρας', + 'timezone_comment' => 'Προσαρμογή των εμφανιζομένων ημερομηνιών σε αυτήν την ζώνη ώρας.', + 'locale' => 'Τοποθεσία', + 'locale_comment' => 'Επιλέξτε την επιθυμητή τοποθεσία για την χρήση γλώσσας.', + ], + 'access_log' => [ + 'hint' => 'Αυτό το αρχείο εμφανίζει μια λίστα με τις επιτυχημένες προσπάθειες σύνδεσης από τους διαχειριστές. Οι εγγραφές διατηρούνται για :days ημέρες.', + 'menu_label' => 'Αρχείο καταγραφής προσβάσεων', + 'menu_description' => 'Λίστα με τις επιτυχημένες προσβάσεις στο back-end.', + 'created_at' => 'Ημερομηνία & Ώρα', + 'login' => 'Σύνδεση', + 'ip_address' => 'Διεύθυνση IP', + 'first_name' => 'Όνομα', + 'last_name' => 'Επώνυμο', + 'email' => 'Email', + ], + 'filter' => [ + 'all' => 'όλα', + 'options_method_not_exists' => "Η κλάση του μοντέλου :model πρέπει να καθορίζει τις επιστρεφόμενες επιλογές της μεθόδου :method() για το φίλτρο ':filter'.", + 'date_all' => 'όλη η περίοδος', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Ανέβασμα ενός CSV αρχείου', + 'import_file' => 'Εισαγωγή αρχείου', + 'first_row_contains_titles' => 'Η πρώτη γραμμή περιέχει τους τίτλούς των στηλων', + 'first_row_contains_titles_desc' => 'Αφήστε το αυτό επιλεγμένο εάν η πρώτη γραμμή στο CSV χρησιμοποιείται για τον τίτλο των στηλών.', + 'match_columns' => '2. Αντιστοίχιση των στηλών του αρχείου με τα πεδία στην βάση δεδομένων', + 'file_columns' => 'Στήλες αρχείου', + 'database_fields' => 'Πεδία βάσης δεδομένων', + 'set_import_options' => '3. Ορισμός επίλογων εισαγωγής', + 'export_output_format' => '1. Μορφή τύπου εξόδου', + 'file_format' => 'Μορφή αρχείου', + 'standard_format' => 'Τυποποιημένη μορφή', + 'custom_format' => 'Προσαρμοσμένη μορφή', + 'delimiter_char' => 'Χαρακτήρας Διαχωριστικού', + 'enclosure_char' => 'Χαρακτήρας Enclosure', + 'escape_char' => 'Χαρακτήρας Escape', + 'select_columns' => '2. Επιλέξτε τις στήλες που θα εξαχθούν', + 'column' => 'Στήλη', + 'columns' => 'Στήλες', + 'set_export_options' => '3. Ορισμός επιλογών εξαγωγής', + 'show_ignored_columns' => 'Εμφάνιση αγνοούμενων στηλών', + 'auto_match_columns' => 'Αυτόματή αντιστοίχιση στηλών', + 'created' => 'Δημιουργήθηκε', + 'updated' => 'Ενημερώθηκε', + 'skipped' => 'Παραλήφθηκε', + 'warnings' => 'Προειδοποιήσεις', + 'errors' => 'Λάθη', + 'skipped_rows' => 'Σειρές που Παραλήφθηκαν', + 'import_progress' => 'Πρόοδός εισαγωγής', + 'processing' => 'Επεξεργασία', + 'import_error' => 'Λάθος εισαγωγής', + 'upload_valid_csv' => 'Παρακαλώ ανεβάστε εάν συμβατό CSV αρχείο.', + 'drop_column_here' => 'Σύρετε μια στήλη εδώ...', + 'ignore_this_column' => 'Αγνόησε αυτήν την στήλη', + 'processing_successful_line1' => 'Η διαδικασία της εξαγωγής αρχείου ολοκληρώθηκε!', + 'processing_successful_line2' => 'Το πρόγραμμα περιήγησης θα μεταβεί στο κατέβασμα του αρχείου.', + 'export_progress' => 'Πρόοδος εξαγωγής', + 'export_error' => 'Εξαγωγή λάθους', + 'column_preview' => 'Προεπισκόπηση στήλης', + 'file_not_found_error' => 'Το αρχείο δεν βρέθηκε', + 'empty_error' => 'Δεν υπάρχουν δεδομένα για σταλούν για εξαγωγή', + 'empty_import_columns_error' => 'παρακαλούμε ορίστε κάποιες στήλες για εισαγωγή.', + 'match_some_column_error' => 'Παρακαλούμε αντιστοιχήστε κάποιες στήλες πρώτα.', + 'required_match_column_error' => 'Παρακαλούμε ορίστε μια αντιστοίχιση για το απαιτούμενο πεδίο :label.', + 'empty_export_columns_error' => 'Παρακαλούμε ορίστε κάποιες στήλες για να εξαχθούν.', + 'behavior_missing_uselist_error' => 'Πρέπει να υλοποιήσετε μια συμπεριφορά χειριστή ListController με την επιλογή εξαγωγής "useList" ενεργοποιημένη.', + 'missing_model_class_error' => 'παρακαλούμε ορίστε την ιδιότητα modelClass για τον τύπο :type', + 'missing_column_id_error' => 'Λείπει το αναγνωριστικό στήλης', + 'unknown_column_error' => 'Άγνωστη στήλη', + 'encoding_not_supported_error' => 'Η κωδικοποίηση του αρχείου προέλευσης δεν αναγνωριστικέ. παρακαλούμε επιλέξτε την προσαρμοσμένη μορφή αρχείου με την κατάλληλη κωδικοποίηση για την εισαγωγή του αρχείου σας.', + 'encoding_format' => 'Κωδικοποίηση αρχείου', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Ανέβασμα και διαχείριση περιεχομένου μέσων - εικόνων, βίντεο, ήχων, εγγράφων,//Upload and manage media contents - images, videos, sounds, documents' + ], + 'mediafinder' => [ + 'label' => 'Media Finder', + 'default_prompt' => 'Click the %s button to find a media item' + ], + 'media' => [ + 'menu_label' => 'Μέσα', + 'upload' => 'Ανέβασμα', + 'move' => 'Μετακίνηση', + 'delete' => 'Διαγραφή', + 'add_folder' => 'Προσθήκη καταλόγου', + 'search' => 'Αναζήτηση', + 'display' => 'Εμφάνιση', + 'filter_everything' => 'Όλα', + 'filter_images' => 'Εικόνες', + 'filter_video' => 'Βίντεο', + 'filter_audio' => 'Ήχος', + 'filter_documents' => 'Έγγραφο', + 'library' => 'Βιβλιοθήκη', + 'size' => 'Μέγεθος', + 'title' => 'Τίτλος', + 'last_modified' => 'Τελευταία τροποποίηση', + 'public_url' => 'Δημόσιο URL', + 'click_here' => 'Κλικ εδώ', + 'thumbnail_error' => 'Σφάλμα κατά την δημιουργία μικρογραφίας.', + 'return_to_parent' => 'Επιστροφή στον γονικό κατάλογο', + 'return_to_parent_label' => 'Πήγαινε επάνω...', + 'nothing_selected' => 'Δεν επιλέχτηκε τίποτα.', + 'multiple_selected' => 'Επιλέχτηκαν πολλαπλά αντικείμενα.', + 'uploading_file_num' => 'Ανέβασμα :number αρχείων...', + 'uploading_complete' => 'Το ανέβασμα ολοκληρώθηκε', + 'uploading_error' => 'Το ανέβασμα απέτυχε', + 'type_blocked' => 'Ο τύπος του αρχείου που χρησιμοποιήθηκε μπλοκαρίστηκε για λόγους ασφαλείας.', + 'order_by' => 'Ταξινόμηση κατά', + 'folder' => 'Κατάλογος', + 'no_files_found' => 'Δεν βρέθηκαν αρχεία από το αίτημα σας.', + 'delete_empty' => 'παρακαλούμε επιλέξτε αντικείμενά για να τα σβήσετε.', + 'delete_confirm' => 'Διαγραφή των επιλεγμένων αντικείμενων;', + 'error_renaming_file' => 'Σφάλμα κατά την μετονομασία του αντικειμένου.', + 'new_folder_title' => 'Νέος κατάλογος', + 'folder_name' => 'Όνομα καταλόγου', + 'error_creating_folder' => 'Σφάλμα κατά την δημιουργία καταλόγου', + 'folder_or_file_exist' => 'Ένας κατάλογος ή αρχείο με το ίδιο όνομα υπάρχει ήδη.', + 'move_empty' => 'παρακαλούμε επιλέξτε αντικείμενα για να τα μετακινήσετε.', + 'move_popup_title' => 'Μετακίνηση αρχείων ή καταλογών.', + 'move_destination' => 'Κατάλογος προορισμού', + 'please_select_move_dest' => 'Παρακαλούμε επιλέξτε ένα κατάλογο προορισμού.', + 'move_dest_src_match' => 'Παρακαλούμε επιλέξτε έναν διαφορετικό κατάλογο προορισμού.', + 'empty_library' => 'Η βιβλιοθήκη Μέσων είναι άδεια. Ανεβάστε αρχεία ή δημιουργήστε καταλόγους για να ξεκινήσετε.', + 'insert' => 'Εισαγωγή', + 'crop_and_insert' => 'Περικοπή & Εισαγωγή', + 'select_single_image' => 'παρακαλούμε επιλέξτε μόνο μια εικόνα.', + 'selection_not_image' => 'Το επιλεγμένο αντικείμενο δεν είναι εικόνα.', + 'restore' => 'Αναίρεση όλων των αλλαγών', + 'resize' => 'Αλλαγή μεγέθους...', + 'selection_mode_normal' => 'Κανονικό', + 'selection_mode_fixed_ratio' => 'Κλειδωμένη αναλογία', + 'selection_mode_fixed_size' => 'Κλειδωμένο μέγεθος', + 'height' => 'Ύψος', + 'width' => 'Πλάτος', + 'selection_mode' => 'Λειτουργία επιλογής', + 'resize_image' => 'Αλλαγή μεγέθους εικόνας', + 'image_size' => 'Μέγεθος εικόνας:', + 'selected_size' => 'Επιλεγμένο:', + ] +]; diff --git a/modules/backend/lang/en/lang.php b/modules/backend/lang/en/lang.php new file mode 100644 index 0000000..aca0ab6 --- /dev/null +++ b/modules/backend/lang/en/lang.php @@ -0,0 +1,646 @@ + [ + 'title' => 'Administration Area', + 'invalid_login' => 'The details you entered did not match our records. Please double-check and try again.', + ], + 'field' => [ + 'invalid_type' => 'Invalid field type used :type.', + 'options_method_invalid_model' => "The attribute ':field' does not resolve to a valid model. Try specifying the options method for model class :model explicitly.", + 'options_method_not_exists' => "The model class :model must define a method :method() returning options for the ':field' form field.", + 'options_static_method_invalid_value' => "The static method ':method()' on :class did not return a valid options array.", + 'colors_method_not_exists' => "The model class :model must define a method :method() returning html color HEX codes for the ':field' form field.", + ], + 'widget' => [ + 'not_registered' => "A widget class name ':name' has not been registered", + 'not_bound' => "A widget with class name ':name' has not been bound to the controller", + ], + 'page' => [ + 'untitled' => 'Untitled', + '404' => [ + 'label' => 'Page Not Found', + 'help' => "We searched and searched but the requested URL just couldn't be found. Perhaps you were looking for something else?", + 'back_link' => 'Go back to the previous page', + ], + 'access_denied' => [ + 'label' => 'Access denied', + 'help' => "You don't have the required permissions to view this page.", + 'cms_link' => 'Return to the back-end', + ], + 'no_database' => [ + 'label' => 'Database missing', + 'help' => "A database is required to access the back-end. Check the database is configured and migrated before trying again.", + 'cms_link' => 'Return to the homepage', + ], + ], + 'partial' => [ + 'not_found_name' => "The partial ':name' is not found.", + 'invalid_name' => 'Invalid partial name: :name.', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Invalid AJAX handler name: :name.', + 'not_found' => "AJAX handler ':name' was not found.", + ], + 'account' => [ + 'impersonate' => 'Impersonate user', + 'impersonate_confirm' => 'Are you sure you want to impersonate this user? You can revert to your original state by logging out.', + 'impersonate_success' => 'You are now impersonating this user', + 'impersonate_working' => 'Impersonating...', + 'impersonating' => 'Impersonating :full_name', + 'stop_impersonating' => 'Stop impersonating', + 'unsuspend' => 'Unsuspend', + 'unsuspend_confirm' => 'Are you sure you want to unsuspend this user?', + 'unsuspend_success' => 'User has been unsuspended.', + 'unsuspend_working' => 'Unsuspending...', + 'signed_in_as' => 'Signed in as :full_name', + 'sign_out' => 'Sign out', + 'login' => 'Login', + 'reset' => 'Reset', + 'restore' => 'Restore', + 'login_placeholder' => 'login', + 'password_placeholder' => 'password', + 'remember_me' => 'Stay logged in', + 'forgot_password' => 'Forgot your password?', + 'enter_email' => 'Enter your email', + 'enter_login' => 'Enter your login', + 'email_placeholder' => 'email', + 'enter_new_password' => 'Enter a new password', + 'password_reset' => 'Password Reset', + 'restore_success' => 'Message sent to your email address with instructions.', + 'restore_error' => "A user could not be found with a login value of ':login'", + 'reset_success' => 'Password has been reset. You may now sign in.', + 'reset_error' => 'Invalid password reset data supplied. Please try again!', + 'reset_fail' => 'Unable to reset your password!', + 'apply' => 'Apply', + 'cancel' => 'Cancel', + 'delete' => 'Delete', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => 'Dashboard', + 'widget_label' => 'Widget', + 'widget_width' => 'Width', + 'full_width' => 'full width', + 'manage_widgets' => 'Manage widgets', + 'add_widget' => 'Add widget', + 'widget_inspector_title' => 'Widget configuration', + 'widget_inspector_description' => 'Configure the report widget', + 'widget_columns_label' => 'Width :columns', + 'widget_columns_description' => 'The widget width, a number between 1 and 12.', + 'widget_columns_error' => 'Please enter the widget width as a number between 1 and 12.', + 'columns' => '{1} column|[2,Inf] columns', + 'widget_new_row_label' => 'Force new row', + 'widget_new_row_description' => 'Put the widget in a new row.', + 'widget_title_label' => 'Widget title', + 'widget_title_error' => 'The Widget Title is required.', + 'reset_layout' => 'Reset layout', + 'reset_layout_confirm' => 'Reset layout back to default?', + 'reset_layout_success' => 'Layout has been reset', + 'make_default' => 'Make default', + 'make_default_confirm' => 'Set the current layout as the default?', + 'make_default_success' => 'Current layout is now the default', + 'collapse_all' => 'Collapse all', + 'expand_all' => 'Expand all', + 'status' => [ + 'widget_title_default' => 'System status', + 'update_available' => '{0} updates available!|{1} update available!|[2,Inf] updates available!', + 'updates_pending' => 'Pending software updates', + 'updates_nil' => 'Software is up to date', + 'updates_link' => 'Update', + 'warnings_pending' => 'Some issues need attention', + 'warnings_nil' => 'No warnings to display', + 'warnings_link' => 'View', + 'core_build' => 'System build', + 'event_log' => 'Event log', + 'request_log' => 'Request log', + 'app_birthday' => 'Online since', + ], + 'welcome' => [ + 'widget_title_default' => 'Welcome', + 'welcome_back_name' => 'Welcome back to :app, :name.', + 'welcome_to_name' => 'Welcome to :app, :name.', + 'first_sign_in' => 'This is the first time you have signed in.', + 'last_sign_in' => 'Your last sign in was', + 'view_access_logs' => 'View access logs', + 'nice_message' => 'Have a great day!', + ], + ], + 'user' => [ + 'name' => 'Administrator', + 'menu_label' => 'Administrators', + 'menu_description' => 'Manage back-end administrator users, groups and permissions.', + 'list_title' => 'Manage Administrators', + 'new' => 'New Administrator', + 'login' => 'Login', + 'first_name' => 'First Name', + 'last_name' => 'Last Name', + 'full_name' => 'Full Name', + 'email' => 'Email', + 'role_field' => 'Role', + 'role_comment' => 'Roles define user permissions, which can be overriden on the user level, on the Permissions tab.', + 'groups' => 'Groups', + 'groups_comment' => 'Specify which groups this account should belong to.', + 'avatar' => 'Avatar', + 'password' => 'Password', + 'password_confirmation' => 'Confirm Password', + 'permissions' => 'Permissions', + 'account' => 'Account', + 'superuser' => 'Super User', + 'superuser_comment' => 'Grants this account unlimited access to all areas of the system. Super users can add and manage other users. ', + 'send_invite' => 'Send invitation by email', + 'send_invite_comment' => 'Sends a welcome message containing login and password information.', + 'delete_confirm' => 'Delete this administrator?', + 'return' => 'Return to admin list', + 'allow' => 'Allow', + 'inherit' => 'Inherit', + 'deny' => 'Deny', + 'activated' => 'Activated', + 'last_login' => 'Last login', + 'created_at' => 'Created at', + 'updated_at' => 'Updated at', + 'deleted_at' => 'Deleted at', + 'show_deleted' => 'Show deleted', + 'group' => [ + 'name' => 'Group', + 'name_field' => 'Name', + 'name_comment' => 'The name is displayed in the group list on the Administrator form.', + 'description_field' => 'Description', + 'is_new_user_default_field_label' => 'Default group', + 'is_new_user_default_field_comment' => 'Add new administrators to this group by default', + 'code_field' => 'Code', + 'code_comment' => 'Enter a unique code if you want to access the group object with the API.', + 'menu_label' => 'Manage Groups', + 'list_title' => 'Manage Groups', + 'new' => 'New Group', + 'delete_confirm' => 'Delete this administrator group?', + 'return' => 'Return to group list', + 'users_count' => 'Users', + ], + 'role' => [ + 'name' => 'Role', + 'name_field' => 'Name', + 'name_comment' => 'The name is displayed in the role list on the Administrator form.', + 'description_field' => 'Description', + 'code_field' => 'Code', + 'code_comment' => 'Enter a unique code if you want to access the role object with the API.', + 'menu_label' => 'Manage Roles', + 'list_title' => 'Manage Roles', + 'new' => 'New Role', + 'delete_confirm' => 'Delete this administrator role?', + 'return' => 'Return to role list', + 'users_count' => 'Users', + ], + 'preferences' => [ + 'not_authenticated' => 'There is no an authenticated user to load or save preferences for.', + ], + 'trashed_hint_title' => 'This account has been deleted', + 'trashed_hint_desc' => 'This account has been deleted and will be unable to be signed in under. To restore it, click the restore user icon in the bottom right', + ], + 'list' => [ + 'default_title' => 'List', + 'search_prompt' => 'Search...', + 'no_records' => 'There are no records in this view.', + 'missing_model' => 'List behavior used in :class does not have a model defined.', + 'missing_column' => 'There are no column definitions for :columns.', + 'missing_columns' => 'List used in :class has no list columns defined.', + 'missing_definition' => "List behavior does not contain a column for ':field'.", + 'missing_parent_definition' => "List behavior does not contain a definition for ':definition'.", + 'behavior_not_ready' => 'List behavior has not been initialized, check that you have called makeLists() in your controller.', + 'invalid_column_datetime' => "Column value ':column' is not a DateTime object, are you missing a \$dates reference in the Model?", + 'pagination' => 'Displayed records: :from-:to of :total', + 'first_page' => 'First page', + 'last_page' => 'Last page', + 'prev_page' => 'Previous page', + 'next_page' => 'Next page', + 'refresh' => 'Refresh', + 'updating' => 'Updating...', + 'loading' => 'Loading...', + 'setup_title' => 'List setup', + 'setup_help' => 'Use checkboxes to select columns you want to see in the list. You can change position of columns by dragging them up or down.', + 'records_per_page' => 'Records per page', + 'records_per_page_help' => 'Select the number of records per page to display. Please note that high number of records on a single page can reduce performance.', + 'check' => 'Check', + 'delete_selected' => 'Delete selected', + 'delete_selected_empty' => 'There are no selected records to delete.', + 'delete_selected_confirm' => 'Delete the selected records?', + 'delete_selected_success' => 'Deleted selected records.', + 'column_switch_true' => 'Yes', + 'column_switch_false' => 'No', + ], + 'fileupload' => [ + 'attachment' => 'Attachment', + 'help' => 'Add a title and description for this attachment.', + 'title_label' => 'Title', + 'description_label' => 'Description', + 'default_prompt' => 'Click the %s or drag a file here to upload', + 'attachment_url' => 'Attachment URL', + 'upload_file' => 'Upload file', + 'upload_error' => 'Upload error', + 'remove_confirm' => 'Are you sure?', + 'remove_file' => 'Remove file', + ], + 'repeater' => [ + 'add_new_item' => 'Add new item', + 'min_items_failed' => ':name requires a minimum of :min items, only :items were provided', + 'max_items_failed' => ':name only allows up to :max items, :items were provided', + ], + 'form' => [ + 'create_title' => 'New :name', + 'update_title' => 'Edit :name', + 'preview_title' => 'Preview :name', + 'create_success' => ':name created', + 'update_success' => ':name updated', + 'delete_success' => ':name deleted', + 'restore_success' => ':name restored', + 'reset_success' => 'Reset complete', + 'missing_id' => 'Form record ID has not been specified.', + 'missing_model' => 'Form behavior used in :class does not have a model defined.', + 'missing_definition' => "Form behavior does not contain a field for ':field'.", + 'not_found' => 'Form record with an ID of :id could not be found.', + 'action_confirm' => 'Are you sure?', + 'create' => 'Create', + 'create_and_close' => 'Create and close', + 'creating' => 'Creating...', + 'creating_name' => 'Creating :name...', + 'save' => 'Save', + 'save_and_close' => 'Save and close', + 'saving' => 'Saving...', + 'saving_name' => 'Saving :name...', + 'delete' => 'Delete', + 'deleting' => 'Deleting...', + 'confirm_delete' => 'Delete record?', + 'confirm_delete_multiple' => 'Delete selected records?', + 'deleting_name' => 'Deleting :name...', + 'restore' => 'Restore', + 'restoring' => 'Restoring...', + 'confirm_restore' => 'Are you sure you want to restore this record?', + 'reset_default' => 'Reset to default', + 'resetting' => 'Resetting', + 'resetting_name' => 'Resetting :name', + 'undefined_tab' => 'Misc', + 'field_off' => 'Off', + 'field_on' => 'On', + 'add' => 'Add', + 'apply' => 'Apply', + 'cancel' => 'Cancel', + 'close' => 'Close', + 'confirm' => 'Confirm', + 'reload' => 'Reload', + 'complete' => 'Complete', + 'ok' => 'OK', + 'or' => 'or', + 'confirm_tab_close' => 'Close the tab? Unsaved changes will be lost.', + 'behavior_not_ready' => 'Form behavior has not been initialized, check that you have called initForm() in your controller.', + 'preview_no_files_message' => 'There are no files uploaded.', + 'preview_no_media_message' => 'There is no media selected.', + 'preview_no_record_message' => 'There is no record selected.', + 'select' => 'Select', + 'select_all' => 'Select all', + 'select_none' => 'Select none', + 'select_placeholder' => 'please select', + 'insert_row' => 'Insert Row', + 'insert_row_below' => 'Insert Row Below', + 'delete_row' => 'Delete Row', + 'concurrency_file_changed_title' => 'File was changed', + 'concurrency_file_changed_description' => "The file you're editing has been changed on disk by another user. You can either reload the file and lose your changes or override the file on the disk.", + 'return_to_list' => 'Return to the list', + ], + 'recordfinder' => [ + 'find_record' => 'Find Record', + 'invalid_model_class' => 'The provided model class ":modelClass" for the recordfinder is invalid', + 'cancel' => 'Cancel', + ], + 'pagelist' => [ + 'page_link' => 'Page link', + 'select_page' => 'Select a page...', + ], + 'relation' => [ + 'missing_config' => "Relation behavior does not have any configuration for ':config'.", + 'missing_definition' => "Relation behavior does not contain a definition for ':field'.", + 'missing_model' => 'Relation behavior used in :class does not have a model defined.', + 'invalid_action_single' => 'This action cannot be performed on a singular relationship.', + 'invalid_action_multi' => 'This action cannot be performed on a multiple relationship.', + 'help' => 'Click on an item to add', + 'related_data' => 'Related :name data', + 'add' => 'Add', + 'add_selected' => 'Add selected', + 'add_a_new' => 'Add a new :name', + 'link_selected' => 'Link selected', + 'link_a_new' => 'Link a new :name', + 'cancel' => 'Cancel', + 'close' => 'Close', + 'add_name' => 'Add :name', + 'create' => 'Create', + 'create_name' => 'Create :name', + 'update' => 'Update', + 'update_name' => 'Update :name', + 'preview' => 'Preview', + 'preview_name' => 'Preview :name', + 'remove' => 'Remove', + 'remove_name' => 'Remove :name', + 'delete' => 'Delete', + 'delete_name' => 'Delete :name', + 'delete_confirm' => 'Are you sure?', + 'link' => 'Link', + 'link_name' => 'Link :name', + 'unlink' => 'Unlink', + 'unlink_name' => 'Unlink :name', + 'unlink_confirm' => 'Are you sure?', + ], + 'reorder' => [ + 'default_title' => 'Reorder records', + 'no_records' => 'There are no records available to sort.', + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => "Model ':class' with an ID of :id could not be found", + 'missing_id' => 'There is no ID specified for looking up the model record.', + 'missing_relation' => "Model ':class' does not contain a definition for ':relation'.", + 'missing_method' => "Model ':class' does not contain a method ':method'.", + 'invalid_class' => "Model :model used in :class is not valid, it must inherit the \Model class.", + 'mass_assignment_failed' => "Mass assignment failed for Model attribute ':attribute'.", + ], + 'warnings' => [ + 'tips' => 'System configuration tips', + 'tips_description' => 'There are issues you need to pay attention to in order to configure the system properly.', + 'permissions' => 'Directory :name or its subdirectories is not writable for PHP. Please set corresponding permissions for the webserver on this directory.', + 'extension' => 'The PHP extension :name is not installed. Please install this library and activate the extension.', + 'plugin_missing' => 'The plugin :name is a dependency but is not installed. Please install this plugin.', + 'debug' => 'Debug mode is enabled. This is not recommended for production installations.', + 'decompileBackendAssets' => 'Assets in the Backend are currently decompiled. This is not recommended for production installations.', + ], + 'editor' => [ + 'menu_label' => 'Editor settings', + 'menu_description' => 'Customize the global editor preferences, such as font size and color scheme.', + 'preview' => 'Preview', + 'font_size' => 'Font size', + 'tab_size' => 'Tab size', + 'use_hard_tabs' => 'Indent using tabs', + 'code_folding' => 'Code folding', + 'code_folding_begin' => 'Mark begin', + 'code_folding_begin_end' => 'Mark begin and end', + 'autocompletion' => 'Autocompletion', + 'word_wrap' => 'Word wrap', + 'highlight_active_line' => 'Highlight active line', + 'auto_closing' => 'Automatically close tags', + 'show_invisibles' => 'Show invisible characters', + 'show_gutter' => 'Show gutter', + 'basic_autocompletion' => 'Basic Autocompletion (Ctrl + Space)', + 'live_autocompletion' => 'Live Autocompletion', + 'enable_snippets' => 'Enable code snippets (Tab)', + 'display_indent_guides' => 'Show indent guides', + 'show_print_margin' => 'Show print margin', + 'mode_off' => 'Off', + 'mode_fluid' => 'Fluid', + '40_characters' => '40 Characters', + '80_characters' => '80 Characters', + 'theme' => 'Color scheme', + 'markup_styles' => 'Markup Styles', + 'custom_styles' => 'Custom stylesheet', + 'custom styles_comment' => 'Custom styles to include in the HTML editor.', + 'markup_classes' => 'Markup Classes', + 'paragraph' => 'Paragraph', + 'link' => 'Link', + 'table' => 'Table', + 'table_cell' => 'Table Cell', + 'image' => 'Image', + 'label' => 'Label', + 'class_name' => 'Class name', + 'markup_tags' => 'Markup Tags', + 'markup_tag' => 'Markup Tag', + 'allowed_empty_tags' => 'Allowed empty tags', + 'allowed_empty_tags_comment' => 'The list of tags that are not removed when they have no content inside.', + 'allowed_tags' => 'Allowed tags', + 'allowed_tags_comment' => 'The list of allowed tags.', + 'no_wrap' => 'Do not wrap tags', + 'no_wrap_comment' => 'The list of tags that should not be wrapped inside block tags.', + 'remove_tags' => 'Remove tags', + 'remove_tags_comment' => 'The list of tags that are removed together with their content.', + 'line_breaker_tags' => 'Line breaker tags', + 'line_breaker_tags_comment' => 'The list of tags that are used to place a line breaker element between.', + 'toolbar_options' => 'Toolbar Options', + 'toolbar_buttons' => 'Toolbar Buttons', + 'toolbar_buttons_comment' => 'The Toolbar Buttons to be displayed in the Rich Editor by default.', + 'toolbar_buttons_preset' => 'Insert a preset toolbar button configuration:', + 'toolbar_buttons_presets' => [ + 'default' => 'Default', + 'minimal' => 'Minimal', + 'full' => 'Full', + ], + 'paragraph_formats' => 'Paragraph Formats', + 'paragraph_formats_comment' => 'The options that will appear in the Paragraph Format dropdown.', + ], + 'tooltips' => [ + 'preview_website' => 'Preview the website', + ], + 'mysettings' => [ + 'menu_label' => 'My Settings', + 'menu_description' => 'Settings related to your administration account', + ], + 'myaccount' => [ + 'menu_label' => 'My account', + 'menu_description' => 'Update your account details such as name, email address and password.', + 'menu_keywords' => 'security login', + ], + 'branding' => [ + 'menu_label' => 'Customize back-end', + 'menu_description' => 'Customize the administration area such as name, colors and logo.', + 'brand' => 'Brand', + 'logo' => 'Logo', + 'logo_description' => 'Upload a custom logo to use in the back-end.', + 'favicon' => 'Favicon', + 'favicon_description' => 'Upload a custom favicon to use in the back-end', + 'app_name' => 'App Name', + 'app_name_description' => 'This name is shown in the title area of the back-end.', + 'app_tagline' => 'App Tagline', + 'app_tagline_description' => 'This name is shown on the sign in screen for the back-end.', + 'colors' => 'Colors', + 'primary_color' => 'Primary color', + 'secondary_color' => 'Secondary color', + 'accent_color' => 'Accent color', + 'styles' => 'Styles', + 'custom_stylesheet' => 'Custom stylesheet', + 'navigation' => 'Navigation', + 'menu_mode' => 'Menu style', + 'menu_mode_inline' => 'Inline', + 'menu_mode_inline_no_icons' => 'Inline (no icons)', + 'menu_mode_tile' => 'Tiles', + 'menu_mode_collapsed' => 'Collapsed', + ], + 'backend_preferences' => [ + 'menu_label' => 'Back-end preferences', + 'menu_description' => 'Manage your account preferences such as desired language.', + 'region' => 'Region', + 'code_editor' => 'Code editor', + 'timezone' => 'Timezone', + 'timezone_comment' => 'Adjust displayed dates to this timezone.', + 'locale' => 'Locale', + 'locale_comment' => 'Select your desired locale for language use.', + ], + 'access_log' => [ + 'hint' => 'This log displays a list of successful sign in attempts by administrators. Records are kept for a total of :days days.', + 'menu_label' => 'Access log', + 'menu_description' => 'View a list of successful back-end user sign ins.', + 'id' => 'ID', + 'created_at' => 'Date & Time', + 'type' => 'Type', + 'login' => 'Login', + 'ip_address' => 'IP address', + 'first_name' => 'First name', + 'last_name' => 'Last name', + 'email' => 'Email', + ], + 'filter' => [ + 'all' => 'all', + 'options_method_not_exists' => "The model class :model must define a method :method() returning options for the ':filter' filter.", + 'date_all' => 'all periods', + 'number_all' => 'all numbers', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Upload a CSV file', + 'import_file' => 'Import file', + 'row' => 'Row :row', + 'first_row_contains_titles' => 'First row contains column titles', + 'first_row_contains_titles_desc' => 'Leave this checked if the first row in the CSV is used as the column titles.', + 'match_columns' => '2. Match the file columns to database fields', + 'file_columns' => 'File columns', + 'database_fields' => 'Database fields', + 'set_import_options' => '3. Set import options', + 'export_output_format' => '1. Export output format', + 'file_format' => 'File format', + 'standard_format' => 'Standard format', + 'custom_format' => 'Custom format', + 'delimiter_char' => 'Delimiter character', + 'enclosure_char' => 'Enclosure character', + 'escape_char' => 'Escape character', + 'select_columns' => '2. Select columns to export', + 'column' => 'Column', + 'columns' => 'Columns', + 'set_export_options' => '3. Set export options', + 'show_ignored_columns' => 'Show ignored columns', + 'auto_match_columns' => 'Auto match columns', + 'created' => 'Created', + 'updated' => 'Updated', + 'skipped' => 'Skipped', + 'warnings' => 'Warnings', + 'errors' => 'Errors', + 'skipped_rows' => 'Skipped Rows', + 'import_progress' => 'Import progress', + 'processing' => 'Processing', + 'import_error' => 'Import error', + 'upload_valid_csv' => 'Please upload a valid CSV file.', + 'drop_column_here' => 'Drop column here...', + 'ignore_this_column' => 'Ignore this column', + 'processing_successful_line1' => 'File export process completed!', + 'processing_successful_line2' => 'The browser will now redirect to the file download.', + 'export_progress' => 'Export progress', + 'export_error' => 'Export error', + 'column_preview' => 'Column preview', + 'file_not_found_error' => 'File not found', + 'empty_error' => 'There was no data supplied to export', + 'empty_import_columns_error' => 'Please specify some columns to import.', + 'match_some_column_error' => 'Please match some columns first.', + 'required_match_column_error' => 'Please specify a match for the required field :label.', + 'empty_export_columns_error' => 'Please specify some columns to export.', + 'behavior_missing_uselist_error' => 'You must implement the controller behavior ListController with the export "useList" option enabled.', + 'missing_model_class_error' => 'Please specify the modelClass property for :type', + 'missing_column_id_error' => 'Missing column identifier', + 'unknown_column_error' => 'Unknown column', + 'encoding_not_supported_error' => 'Source file encoding is not recognized. Please select the custom file format option with the proper encoding to import your file.', + 'encoding_format' => 'File encoding', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1250' => 'Windows-1250 (CP1250, Central and Eastern European)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)', + ], + ], + 'permissions' => [ + 'manage_media' => 'Upload and manage media contents - images, videos, sounds, documents', + 'allow_unsafe_markdown' => 'Use unsafe Markdown (Can include Javascript)', + ], + 'mediafinder' => [ + 'label' => 'Media Finder', + 'default_prompt' => 'Click the %s button to find a media item', + 'no_image' => 'The image could not be found', + ], + 'media' => [ + 'menu_label' => 'Media', + 'upload' => 'Upload', + 'move' => 'Move', + 'delete' => 'Delete', + 'add_folder' => 'Add folder', + 'search' => 'Search', + 'display' => 'Display', + 'filter_everything' => 'Everything', + 'filter_images' => 'Images', + 'filter_video' => 'Video', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Documents', + 'library' => 'Library', + 'size' => 'Size', + 'title' => 'Title', + 'last_modified' => 'Last modified', + 'public_url' => 'URL', + 'click_here' => 'Click here', + 'thumbnail_error' => 'Error generating thumbnail.', + 'return_to_parent' => 'Return to the parent folder', + 'return_to_parent_label' => 'Go up ..', + 'nothing_selected' => 'Nothing is selected.', + 'multiple_selected' => 'Multiple items selected.', + 'uploading_file_num' => 'Uploading :number file(s)...', + 'uploading_complete' => 'Upload complete', + 'uploading_error' => 'Upload failed', + 'type_blocked' => 'The file type used is blocked for security reasons.', + 'order_by' => 'Order by', + 'direction' => 'Direction', + 'direction_asc' => 'Ascending', + 'direction_desc' => 'Descending', + 'folder' => 'Folder', + 'no_files_found' => 'No files found by your request.', + 'delete_empty' => 'Please select items to delete.', + 'delete_confirm' => 'Delete the selected item(s)?', + 'error_renaming_file' => 'Error renaming the item.', + 'new_folder_title' => 'New folder', + 'folder_name' => 'Folder name', + 'error_creating_folder' => 'Error creating folder', + 'folder_or_file_exist' => 'A folder or file with the specified name already exists.', + 'move_empty' => 'Please select items to move.', + 'move_popup_title' => 'Move files or folders', + 'move_destination' => 'Destination folder', + 'please_select_move_dest' => 'Please select a destination folder.', + 'move_dest_src_match' => 'Please select another destination folder.', + 'empty_library' => 'It looks a bit empty here. Upload files or create folders to get started.', + 'insert' => 'Insert', + 'crop_and_insert' => 'Crop & Insert', + 'select_single_image' => 'Please select a single image.', + 'selection_not_image' => 'The selected item is not an image.', + 'restore' => 'Undo all changes', + 'resize' => 'Resize...', + 'selection_mode_normal' => 'Normal', + 'selection_mode_fixed_ratio' => 'Fixed ratio', + 'selection_mode_fixed_size' => 'Fixed size', + 'height' => 'Height', + 'width' => 'Width', + 'selection_mode' => 'Selection mode', + 'resize_image' => 'Resize image', + 'image_size' => 'Image size:', + 'selected_size' => 'Selected:', + ], +]; diff --git a/modules/backend/lang/es-ar/lang.php b/modules/backend/lang/es-ar/lang.php new file mode 100644 index 0000000..ec5d209 --- /dev/null +++ b/modules/backend/lang/es-ar/lang.php @@ -0,0 +1,254 @@ + [ + 'invalid_type' => 'El tipo de campo utilizado es inválido :type.', + 'options_method_not_exists' => 'La clase del modelo :model debe definir un método :method() que devuelva opciones para el campo ":field".', + ], + 'widget' => [ + 'not_registered' => "No se ha registrado ningún módulo con la clase ':name'.", + 'not_bound' => "El módulo con la clase ':name' no se ha unido al controlador.", + ], + 'page' => [ + 'untitled' => "Sin título", + 'access_denied' => [ + 'label' => "Acceso denegado.", + 'help' => "No tiene permisos necesarios para ver esta página.", + 'cms_link' => "Regresar al backend.", + ], + ], + 'partial' => [ + 'not_found_name' => "No se encuentra el parcial ':name'.", + ], + 'account' => [ + 'sign_out' => 'Salir', + 'login' => 'Entrar', + 'reset' => 'Reiniciar', + 'restore' => 'Restaurar', + 'login_placeholder' => 'Usuario', + 'password_placeholder' => 'Contraseña', + 'forgot_password' => "Olvidó su contraseña?", + 'enter_email' => "Ingrese su email", + 'enter_login' => "Ingrese su usuario", + 'email_placeholder' => "email", + 'enter_new_password' => "Ingrese una nueva contraseña.", + 'password_reset' => "Reiniciar contraseña.", + 'restore_success' => "Le hemos enviado un email con la nueva contraseña.", + 'restore_error' => "El usuario no es válido ':login'.", + 'reset_success' => "Su contraseña fue correctamente reiniciada.", + 'reset_error' => "La contraseña es inválida. Por favor, intente otra vez.", + 'reset_fail' => "No se puede reiniciar su contraseña.", + 'apply' => 'Aplicar', + 'cancel' => 'Cancelar', + 'delete' => 'Borrar', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => 'Tablero', + 'widget_label' => 'Módulo', + 'widget_width' => 'Ancho', + 'full_width' => 'Ancho completo', + 'add_widget' => 'Agregar módulo', + 'widget_inspector_title' => 'Configurar módulo', + 'widget_inspector_description' => 'Configurar el módulo de informe.', + 'widget_columns_label' => 'Ancho :columnas', + 'widget_columns_description' => 'Ancho del módulo, un número entre 1 y 10.', + 'widget_columns_error' => 'Por favor introduzca el ancho del módulo, un número entre 1 y 10.', + 'columns' => '{1} columna|[2,Inf] columnas', + 'widget_new_row_label' => 'Forzar nueva fila', + 'widget_new_row_description' => 'Coloca el módulo en una nueva fila.', + 'widget_title_label' => 'Título del módulo', + 'widget_title_error' => 'El título del módulo es requerido.', + 'status' => [ + 'widget_title_default' => 'Estado del sistema', + 'online' => 'online', + 'update_available' => '{0} actualizaciones disponibles!|{1} actualizaciones disponibles!|[2,Inf] actualizaciones disponibles!', + ] + ], + 'user' => [ + 'name' => 'Administrador', + 'menu_label' => 'Administradores', + 'menu_description' => 'Gestionar backend de administrador de usuarios, grupos y permisos.', + 'list_title' => 'Gestionar administradores', + 'new' => 'Nuevo administrador', + 'login' => "Acceso", + 'first_name' => "Nombre", + 'last_name' => "Apellido", + 'full_name' => "Nombre completo", + 'email' => "Email", + 'groups' => "Grupos", + 'groups_comment' => "Especifique a qué grupos pertenece esta persona.", + 'avatar' => "Avatar", + 'password' => "Contraseña", + 'password_confirmation' => "Confirmar contraseña", + 'superuser' => "Super administrador", + 'superuser_comment' => "Marque esta casilla para permitir que esta persona tenga acceso a todas las áreas.", + 'send_invite' => 'Enviar invitación por email.', + 'send_invite_comment' => 'Utilice esta casilla de verificación para enviar una invitación al usuario por email.', + 'delete_confirm' => 'Realmente desea eliminar este administrador?', + 'return' => 'Regresar a la lista de administradores', + 'allow' => 'Permitir', + 'inherit' => 'Heredar', + 'deny' => 'Denegar', + 'group' => [ + 'name' => 'Grupo', + 'name_field' => 'Nombre', + 'menu_label' => 'Grupos', + 'list_title' => 'Gestionar Grupos', + 'new' => 'Nuevo Grupo', + 'delete_confirm' => 'Realmente desea eliminar este grupo de administradores?', + 'return' => 'Regresar a la lista de grupos', + ], + 'preferences' => [ + 'not_authenticated' => 'No existe un usuario autenticado para cargar o guardar las preferencias.' + ] + ], + 'list' => [ + 'default_title' => 'Listar', + 'search_prompt' => 'Buscar...', + 'no_records' => 'No hay registros en esta lista.', + 'missing_model' => 'El comportamiento de lista utilizado en :class no tiene un modelo definido.', + 'missing_column' => 'No hay definiciones de columna para :columns.', + 'missing_columns' => 'La lista utilizada en :class no tiene columnas definidas.', + 'missing_definition' => "Comportamiento de lista no contiene una columna para ':field'.", + 'behavior_not_ready' => 'Comportamiento de lista no se ha inicializado, compruebe que ha llamado makeLists() en el controlador.', + 'invalid_column_datetime' => "Columna valor ':column' no es un objeto DateTime, has perdido la referencia \$dates en el Modelo?", + 'pagination' => 'Mostrando registros: :from-:to de :total', + 'prev_page' => 'Página anterior', + 'next_page' => 'Página siguiente', + 'loading' => 'Cargando...', + 'setup_title' => 'Configuración de la lista', + 'setup_help' => 'Utilice las casillas de verificación para seleccionar las columnas que desea ver en la lista. Puede cambiar la posición de las columnas arrastrándolas hacia arriba o hacia abajo.', + 'records_per_page' => 'Registros por página', + 'records_per_page_help' => 'Seleccione el número de registros por página para mostrar. Tenga en cuenta que un alto número de registros en una sola página puede reducir el rendimiento.', + ], + 'fileupload' => [ + 'attachment' => 'Adjunto', + 'help' => 'Añadir un título y una descripción para este Adjunto.', + 'title_label' => 'Título', + 'description_label' => 'Descripción' + ], + + 'form' => [ + 'create_title' => "Nuevo :name", + 'update_title' => "Editar :name", + 'preview_title' => "Vista previa :name", + 'create_success' => ':name ha sido creado con éxito.', + 'update_success' => ':name se ha actualizado correctamente.', + 'delete_success' => ':name se ha eliminado correctamente.', + 'missing_id' => "El formulario de registro de identificación no se ha especificado.", + 'missing_model' => 'El comportamiento del formulario utilizado en :class no tiene un modelo definido.', + 'missing_definition' => "El comportamiento de formulario no contiene un campo para':field'.", + 'not_found' => 'El registro de formulario con el ID :id no se pudo encontrar.', + 'create' => 'Crear', + 'create_and_close' => 'Crear y cerrar', + 'creating' => 'Creando...', + 'save' => 'Guardar', + 'save_and_close' => 'Guardar y cerrar', + 'saving' => 'Guardando...', + 'delete' => 'Borrar', + 'deleting' => 'Borrando...', + 'undefined_tab' => 'Misc', + 'field_off' => 'Off', + 'field_on' => 'On', + 'add' => 'Agregar', + 'apply' => 'Aplicar', + 'cancel' => 'Cancelar', + 'close' => 'Cerrar', + 'ok' => 'OK', + 'or' => 'o', + 'confirm_tab_close' => 'Realmente desea cerrar la cuenta? Se perderán los cambios no guardados.', + 'behavior_not_ready' => 'Por favor compruebe que ha llamado a la funcion initForm() en el controlador.', + 'preview_no_files_message' => 'Los archivos no fueron cargados.', + 'select' => 'Seleccionar', + 'select_all' => 'seleccionar todo', + 'select_none' => 'no seleccionar ninguno', + 'select_placeholder' => 'Seleccionar', + 'insert_row' => 'Insertar fila', + 'delete_row' => 'Eliminar fila', + 'concurrency-file-changed-title' => 'El archivo fue modificado', + 'concurrency-file-changed-description' => 'El archivo que se encuentra editando fue modificado por otro usuario. Puede recargar el archivo y perder los cambios o sobreescribir el archivo en el disco.', + 'reload' => 'Recargar', + ], + 'relation' => [ + 'missing_definition' => "Relación comportamiento no contiene una definición para ':field'.", + 'missing_model' => "Relación comportamiento utilizado en :class no tiene un modelo definido.", + 'invalid_action_single' => "Esta acción no se puede realizar en una relación singular.", + 'invalid_action_multi' => "Esta acción no se puede realizar en una relación múltiple.", + 'help' => "Haga clic en un elemento para añadir.", + 'related_data' => "Relacionar :name datos.", + 'add' => "Agregar", + 'add_selected' => "Agregar seleccionado", + 'add_a_new' => "Agregar un nuevo :name", + 'cancel' => "Cancelar", + 'add_name' => "Agregar :name", + 'create' => "Crear", + 'create_name' => "Crear :name", + 'update' => "Actualizar", + 'update_name' => "Actualizar :name", + 'remove' => "Remover", + 'remove_name' => "Remover :name", + 'delete' => "Borrar", + 'delete_name' => "Borrar :name", + 'delete_confirm' => "Está seguro?", + ], + 'model' => [ + 'name' => "Modelo", + 'not_found' => "No se pudo encontrar el modelo ':class' con el ID :id.", + 'missing_id' => "No se especificó un ID para encontrar el modelo guardado.", + 'missing_relation' => "El modelo ':class' no contiene una definición para ':relation'.", + 'invalid_class' => "El modelo :model utilizado en :class no es váildo, este debería heredar la clase del \Model.", + 'mass_assignment_failed' => "Asignación masiva falló para el atributo del modelo ':attribute'.", + ], + 'warnings' => [ + 'tips' => 'Consejos de configuración del sistema.', + 'tips_description' => 'Hay problemas que necesitan de su atención para configurar el sistema correctamente.', + 'permissions' => 'El directorio :name o los subdirectorios no se puede escribir por PHP. Por favor establezca los permisos correctos para el servidor web en este directorio.', + 'extension' => 'La extensión PHP :name no está instalada. Por favor instale esta librería y active la extensión.' + ], + 'editor' => [ + 'menu_label' => 'Preferencias del editor de código', + 'menu_description' => 'Configurar preferencias del editor de código, como el tamaño de la letra y el color del esquema.', + 'font_size' => 'Tamaño de la letra', + 'tab_size' => '>Tamaño de la solapa', + 'use_hard_tabs' => 'Espacio entre solapas', + 'code_folding' => 'Código plegable', + 'word_wrap' => 'Ajuste de línea', + 'highlight_active_line' => 'Resaltar línea activa', + 'show_invisibles' => 'Mostrar caracteres invisibles', + 'show_gutter' => 'Mostrar canal', + 'theme' => 'Color del esquema', + ], + 'tooltips' => [ + 'preview_website' => 'Vista previa de la página web' + ], + 'mysettings' => [ + 'menu_label' => 'Mi configuración', + 'menu_description' => 'Ajustes relacionados con su cuenta de administración', + ], + 'myaccount' => [ + 'menu_label' => 'Mi cuenta', + 'menu_description' => 'Actualizar información de su cuenta, como nombre, dirección de correo electrónico y contraseña.', + 'menu_keywords' => 'Inicio seguro' + ], + 'backend_preferences' => [ + 'menu_label' => 'Preferencias de backend', + 'menu_description' => 'Gestionar preferencias de idioma y la apariencia del backend.', + 'locale' => 'Idioma', + 'locale_comment' => 'Seleccione la localización para el uso del lenguaje.', + ], + 'access_log' => [ + 'hint' => 'Este registro muestra la lista de ingresos al panel de administración. Los registros se mantienen por un total de :days días.', + 'menu_label' => 'Registro de acceso', + 'menu_description' => 'Ver registro de ingresos al panel de administracion.', + 'created_at' => 'Fecha y hora', + 'login' => 'Acceso', + 'ip_address' => 'IP', + 'first_name' => 'Nombre', + 'last_name' => 'Apellido', + 'email' => 'Email', + ], + 'filter' => [ + 'all' => 'Todo' + ] +]; diff --git a/modules/backend/lang/es/lang.php b/modules/backend/lang/es/lang.php new file mode 100644 index 0000000..e8c0a25 --- /dev/null +++ b/modules/backend/lang/es/lang.php @@ -0,0 +1,541 @@ + [ + 'title' => 'Area de Administración' + ], + 'field' => [ + 'invalid_type' => 'El tipo de campo utilizado es inválido :type.', + 'options_method_not_exists' => 'El modelo clase: model debe definir un método: method() opciones recurrentes para el ":field" desde campo.' + ], + 'widget' => [ + 'not_registered' => "La clase del modulo ':name' no ha sido registrada", + 'not_bound' => "El módulo con la clase ':name' no se ha unido al controlador" + ], + 'page' => [ + 'untitled' => 'Sin título', + 'access_denied' => [ + 'label' => 'Acceso denegado', + 'help' => 'No tiene permisos necesarios para ver esta página.', + 'cms_link' => 'Volver al panel de administración' + ], + ], + 'partial' => [ + 'not_found_name' => "El parcial ':name' no se encuentra." + ], + 'account' => [ + 'sign_out' => 'Desconectarse', + 'login' => 'Entrar', + 'reset' => 'Restablecer', + 'restore' => 'Restaurar', + 'login_placeholder' => 'usuario', + 'password_placeholder' => 'contraseña', + 'forgot_password' => '¿Olvidó su clave?', + 'enter_email' => 'Ingrese su correo', + 'enter_login' => 'Ingrese su usuario', + 'email_placeholder' => 'correo', + 'enter_new_password' => 'Ingrese una nueva contraseña', + 'password_reset' => 'Restablecer la contraseña', + 'restore_success' => 'Correo electrónico enviado a su dirección con las instruciones.', + 'restore_error' => "No se ha encontrado el usuario ':login'", + 'reset_success' => 'Contraseña ha sido restablecida. Ahora puede iniciar sesión', + 'reset_error' => 'La información para restablecer la contraseña no es valida. ¡Por favor, vuelva a intentarlo!', + 'reset_fail' => '¡No es posible restablecer la contraseña!', + 'apply' => 'Aplicar', + 'cancel' => 'Cancelar', + 'delete' => 'Borrar', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Escritorio', + 'widget_label' => 'Módulo', + 'widget_width' => 'Ancho', + 'full_width' => 'ancho completo', + 'manage_widgets' => 'Gestionar modulos', + 'add_widget' => 'Agregar un módulo', + 'widget_inspector_title' => 'Configuración del módulo', + 'widget_inspector_description' => 'Configuración del módulo de reporte', + 'widget_columns_label' => 'Ancho :columns', + 'widget_columns_description' => 'El ancho del módulo, número entre 1 y 10.', + 'widget_columns_error' => 'Por favor, ingrese un número entre 1 y 10 para el ancho del módulo.', + 'columns' => '{1} columna|[2,Inf] columnas', + 'widget_new_row_label' => 'Forzar nueva línea', + 'widget_new_row_description' => 'Insertar el módulo en una nueva fila.', + 'widget_title_label' => 'Título del módulo', + 'widget_title_error' => 'El título del módulo es obligatorio.', + 'reset_layout' => 'Restablecer diseño', + 'reset_layout_confirm' => 'Restablecer diseño de vualta a los valores por defecto?', + 'reset_layout_success' => 'El diseño se ha restablecido', + 'make_default' => 'Predeterminar', + 'make_default_confirm' => 'Establecer el diseño actual por defecto?', + 'make_default_success' => 'Diseño actual es ahora el predeterminado', + 'status' => [ + 'widget_title_default' => 'Estado del sistema', + 'update_available' => '{0} actualizaciones disponibles!|{1} actualización disponible!|[2,Inf] actualizaciones disponibles!', + 'updates_pending' => 'Actualizaciones de software pendientes', + 'updates_nil' => 'Software está actualizado', + 'updates_link' => 'Actualiza', + 'warnings_pending' => 'Algunas incidencias necesitan atención', + 'warnings_nil' => 'No hay avisos a mostrar', + 'warnings_link' => 'Ver', + 'core_build' => 'Versión del sistema', + 'event_log' => 'Registro de eventos', + 'request_log' => 'Registro de peticiones', + 'app_birthday' => 'En línea desde' + ], + 'welcome' => [ + 'widget_title_default' => 'Bienvenido', + 'welcome_back_name' => 'Bienvenido de nuevo a :app, :name.', + 'welcome_to_name' => 'Bienvenido a :app, :name.', + 'first_sign_in' => 'Esta es la primera vez que ha iniciado sesión.', + 'last_sign_in' => 'Su última sesión fue', + 'view_access_logs' => 'Ver los registros de acceso', + 'nice_message' => '¡Que tengas un gran día!' + ] + ], + 'user' => [ + 'name' => 'Administrador', + 'menu_label' => 'Administradores', + 'menu_description' => 'Gestionar usuarios, grupos y permisos para el back-end.', + 'list_title' => 'Gestionar administradores', + 'new' => 'Nuevo Administrador', + 'login' => 'Entrar', + 'first_name' => 'Nombres', + 'last_name' => 'Apellidos', + 'full_name' => 'Nombre Completo', + 'email' => 'Correo', + 'groups' => 'Grupos', + 'groups_comment' => 'Especificar a que grupos debe pertenecer la cuenta. Los grupos definen permisos de usuario, que pueden reemplazar los de nivel de usuario, en la ficha permisos.', + 'avatar' => 'Avatar', + 'password' => 'Contraseña', + 'password_confirmation' => 'Confirmar Contraseña', + 'permissions' => 'Permisos', + 'account' => 'Cuenta', + 'superuser' => 'Super Usuario', + 'superuser_comment' => 'Permitir que esta cuenta tenga acceso a todas las áreas del sistema. Los super usuarios pueden añadir y gestionar otros usuarios.', + 'send_invite' => 'Enviar invitación por correo electrónico', + 'send_invite_comment' => 'Enviar una invitación conteniendo la información de inicio de sesión y contraseña.', + 'delete_confirm' => '¿Eliminar este administrador?', + 'return' => 'Regresar a la lista de administradores', + 'allow' => 'Permitir', + 'inherit' => 'Heredar', + 'deny' => 'Denegar', + 'group' => [ + 'name' => 'Grupo', + 'name_comment' => 'El nombre aparece en la lista de grupo en el formulario de crear/editar de Administrador.', + 'name_field' => 'Nombre', + 'description_field' => 'Descripción', + 'is_new_user_default_field_label' => 'Grupo por Defecto', + 'is_new_user_default_field' => 'Añadir a los nuevos administradores a este grupo por defecto', + 'code_field' => 'Código', + 'code_comment' => 'Entrar un código único para acceder a ella con la API.', + 'menu_label' => 'Gestionar Grupos', + 'list_title' => 'Gestionar Grupos', + 'new' => 'Nuevo Grupo', + 'delete_confirm' => '¿Eliminar este grupo de administradores?', + 'return' => 'Volver a la lista de grupos', + 'users_count' => 'Usuarios' + ], + 'preferences' => [ + 'not_authenticated' => 'No existe un usuario autenticado para cargar o guardar las preferencias para.', + ] + ], + 'list' => [ + 'default_title' => 'Lista', + 'search_prompt' => 'Buscar...', + 'no_records' => 'No hay registros en esta vista.', + 'missing_model' => 'El comportamiento de la lista utilizada en :class no tiene un modelo definido.', + 'missing_column' => 'No hay definiciones de columna para :columns.', + 'missing_columns' => 'Lista usada en :class no tiene lista columnas definidas.', + 'missing_definition' => "Comportamiento de la lista no contiene una columna para ':field'.", + 'missing_parent_definition' => "Comportamiento de la lista no contiene una definición para ':definition'.", + 'behavior_not_ready' => 'Comportamiento de la lista no inicializado, compruebe que han llamado makeLists() en el controlador.', + 'invalid_column_datetime' => "¿Valor de la columna ':column' no es un objeto DateTime, le falta una referencia de \$dates en el Modelo?", + 'pagination' => 'Registros visualizados: :from-:to de :total', + 'prev_page' => 'Página anterior', + 'next_page' => 'Página siguiente', + 'refresh' => 'Refrescar', + 'updating' => 'Actualizando...', + 'loading' => 'Cargando...', + 'setup_title' => 'Configurar lista', + 'setup_help' => 'Utilice las casillas de verificación para seleccionar las columnas que desea ver en la lista. Usted puede cambiar la posición de las columnas arrastrándolas arriba o hacia abajo.', + 'records_per_page' => 'Registros por página', + 'records_per_page_help' => 'Seleccione el número de registros por página para mostrar. Tenga en cuenta que un número alto de registros en una sola página puede reducir el rendimiento.', + 'check' => 'Comprueba', + 'delete_selected' => 'Eliminar seleccionados', + 'delete_selected_empty' => 'No hay registros seleccionados para eliminar.', + 'delete_selected_confirm' => '¿Borrar los registros seleccionados?', + 'delete_selected_success' => 'Eliminados los registros seleccionados.', + 'column_switch_true' => 'Sí', + 'column_switch_false' => 'No' + ], + 'fileupload' => [ + 'attachment' => 'Adjunto', + 'help' => 'Agregue un título y descripción al adjunto', + 'title_label' => 'Título', + 'description_label' => 'Descripción', + 'default_prompt' => 'Haz clic en %s o arrastra un archivo aquí para subir', + 'attachment_url' => 'URL Adjunto', + 'upload_file' => 'Subir archivo', + 'upload_error' => 'Error al subir.', + 'remove_confirm' => '¿Está seguro?', + 'remove_file' => 'Eliminar archivo' + ], + 'form' => [ + 'create_title' => 'Nuevo :name', + 'update_title' => 'Editar :name', + 'preview_title' => 'Vista previa de :name', + 'create_success' => ':name creado', + 'update_success' => ':name actualizado', + 'delete_success' => ':name borrado', + 'reset_success' => 'Restablecido con éxito', + 'missing_id' => 'No se ha especificado el identificador del registro de formulario.', + 'missing_model' => 'El comportamiento del formulario utilizado en :class no tiene un modelo definido.', + 'missing_definition' => "El comportamiento del formulario no contiene un campo para ':field'.", + 'not_found' => 'El registro del formulario con un ID de :id no se pudo encontrar.', + 'action_confirm' => '¿Está usted seguro?', + 'create' => 'Crear', + 'create_and_close' => 'Crear y cerrar', + 'creating' => 'Creando...', + 'creating_name' => 'Creando :name...', + 'save' => 'Guardar', + 'save_and_close' => 'Guardar y cerrar', + 'saving' => 'Guardando...', + 'saving_name' => 'Guardando :name...', + 'delete' => 'Borrar', + 'deleting' => 'Borrando...', + 'confirm_delete' => '¿Borrar registro?', + 'confirm_delete_multiple' => '¿Borrar los registros seleccionados?', + 'deleting_name' => 'Borrando :name...', + 'reset_default' => 'Restablecer por defecto', + 'resetting' => 'Restableciendo', + 'resetting_name' => 'Restableciendo :name', + 'undefined_tab' => 'Varios', + 'field_off' => 'Apagar', + 'field_on' => 'Encender', + 'add' => 'Agregar', + 'apply' => 'Aplicar', + 'cancel' => 'Cancelar', + 'close' => 'Cerrar', + 'confirm' => 'Confirmar', + 'reload' => 'Recargar', + 'complete' => 'Completo', + 'ok' => 'OK', + 'or' => 'o', + 'confirm_tab_close' => '¿Cerrar la pestaña? Se perderán los cambios no guardados.', + 'behavior_not_ready' => 'El comportamiento del formulario no se ha inicializado, compruebe que ha llamado initForm() en el controlador.', + 'preview_no_files_message' => 'Los archivos no se han subido', + 'preview_no_record_message' => 'No hay ningún registro seleccionado.', + 'select' => 'Seleccionar', + 'select_all' => 'seleccionar todo', + 'select_none' => 'no seleccionar ninguno', + 'select_placeholder' => 'por favor seleccione', + 'insert_row' => 'Agregar Fila', + 'insert_row_below' => 'Insertar fila debajo', + 'delete_row' => 'Borrar Fila', + 'concurrency_file_changed_title' => 'Archivo ha cambiado', + 'concurrency_file_changed_description' => "El archivo que está editando ha sido cambiado en el disco por otro usuario. Usted puede volver a cargar el archivo y perder los cambios o sobreescribir el archivo en el disco.", + 'return_to_list' => 'Volver a listado' + ], + 'recordfinder' => [ + 'find_record' => 'Buscar Registro' + ], + 'relation' => [ + 'missing_config' => "Relación de comportamiento no tiene ninguna configuración para ':config'.", + 'missing_definition' => "Relación de comportamiento no contiene una definición para ':field'.", + 'missing_model' => 'Relación de comportamiento utilizado en :class no tiene un modelo definido.', + 'invalid_action_single' => 'Esta acción no se puede realizar en una relación singular.', + 'invalid_action_multi' => 'Esta acción no se puede realizar en una relación múltiple.', + 'help' => 'Haga clic en un elemento para añadir.', + 'related_data' => 'Relacionar :name datos', + 'add' => 'Agregar', + 'add_selected' => 'Agregar seleccionado', + 'add_a_new' => 'Agregar un nuevo :name', + 'link_selected' => 'Vinculo selecionado', + 'link_a_new' => 'Vinculo a nuevo :name', + 'cancel' => 'Cancelar', + 'close' => 'Cerrar', + 'add_name' => 'Agregar :name', + 'create' => 'Crear', + 'create_name' => 'Crear :name', + 'update' => 'Actualizar', + 'update_name' => 'Actualizar :name', + 'preview' => 'Vista previa', + 'preview_name' => 'Vista previa :name', + 'remove' => 'Remover', + 'remove_name' => 'Remover :name', + 'delete' => 'Borrar', + 'delete_name' => 'Borrar :name', + 'delete_confirm' => '¿Está usted seguro?', + 'link' => 'Vincular', + 'link_name' => 'Vincular :name', + 'unlink' => 'Desvincular', + 'unlink_name' => 'Desvincular :name', + 'unlink_confirm' => '¿Está usted seguro?' + ], + 'reorder' => [ + 'default_title' => 'Reordenar registros', + 'no_records' => 'No existen registros disponibles para ordenar.' + ], + 'model' => [ + 'name' => 'Modelo', + 'not_found' => "Modelo ':class' con el ID :id no se pudo encontrar", + 'missing_id' => 'No se ha especificado un ID para encontrar el modelo guardado.', + 'missing_relation' => "Modelo ':class' no contiene una definición para ':relation'.", + 'missing_method' => "Modelo ':class' no contiene un método ':method'.", + 'invalid_class' => "Modelo :model utilizado en :class no es váildo, este debería heredar la clase del \Model.", + 'mass_assignment_failed' => "Asignación masiva falló para el atributo del Modelo ':attribute'." + ], + 'warnings' => [ + 'tips' => 'Consejos de configuración del sistema', + 'tips_description' => 'Hay problemas que necesitan de su atención para configurar el sistema correctamente.', + 'permissions' => 'Directorio :name o los subdirectorios no se puede escribir por PHP. Por favor establecer los permisos correctos para el servidor web en este directorio.', + 'extension' => 'La extensión PHP :name no está instalada. Por favor instalar esta librería y activar la extensión.' + ], + 'editor' => [ + 'menu_label' => 'Preferencias del Editor', + 'menu_description' => 'Configurar las preferencias del editor de código, como el tamaño de la letra y el color del esquema.', + 'font_size' => 'Tamaño de la letra', + 'tab_size' => 'Tamaño de la Solapa', + 'use_hard_tabs' => 'Espacio entre solapas', + 'code_folding' => 'Código Plegable', + 'code_folding_begin' => 'Marca comienzo', + 'code_folding_begin_end' => 'Marca comienzo y fin', + 'autocompletion' => 'Autocompletado', + 'word_wrap' => 'Ajuste de línea', + 'highlight_active_line' => 'Resaltar línea activa', + 'auto_closing' => 'Cerrado de etiquetas automático', + 'show_invisibles' => 'Mostrar caracteres invisibles', + 'show_gutter' => 'Mostrar numeros de línea', + 'basic_autocompletion' => 'Autocompletado Basico (Ctrl + Espacio)', + 'live_autocompletion' => 'Autocompletado en Vivo', + 'enable_snippets' => 'Activar uso de Snippets', + 'display_indent_guides' => 'Mostrar Guias de Identado', + 'show_print_margin' => 'Mostrar Margen de impresión', + 'mode_off' => 'Off', + 'mode_fluid' => 'Fluido', + '40_characters' => '40 Caracteres', + '80_characters' => '80 Caracteres', + 'theme' => 'Color del esquema', + 'markup_styles' => 'Estilos de marcado', + 'custom_styles' => 'Hoja de estilo personalizada', + 'custom styles_comment' => 'Estilos personalizados para incluir en el editor HTML.', + 'markup_classes' => 'Clases de marcado', + 'paragraph' => 'Párrafo', + 'link' => 'Enlace', + 'table' => 'Tabla', + 'table_cell' => 'Celda de Tabla', + 'image' => 'Imagen', + 'label' => 'Etiqueta', + 'class_name' => 'Nombre de Clase', + 'markup_tags' => 'Etiquetas de marcado', + 'allowed_empty_tags' => 'Permitir etiquetas vacias', + 'allowed_empty_tags_comment' => 'La lista de etiquetas que no se quitan cuando no tienen ningún contenido dentro.', + 'allowed_tags' => 'Etiquetas permitidas', + 'allowed_tags_comment' => 'La lista de etiquetas permitidas.', + 'no_wrap' => 'No envuelva las etiquetas', + 'no_wrap_comment' => 'La lista de etiquetas que no deben estar envueltas dentro de etiquetas de bloque.', + 'remove_tags' => 'Quitar etiquetas', + 'remove_tags_comment' => 'La lista de etiquetas que se eliminan junto con su contenido.' + ], + 'tooltips' => [ + 'preview_website' => 'Vista previa del sitio' + ], + 'mysettings' => [ + 'menu_label' => 'Mis configuraciones', + 'menu_description' => 'Configuraciones relacionadas con su cuenta' + ], + 'myaccount' => [ + 'menu_label' => 'Mi Cuenta', + 'menu_description' => 'Actualice la información de su cuenta, como nombre, dirección de correo electrónico y contraseña.', + 'menu_keywords' => 'Inicio de sesión de seguridad' + ], + 'branding' => [ + 'menu_label' => 'Personalizar back-end', + 'menu_description' => 'Perzonalizar el área de administración, así como el nombre, los colores y el logo.', + 'brand' => 'Marca', + 'logo' => 'Logo', + 'logo_description' => 'Subir un logo personalizado para usarlo en el back-end.', + 'app_name' => 'Nombre de la aplicación', + 'app_name_description' => 'Este nombre se mostrará en el título del back-end.', + 'app_tagline' => 'Eslogan', + 'app_tagline_description' => 'Se mostrará en la página de inicio de sesión del back-end.', + 'colors' => 'Colores', + 'primary_color' => 'Primario color', + 'secondary_color' => 'Secundario color', + 'accent_color' => 'Color de énfasis', + 'styles' => 'Estilos', + 'custom_stylesheet' => 'Hoja de estilo personalizada', + 'navigation' => 'Navegación', + 'menu_mode' => 'Estilo de Menú', + 'menu_mode_inline' => 'Inline', + 'menu_mode_tile' => 'Mosaicos', + 'menu_mode_collapsed' => 'Colapsado' + ], + 'backend_preferences' => [ + 'menu_label' => 'Preferencias del panel de administración', + 'menu_description' => 'Gestione la preferencia de idioma y la apariencia del panel.', + 'region' => 'Región', + 'code_editor' => 'Editor de Código', + 'timezone' => 'Zona horaria', + 'timezone_comment' => 'Ajustar las fechas mostradas a esta zona horaria.', + 'locale' => 'Idioma', + 'locale_comment' => 'Seleccione su localización deseada para el uso del idioma.' + ], + 'access_log' => [ + 'hint' => 'Este registro muestra la lista de ingresos al panel de administración. Los registros se mantienen por un total de :days días.', + 'menu_label' => 'Registro de acceso', + 'menu_description' => 'Ver registro de ingresos al panel de administracion.', + 'created_at' => 'Fecha y hora', + 'login' => 'Entrar', + 'ip_address' => 'IP', + 'first_name' => 'Nombre', + 'last_name' => 'Apellido', + 'email' => 'Correo' + ], + 'filter' => [ + 'all' => 'todo', + 'options_method_not_exists' => "La clase de modelo :model debe definir un método :method() para regresar opciones para el filtro ':filter'.", + 'date_all' => 'todo el período', + 'number_all' => 'todos los números' + ], + 'import_export' => [ + 'upload_csv_file' => '1. Subir un archivo CSV', + 'import_file' => 'Importar archivo', + 'first_row_contains_titles' => 'Primera fila contiene títulos de columna', + 'first_row_contains_titles_desc' => 'Dejelo activado si la primera fila en el CSV se utiliza como los títulos de columna.', + 'match_columns' => '2. Hacer coincidir las columnas del archivo con los campos de la base de datos', + 'file_columns' => 'Archivo de columnas', + 'database_fields' => 'Campos de base de datos', + 'set_import_options' => '3. Establecer opciones de importación', + 'export_output_format' => '1. Formato de salida de la exportación', + 'file_format' => 'Formato de archivo', + 'standard_format' => 'Formato estándar', + 'custom_format' => 'Formato personalizado', + 'delimiter_char' => 'Carácter delimitador', + 'enclosure_char' => 'Carácter recinto', + 'escape_char' => 'Carácter de escape', + 'select_columns' => '2. Seleccionar columnas a exportar', + 'column' => 'Columna', + 'columns' => 'Columnas', + 'set_export_options' => '3. Establecer opciones de exportación', + 'show_ignored_columns' => 'Mostrar columnas ignoradas', + 'auto_match_columns' => 'Auto coincidir columnas', + 'created' => 'Creado', + 'updated' => 'Actualizado', + 'skipped' => 'Omitido', + 'warnings' => 'Advertencias', + 'errors' => 'Errores', + 'skipped_rows' => 'Filas saltadas', + 'import_progress' => 'Progreso de Importación', + 'processing' => 'Procesando', + 'import_error' => 'Error de importación', + 'upload_valid_csv' => 'Por favor suba un archivo CSV valido.', + 'drop_column_here' => 'Soltar la columna aquí...', + 'ignore_this_column' => 'Ignora esta columna', + 'processing_successful_line1' => 'Proceso de exportación de archivo completada!', + 'processing_successful_line2' => 'El navegador ahora redirigirá a la descarga del archivo.', + 'export_progress' => 'Progreso de exportación', + 'export_error' => 'Error de exportación', + 'column_preview' => 'Previsualización de la columna', + 'file_not_found_error' => 'Archivo no encontrado', + 'empty_error' => 'No había datos suministrados para exportar', + 'empty_import_columns_error' => 'Por favor especificar algunas columnas a importar.', + 'match_some_column_error' => 'Por favor, coincida algunas columnas en primer lugar.', + 'required_match_column_error' => 'Por favor, especifique una coincidencia para el campo requerido :label.', + 'empty_export_columns_error' => 'Por favor especificar algunas columnas para exportar.', + 'behavior_missing_uselist_error' => 'Debe implementar el comportamiento del controlador ListController con la opción de exportación "useList" activada.', + 'missing_model_class_error' => 'Por favor especificar la propiedad modelClass para :type', + 'missing_column_id_error' => 'Falta identificador de la columna', + 'unknown_column_error' => 'Columna desconocida', + 'encoding_not_supported_error' => 'La codificación del Archivo fuente no se reconoce. Por favor, seleccione la opción de formato de archivo personalizado con la codificación correcta para importar el archivo.', + 'encoding_format' => 'Codificación de archivo', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Subir y gestionar contenidos multimedia - imágenes, vídeos, sonidos y documentos' + ], + 'mediafinder' => [ + 'label' => 'Buscador de multimedia', + 'default_prompt' => 'Haga clic en el botón %s para buscar un elemento multimedia', + ], + 'media' => [ + 'menu_label' => 'Medios', + 'upload' => 'Subir', + 'move' => 'Mover', + 'delete' => 'Eliminar', + 'add_folder' => 'Nueva carpeta', + 'search' => 'Buscar', + 'display' => 'Mostrar', + 'filter_everything' => 'Todo', + 'filter_images' => 'Imágenes', + 'filter_video' => 'Vídeo', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Documentos', + 'library' => 'Biblioteca', + 'size' => 'Tamaño', + 'title' => 'Título', + 'last_modified' => 'Última modificación', + 'public_url' => 'URL pública', + 'click_here' => 'Haz click aquí', + 'thumbnail_error' => 'Error generando la miniatura.', + 'return_to_parent' => 'Volver a la carpeta anterior', + 'return_to_parent_label' => 'Atrás ..', + 'nothing_selected' => 'No se ha seleccionado nada.', + 'multiple_selected' => 'Se han seleccionado varios elementos.', + 'uploading_file_num' => 'Subiendo :number archivo(s)...', + 'uploading_complete' => 'Subida completada', + 'uploading_error' => 'Error al subir', + 'type_blocked' => 'El tipo de archivo usado ha sido bloqueado por motivos de seguridad.', + 'order_by' => 'Ordenar por', + 'folder' => 'Carpeta', + 'no_files_found' => 'No se han encontrado archivos.', + 'delete_empty' => 'Por favor, selecciona los elementos que quieres eliminar.', + 'delete_confirm' => '¿Deseas eliminar los elementos seleccionados?', + 'error_renaming_file' => 'Error al renombrar el elemento.', + 'new_folder_title' => 'Nueva carpeta', + 'folder_name' => 'Nombre de la carpeta', + 'error_creating_folder' => 'Error al crear la carpeta', + 'folder_or_file_exist' => 'Ya existe un archivo o carpeta con este nombre.', + 'move_empty' => 'Por favor, selecciona los elementos que quieres mover.', + 'move_popup_title' => 'Mover archivos o carpetas', + 'move_destination' => 'Carpeta de destino', + 'please_select_move_dest' => 'Por favor, selecciona una carpeta de destino.', + 'move_dest_src_match' => 'Por favor, selecciona otra carpeta de destino.', + 'empty_library' => 'La biblioteca de medios está vacía. Sube archivos o crea carpetas para empezar.', + 'insert' => 'Insertar', + 'crop_and_insert' => 'Cortar e insertar', + 'select_single_image' => 'Por favor, selecciona sólo una imagen.', + 'selection_not_image' => 'El elemento seleccionado no es una imagen.', + 'restore' => 'Deshacer todos los cambios', + 'resize' => 'Redimensionar...', + 'selection_mode_normal' => 'Normal', + 'selection_mode_fixed_ratio' => 'Aspecto fijo', + 'selection_mode_fixed_size' => 'Tamaño fijo', + 'height' => 'Alto', + 'width' => 'Ancho', + 'selection_mode' => 'Modo de selección', + 'resize_image' => 'Redimensionar imagen', + 'image_size' => 'Tamaño de la imagen:', + 'selected_size' => 'Selección:' + ], +]; diff --git a/modules/backend/lang/et/lang.php b/modules/backend/lang/et/lang.php new file mode 100644 index 0000000..765ce9e --- /dev/null +++ b/modules/backend/lang/et/lang.php @@ -0,0 +1,561 @@ + [ + 'title' => 'Haldusliides' + ], + 'field' => [ + 'invalid_type' => 'Välja tüüpi :type pole olemas.', + 'options_method_invalid_model' => "Atribuut ':field' ei vasta ühelegi olemasolevale andmemudelile. Palun defineeri valikväärtuste funktioon :model andmemudelis.", + 'options_method_not_exists' => "Andmemudelis :model peab olema defineeritud funktsioon :method(), mis tagastab valikväärtused välja ':field' jaoks." + ], + 'widget' => [ + 'not_registered' => "Vidina klassinimi ':name' pole registreeritud", + 'not_bound' => "Vidin klassinimega ':name' pole seotud kontrolleriga" + ], + 'page' => [ + 'untitled' => 'Nimeta', + 'access_denied' => [ + 'label' => 'Juurdepääs keelatud', + 'help' => "Sul pole vajalikke õiguseid, et seda lehte näha.", + 'cms_link' => 'Tagasi haldusliidesesse' + ], + 'no_database' => [ + 'label' => 'Andmebaas puudub', + 'help' => "Haldusliidese kasutamiseks peab olemas seadistatud andmebaas. Enne jätkamist palun kontrolli andmebaasi seadistust.", + 'cms_link' => 'Tagasi kodulehele' + ], + ], + 'partial' => [ + 'not_found_name' => "Koodiblokki ':name' ei leitud." + ], + 'account' => [ + 'sign_out' => 'Logi välja', + 'login' => 'Logi sisse', + 'reset' => 'Lähtesta', + 'restore' => 'Taasta', + 'login_placeholder' => 'logi sisse', + 'password_placeholder' => 'parool', + 'forgot_password' => 'Unustasid parooli?', + 'enter_email' => 'Sisesta oma e-post', + 'enter_login' => 'Sisesta oma kasutajanimi', + 'email_placeholder' => 'e-post', + 'enter_new_password' => 'Siseta uus parool', + 'password_reset' => 'Parooli lähtestamine', + 'restore_success' => 'Sinu e-posti aadressile saadeti kiri juhistega.', + 'restore_error' => "Sellist kasutajat ei ole süsteemis: ':login'", + 'reset_success' => 'Parool on lähtestatud, võid nüüd oma uue parooli sisse logida.', + 'reset_error' => 'Sisestasid parooli lähtestamiseks vigased andmed. Palun proovi uuesti!', + 'reset_fail' => 'Parooli lähtestamine ebaõnnestus!', + 'apply' => 'Rakenda', + 'cancel' => 'Loobu', + 'delete' => 'Kustuta', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Töölaud', + 'widget_label' => 'Vidin', + 'widget_width' => 'Laius', + 'full_width' => 'täislaius', + 'manage_widgets' => 'Halda vidinaid', + 'add_widget' => 'Lisa vidin', + 'widget_inspector_title' => 'Vidina seaded', + 'widget_inspector_description' => 'Seadista töölaua vidin', + 'widget_columns_label' => 'Laius :columns', + 'widget_columns_description' => 'Vidina laius ekraanil, vahemikus 1 kuni 10.', + 'widget_columns_error' => 'Vidina laius peab olema täisarv vahemikus 1-10.', + 'columns' => '{1} veerg|[2,Inf] veergu', + 'widget_new_row_label' => 'Näita uuel real', + 'widget_new_row_description' => 'Näita vidinat alati uuel real.', + 'widget_title_label' => 'Vidina nimi', + 'widget_title_error' => 'Vidina nimi on kohustuslik.', + 'reset_layout' => 'Lähtesta paigutus', + 'reset_layout_confirm' => 'Lähtesta vidinate paigutus vaikeseadele?', + 'reset_layout_success' => 'Vidinate paigutus on lähtestatud', + 'make_default' => 'Määra vaikeseadeks', + 'make_default_confirm' => 'Kas soovid määrata praeguse vidinate paigutuse vaikeseadeks?', + 'make_default_success' => 'Praegune paigutus on nüüd vaikeseade.', + 'collapse_all' => 'Peida kõik', + 'expand_all' => 'Näita kõiki', + 'status' => [ + 'widget_title_default' => 'Süsteemi olek', + 'update_available' => '{0} uuendust saadval!|{1} uuendus saadaval!|[2,Inf] uuendust saadaval!', + 'updates_pending' => 'Ootel süsteemiuuendused', + 'updates_nil' => 'Süsteem on ajakohane', + 'updates_link' => 'Uuenda', + 'warnings_pending' => 'Mõned küsimused nõuavad tähelepanu', + 'warnings_nil' => 'Kõik on korras', + 'warnings_link' => 'Vaata', + 'core_build' => 'Süsteemi versioon', + 'event_log' => 'Sündmuste logi', + 'request_log' => 'Päringute logi', + 'app_birthday' => 'Süsteem on töös alates', + ], + 'welcome' => [ + 'widget_title_default' => 'Tere tulemast', + 'welcome_back_name' => ':app. Tere tulemast tagasi, :name.', + 'welcome_to_name' => ':app. Tere, :name.', + 'first_sign_in' => 'See on esimene kord kui oled sisse loginud.', + 'last_sign_in' => 'Sinu viimane sisselogimine oli', + 'view_access_logs' => 'Vaata juurdepääsu logi', + 'nice_message' => 'Kena päeva jätku!', + ] + ], + 'user' => [ + 'name' => 'Administraator', + 'menu_label' => 'Administraatorid', + 'menu_description' => 'Muuda haldusliidese kasutajaid, õiguseid ja gruppe.', + 'list_title' => 'Halda administraatoreid', + 'new' => 'Uus administraator', + 'login' => 'Logi sisse', + 'first_name' => 'Eesnimi', + 'last_name' => 'Perenimi', + 'full_name' => 'Täisnimi', + 'email' => 'E-post', + 'groups' => 'Grupid', + 'groups_comment' => 'Määra millistesse gruppidesse kasutaja kuulub. Grupid määravad ära kasutaja juurdepääsu õigused, mida on võimalik eralid seadistada ka õiguste alt.', + 'avatar' => 'Avatar', + 'password' => 'Parool', + 'password_confirmation' => 'Korda parooli', + 'permissions' => 'Õigused', + 'account' => 'Konto', + 'superuser' => 'Ülemkasutaja', + 'superuser_comment' => 'Ülemkasutajal on juurdepääs kogu süsteemile. Samuti on õigus luua uusi kasutajakontosid. ', + 'send_invite' => 'Saada kutse e-postiga', + 'send_invite_comment' => 'Saadat tervituskiri, mis sisaldab ka sisse logimiseks vajalikku kasutajanime ja parooli.', + 'delete_confirm' => 'Kustuta administraator?', + 'return' => 'Tagasin nimekirja', + 'allow' => 'Luba', + 'inherit' => 'Päritud', + 'deny' => 'Keela', + 'activated' => 'Aktiveeritud', + 'last_login' => 'Viimane sisselogimine', + 'created_at' => 'Loodud', + 'updated_at' => 'Muudetud', + 'group' => [ + 'name' => 'Grupp', + 'name_comment' => 'Grupi nime kuvatakse administraatori loomise ja muutmise vormides olevas gruppide nimekirjas.', + 'name_field' => 'Nimi', + 'description_field' => 'Kirjeldus', + 'is_new_user_default_field_label' => 'Vaikimisi grupp', + 'is_new_user_default_field_comment' => 'Uued kasutajad lisatakse automaatselt sellesse gruppi', + 'code_field' => 'Kood', + 'code_comment' => 'Unikaalne kood, mida kasutatakse süsteemisiseselt.', + 'menu_label' => 'Halda gruppe', + 'list_title' => 'Halda gruppe', + 'new' => 'Uus grupp', + 'delete_confirm' => 'Kusuta see grupp?', + 'return' => 'Tagasi nimekirja', + 'users_count' => 'Kasutajad' + ], + 'preferences' => [ + 'not_authenticated' => 'Puudub autoriseeritud kasutaja kellele seadeid laadida või salvestada.' + ] + ], + 'list' => [ + 'default_title' => 'Nimekiri', + 'search_prompt' => 'Otsi...', + 'no_records' => 'Siin vaates pole ühtegi kirjet.', + 'missing_model' => 'Klassis :class ei ole nimekirjade jaoks defineeritud andmemudelit.', + 'missing_column' => ':columns jaoks puuduvad veergude definitsioonid.', + 'missing_columns' => 'Klassis :class kasutatud nimekirjal puudvad veergude definitsioonid.', + 'missing_definition' => "':field' jaoks puudub nimekirja veeru definitsioon.", + 'missing_parent_definition' => "Nimekirjal puudub definitsioon ':definition' kohta.", + 'behavior_not_ready' => 'Nimekirjade funktsionaalsus pole initsialiseeritud, vaata üle, et makeLists() oleks kontrolleris välja kutsutud.', + 'invalid_column_datetime' => "Veeru väärtus ':column' ei ole DateTime objekt. Võibolla on andmemudelis puudu \$dates muutuja viide?", + 'pagination' => 'Kuvatud kirjeid: :from-:to. Kokku: :total', + 'first_page' => 'Esimene leht', + 'last_page' => 'Viimane leht', + 'prev_page' => 'Eelmine leht', + 'next_page' => 'Järgmine leht', + 'refresh' => 'Laadi uuesti', + 'updating' => 'Uuendan...', + 'loading' => 'Laen...', + 'setup_title' => 'Nimekirja seadistus', + 'setup_help' => 'Vali veerud, mida soovid näha nimekirjas. Veergude järjestust saad muuta lohistades neid üles-alla.', + 'records_per_page' => 'Kirjeid lehel', + 'records_per_page_help' => 'Vali kirjete arv, mida soovid ühel lehel kuvada. NB! mida rohkem kirjeid lehel kuvatakse, seda kauem võtab aega lehe laadimine.', + 'check' => 'Vali', + 'delete_selected' => 'Kustuta valitud', + 'delete_selected_empty' => 'Ühtegi kirjet ei valitud.', + 'delete_selected_confirm' => 'Kustuta valitud kirjed?', + 'delete_selected_success' => 'Valitud kirjed on kustutatud.', + 'column_switch_true' => 'Jah', + 'column_switch_false' => 'Ei' + ], + 'fileupload' => [ + 'attachment' => 'Manus', + 'help' => 'Manuse nimi ja kirjeldus.', + 'title_label' => 'Nimi', + 'description_label' => 'Kirjeldus', + 'default_prompt' => 'Faili üleslaadimiseks kliki %s või lohista fail siia', + 'attachment_url' => 'Manuse URL', + 'upload_file' => 'Lae fail üles', + 'upload_error' => 'Üleslaadimisel tekkis viga', + 'remove_confirm' => 'Oled sa kindel?', + 'remove_file' => 'Eemalda fail' + ], + 'form' => [ + 'create_title' => 'Loomine: :name', + 'update_title' => 'Muutmine: :name', + 'preview_title' => 'Eelvaade: :name', + 'create_success' => ':name loodud', + 'update_success' => ':name muudetud', + 'delete_success' => ':name kustutatud', + 'reset_success' => 'Lähtestamine edukas', + 'missing_id' => 'Vormis puudus kirje ID.', + 'missing_model' => 'Klassis :class ei ole vormi jaoks defineeritud andmemudelit.', + 'missing_definition' => "Väli ':field' ei ole vormis defineeritud.", + 'not_found' => 'Kirjet ID-ga :id ei leitud.', + 'action_confirm' => 'Oled sa kindel?', + 'create' => 'Loo', + 'create_and_close' => 'Loo ja sulge', + 'creating' => 'Loon...', + 'creating_name' => 'Loon objekti :name...', + 'save' => 'Salvesta', + 'save_and_close' => 'Salvesta ja sulge', + 'saving' => 'Salvestan...', + 'saving_name' => 'Salvestan objekti :name...', + 'deleting' => 'Kustutan...', + 'delete' => 'Kustuta', + 'confirm_delete' => 'Kustuta kirje?', + 'confirm_delete_multiple' => 'Kustuta valitud kirjed?', + 'deleting_name' => 'Kustutan objekti :name...', + 'reset_default' => 'Lähtesta vaikeväärtus', + 'resetting' => 'Lähtestan', + 'resetting_name' => 'Lähtestan objekti :name', + 'undefined_tab' => 'Muu', + 'field_off' => 'Ei', + 'field_on' => 'Jah', + 'add' => 'Lisa', + 'apply' => 'Rakenda', + 'cancel' => 'Loobu', + 'close' => 'Sulge', + 'confirm' => 'Kinnita', + 'reload' => 'Lae uuesti', + 'complete' => 'Lõpeta', + 'ok' => 'OK', + 'or' => 'või', + 'confirm_tab_close' => 'Sulge vaheleht? Salvestamata muudatused lähevad kaduma.', + 'behavior_not_ready' => 'Vormi funktsionaalsus pole initsialiseeritud, vaata üle, et initForm() oleks kontrolleris välja kutsutud.', + 'preview_no_files_message' => 'Ühtegi faili pole üles laetud.', + 'preview_no_media_message' => 'Ühtegi meediafaili pole valitud.', + 'preview_no_record_message' => 'Ühtegi kirjet pole valitud.', + 'select' => 'Vali', + 'select_all' => 'Vali kõik', + 'select_none' => 'vali ükski', + 'select_placeholder' => 'palun vali', + 'insert_row' => 'Lisa rida', + 'insert_row_below' => 'Lisa rida alla', + 'delete_row' => 'Kustuta rida', + 'concurrency_file_changed_title' => 'Faili on muudetud', + 'concurrency_file_changed_description' => "Teine kasutaja on muutnud sama faili, mida sina praegu muudad. Võid faili uuesti laadida ja sellega kaotada oma muudatused või kirjutada üle teise kasutaja muudatused.", + 'return_to_list' => 'Tagasi nimekirja' + ], + 'recordfinder' => [ + 'find_record' => 'Leia kirje', + 'cancel' => 'Loobu', + ], + 'pagelist' => [ + 'page_link' => 'Lehe link', + 'select_page' => 'Vali leht...' + ], + 'relation' => [ + 'missing_config' => "':config' jaoks puuduvad seoste definitsioonid.", + 'missing_definition' => "Välja ':field' jaoks puudub seose definitsioon.", + 'missing_model' => 'Klassis :class ei ole seoste jaoks defineeritud andmemudelit.', + 'invalid_action_single' => 'Üks-ühele seosega ei saa seda tegevust sooritada.', + 'invalid_action_multi' => 'Mitu-mitmele seosega ei saa seda tegevust sooritada.', + 'help' => 'Lisamiseks kliki kirjel', + 'related_data' => 'Seotud objekti andmed: :name', + 'add' => 'Lisa', + 'add_selected' => 'Lisa valitud', + 'add_a_new' => 'Lisa uus :name', + 'link_selected' => 'Lisa valitud', + 'link_a_new' => 'Lisa uus :name', + 'cancel' => 'Loobu', + 'close' => 'Sulge', + 'add_name' => 'Lisa :name', + 'create' => 'Loo', + 'create_name' => 'Loo :name', + 'update' => 'Uuenda', + 'update_name' => 'Uuenda objekti :name', + 'preview' => 'Eelvaade', + 'preview_name' => 'Objekti :name eelvaade', + 'remove' => 'Eemalda', + 'remove_name' => 'Eemalda :name', + 'delete' => 'Kustuta', + 'delete_name' => 'Kustuta :name', + 'delete_confirm' => 'Oled sa kindel?', + 'link' => 'Lisa seos', + 'link_name' => 'Lisa :name', + 'unlink' => 'Eemalda', + 'unlink_name' => 'Eemalda :name', + 'unlink_confirm' => 'Oled sa kindel?' + ], + 'reorder' => [ + 'default_title' => 'Muuda järjestust', + 'no_records' => 'Ühtegi kirjet ei leitud.' + ], + 'model' => [ + 'name' => 'Andmemudel', + 'not_found' => "Andmemudelit ':class' ID-ga :id ei leitud", + 'missing_id' => 'Andmemudeli ID väärtus puudub.', + 'missing_relation' => "Andmemudelil ':class' puudub definitsioon seosele ':relation'.", + 'missing_method' => "Andmemudelil ':class' puudub funktsioon ':method'.", + 'invalid_class' => "Klassis :class kasutatud andmemudel :model ei ole korrektne. See peab olema päritud klassist \Model.", + 'mass_assignment_failed' => "Andmemudeli atribuudi ':attribute' väärtuste määramine ebaõnnestus." + ], + 'warnings' => [ + 'tips' => 'Näpunäited süsteemi seadistamiseks', + 'tips_description' => 'Süsteemi õigeks seadistamiseks on vaja meeles pidada paari olulist aspekti.', + 'permissions' => 'PHP-l ei ole õigust kirjutada katallogi :name või selle alamkataloogidesse. Palun paranda kataloogide juurdepääsuõigused serveris.', + 'extension' => 'PHP laiendus :name ei ole paigaldatud. Süsteemi toimiseks on vajalik selle paigaldamine.', + 'plugin_missing' => 'Plugin :name on vajalik süsteemi toimimiseks, kuid seda pole paigaldatud. Palun paigalda see plugin.', + ], + 'editor' => [ + 'menu_label' => 'Tekstiredaktori seadistused', + 'menu_description' => 'Isikupärast kõikjal kasutatavaid redaktori seadeid, nagu teksti suurus ja värvivalik.', + 'font_size' => 'Teksti suurus', + 'tab_size' => 'Taande suurus', + 'use_hard_tabs' => 'Ära kasuta taandel tühikuid', + 'code_folding' => 'Koodi murdmine', + 'code_folding_begin' => 'Murdmise algus', + 'code_folding_begin_end' => 'Murdmise algus ja lõpp', + 'autocompletion' => 'Automaattäitmine', + 'word_wrap' => 'Sõnamurdmine', + 'highlight_active_line' => 'Tõsta aktiivne rida esile', + 'auto_closing' => 'Automaatselt sulge HTML tägid', + 'show_invisibles' => 'Näita peidetu märke', + 'show_gutter' => 'Näita jalust', + 'basic_autocompletion'=> 'Lihtne automaattäitmine (Ctrl + Space)', + 'live_autocompletion'=> 'Live automaattäitmine', + 'enable_snippets'=> 'Kasuta eeldefineeritud koodijuppe (Tab)', + 'display_indent_guides'=> 'Näide taande juhtjooni', + 'show_print_margin'=> 'Näita printimise juhtjooni', + 'mode_off' => 'Väljas', + 'mode_fluid' => 'Voolav', + '40_characters' => '40 tähemärki', + '80_characters' => '80 tähemärki', + 'theme' => 'Värvivalik', + 'markup_styles' => 'Markup stiilid', + 'custom_styles' => 'Kohandatud CSS', + 'custom styles_comment' => 'Kohandatud CSS reglid, mis lisada HTML redaktorile.', + 'markup_classes' => 'Markup klassid', + 'paragraph' => 'Lõik', + 'link' => 'Link', + 'table' => 'Tabel', + 'table_cell' => 'Tabeli lahter', + 'image' => 'Pilt', + 'label' => 'Silt', + 'class_name' => 'Klassi nimi', + 'markup_tags' => 'Markup tägid', + 'allowed_empty_tags' => 'Luba tühjad HTML tägid', + 'allowed_empty_tags_comment' => 'Nimekiri HTML tägidest, mida automaatselt ei eemaldata kui neis pole sisu.', + 'allowed_tags' => 'Lubatud HTML tägid', + 'allowed_tags_comment' => 'Nimekiri lubatud HTML tägidest.', + 'no_wrap' => 'HTML blokktägid', + 'no_wrap_comment' => 'Nimekiri HTML tägidest, mida ei ole automaatselt vaja panna blokktägide sisse.', + 'remove_tags' => 'Eemalda HTML tägid', + 'remove_tags_comment' => 'Nimekiri HTML tägidest, mis eemaldatakse automaatselt koos sisuga.' + ], + 'tooltips' => [ + 'preview_website' => 'Kodulehe eelvaade' + ], + 'mysettings' => [ + 'menu_label' => 'Minu seaded', + 'menu_description' => 'Sinu haldusliidese kontoga seonduvad seadistused' + ], + 'myaccount' => [ + 'menu_label' => 'Minu konto', + 'menu_description' => 'Muuda oma konto andmeid nagu nimi, e-posti aadress ja parool.', + 'menu_keywords' => 'parool konto turva sala' + ], + 'branding' => [ + 'menu_label' => 'Isikupärasta haldusliidest', + 'menu_description' => 'Muuda haldusliidese välimust (nt nimi, värvid, logo)', + 'brand' => 'Bränd', + 'logo' => 'Logo', + 'logo_description' => 'Lae üles logo, mida kasutada haldusliideses.', + 'app_name' => 'Haldusliidese nimi', + 'app_name_description' => 'Seda nime kuvatakse haldusliidese päises.', + 'app_tagline' => 'Tervitustekst', + 'app_tagline_description' => 'Seda teksti kuvatakse haldusliidesesse sisselogimisel.', + 'colors' => 'Värvid', + 'primary_color' => 'Peamine värv', + 'secondary_color' => 'Teine color', + 'accent_color' => 'Aktsendi color', + 'styles' => 'Stiilid', + 'custom_stylesheet' => 'Kohandatud CSS', + 'navigation' => 'Navigatsioon', + 'menu_mode' => 'Menüü stiil', + 'menu_mode_inline' => 'Järjekorras', + 'menu_mode_tile' => 'Kastid', + 'menu_mode_collapsed' => 'Minimaalne' + ], + 'backend_preferences' => [ + 'menu_label' => 'Haldusliidese seaded', + 'menu_description' => 'Muuda oma haldusliidese seadeid nagu keel jm.', + 'region' => 'Regioon', + 'code_editor' => 'Koodi redaktor', + 'timezone' => 'Ajatsoon', + 'timezone_comment' => 'Kuva kõiki kuupäevi selles ajatsoonis.', + 'locale' => 'Keel', + 'locale_comment' => 'Vali haldusliidese keel.' + ], + 'access_log' => [ + 'hint' => 'See logi sisaldab kõiki edukaid sisselogimisi haldusliidesesse. Andmeid hoitakse maksimaalselt :days päeva.', + 'menu_label' => 'Juurdepääsu logi', + 'menu_description' => 'Näita kõiki õnnestunud sisselogimisi.', + 'created_at' => 'Kuupäev', + 'login' => 'Kasutjanimi', + 'ip_address' => 'IP aaddress', + 'first_name' => 'Eesnimi', + 'last_name' => 'Perenimi', + 'email' => 'E-post' + ], + 'filter' => [ + 'all' => 'kõik', + 'options_method_not_exists' => "Andmemudelis :model peab olema defineeritud functioon :method(), mis tagastab valikud filtrile ':filter'.", + 'date_all' => 'kõik perioodid' + ], + 'import_export' => [ + 'upload_csv_file' => '1. Lae üles CSV fail', + 'import_file' => 'Impordi fail', + 'first_row_contains_titles' => 'Esimene rida sisaldab veerupäiseid', + 'first_row_contains_titles_desc' => 'Märgi see kast kui üleslaetavas CSV failis on esimesel real veergude nimed.', + 'match_columns' => '2. Ühenda failis olevad veerud andmebaasi väljadega', + 'file_columns' => 'Faili veerud', + 'database_fields' => 'Andmebaasi väljad', + 'set_import_options' => '3. Määra impordi valikud', + 'export_output_format' => '1. Ekspordi väljundi formaat', + 'file_format' => 'Failiformaat', + 'standard_format' => 'Tavaline', + 'custom_format' => 'Kohandatud', + 'delimiter_char' => 'Veergude eraldaja', + 'enclosure_char' => 'Veerud on ümbritsetud', + 'escape_char' => 'Paomärk', + 'select_columns' => '2. Vali veerud, mida eksportida', + 'column' => 'Veerg', + 'columns' => 'Veerud', + 'set_export_options' => '3. Määra ekspordi valikud', + 'show_ignored_columns' => 'Näita väljajätetud veergusid', + 'auto_match_columns' => 'Ühenda andmed automaatselt', + 'created' => 'Loodud', + 'updated' => 'Uuendatud', + 'skipped' => 'Vahelejäetud', + 'warnings' => 'Hoiatusi', + 'errors' => 'Vigu', + 'skipped_rows' => 'Vahelejäetud read', + 'import_progress' => 'Impordi progress', + 'processing' => 'Töötlen', + 'import_error' => 'Impordi viga', + 'upload_valid_csv' => 'Palun lae üles korrektne CSV fail.', + 'drop_column_here' => 'Lohista veerg siia...', + 'ignore_this_column' => 'Jäta see veerg vahele', + 'processing_successful_line1' => 'Faili loomise protsess lõpetatud!', + 'processing_successful_line2' => 'Veebilehitseja suunab kohe edasi faili allalaadimisele.', + 'export_progress' => 'Ekspordi progress', + 'export_error' => 'Ekspordi viga', + 'column_preview' => 'Veeru eelvaade', + 'file_not_found_error' => 'Faili ei leitud', + 'empty_error' => 'Eksportimiseks ei leitud andmeid', + 'empty_import_columns_error' => 'Impordiks peab valima vähemalt ühe veeru.', + 'match_some_column_error' => 'Palun seo mõni veerg andmebaasi väljaga.', + 'required_match_column_error' => 'Kohustuslik väli :label peab olema seotud.', + 'empty_export_columns_error' => 'Ekspordiks peab valima vähemalt ühe veeru.', + 'behavior_missing_uselist_error' => 'Kontrolleris peab olema kasutusel nimekirjade funktsionaalsus ning peab olema määratud "useList" valik.', + 'missing_model_class_error' => 'Palun määra andmemudeli klassi atribuudi tüüp: :type', + 'missing_column_id_error' => 'Puudu veeru ID', + 'unknown_column_error' => 'Tundmatu veerg', + 'encoding_not_supported_error' => 'Lähtefaili kodeering ei ole tuvastatav. Importimiseks määra kodeering kohandatud impordi seadete alt.', + 'encoding_format' => 'Faili kodeering', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Upload and manage media contents - images, videos, sounds, documents' + ], + 'mediafinder' => [ + 'label' => 'Media Finder', + 'default_prompt' => 'Click the %s button to find a media item' + ], + 'media' => [ + 'menu_label' => 'Media', + 'upload' => 'Upload', + 'move' => 'Move', + 'delete' => 'Delete', + 'add_folder' => 'Add folder', + 'search' => 'Search', + 'display' => 'Display', + 'filter_everything' => 'Everything', + 'filter_images' => 'Images', + 'filter_video' => 'Video', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Documents', + 'library' => 'Library', + 'size' => 'Size', + 'title' => 'Title', + 'last_modified' => 'Last modified', + 'public_url' => 'Download URL', + 'click_here' => 'Click here', + 'thumbnail_error' => 'Error generating thumbnail.', + 'return_to_parent' => 'Return to the parent folder', + 'return_to_parent_label' => 'Go up ..', + 'nothing_selected' => 'Nothing is selected.', + 'multiple_selected' => 'Multiple items selected.', + 'uploading_file_num' => 'Uploading :number file(s)...', + 'uploading_complete' => 'Upload complete', + 'uploading_error' => 'Upload failed', + 'type_blocked' => 'The file type used is blocked for security reasons.', + 'order_by' => 'Order by', + 'folder' => 'Folder', + 'no_files_found' => 'No files found by your request.', + 'delete_empty' => 'Please select items to delete.', + 'delete_confirm' => 'Delete the selected item(s)?', + 'error_renaming_file' => 'Error renaming the item.', + 'new_folder_title' => 'New folder', + 'folder_name' => 'Folder name', + 'error_creating_folder' => 'Error creating folder', + 'folder_or_file_exist' => 'A folder or file with the specified name already exists.', + 'move_empty' => 'Please select items to move.', + 'move_popup_title' => 'Move files or folders', + 'move_destination' => 'Destination folder', + 'please_select_move_dest' => 'Please select a destination folder.', + 'move_dest_src_match' => 'Please select another destination folder.', + 'empty_library' => 'It looks a bit empty here. Upload files or create folders to get started.', + 'insert' => 'Insert', + 'crop_and_insert' => 'Crop & Insert', + 'select_single_image' => 'Please select a single image.', + 'selection_not_image' => 'The selected item is not an image.', + 'restore' => 'Undo all changes', + 'resize' => 'Resize...', + 'selection_mode_normal' => 'Normal', + 'selection_mode_fixed_ratio' => 'Fixed ratio', + 'selection_mode_fixed_size' => 'Fixed size', + 'height' => 'Height', + 'width' => 'Width', + 'selection_mode' => 'Selection mode', + 'resize_image' => 'Resize image', + 'image_size' => 'Image size:', + 'selected_size' => 'Selected:' + ], +]; diff --git a/modules/backend/lang/fa/lang.php b/modules/backend/lang/fa/lang.php new file mode 100644 index 0000000..c16a11e --- /dev/null +++ b/modules/backend/lang/fa/lang.php @@ -0,0 +1,585 @@ + [ + 'title' => 'بخش مدیریت', + ], + 'field' => [ + 'invalid_type' => 'نوع فیلد :type نا معتبر می باشد.', + 'options_method_invalid_model' => "خصیصه ':field' به مدل معتبری اشاره نمی کند. گزینه مورد نظر را در مدل :model ایجاد نمایید.", + 'options_method_not_exists' => 'کلاس مدل :model باید شامل متد :method() باشد و گزینه های مورد نیاز ":field" را بازنشاند.', + ], + 'widget' => [ + 'not_registered' => "کلاس مربوط به ابزارک ':name' به سیستم معرفی نشده است", + 'not_bound' => "ابزارکی تعریف شده در کلاس با نام ':name' به هیچ کنترلری ارتباط داده نشده است", + ], + 'page' => [ + 'untitled' => "بدون عنوان", + 'access_denied' => [ + 'label' => "شما مجوز دسترسی ندارید", + 'help' => "شما مجوز لازم براس دسترسی به این صفحه را ندارید.", + 'cms_link' => "بازگشت به مدیریت", + ], + 'no_database' => [ + 'label' => 'پایگاه داده یافت نشد', + 'help' => "جهت استفاده از بخش مدیریت به یک پایگاه داده نیاز دارید. تنظیمات پایگاه داده را بررسی نموده و از نصب جدولها در آن اطمینان حاصل کنید.", + 'cms_link' => 'Return to the homepage' + ], + ], + 'partial' => [ + 'not_found_name' => "بخشی با نام ':name' یافت نشد.", + ], + 'account' => [ + 'signed_in_as' => 'وارد شده به عنوان :full_name', + 'sign_out' => 'خروج', + 'login' => 'ورود', + 'reset' => 'تنظیم مجدد', + 'restore' => 'بازنشاندن', + 'login_placeholder' => 'ورود', + 'password_placeholder' => 'کلمه عبور', + 'remember_me' => 'مرا به خاطر نگهدار', + 'forgot_password' => "کلمه عبور خود را فراموش کرده اید؟", + 'enter_email' => "پست الکترونیکی خود را وارد نمایید", + 'enter_login' => "نام کاربری خود را وارد نمایید", + 'email_placeholder' => "پست الکترونیکی", + 'enter_new_password' => "کلمه عبور جدید را وارد نمایید", + 'password_reset' => "بازنشاندن کلمه عبور", + 'restore_success' => "یک نامه به پست الکترونیکی شما جهت شروع عملیات بارگرداندن کلمه عبور ارسال شد.", + 'restore_error' => "کاربری با نام کاریری ':login' یافت نشد.", + 'reset_success' => "کلمه عبور شما بارگردانی شد و شما هم اکنون میتوانید وارد سیستم شوید.", + 'reset_error' => "اطلاعات رمز عبور نا معتبر است , لطفا مجددا تلاش نمایید!", + 'reset_fail' => "عدم توانایی در بازنشاندن کلمه عبور شما!", + 'apply' => 'اعمال کردن', + 'cancel' => 'انصراف', + 'delete' => 'حذف', + 'ok' => 'تایید', + ], + 'dashboard' => [ + 'menu_label' => 'میز کار', + 'widget_label' => 'ابزارک', + 'widget_width' => 'عرض', + 'full_width' => 'عرض کامل', + 'manage_widgets' => 'مدیرت ابزارک ها', + 'add_widget' => 'افزودن ابزارک', + 'widget_inspector_title' => 'تنظیمات ابزارک', + 'widget_inspector_description' => 'پیکر بندی ابزارک گزارشگیری', + 'widget_columns_label' => 'عرض :columns', + 'widget_columns_description' => 'عرض ابزارک باید عددی مابین 1 تا 10 باشد.', + 'widget_columns_error' => 'لطفا عرض ابزارک را عددی مابین 1 تا 10 وارد نمایید.', + 'columns' => '{1} ستون|[2,Inf] ستون ها', + 'widget_new_row_label' => 'تحمیل سطر جدید', + 'widget_new_row_description' => 'افزودن ابزارک در سطر جدید.', + 'widget_title_label' => 'عنوان ابزارک', + 'widget_title_error' => 'گزینه "عنوان ابزارک" حتما باید وارد شود.', + 'reset_layout' => 'تنظیم مجدد طرح بندی', + 'reset_layout_confirm' => 'آیا از تنظیم مجدد طرح بندی به حالت پیشفرض اطمینان دارید؟', + 'reset_layout_success' => 'تنطیم مجدد طرح بندی انجام شد.', + 'make_default' => 'استفاده به عنوان پیشفرض', + 'make_default_confirm' => 'آیا از استفاده طرح بندی کنونی به عنوان پیشفرض اطمینان دارید؟', + 'make_default_success' => 'طرح بندی کنونی به عنوان پیشفرض تایین شد.', + 'collapse_all' => 'بستن همه', + 'expand_all' => 'باز کردن همه', + 'status' => [ + 'widget_title_default' => 'وضعیت سیستم', + 'update_available' => '{0} به روز رسانی موجود است!|{1} به روز رسانی موجود است!|[2,Inf] به روز رسانی موجود است!', + 'updates_pending' => 'به روزرسانی جدید موجود است.', + 'updates_nil' => 'شما از آخرین نسخه استفاده می کنید.', + 'updates_link' => 'به روز رسانی', + 'warnings_pending' => 'مشکلی وجود دارد که نیاز به بررسی شما دارد.', + 'warnings_nil' => 'مشکلی جهت نمایش وجود ندارد', + 'warnings_link' => 'نمایش', + 'core_build' => 'ویرایش سیستم', + 'event_log' => 'گزارش رویداد ها', + 'request_log' => 'گزارش درخواست ها', + 'app_birthday' => 'نصب شده از', + ], + 'welcome' => [ + 'widget_title_default' => 'خوش آمدید', + 'welcome_back_name' => ':name به :app خوش آمدید.', + 'welcome_to_name' => ':name به :app خوش آمدید.', + 'first_sign_in' => 'اولین ورود شما به سیستم می باشد', + 'last_sign_in' => 'آخرین ورود شما', + 'view_access_logs' => 'نمایش گزارش دسترسی ها', + 'nice_message' => 'روز خوبی داشته باشید', + ] + ], + 'user' => [ + 'name' => 'مدیریت', + 'menu_label' => 'مدیران', + 'menu_description' => 'مدیریت کاربران , گروه ها و دسترسی های مدیران.', + 'list_title' => 'مدیریت مدیران', + 'new' => 'مدیر جدید', + 'login' => "ورود", + 'first_name' => "نام", + 'last_name' => "نام خانوادگی", + 'full_name' => "نام کامل", + 'email' => "ایمیل", + 'role_field' => 'نقش', + 'role_comment' => 'نقش ها، مجوز های کاربران را تعیین می کنند که توسط سطوح کاربرای در سربرگ مجوز ها می توانند مورد ارجحیت قرار گیرند و تغییر کنند.', + 'groups' => "گروه ها", + 'groups_comment' => "اختصاص به گروهی که این شخص به آن تعلق دارد.", + 'avatar' => "نمایه", + 'password' => "کلمه عبور", + 'password_confirmation' => "تکرار کلمه عبور", + 'permissions' => 'مجوز های دسترسی', + 'account' => 'حساب کاربری', + 'superuser' => "کاربر ممتاز", + 'superuser_comment' => "اگر میخواهید این شخص به تمام قسمت ها دسترسی داشته باشد این گزینه را فعال نمایید.", + 'send_invite' => 'دعوت نامه توسط پست الکترونیکی ارسال شود', + 'send_invite_comment' => 'جهت ارسال دعوت نامه به پست الکترونیکی این شخص این گزینه را فعال نمایید', + 'delete_confirm' => 'آیا از حذف این مدیر اطمینان دارید؟', + 'return' => 'بازگشت به لیست مدیران', + 'allow' => 'اجازه دسترسی', + 'inherit' => 'ارث بری', + 'deny' => 'عدم دسترسی', + 'activated' => 'فعال شده', + 'last_login' => 'آخرین ورود', + 'created_at' => 'ایجاد شده در', + 'updated_at' => 'ویرایش شده در', + 'group' => [ + 'name' => 'گروه', + 'name_field' => 'نام', + 'name_comment' => 'نام در لیست گروه های در فرم مدیریت در هنگام ویرایش یا ایجاد به نمایش در می آید.', + 'description_field' => 'توضیحات', + 'is_new_user_default_field_label' => 'گروه پیشفرض', + 'is_new_user_default_field_comment' => 'بطور پیشفرض مدیران جدید را در این گروه ایجاد کن.', + 'code_field' => 'کد', + 'code_comment' => 'کد یکتایی را جهت دسترسی به آن توسط API وارد نمایید.', + 'menu_label' => 'گروه ها', + 'list_title' => 'مدیریت گروه ها', + 'new' => 'گروه مدیریت جدید', + 'delete_confirm' => 'آیا از حذف این گروه از مدیران اطمینان دارید?', + 'return' => 'بازگشت به لیست گروه ها', + 'users_count' => 'کاربران' + ], + 'role' => [ + 'name' => 'نقش', + 'name_field' => 'نام', + 'name_comment' => 'نام در لیست نقشها در بخش مدیریت به نمایش در می آید.', + 'description_field' => 'توضیحات', + 'code_field' => 'کد', + 'code_comment' => 'کد منحصربفرد نقش را جهت دسترسی به آن توسط رابط برنامه نویسی وارد نمایید.', + 'menu_label' => 'مدیریت نقش ها', + 'list_title' => 'مدیریت نقش ها', + 'new' => 'نقش جدید', + 'delete_confirm' => 'آیا از حذف این نقش اطمینان دارید؟', + 'return' => 'بازگشت به لیست نقش ها', + 'users_count' => 'کاربران' + ], + 'preferences' => [ + 'not_authenticated' => 'هیچ کاربر ثبت شده ای جهت بارگذاری یا ذخیره تنظیمات وجود ندارد.' + ] + ], + 'list' => [ + 'default_title' => 'لیست', + 'search_prompt' => 'جستجو...', + 'no_records' => 'چیزی یافت نشد.', + 'missing_model' => 'هیچ مدلی برای لیست استفاده شده در کلاس :class تعریف نشده است.', + 'missing_column' => 'ستونی برای :columns تعریف نشده است.', + 'missing_columns' => 'ستونی برای لیست عریف شده در :class موجود نیست.', + 'missing_definition' => "در لیست تعریف شده ستونی برای ':field' موجود نیست.", + 'missing_parent_definition' => "کنترل کننده لیست شامل تعریف ':definition' نمی باشد.", + 'behavior_not_ready' => 'لسیت مقدار دهی اولیه شده است ، لطفا بررسی نمایید که متد makeLists() در کنترلر خود فراخوانی کرده باشید.', + 'invalid_column_datetime' => "ستون ':column' از نوع شی تاریخ نمی باشد ، لطفا بررسی نمایید که این ستون در مدل از نوع تاریخ تعریف شده باشد.", + 'pagination' => 'نمایش :from تا :to از :total مورد', + 'first_page' => 'اولین صفحه', + 'last_page' => 'آخرین صفحه', + 'prev_page' => 'صفحه قبل', + 'next_page' => 'صفحه بعد', + 'refresh' => 'بازنشانی', + 'updating' => 'درحال به روز رسانی...', + 'loading' => 'در حال بارگذاری...', + 'setup_title' => 'راه اندازی لیست', + 'setup_help' => 'ستون هایی را که میخواهید مشاهده نمایید را انتخاب نمایید. میتوانید محل قرار گیری ستونها را با جابجا نمودن آنها به .', + 'records_per_page' => 'مورد در هر صفحه', + 'records_per_page_help' => 'تعداد موارد نمایش داده شده در هر صفحه را انتخاب نمایید. لطفا توجه نمایید نمایش تعداد زیادی از موارد در هر صفحه از کارایی سیستم میکاهد.', + 'check' => 'بررسی', + 'delete_selected' => 'حذف انتخاب شده ها', + 'delete_selected_empty' => 'مورد جهت حذف انتخاب نشده است.', + 'delete_selected_confirm' => 'آیا میخواهید موارد انتخابی را حذف کنید؟', + 'delete_selected_success' => 'حدف موارد انخابی انجام شد.', + 'column_switch_true' => 'بله', + 'column_switch_false' => 'خیر' + ], + 'fileupload' => [ + 'attachment' => 'فایل ضمیمه', + 'help' => 'برای فایل ضمیمه عنوان و توضیح اختصاص بهری وارد نمایید.', + 'title_label' => 'عنوان', + 'description_label' => 'توضیحات', + 'default_prompt' => 'فایل را جهت ارسال به این نقطه بکشید و یا %s را کلیک کنید', + 'attachment_url' => 'نشانی پیوست', + 'upload_file' => 'ارسال فایل', + 'upload_error' => 'خطا در ارسال فایل', + 'remove_confirm' => 'آیا اطمینان دارید؟', + 'remove_file' => 'حذف فایل' + ], + 'form' => [ + 'create_title' => ":name جدید", + 'update_title' => "ویرایش :name", + 'preview_title' => "پیش نمایش :name", + 'create_success' => ':name با موفقیت ایجاد شد.', + 'update_success' => ':name با موفقیت به روز رسانی شد.', + 'delete_success' => ':name با موفقیت حذف شد.', + 'reset_success' => 'بازنشانی موفق بود', + 'missing_id' => "رکورد مشخصه (ID) برای فرم انتخاب نشده است.", + 'missing_model' => 'مدلی برای فرن تعریف شده در کلاس :class مشخص نشده است.', + 'missing_definition' => "فرم مورد نظر شامل فیلدی برای ':field' نمی باشد.", + 'not_found' => 'فرمی با مشخصه :id یافت نشد.', + 'action_confirm' => "آیا اطمینان دارید؟", + 'create' => 'ایجاد', + 'create_and_close' => 'ایجاد و خروج', + 'creating' => 'در حال ایجاد...', + 'creating_name' => 'درحال ایجاد :name...', + 'save' => 'ذخیره', + 'save_and_close' => 'ذخیره و خروج', + 'saving' => 'در حال ذخیره...', + 'saving_name' => 'درحال ذخیره :name...', + 'delete' => 'حذف', + 'deleting' => 'در حال حذف...', + 'confirm_delete' => 'آیا از حذف این مورد اطمینان دارید؟', + 'confirm_delete_multiple' => 'آیا از حذف موارد انتخاب شده اطمینان دارید؟', + 'deleting_name' => 'درحال حذف :name...', + 'reset_default' => 'بازگشت به پیش فرض', + 'resetting' => 'بازنشانی', + 'resetting_name' => 'بازنشانی name:', + 'undefined_tab' => 'متفرقه', + 'field_off' => 'بله', + 'field_on' => 'خیر', + 'add' => 'افزودن', + 'apply' => 'اعمال', + 'cancel' => 'انصراف', + 'close' => 'خروج', + 'confirm' => 'تایید', + 'reload' => 'بارگذاری مجدد', + 'complete' => 'تکمیل', + 'ok' => 'تایید', + 'or' => 'یا', + 'confirm_tab_close' => 'در صورت بستن این پنجره موارد ذخیره نشده از بین خواهند رفت. آیا از حذف شدن این پنجره اطمینان دارید؟', + 'behavior_not_ready' => 'فرم مور نظر مقدار دهی اولیه نشده است ، بررسی کنید که متد initForm() در کنترلر فرتخوانی شده باشد.', + 'preview_no_files_message' => 'فایلی جهت ارسال وجود ندارد', + 'preview_no_media_message' => 'رسانه ای انتخاب نشده است.', + 'preview_no_record_message' => 'موردی انتخاب نشده است.', + 'select' => 'انتخاب', + 'select_all' => 'انتخاب همه', + 'select_none' => 'هیچ کدام را انتخاب نکنید', + 'select_placeholder' => 'لطفا انتخاب نمایید', + 'insert_row' => 'افزودن سطر', + 'insert_row_below' => 'افزودن سطر بعد از', + 'delete_row' => 'حذف سطر', + 'concurrency_file_changed_title' => 'فایل تغییر کرد', + 'concurrency_file_changed_description' => 'فایلی که شما ویرایش کردید توسط کاربر دیگری تغییر یافته و ذخیره شده است. شما میتوانید فایل را مجددا بارگذاری نمایید و تغییراتی که اعمال کرده اید را از دست بدهید و یا تغییرات اعمال شده توسط آن کاربر را بین برده و فایل را بازنویسی نمایید.', + 'return_to_list' => 'بازگشت به لیست' + ], + 'recordfinder' => [ + 'find_record' => 'انتخاب مورد', + 'cancel' => 'انصراف', + ], + 'pagelist' => [ + 'page_link' => 'لینک صفحه', + 'select_page' => 'صفحه ای را انتخاب نمایید...' + ], + 'relation' => [ + 'missing_config' => "کنترل کننده ارتباطات پایگاه داده شامل تعریفی برای ':config' نمی باشد.", + 'missing_definition' => "در ارتباط مورد نظر فیلد ':field' وجود ندارد.", + 'missing_model' => "مدلی برای ارتباط موجود در :class وجود ندارد.", + 'invalid_action_single' => "این عمل در ارتباط یک تعرفه نمبتواند اعمال شود.", + 'invalid_action_multi' => "این عمل در ارتباط چند طرفه نمیتواند اعمال شود.", + 'help' => "بر روی یک گزینه کلیک کنید تا افزوده شود", + 'related_data' => "اطلاعات :name مرتبط", + 'add' => "افزودن", + 'add_selected' => "افرودن انتخاب شده ها", + 'add_a_new' => ":name جدید", + 'link_selected' => "لینک انتخاب شده ها", + 'link_a_new' => "لینک :name جدید", + 'cancel' => "انصراف", + 'close' => "بستن", + 'add_name' => "افزودن :name", + 'create' => "ایجاد", + 'create_name' => "ایجاد :name", + 'update' => "بروز رسانی", + 'update_name' => "بروز رسانی :name", + 'preview' => "پیش نمایش", + 'preview_name' => "پیش نمایش :name", + 'remove' => "حذف", + 'remove_name' => "حذف :name", + 'delete' => "حذف", + 'delete_name' => "حذف :name", + 'delete_confirm' => "آیا اطمینان دارید؟", + 'link' => "لینک", + 'link_name' => "لینک :name", + 'unlink' => "حذف لینک", + 'unlink_name' => "حذف لینک :name", + 'unlink_confirm' => "آبا اطمینان دارید؟", + ], + 'reorder' => [ + 'default_title' => 'مرتب سازی موارد', + 'no_records' => 'موردی جهت مرتب سازی یافت نشد.', + ], + 'model' => [ + 'name' => "مدل", + 'not_found' => "مدل ':class' با مشخصه ی :id یافت نشد", + 'missing_id' => "مشخصه ای برای مودل مورد نظر یافت نشد.", + 'missing_relation' => "مدل ':class' شامل تعریفی از ':relation'.", + 'missing_method' => "مدل ':class' متدی با نام ':method' ندارد.", + 'invalid_class' => "مدل :model استفاده شده در :class معتبر نمی باشد، این مدل باید از کلاس \Model ارث برده باشد.", + 'mass_assignment_failed' => "عدم توانایی در مقدار دهی ':attribute'.", + ], + 'warnings' => [ + 'tips' => 'راهنمایی پیکر بندی سیستم', + 'tips_description' => 'مشکلاتی در پیکربندی سیستم وجود دارد، شما باید تنظیمات زیر را بررسی نمایید.', + 'permissions' => 'پوشه :name یا یکی از زیر پوشه های آن برای PHP قابل نوشتن نیستند. لطفا تنظیمات این پوشه را تعییر دهید.', + 'extension' => 'افزونه PHP با نام :name نصب نشده است. لطفن این افزونه را نصب کرده و فعال نمایید.', + 'plugin_missing' => 'افزونه :name مورد نیاز است ولی نصب نشده. لطفا این افزونه را نصب کنید.', + ], + 'editor' => [ + 'menu_label' => 'تنظیمات ویرایشگر کد', + 'menu_description' => 'سفارشی سازی ویرایشگر کد، مانند اندازه فونت و رنگ بندی آن.', + 'font_size' => 'اندازه فونت', + 'tab_size' => 'اندازه کاراکتر TAB', + 'use_hard_tabs' => 'فاصله گذاری با استفاده از TAB', + 'code_folding' => 'بلاک بندی کدها', + 'code_folding_begin' => 'ابتدای علامت گذاری', + 'code_folding_begin_end' => 'ابتدا و انتهای علامت گذاری', + 'autocompletion' => 'تکمیل خودکار', + 'word_wrap' => 'چیدمان کلمات', + 'highlight_active_line' => 'مشخص نودن خط فعال', + 'auto_closing' => 'نشانه ها و کاراکترهای خاص بصورت خودکار بسته شوند', + 'show_invisibles' => 'نمایش کاراکتر های مخفی', + 'show_gutter' => 'نمایش نشانگر', + 'basic_autocompletion'=> 'تکمیل خودکار عمومی (Ctrl + Space)', + 'live_autocompletion'=> 'تکمیل خودکار زنده', + 'enable_snippets'=> 'فعال سازی قطعه کد ها (Tab)', + 'display_indent_guides'=> 'نمایش راهنمای تو رفتگی', + 'show_print_margin'=> 'نمایش حاشیه چاپ', + 'mode_off' => 'خاموش', + 'mode_fluid' => 'سیال', + '40_characters' => '40 کاراکتر', + '80_characters' => '80 کاراکتر', + 'theme' => 'رنگ بندی', + 'markup_styles' => 'سبک نشانه گذاری', + 'custom_styles' => 'شیوه نامه های سفارشی', + 'custom styles_comment' => 'شیوه نامه های سفارشی جهت وارد کردن در ویرایش گر HTML.', + 'markup_classes' => 'کلاس های نشانه گذاری', + 'paragraph' => 'پاراگراف', + 'link' => 'لینک', + 'table' => 'جدول', + 'table_cell' => 'سلول جدول', + 'image' => 'تصویر', + 'label' => 'برچسب', + 'class_name' => 'نام کلاس', + 'markup_tags' => 'تگ های نشانه گذاری', + 'allowed_empty_tags' => 'اجاره استفاده از تگ های خالی', + 'allowed_empty_tags_comment' => 'لیست تگ های ای که در صورت خالی بودن حذف نشوند.', + 'allowed_tags' => 'تگ های مجاز', + 'allowed_tags_comment' => 'لیست تگ های مجاز', + 'no_wrap' => 'تگ های بدون دربرگیرنده', + 'no_wrap_comment' => 'لیست تگ هایی که درون تک بلاک قرار نمیگیرند', + 'remove_tags' => 'تگ های غیر مجاز', + 'remove_tags_comment' => 'تگ هایی که در صورت وارد شدن در ویرایش گر با محتوی خود حذف می شوند', + 'toolbar_buttons' => 'دکمه های جعبه ابزار', + 'toolbar_buttons_comment' => 'دکمه های پیشفرض جهت نمایش در ویرایشگر.', + ], + 'tooltips' => [ + 'preview_website' => 'پیش نمایش وب سایت' + ], + 'mysettings' => [ + 'menu_label' => 'تنظیمات من', + 'menu_description' => 'تنظیمات مربوط به حساب کاربری شما', + ], + 'myaccount' => [ + 'menu_label' => 'حساب کاربری من', + 'menu_description' => 'به روز رسانی اطلاعات حساب کار بری شما مانند نام و کلمه عبور و ... .', + 'menu_keywords' => 'ورود امن' + ], + 'branding' => [ + 'menu_label' => 'شخصی سازی بخش مدیریت', + 'menu_description' => 'شخصی سازی بخش مدیریت مانند نام، رنگ ها و لوگو.', + 'brand' => 'برند', + 'logo' => 'لوگو', + 'logo_description' => 'لوگوی شخصی سازی شده خود را جهت استفاده در بخش مدیریت ارسال نمایید.', + 'app_name' => 'نام برنامه', + 'app_name_description' => 'این نام در بخش عنوان قسمت مدیریت نمایش داده می شود.', + 'app_tagline' => 'شعار برنامه', + 'app_tagline_description' => 'این شعار در قسمت ورود به بخش مدیریت نمایش داده می شود.', + 'colors' => 'رنگ ها', + 'primary_color' => 'اصلی color', + 'secondary_color' => 'ثانویه color', + 'accent_color' => 'Accent color', + 'styles' => 'شیوه نامه ها', + 'custom_stylesheet' => 'شیوه نامه های سفارشی', + 'navigation' => 'ناو بری', + 'menu_mode' => 'سبک منو', + 'menu_mode_inline' => 'آیکون در کنار', + 'menu_mode_tile' => 'آیکون در بالا', + 'menu_mode_collapsed' => 'جمع شونده' + ], + 'backend_preferences' => [ + 'menu_label' => 'تنظیمات مدیریت', + 'menu_description' => 'تنظیمات مربوط به زبان مربوط به قسمت مدیریت.', + 'region' => 'بخش', + 'code_editor' => 'ویرایشگر کد', + 'timezone' => 'منطقه زمانی', + 'timezone_comment' => 'تنطیم نمایش تاریخ زمانی در این محدوده', + 'locale' => 'زبان', + 'locale_comment' => 'زبان مورد نظر خود را انتخاب نمایید.', + ], + 'access_log' => [ + 'hint' => 'این لیست نشاندهنده ورود کاربران مدیر به سیستم می باشد. موارد برای مدت :days روز نگهداری می شوند.', + 'menu_label' => 'ثبت دسترسی ها', + 'menu_description' => 'نمایش لیست ورود موفقیت آمیز کاربران مدیر.', + 'created_at' => 'زمان و تاریخ', + 'login' => 'ورود', + 'ip_address' => 'نشانی IP', + 'first_name' => 'نام', + 'last_name' => 'نام خانوادگی', + 'email' => 'پست الکترونیکی', + ], + 'filter' => [ + 'all' => 'همه', + 'options_method_not_exists' => "مدل :model باید شامل متدی به نام :method() باشد که گزینه های ':filter' را بازگرداند.", + 'date_all' => 'تمام دوره های زمانی', + 'number_all' => 'همه شماره ها', + ], + 'import_export' => [ + 'upload_csv_file' => '1. ارسال فایل CSV.', + 'import_file' => 'درورن ریزی فایل', + 'first_row_contains_titles' => 'سطر اول شامل عنوان ستون ها می باشد', + 'first_row_contains_titles_desc' => 'اگر سطر اول فایل CSV حاوی عنوان ستون ها می باشد این گزینه را انتخاب نمایید.', + 'match_columns' => '2. مطابقت سازی ستون های فایل با فیلد های پایگاه داده', + 'file_columns' => 'ستون های فایل', + 'database_fields' => 'فیلد های پایگاه داده', + 'set_import_options' => '3. تنظیم گزینه های درون ریزی', + 'export_output_format' => '1. قالب خروجی برون ریزی', + 'file_format' => 'نوع فایل', + 'standard_format' => 'قالب استاندارد', + 'custom_format' => 'قالب سفارشی', + 'delimiter_char' => 'کاراکار جدا کننده', + 'enclosure_char' => 'کاراکتر Enclosure', + 'escape_char' => 'کاراکتر Escape', + 'select_columns' => '2. انتخاب ستون ها جهت برون ریزی', + 'column' => 'ستون', + 'columns' => 'ستون ها', + 'set_export_options' => '3. تنظیم گزینه های برون ریزی', + 'show_ignored_columns' => 'نمایش ستون های نادیده گرفته شده', + 'auto_match_columns' => 'مطابقت خودکار ستون ها', + 'created' => 'ایجاد شده', + 'updated' => 'به روز رسانی شده', + 'skipped' => 'نادیده گرفته شده', + 'warnings' => 'هشدار ها', + 'errors' => 'خطاها', + 'skipped_rows' => 'سطر های نادیده گرفته شده', + 'import_progress' => 'پردازش درون ریزی', + 'processing' => 'در حال پردازش', + 'import_error' => 'خطا در درون ریزی', + 'upload_valid_csv' => 'لطفا فایل CSV معتبری را ارسال نمایید', + 'drop_column_here' => 'ستون را این جا بکشید...', + 'ignore_this_column' => 'این ستون را نادیده بگیر', + 'processing_successful_line1' => 'عملیات برون ریزی فایل با موفقیت انجام شد', + 'processing_successful_line2' => 'مرورگر به صورت خودکار به نشانی دانلود فایل هدایت خواهد شد. ', + 'export_progress' => 'پردازش برون ریزی', + 'export_error' => 'خطا در ایجاد خروجی', + 'column_preview' => 'پیش نمایش ستون', + 'file_not_found_error' => 'فایل یافت نشد', + 'empty_error' => 'داده ای جهت ایجاد خروجی وجود ندارد', + 'empty_import_columns_error' => 'لطفا نام ستون جهت درون ریزی را انتخاب نمایید.', + 'match_some_column_error' => 'لطفا ستون ها را مطابقت دهید', + 'required_match_column_error' => 'لطفا موردی را جهت :label که مورد نیاز می باشد را مطابقت دهید.', + 'empty_export_columns_error' => 'لطفا ستون هایی را که میخواهید در فایل برون ریزی استفاده شوند را انتخاب نمایید.', + 'behavior_missing_uselist_error' => 'حهت برون ریزی باید کنترلر از ListController در لیست کنترل کننده ها استفاده نماید.', + 'missing_model_class_error' => 'لطفا کلاس مدل :type را مشخص نمایید.', + 'missing_column_id_error' => 'مشخصه ستون یافت نشد', + 'unknown_column_error' => 'ستون نا مشخص', + 'encoding_not_supported_error' => 'نوع کدینگ فایل منبع قابل شناسایی نمی باشد. لطفا جهت درون ریزی نوع انکدینگ فایل را انتخاب نمایید.', + 'encoding_format' => 'کدینگ فایل', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'مدیریت چند رسانه ها' + ], + 'mediafinder' => [ + 'label' => 'جستجوگر رسانه', + 'default_prompt' => '%s را جهت انتخاب فایل چند رسانه ای انتخاب کنید' + ], + 'media' => [ + 'menu_label' => 'چند رسانه ای', + 'upload' => 'ارسال', + 'move' => 'جابجایی', + 'delete' => 'حذف', + 'add_folder' => 'پوشه جدید', + 'search' => 'جستجو', + 'display' => 'نمایش', + 'filter_everything' => 'همه', + 'filter_images' => 'تصاویر', + 'filter_video' => 'ویدیو', + 'filter_audio' => 'صوتی', + 'filter_documents' => 'اسناد', + 'library' => 'کتاب خانه', + 'size' => 'اندازه', + 'title' => 'عنوان', + 'last_modified' => 'آخرین تغییرات', + 'public_url' => 'نشانی عمومی', + 'click_here' => 'اینجا کلیک کنید', + 'thumbnail_error' => 'خطا در ایجاد تصویر بند انگشتی', + 'return_to_parent' => 'بازگشت به پوشه قبل', + 'return_to_parent_label' => 'بازگشت ..', + 'nothing_selected' => 'چیزی انتخاب نشده است.', + 'multiple_selected' => 'چند مورد انتخاب شده است.', + 'uploading_file_num' => 'ارسال :number فایل(ها)...', + 'uploading_complete' => 'ارسال انجام شد', + 'uploading_error' => 'خطا در ارسال', + 'type_blocked' => 'نوع فایل استفاده شده به دلیل مسایل امنیتی مجاز نمی باشد..', + 'order_by' => 'مرتب سازی با', + 'direction' => 'جهت', + 'direction_asc' => 'صعودی', + 'direction_desc' => 'نزولی', + 'folder' => 'پوشه', + 'no_files_found' => 'فایلی با درخواست شما یافت نشد', + 'delete_empty' => 'لطفا موارد را جهت حذف انتخاب نمایید', + 'delete_confirm' => 'آیا از حذف مورد(های) انتخاب شده اطمینان دارید؟', + 'error_renaming_file' => 'خطا در تغییر نام.', + 'new_folder_title' => 'پوشه ی جدید', + 'folder_name' => 'نام پوشه', + 'error_creating_folder' => 'خطا در ایجاد پوشه', + 'folder_or_file_exist' => 'پوشه یا فایلی با نام وارد شده از قبل وجود دارد.', + 'move_empty' => 'لطفا موارد را جهت جابجایی انتخاب نمایید', + 'move_popup_title' => 'جابحایی فایل یا پوشه ها', + 'move_destination' => 'پوشه مقصد', + 'please_select_move_dest' => 'لطفا پوشه مقصد را انتخاب نمائید.', + 'move_dest_src_match' => 'لطفا پوشه دیگری را انتخاب نمایید.', + 'empty_library' => 'اینجا کمی خالی به نظر می رسد. برای شروع فایل هایتان را بارگذاری کنید یا پوشه ای بسازید.', + 'insert' => 'قرار دادن', + 'crop_and_insert' => 'بریدن و افزودن', + 'select_single_image' => 'لطفا یک تصویر انتخاب نمایید', + 'selection_not_image' => 'مورد انتخاب شده تصویر نمی باشد', + 'restore' => 'حذف همه تغییرات', + 'resize' => 'تغییر اندازه...', + 'selection_mode_normal' => 'معمولی', + 'selection_mode_fixed_ratio' => 'نسبت ثابت', + 'selection_mode_fixed_size' => 'اندازه ثابت', + 'height' => 'ارتفاع', + 'width' => 'عرض', + 'selection_mode' => 'حالت انتخابی', + 'resize_image' => 'تغییر اندازه تصویر', + 'image_size' => 'اندازه تصویر:', + 'selected_size' => 'انتخاب شده:' + ] +]; diff --git a/modules/backend/lang/fi/lang.php b/modules/backend/lang/fi/lang.php new file mode 100644 index 0000000..7e0afd7 --- /dev/null +++ b/modules/backend/lang/fi/lang.php @@ -0,0 +1,584 @@ + [ + 'title' => 'Ylläpitoalue' + ], + 'field' => [ + 'invalid_type' => 'Kentän tyyppi :type ei ole sallittu.', + 'options_method_invalid_model' => "Attribuutti ':field' ratkaise kelvollista mallia. Spesifioit vaihtoehtoinen metodi mallille :model explisiittisesti.", + 'options_method_not_exists' => "Luokan :model täytyy määritellä metodi :method(), joka palauttaa ':field' lomakekentän ehdot." + ], + 'widget' => [ + 'not_registered' => "Vimpaimen luokan nimi ':name' ei ole rekisteröity", + 'not_bound' => "Vimpaimen luokkaa nimellä ':name' ei ole löydetty ohjaimeen" + ], + 'page' => [ + 'untitled' => 'Nimetön', + 'access_denied' => [ + 'label' => 'Pääsy kielletty', + 'help' => "Sinulla ei ole tarvittavia oikeuksia tälle sivulle.", + 'cms_link' => 'Palaa ylläpitopuolelle' + ], + 'no_database' => [ + 'label' => 'Tietokanta puuttuu', + 'help' => "Tietokanta on pakollinen. Varmista, että tietokanta on olemassa ja pystyssä kunnes kokeilet uudelleen.", + 'cms_link' => 'Palaa kotisivulle' + ], + ], + 'partial' => [ + 'not_found_name' => "Osiota ':name' ei löydy." + ], + 'account' => [ + 'signed_in_as' => 'Kirjauduit nimellä :full_name', + 'sign_out' => 'Kirjaudu ulos', + 'login' => 'Kirjaudu', + 'reset' => 'Nollaa', + 'restore' => 'Palauta', + 'login_placeholder' => 'tunnus', + 'password_placeholder' => 'salasana', + 'remember_me' => 'Pysy kirjautuneena', + 'forgot_password' => 'Unohditko salasanasi?', + 'enter_email' => 'Kirjoita sähköpostiosoitteesi', + 'enter_login' => 'Kirjautumisesi', + 'email_placeholder' => 'sähköposti', + 'enter_new_password' => 'Anna uusi salasana', + 'password_reset' => 'Salasanan nollaus', + 'restore_success' => 'Viesti on lähetetty sähköpostiosoitteeseesi. Seuraa ohjeita.', + 'restore_error' => "':login' nimistä käyttäjää ei löydy.", + 'reset_success' => 'Salasana nollattu. Voit kirjautua nyt sisään.', + 'reset_error' => 'Virheellinen salasanan nollausdata. Ole hyvä ja yritä uudelleen!', + 'reset_fail' => 'Salasanaasi ei voida nollata!', + 'apply' => 'Käytä', + 'cancel' => 'Peruuta', + 'delete' => 'Poista', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Dashboard', + 'widget_label' => 'Vimpain', + 'widget_width' => 'Leveys', + 'full_width' => 'täysleveä', + 'manage_widgets' => 'Hallinnoi vimpaimia', + 'add_widget' => 'Lisää vimpain', + 'widget_inspector_title' => 'Vimpainten konfigurointi', + 'widget_inspector_description' => 'Konfiguroi raporttivimpain', + 'widget_columns_label' => 'Leveys :columns', + 'widget_columns_description' => 'Vimpaimen leveys, numero 1 ja 10 väliltä.', + 'widget_columns_error' => 'Anna vimpaimen leveys numeerisena 1–10 väliltä.', + 'columns' => '{1} palsta|[2,Inf] palstaa', + 'widget_new_row_label' => 'Pakota uusi rivi', + 'widget_new_row_description' => 'Laita vimpain uudelle riville.', + 'widget_title_label' => 'Vimpaimen nimi', + 'widget_title_error' => 'Vimpaimen nimi on pakollinen.', + 'reset_layout' => 'Nollaa ulkoasu', + 'reset_layout_confirm' => 'Palauta oletusulkoasu?', + 'reset_layout_success' => 'Ulkoasu on palautettu', + 'make_default' => 'Aseta oletukseksi', + 'make_default_confirm' => 'Tee nykyisestä ulkoasusta oletus?', + 'make_default_success' => 'Nykyinen ulkoasu on nyt oletus', + 'collapse_all' => 'Kutista kaikki', + 'expand_all' => 'Laajenna kaikki', + 'status' => [ + 'widget_title_default' => 'Järjestelmän tila', + 'update_available' => '{0} päivitystä saatavilla!|{1} päivitys saatavilla!|[2,Inf] päivitystä saatavilla!', + 'updates_pending' => 'Odottavat ohjelmistopäivitykset', + 'updates_nil' => 'Ohjelmisto on ajantasalla', + 'updates_link' => 'Päivitä', + 'warnings_pending' => 'Muutama asia vaatii huomiotasi', + 'warnings_nil' => 'Ei varoituksia näytettäväksi', + 'warnings_link' => 'Näytä', + 'core_build' => 'Järjestelmän versio', + 'event_log' => 'Tapahtumaloki', + 'request_log' => 'Pyyntöloki', + 'app_birthday' => 'Linjoilla alkaen', + ], + 'welcome' => [ + 'widget_title_default' => 'Tervetuloa', + 'welcome_back_name' => 'Tervetuloa takaisin :app, :name.', + 'welcome_to_name' => 'Tervetuloa takaisin :app, :name.', + 'first_sign_in' => 'Tämä on ensimmäinen kirjautumisesi.', + 'last_sign_in' => 'Viimeisin kirjautumisesi', + 'view_access_logs' => 'Tarkastele kirjautumislokiasi', + 'nice_message' => 'Hauskaa päivää!', + ] + ], + 'user' => [ + 'name' => 'Ylläpitäjä', + 'menu_label' => 'Ylläpitäjät', + 'menu_description' => 'Hallinnoi ylläpitäjiä, ryhmiä ja oikeuksia.', + 'list_title' => 'Hallinnoi ylläpitäjiä', + 'new' => 'Uusi Ylläpitäjä', + 'login' => 'Kirjautumistunnus', + 'first_name' => 'Etunimi', + 'last_name' => 'Sukunimi', + 'full_name' => 'Koko nimi', + 'email' => 'Sähköposti', + 'role_field' => 'Rooli', + 'role_comment' => 'Rooli määrittelee käyttöoikeustason, joka voidaan yliajaa käyttäjätasolla Oikeudet välilehdellä.', + 'groups' => 'Ryhmät', + 'groups_comment' => 'Valitse ryhmät, joihin tilin tulisi kuulua. Ryhmät määrittelevät oikeudet, jotka voidaan yliajaa käyttäjäkohtaisesti Oikeudet välilehdeltä.', + 'avatar' => 'Avatar', + 'password' => 'Salasana', + 'password_confirmation' => 'Vahvista salasana', + 'permissions' => 'Oikeudet', + 'account' => 'Tili', + 'superuser' => 'Superkäyttäjä', + 'superuser_comment' => 'Anna tilille rajoittamattomat pääkäyttäjän oikeudet. Pääkäyttäjä voi hallinnoida käyttäjiä. ', + 'send_invite' => 'Lähetä kutsu sähköpostitse', + 'send_invite_comment' => 'Lähetä tervetuloviesti kirjautumistiedoilla.', + 'delete_confirm' => 'Poista tämä ylläpitäjä?', + 'return' => 'Palaa ylläpitäjälistaukseen', + 'allow' => 'Salli', + 'inherit' => 'Periytä', + 'deny' => 'Kiellä', + 'activated' => 'Aktivoitu', + 'last_login' => 'Viimeisin kirjautuminen', + 'created_at' => 'Luontipäivä', + 'updated_at' => 'Päivityspäiväys', + 'group' => [ + 'name' => 'Ryhmä', + 'name_comment' => 'Nimi näytetään ryhmän listauksessa Luo/Muokkaa ylläpitolomakkeella.', + 'name_field' => 'Nimi', + 'description_field' => 'Kuvaus', + 'is_new_user_default_field_label' => 'Oletusryhmä', + 'is_new_user_default_field_comment' => 'Lisää uudet ylläpitäjät tähän ryhmään automaattisesti', + 'code_field' => 'Koodi', + 'code_comment' => 'Lisää uniikkikoodi jolla päästään ryhmäobjektin API:in.', + 'menu_label' => 'Hallinnoi ryhmiä', + 'list_title' => 'Hallinnoi ryhmiä', + 'new' => 'Uusi ryhmä', + 'delete_confirm' => 'Poista tämä ylläpitoryhmä?', + 'return' => 'Palaa ryhmälistaukseen', + 'users_count' => 'Käyttäjät' + ], + 'role' => [ + 'name' => 'Rooli', + 'name_field' => 'Nimi', + 'name_comment' => 'Nimi näytetään roolilistauksessa Hallintalomakkeella.', + 'description_field' => 'Kuvaus', + 'code_field' => 'Koodi', + 'code_comment' => 'Anna uniikkikoodi, mikäli haluat päästä kiinni API:n kautta rooli objektiin.', + 'menu_label' => 'Hallitse Rooleja', + 'list_title' => 'Hallitse Rooleja', + 'new' => 'Uusi Rooli', + 'delete_confirm' => 'Poista tämä hallintarooli?', + 'return' => 'Palaa roolilistaukseen', + 'users_count' => 'Käyttäjät' + ], + 'preferences' => [ + 'not_authenticated' => 'Sallittua käyttäjää, joka voisi tallentaa asetukset, ei löydy.' + ] + ], + 'list' => [ + 'default_title' => 'Lista', + 'search_prompt' => 'Etsi...', + 'no_records' => 'Ei tietueita tässä näkymässä.', + 'missing_model' => 'Luokalle :class ei löydy mallia.', + 'missing_column' => 'Sarakkeille :columns ei ole määritelmiä.', + 'missing_columns' => 'Lista luokassa :class ei määrittele sarakkeita.', + 'missing_definition' => "Lista ei sisällä saraketta ':field'.", + 'missing_parent_definition' => "Lista ei sisällä määritelmää ':definition'.", + 'behavior_not_ready' => 'Luettelokäyttäytymistä ei ole alustettu, tarkista, että olet kutsunut makeLists() ohjaimessasi', + 'invalid_column_datetime' => "Sarakkeen ':column' arvo ei ole DateTime objekti. Puuttuuko sinulta \$dates referenssimallistasi?", + 'pagination' => 'Näytetään tiedot: :from-:to / :total', + 'first_page' => 'Ensimmäinen sivu', + 'last_page' => 'Viimeinen sivu', + 'prev_page' => 'Edellinen sivu', + 'next_page' => 'Seuraava sivu', + 'refresh' => 'Päivitä', + 'updating' => 'Päivitetään...', + 'loading' => 'Ladataan...', + 'setup_title' => 'Listan asetukset', + 'setup_help' => 'Käytä valintalaatikkoja valitaksesi sarakkeet, jotka haluat nähdä listassa. Voit muuttaa sarakkeiden järjestystä vetämällä ylös tai alas.', + 'records_per_page' => 'Tietuetta per sivu', + 'records_per_page_help' => 'Valitse kohteiden määrä per sivu. Huomaathan, että suurempi numero voi vähentää suorituskykyä.', + 'check' => 'Valitse', + 'delete_selected' => 'Poista valitut', + 'delete_selected_empty' => 'Yhtään tietuetta ei ole valittu poistettavaksi.', + 'delete_selected_confirm' => 'Poistetaan valitut tietueet?', + 'delete_selected_success' => 'Tietueet poistettu.', + 'column_switch_true' => 'Kyllä', + 'column_switch_false' => 'Ei' + ], + 'fileupload' => [ + 'attachment' => 'Liite', + 'help' => 'Lisää nimi ja kuvaus tälle liitteelle.', + 'title_label' => 'Nimi', + 'description_label' => 'Kuvaus', + 'default_prompt' => 'Napsauta %s tai raahaa tiedosto tähän siirtoa varten', + 'attachment_url' => 'Liitteen URL-osoite', + 'upload_file' => 'Siirrä tiedosto', + 'upload_error' => 'Virhe siirrossa', + 'remove_confirm' => 'Oletko varma?', + 'remove_file' => 'Poista tiedosto' + ], + 'form' => [ + 'create_title' => 'Uusi :name', + 'update_title' => 'Muokkaa :name', + 'preview_title' => 'Esikatsele :name', + 'create_success' => ':name luotu', + 'update_success' => ':name siirretty', + 'delete_success' => ':name poistettu', + 'reset_success' => 'Palautus valmis', + 'missing_id' => 'Lomakkeen tietue ID ei ole määritelty.', + 'missing_model' => 'Lomake luokassa :class ei ole mallia määriteltynä.', + 'missing_definition' => "Lomake ei sisällä kenttää ':field'.", + 'not_found' => 'Lomaketta ID:llä :id ei voitu löytää.', + 'action_confirm' => 'Oletko aivan varma?', + 'create' => 'Luo', + 'create_and_close' => 'Luo ja sulje', + 'creating' => 'Luodaan...', + 'creating_name' => 'Luodaan :name...', + 'save' => 'Tallenna', + 'save_and_close' => 'Tallenna ja sulje', + 'saving' => 'Tallennetaan...', + 'saving_name' => 'Tallennetaan :name...', + 'delete' => 'Poista', + 'deleting' => 'Poistetaan...', + 'confirm_delete' => 'Poista tietue?', + 'confirm_delete_multiple' => 'Poista valitut tietueet?', + 'deleting_name' => 'Poistetaan :name...', + 'reset_default' => 'Palauta oletukseksi', + 'resetting' => 'Palautetaan', + 'resetting_name' => 'Palautetaan :name', + 'undefined_tab' => 'Muuta', + 'field_off' => 'Pois', + 'field_on' => 'Päällä', + 'add' => 'Lisää', + 'apply' => 'Ota käyttöön', + 'cancel' => 'Peruuta', + 'close' => 'Sulje', + 'confirm' => 'Vahvista', + 'reload' => 'Lataa uudelleen', + 'complete' => 'Valmista', + 'ok' => 'OK', + 'or' => 'tai', + 'confirm_tab_close' => 'Sulje välilehti? Tallentamattomat muutokset häviävät.', + 'behavior_not_ready' => 'Lomaketta ei ole alustettu, tarkista, että olet kutsunut initForm() ohjaimessasi.', + 'preview_no_files_message' => 'Ei siirrettyjä tiedostoja.', + 'preview_no_media_message' => 'Ei valittua mediaa.', + 'preview_no_record_message' => 'Ei valittua tietuetta.', + 'select' => 'Valitse', + 'select_all' => 'Valitse kaikki', + 'select_none' => 'Älä valitse mitään', + 'select_placeholder' => 'ole hyvä ja valitse', + 'insert_row' => 'Lisää rivi', + 'insert_row_below' => 'Lisää rivi alapuolelle', + 'delete_row' => 'Poista rivi', + 'concurrency_file_changed_title' => 'Tiedosto muutettu', + 'concurrency_file_changed_description' => "Toinen käyttäjä on muokannut samaa tiedostoa, jota olet muokkaamassa. Voit joko ladata tiedoston ja menettää tekemäsi muutokset tai ylikirjoittaa toisen käyttäjän tekemät muutokset.", + 'return_to_list' => 'Palaa listaukseen' + ], + 'recordfinder' => [ + 'find_record' => 'Etsi tietue', + 'cancel' => 'Peruuta', + ], + 'pagelist' => [ + 'page_link' => 'Linkki sivuun', + 'select_page' => 'Valitse sivu...' + ], + 'relation' => [ + 'missing_config' => "Suhteella ei ole mitään asetuksia ':config'.", + 'missing_definition' => "Suhteella ei ole määritelmää ':field'.", + 'missing_model' => 'Suhde luokassa :class ei määrittele mallia.', + 'invalid_action_single' => 'Tätä toimintoa ei voida suorittaa yksisuuntaisessa suhteessa.', + 'invalid_action_multi' => 'Tätä toimintoa ei voida suorittaa monisuuntaisessa suhteessa.', + 'help' => 'Valitse kohde lisättäväksi', + 'related_data' => 'Liittyvä data: :name', + 'add' => 'Lisää', + 'add_selected' => 'Lisää valitut', + 'add_a_new' => 'Lisää uusi :name', + 'link_selected' => 'Linkitä valittu', + 'link_a_new' => 'Linkitä uusi :name', + 'cancel' => 'Peruuta', + 'close' => 'Sulje', + 'add_name' => 'Lisää :name', + 'create' => 'Luo', + 'create_name' => 'Luo :name', + 'update' => 'Päivitä', + 'update_name' => 'Päivitä :name', + 'preview' => 'Esikatsele', + 'preview_name' => 'Esikatsele :name', + 'remove' => 'Poista', + 'remove_name' => 'Poista :name', + 'delete' => 'Poista', + 'delete_name' => 'Poista :name', + 'delete_confirm' => 'Oletko varma?', + 'link' => 'Linkki', + 'link_name' => 'Linkki :name', + 'unlink' => 'Poista linkki', + 'unlink_name' => 'Poista linkki :name', + 'unlink_confirm' => 'Oletko varma?' + ], + 'reorder' => [ + 'default_title' => 'Järjestä tietueet uudelleen', + 'no_records' => 'Ei järjestettäviä tietueita.' + ], + 'model' => [ + 'name' => 'Malli', + 'not_found' => "Mallia ':class' ID:llä :id ei löydy", + 'missing_id' => 'Mallikohteiden tarkastelemiseen ei ole määritetty ID:tä.', + 'missing_relation' => "Malli ':class' ei sisällä määritelmää suhteelle ':relation'.", + 'missing_method' => "Malli ':class' ei sisällä metodia ':method'.", + 'invalid_class' => "Mallia :model luokassa :class ei ole kelvollinen, sen täytyy periä \Model luokka.", + 'mass_assignment_failed' => "Massan osoittaminen epäonnistui malli attribuutille ':attribute'." + ], + 'warnings' => [ + 'tips' => 'Järjestelmän kokoonpanovinkkejä', + 'tips_description' => 'On olemassa ongelmia, joihin sinun on kiinnitettävä huomiota järjestelmän oikein määrittelemiseksi.', + 'permissions' => 'Hakemisto :name tai sen alihakemistot ei ole PHP:n kirjoitettavissa. Aseta vastaavat oikeudet tälle hakemistolle verkkopalvelimella.', + 'extension' => 'PHP laajennus :name ei ole asennettuna. Asenna ja aktivoi kyseinen laajennus.', + 'plugin_missing' => 'Lisäosa :name on riippuvuus, mutta sitä ei ole asennettu. Asenna lisäosa.', + ], + 'editor' => [ + 'menu_label' => 'Editorin asetukset', + 'menu_description' => 'Kustomoi peruasetuksia, kuten kirjasinkoko ja väriteema.', + 'font_size' => 'Kirjasimen koko', + 'tab_size' => 'Tabulaattorin koko', + 'use_hard_tabs' => 'Sisennä tabulaattorin avulla', + 'code_folding' => 'Koodin taitto', + 'code_folding_begin' => 'Merkitse alku', + 'code_folding_begin_end' => 'Merkitse alku ja loppu', + 'autocompletion' => 'Automaattinen täydennys', + 'word_wrap' => 'Tekstin rivitys', + 'highlight_active_line' => 'Korosta aktiivinen rivi', + 'auto_closing' => 'Sulje tagit automaattisesti', + 'show_invisibles' => 'Näytä piilomerkit', + 'show_gutter' => 'Näytä palstojen väli', + 'basic_autocompletion'=> 'Perus automaattinen täydennys (Ctrl + Space)', + 'live_autocompletion'=> 'Reaaliaikainen automaattinen täydennys', + 'enable_snippets'=> 'Ota koodinpätkät käyttöön (Sarkain)', + 'display_indent_guides'=> 'Näytä sisennyslinjat', + 'show_print_margin'=> 'Näytä tulostusmarginaali', + 'mode_off' => 'Pois pältä', + 'mode_fluid' => 'Venyvä', + '40_characters' => '40 merkkiä', + '80_characters' => '80 merkkiä', + 'theme' => 'Väriteema', + 'markup_styles' => 'Markup-tyylit', + 'custom_styles' => 'Oma tyylitiedosto', + 'custom styles_comment' => 'Omat tyylit jotka käytetään HTML-editorissa.', + 'markup_classes' => 'Markup-luokat', + 'paragraph' => 'Kappale', + 'link' => 'Linkki', + 'table' => 'Taulukko', + 'table_cell' => 'Taulukon solu', + 'image' => 'Kuva', + 'label' => 'Nimi', + 'class_name' => 'Luokan nimi', + 'markup_tags' => 'Markup-tagit', + 'allowed_empty_tags' => 'Sallitut tyhjät tagit', + 'allowed_empty_tags_comment' => 'Lista tageista, joita ei poisteta vaikka niiden sisällä ei ole sisältöä.', + 'allowed_tags' => 'Sallitut tagit', + 'allowed_tags_comment' => 'Lista sallituista tageista.', + 'no_wrap' => 'Älä kääri tageja', + 'no_wrap_comment' => 'Lista tageista, joita ei tulisi kääriä block tagin sisälle.', + 'remove_tags' => 'Poista tagit', + 'remove_tags_comment' => 'Lista tageista, jotka poistetaan sisältöineen.', + 'toolbar_buttons' => 'Työkalurivin Nappulat', + 'toolbar_buttons_comment' => 'Työkalurivin nappulat, jotka näytetään editorissa oletuksena.', + ], + 'tooltips' => [ + 'preview_website' => 'Esikatsele verkkosivusto' + ], + 'mysettings' => [ + 'menu_label' => 'Omat asetukset', + 'menu_description' => 'Ylläpitäjän tiliin liittyvät asetukset.' + ], + 'myaccount' => [ + 'menu_label' => 'Oma tili', + 'menu_description' => 'Päivitä tilisi asetukset, kuten nimesi, sähköpostisi ja salasanasi.', + 'menu_keywords' => 'tietoturvakirjautuminen' + ], + 'branding' => [ + 'menu_label' => 'Kustomoi ylläpito', + 'menu_description' => 'Muokkaa ylläpitoaluetta, kuten nimeä, värejä ja logo.', + 'brand' => 'Brändi', + 'logo' => 'Logo', + 'logo_description' => 'Siirrä haluamasi logo ylläpitopuolelle.', + 'app_name' => 'Sovelluksen nimi', + 'app_name_description' => 'Tämä näytetään ylläpidon Title-rivillä', + 'app_tagline' => 'Sovelluksen esittelylause', + 'app_tagline_description' => 'Tämä näytetään hallintapaneelin kirjautumissivulla', + 'colors' => 'Värit', + 'primary_color' => 'Primaariväri', + 'secondary_color' => 'Sekundaariväri', + 'accent_color' => 'Korostusväri', + 'styles' => 'Tyylit', + 'custom_stylesheet' => 'Oma CSS-tyyli', + 'navigation' => 'Navigaatio', + 'menu_mode' => 'Valikon tyyli', + 'menu_mode_inline' => 'Rivissä', + 'menu_mode_tile' => 'Laatat', + 'menu_mode_collapsed' => 'Taitettu' + ], + 'backend_preferences' => [ + 'menu_label' => 'Hallinnan asetukset', + 'menu_description' => 'Hallitse oman tilisi asetuksia, kuten kieltä.', + 'region' => 'Alue', + 'code_editor' => 'Koodieditori', + 'timezone' => 'Aikavyöhyke', + 'timezone_comment' => 'Säätää kellonajat tähän aikavyöhykkeeseen.', + 'locale' => 'Kieli', + 'locale_comment' => 'Valitse haluttu käyttöliittymän kieli.' + ], + 'access_log' => [ + 'hint' => 'Tämä loki näyttää listan onnistuneista kirjautumisista järjestelmänvalvojilta. Tiedot pidetään tallessa :days päivää.', + 'menu_label' => 'Käyttöloki', + 'menu_description' => 'Näytä lista onnistuneista kirjautumisista hallintapaneeliin.', + 'created_at' => 'Pvm & aika', + 'login' => 'Kirjautuminen', + 'ip_address' => 'IP-osoite', + 'first_name' => 'Etunimi', + 'last_name' => 'Sukunimi', + 'email' => 'Sähköposti' + ], + 'filter' => [ + 'all' => 'kaikki', + 'options_method_not_exists' => "Mallin :model täytyy määritellä metodi :method(), joka palauttaa ehdot ':filter' suodattimelle.", + 'date_all' => 'kaikilta ajoilta' + ], + 'import_export' => [ + 'upload_csv_file' => '1. Vie CSV-tiedosto', + 'import_file' => 'Tuo tiedosto', + 'first_row_contains_titles' => 'Ensimmäinen rivi sisältää sarakkeiden nimet', + 'first_row_contains_titles_desc' => 'Jätä tämä valituksi jos ensimmäinen rivi on käytössä sarakkeiden nimiin.', + 'match_columns' => '2. Sovita tiedostosarakkeet tietokannan kenttiin', + 'file_columns' => 'Tiedostosarakkeet', + 'database_fields' => 'Tietokannan kentät', + 'set_import_options' => '3. Aseta tuontiasetukset', + 'export_output_format' => '1. Vientiformaatti', + 'file_format' => 'Tiedostoformaatti', + 'standard_format' => 'Oletusformaatti', + 'custom_format' => 'Oma formaatti', + 'delimiter_char' => 'Erotinmerkki', + 'enclosure_char' => 'Sisällytysmerkki', + 'escape_char' => 'Escape-merkki', + 'select_columns' => '2. Valitse sarakkeet vientiin', + 'column' => 'Sarake', + 'columns' => 'Sarakkeet', + 'set_export_options' => '3. Aseta vientiasetukset', + 'show_ignored_columns' => 'Näytä ohitetut sarakkeet', + 'auto_match_columns' => 'Hae sarakkeet automaattisesti', + 'created' => 'Luotu', + 'updated' => 'Päivitetty', + 'skipped' => 'Hypätty yli', + 'warnings' => 'Varoitukset', + 'errors' => 'Virheet', + 'skipped_rows' => 'Ylihypätyt rivit', + 'import_progress' => 'Tuontiprosessi', + 'processing' => 'Prosessoidaan', + 'import_error' => 'Virhe tuonnissa', + 'upload_valid_csv' => 'Siirrä oikeassa muodossa oleva CSV-tiedosto.', + 'drop_column_here' => 'Pudota sarake tähän...', + 'ignore_this_column' => 'Ohita tämä sarake', + 'processing_successful_line1' => 'Tiedoston vientiprosessi valmis!', + 'processing_successful_line2' => 'Selain ohjaa sinut seuraavaksi tiedoston lataukseen.', + 'export_progress' => 'Vienti käynnissä', + 'export_error' => 'Virhe viennissä', + 'column_preview' => 'Sarakkeen esikatselu', + 'file_not_found_error' => 'Tiedostoa ei löytynyt', + 'empty_error' => 'Tietoja ei toimitettu vientiin', + 'empty_import_columns_error' => 'Valitse joitain sarakkeita tuontiin.', + 'match_some_column_error' => 'Sovita joitain sarakkeita ensin.', + 'required_match_column_error' => 'Määrittele vastike vaaditulle kentälle :label.', + 'empty_export_columns_error' => 'Valitse joitain sarakkeita vientiin.', + 'behavior_missing_uselist_error' => 'Sinun täytyy toteuttaa ohjaimen toiminto ListController, jossa viennin "useList" asetus on päällä.', + 'missing_model_class_error' => 'Määritä modelClass omaisuus :type', + 'missing_column_id_error' => 'Sarakkeen tunniste puuttuu', + 'unknown_column_error' => 'Tuntematon sarake', + 'encoding_not_supported_error' => 'Koodausta ei tunnisteta. Valitse Mukautettu formaatti -vaihtoehto kelvollisella koodauksella.', + 'encoding_format' => 'Tiedoston koodaus', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Länsi-Eurooppalainen)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Keski-Eurooppalainen)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, Etelä-Eurooppalainen)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, Pohjois-Eurooppalainen)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Kyrillinen)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, arabialainen)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Kreikkalainen)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Heprealainen)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkkilainen)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Pohjoismainen)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thaimaalainen)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Balttilainen)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Kelttiläinen)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Länsi-Eurooppalainen vedos euro symbolilla)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Siirrä ja hallitse mediaa - kuvat, videot, äänet, dokumentit' + ], + 'mediafinder' => [ + 'label' => 'Mediaetsin', + 'default_prompt' => 'Klikkaa %s nappulaa etsiäksesi media' + ], + 'media' => [ + 'menu_label' => 'Media', + 'upload' => 'Siirrä palvelimelle', + 'move' => 'Siirrä', + 'delete' => 'Poista', + 'add_folder' => 'Lisää kansio', + 'search' => 'Etsi', + 'display' => 'Näytä', + 'filter_everything' => 'Kaikki', + 'filter_images' => 'Kuvat', + 'filter_video' => 'Videot', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Dokumentit', + 'library' => 'Kirjasto', + 'size' => 'Koko', + 'title' => 'Otsikko', + 'last_modified' => 'Viimeksi muokattu', + 'public_url' => 'URL', + 'click_here' => 'Klikkaa tässä', + 'thumbnail_error' => 'Virhe luotaessa esikatselukuvaa.', + 'return_to_parent' => 'Palaa isäntäkansioon', + 'return_to_parent_label' => 'Siirry ylös ..', + 'nothing_selected' => 'Ei valintaa.', + 'multiple_selected' => 'Useita valittu.', + 'uploading_file_num' => 'Siirretään :number tiedosto(a)...', + 'uploading_complete' => 'Siirto valmis', + 'uploading_error' => 'Siirto epäonnistui', + 'type_blocked' => 'Tietoturvasyistä tiedosto muoto ei ole sallittu.', + 'order_by' => 'Järjestä', + 'direction' => 'Suunta', + 'direction_asc' => 'Nouseva', + 'direction_desc' => 'Laskeva', + 'folder' => 'Kansio', + 'no_files_found' => 'Pyynnölläsi ei löytynyt tiedostoja.', + 'delete_empty' => 'Ole hyvä ja valitse poistettavat tiedostot.', + 'delete_confirm' => 'Poistetaan tiedosto(t)?', + 'error_renaming_file' => 'Virhe nimettäessä tiedostoa.', + 'new_folder_title' => 'Uusi kansio', + 'folder_name' => 'Kansion nimi', + 'error_creating_folder' => 'Virhe luotaessa kasiota', + 'folder_or_file_exist' => 'Samanniminen tiedosto tai kansio on jo olemassa.', + 'move_empty' => 'Valitse siirrettävät tiedostot.', + 'move_popup_title' => 'Siirrä tiedotoja tai kansioita', + 'move_destination' => 'Kohdekansio', + 'please_select_move_dest' => 'Ole hyvä ja valitse kohdekansio.', + 'move_dest_src_match' => 'Ole hyvä ja valitse toinen kohdekansio.', + 'empty_library' => 'Näyttää tyhjälle – alkajaisiksi, siirrä tiedosto tai luo kansio.', + 'insert' => 'Liitä', + 'crop_and_insert' => 'Rajaa & Liitä', + 'select_single_image' => 'Valitse vain yksi kuva.', + 'selection_not_image' => 'Valittu tiedosto ei ole kuva.', + 'restore' => 'Hylkää kaikki muutokset', + 'resize' => 'Muuta kokoa...', + 'selection_mode_normal' => 'Normaali', + 'selection_mode_fixed_ratio' => 'Säilytä mittasuhteet', + 'selection_mode_fixed_size' => 'Säilytä koko', + 'height' => 'Korkeus', + 'width' => 'Leveys', + 'selection_mode' => 'Valintamoodi', + 'resize_image' => 'Muuta kuvakokoa', + 'image_size' => 'Kuvakoko:', + 'selected_size' => 'Valittuna:' + ], +]; diff --git a/modules/backend/lang/fr/lang.php b/modules/backend/lang/fr/lang.php new file mode 100644 index 0000000..14a14e4 --- /dev/null +++ b/modules/backend/lang/fr/lang.php @@ -0,0 +1,604 @@ + [ + 'title' => 'Zone d’administration', + 'invalid_login' => 'L\'utilisateur saisie ne correspond à aucun utilisateur enregistré. Merci de vérifier votre saisie et de réessayer.' + ], + 'field' => [ + 'invalid_type' => 'Type de champ invalide :type.', + 'options_method_invalid_model' => "L’attribut ':field' ne correspond à aucun modèle valide. Essayez de spécifier explicitement la méthode d’options pour la classe du modèle ':model'.", + 'options_method_not_exists' => 'La classe du modèle :model doit définir une méthode :method() renvoyant des options pour le champ ":field" du formulaire.', + 'colors_method_not_exists' => "La classe du modèle :model doit définir une méthode :method() renvoyant le code html en héxadécimal de la couleur du champ ':field' du formulaire." + ], + 'widget' => [ + 'not_registered' => 'Aucun widget au nom de classe ":name" n’a été enregistré', + 'not_bound' => 'Un widget au nom de classe ":name" n’a pas été lié au contrôleur' + ], + 'page' => [ + 'untitled' => 'Sans titre', + 'access_denied' => [ + 'label' => 'Accès refusé', + 'help' => 'Vous n’êtes pas autorisé à consulter cette page.', + 'cms_link' => 'Retour à l’interface d’administration' + ], + 'no_database' => [ + 'label' => 'Base de données introuvable', + 'help' => 'Une base de données est requise pour l’accès à l’interface d’administration. Veuillez vérifier que la base de données existe et que les migrations ont été effectuées avant de ré-essayer.', + 'cms_link' => 'Retour à l’accueil' + ], + ], + 'partial' => [ + 'not_found_name' => 'Le modèle partiel ":name" est introuvable.' + ], + 'account' => [ + 'signed_in_as' => 'Connecté en tant que :full_name', + 'sign_out' => 'Déconnexion', + 'login' => 'OK', + 'reset' => 'Réinitialiser', + 'restore' => 'Restaurer', + 'login_placeholder' => 'identifiant', + 'password_placeholder' => 'mot de passe', + 'remember_me' => 'Rester connecté', + 'forgot_password' => 'Mot de passe oublié ?', + 'enter_email' => 'Saisir votre adresse e-mail', + 'enter_login' => 'Saisir votre identifiant', + 'email_placeholder' => 'adresse e-mail', + 'enter_new_password' => 'Saisir votre nouveau mot de passe', + 'password_reset' => 'Réinitialiser le mot de passe', + 'restore_success' => 'Un e-mail contenant les instructions a été envoyé à l’adresse e-mail de votre compte.', + 'restore_error' => 'L’identifiant ":login" ne correspond à aucun utilisateur', + 'reset_success' => 'Mot de passe réinitialisé avec succès. Vous pouvez maintenant vous connecter.', + 'reset_error' => 'Données de réinitialisation du mot de passe invalides. Veuillez réessayer !', + 'reset_fail' => 'Réinitialisation du mot de passe impossible !', + 'apply' => 'Appliquer', + 'cancel' => 'Annuler', + 'delete' => 'Supprimer', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Tableau de bord', + 'widget_label' => 'Widget', + 'widget_width' => 'Taille', + 'full_width' => 'Plein écran', + 'manage_widgets' => 'Gestion des Widgets', + 'add_widget' => 'Ajouter un Widget', + 'widget_inspector_title' => 'Configuration du Widget', + 'widget_inspector_description' => 'Configurer le Widget', + 'widget_columns_label' => 'Largeur en nombre de colonnes :columns', + 'widget_columns_description' => 'La largeur du Widget doit être comprise entre 1 et 10.', + 'widget_columns_error' => 'Veuillez définir la largeur du Widget avec un nombre compris entre 1 et 10.', + 'columns' => '{1} colonne|[2,Inf] colonnes', + 'widget_new_row_label' => 'Forcer l’affichage sur une nouvelle ligne', + 'widget_new_row_description' => 'Placer le Widget sur une nouvelle ligne.', + 'widget_title_label' => 'Titre du Widget', + 'widget_title_error' => 'Le titre du Widget est obligatoire.', + 'reset_layout' => 'Réinitialisation de la maquette', + 'reset_layout_confirm' => 'Réinitialisation vers la maquette par défaut ?', + 'reset_layout_success' => 'La maquette a été réinitialisée', + 'make_default' => 'Par défaut', + 'make_default_confirm' => 'Définir la maquette actuelle comme celle par défaut ?', + 'make_default_success' => 'La maquette actuelle est définie comme celle par défaut', + 'collapse_all' => 'Réduire tout', + 'expand_all' => 'Développer tout', + 'status' => [ + 'widget_title_default' => 'État du système', + 'update_available' => '{0} mise à jour disponible !|{1} mise à jour disponible !|[2,Inf] mises à jour disponibles !', + 'updates_pending' => 'Mises à jour du logiciel en attente', + 'updates_nil' => 'Le logiciel est à jour', + 'updates_link' => 'Mettre à jour', + 'warnings_pending' => 'Certaines anomalies méritent votre attention', + 'warnings_nil' => 'Aucun avertissement à afficher', + 'warnings_link' => 'Voir', + 'core_build' => 'Version du système', + 'event_log' => 'Journal des évènements', + 'request_log' => 'Journal des requêtes', + 'app_birthday' => 'En ligne depuis', + ], + 'welcome' => [ + 'widget_title_default' => 'Bienvenue', + 'welcome_back_name' => 'Bienvenue sur :app, :name.', + 'welcome_to_name' => 'Bienvenue sur :app, :name.', + 'first_sign_in' => 'C’est la première fois que vous vous connectez.', + 'last_sign_in' => 'Votre dernière connexion remonte au', + 'view_access_logs' => 'Consulter le journal des accès', + 'nice_message' => 'Passez une agréable journée !', + ] + ], + 'user' => [ + 'name' => 'Administrateur', + 'menu_label' => 'Administrateurs', + 'menu_description' => 'Gérer les utilisateurs, les groupes et les permissions de l’interface d’administration.', + 'list_title' => 'Gérer les administrateurs', + 'new' => 'Créer un nouvel administrateur', + 'login' => 'Identifiant', + 'first_name' => 'Prénom', + 'last_name' => 'Nom', + 'full_name' => 'Nom complet', + 'email' => 'Adresse e-mail', + 'role_field' => 'Rôle', + 'role_comment' => 'Les rôles définissent les permissions de l\'utilisateur, elles peuvent être écrasés au niveau de l\'utilisateur dans l\'onglet "Permissions".', + 'groups' => 'Groupes', + 'groups_comment' => 'Préciser les groupes auxquels ce compte doit appartenir.', + 'avatar' => 'Avatar', + 'password' => 'Mot de passe', + 'password_confirmation' => 'Confirmer le mot de passe', + 'permissions' => 'Permissions', + 'account' => 'Compte', + 'superuser' => 'Super utilisateur', + 'superuser_comment' => 'Donner à ce compte un niveau d’accès illimité à toutes les sections du système. Les super-utilisateurs peuvent ajouter et gérer les autres utilisateurs. ', + 'send_invite' => 'Envoyer une invitation par e-mail', + 'send_invite_comment' => 'Envoyer une invitation aux utilisateurs par e-mail contenant l’identifiant et le mot de passe.', + 'delete_confirm' => 'Supprimer cet administrateur ?', + 'return' => 'Retour à la liste des administrateurs', + 'allow' => 'Autoriser', + 'inherit' => 'Hériter', + 'deny' => 'Interdire', + 'activated' => 'Activé', + 'last_login' => 'Dernière connexion', + 'created_at' => 'Créé le', + 'updated_at' => 'Mis à jour le', + 'deleted_at' => 'Supprimé le', + 'show_deleted' => 'Afficher les supprimés', + 'group' => [ + 'name' => 'Groupe', + 'name_comment' => 'Le nom est affiché dans la liste des groupes dans le formulaire de création/modification des administrateurs.', + 'name_field' => 'Nom', + 'description_field' => 'Description', + 'is_new_user_default_field_label' => 'Groupe par défaut', + 'is_new_user_default_field_comment' => 'Ajouter les nouveaux administrateurs dans ce groupe par défaut.', + 'code_field' => 'Code', + 'code_comment' => 'Saisir un code d’accès unique si vous souhaitez accéder à ce groupe via l’API.', + 'menu_label' => 'Groupes', + 'list_title' => 'Gérer les groupes', + 'new' => 'Ajouter un groupe d’administrateur', + 'delete_confirm' => 'Supprimer ce groupe d’administrateurs ?', + 'return' => 'Retour à la liste des groupes', + 'users_count' => 'Utilisateurs' + ], + 'role' => [ + 'name' => 'Rôle', + 'name_field' => 'Nom', + 'name_comment' => 'Le nom est affiché dans la liste des rôles du formulaire de gestion des Administrateurs.', + 'description_field' => 'Description', + 'code_field' => 'Code', + 'code_comment' => 'Saisir un code d’accès unique si vous souhaitez accéder à ce rôle via l’API.', + 'menu_label' => 'Gérer les rôles', + 'list_title' => 'Gérer les rôles', + 'new' => 'Nouveau rôle', + 'delete_confirm' => 'Supprimer le rôle administrateur ?', + 'return' => 'Retourner à la liste des rôles', + 'users_count' => 'Utilisateurs' + ], + 'preferences' => [ + 'not_authenticated' => 'Il n’y a aucun utilisateur authentifié pour lequel il est possible de charger ou modifier les préférences.' + ], + 'trashed_hint_title' => 'Ce compte a été supprimé', + 'trashed_hint_desc' => 'Ce compte a été supprimé et il sera impossible de se connecter avec. Pour le récupérer, cliquer sur l\'icône "Utilisateur" en bas à droite.', + ], + 'list' => [ + 'default_title' => 'Liste', + 'search_prompt' => 'Rechercher…', + 'no_records' => 'Il n’y a aucun résultat dans cette vue.', + 'missing_model' => 'La liste utilisée dans la classe :class n’a pas de modèle défini.', + 'missing_column' => 'Il n’y a pas de définition pour la colonne :columns.', + 'missing_columns' => 'La liste utilisée dans la classe :class n’a pas de colonne de liste définie.', + 'missing_definition' => 'La liste utilisée ne contient de pas de colonne pour le champ ":field".', + 'missing_parent_definition' => "Le behavior List ne contient pas de définition pour ':definition'.", + 'behavior_not_ready' => 'La liste utilisée n’a pas été initialisée, vérifier que la méthode d’appel de makeLists() a été soumise au contrôleur.', + 'invalid_column_datetime' => 'La valeur de la colonne ":column" n’est pas un objet DateTime, manque-t-il une référence dans la propriété \$dates du modèle ?', + 'pagination' => 'Enregistrements affichés : :from-:to sur :total', + 'first_page' => 'Première page', + 'last_page' => 'Dernière page', + 'prev_page' => 'Page précédente', + 'next_page' => 'Page suivante', + 'refresh' => 'Actualiser', + 'updating' => 'Mise à jour…', + 'loading' => 'Chargement…', + 'setup_title' => 'Configuration de la liste', + 'setup_help' => 'Cocher les colonnes qui doivent être affichées dans la liste. Il est possible de modifier l’ordre des colonnes en les glissant vers le haut ou le bas.', + 'records_per_page' => 'Nombre d’enregistrements par page', + 'records_per_page_help' => 'Choisir le nombre d’enregistrements à afficher. Note : un nombre d’enregistrements trop élevé sur une seule page peut réduire les performances.', + 'check' => 'Sélectionner', + 'delete_selected' => 'Supprimer la sélection', + 'delete_selected_empty' => 'Il n’y a aucun enregistrement à supprimer', + 'delete_selected_confirm' => 'Confirmer la suppression des enregistrements sélectionnés ?', + 'delete_selected_success' => 'Les enregistrements ont été supprimés.', + 'column_switch_true' => 'Oui', + 'column_switch_false' => 'Non' + ], + 'fileupload' => [ + 'attachment' => 'Pièce jointe', + 'help' => 'Ajouter un titre et une description pour cette pièce jointe.', + 'title_label' => 'Titre', + 'description_label' => 'Description', + 'default_prompt' => 'Cliquer sur %s ou déposer un fichier ici pour le télécharger', + 'attachment_url' => 'Adresse URL du fichier joint', + 'upload_file' => 'Télécharger le fichier', + 'upload_error' => 'Erreur lors du téléchargement', + 'remove_confirm' => 'Confirmer l’action ?', + 'remove_file' => 'Supprimer le fichier', + ], + 'repeater' => [ + 'min_items_failed' => ':name nécéssite un minimum de :min choix sélectionné, seulement :items sont sélectionné(s)', + 'max_items_failed' => ':name accepte un maximum de :max choix sélectionné, :items sont sélectionés', + ], + 'form' => [ + 'create_title' => 'Créer un(e) :name', + 'update_title' => 'Mise à jour d\'un(e) :name', + 'preview_title' => 'Aperçu d\'un(e) :name', + 'create_success' => ':name créé(e) avec succès', + 'update_success' => ':name modifié(e) avec succès', + 'restore_success' => ':name récuperé avec succès', + 'delete_success' => ':name supprimé(e) avec succès', + 'reset_success' => 'Réinitialisation terminée', + 'missing_id' => 'L’ID de l’enregistrement du formulaire n’est pas précisé.', + 'missing_model' => 'Le behavior formulaire utilisé dans la classe :class n’a pas de modèle défini.', + 'missing_definition' => 'Le behavior formulaire utilisé n’a pas de champ pour ":field".', + 'not_found' => 'Aucun enregistrement de formulaire ne correspond a l’ID :id.', + 'action_confirm' => 'Confirmer l’action ?', + 'create' => 'Créer', + 'create_and_close' => 'Créer et fermer', + 'creating' => 'Création en cours…', + 'creating_name' => 'Création d\'un(e) :name en cours…', + 'save' => 'Enregistrer', + 'save_and_close' => 'Enregistrer et fermer', + 'saving' => 'Enregistrement en cours…', + 'saving_name' => 'Enregistrement d\'un(e) :name en cours…', + 'delete' => 'Supprimer', + 'deleting' => 'Suppression en cours…', + 'confirm_delete' => 'Supprimer cet enregistrement?', + 'confirm_delete_multiple' => 'Supprimer les enregistrements sélectionnés ?', + 'deleting_name' => 'Suppression d\'un(e) :name en cours…', + 'restore' => 'Récupérer', + 'restoring' => 'Récupération', + 'confirm_restore' => 'Êtes-vous certain de vouloir récupérer cet enregistrement ?', + 'reset_default' => 'Restaurer les valeurs par défaut', + 'resetting' => 'Restauration', + 'resetting_name' => 'Restauration d\'un(e) :name', + 'undefined_tab' => 'Divers', + 'field_off' => 'Off', + 'field_on' => 'On', + 'add' => 'Ajouter', + 'apply' => 'Appliquer', + 'cancel' => 'Annuler', + 'close' => 'Fermer', + 'confirm' => 'Confirmer', + 'reload' => 'Recharger', + 'complete' => 'Terminé', + 'ok' => 'OK', + 'or' => 'ou', + 'confirm_tab_close' => 'Fermer cet onglet ? Les modifications réalisées seront perdues.', + 'behavior_not_ready' => 'Le behavior formulaire n’a pas encore été initialisé, vérifier que la méthode initForm() est appelée par le contrôleur.', + 'preview_no_files_message' => 'Les fichiers ne sont pas envoyés.', + 'preview_no_media_message' => 'Aucun média sélectionné.', + 'preview_no_record_message' => 'Il n’y a aucun enregistrement sélectionné.', + 'select' => 'Sélectionner', + 'select_all' => 'tout sélectionner', + 'select_none' => 'Ne rien sélectionner', + 'select_placeholder' => 'Sélectionner une valeur', + 'insert_row' => 'Insérer une ligne', + 'insert_row_below' => 'Insérer une ligne dessous', + 'delete_row' => 'Supprimer une ligne', + 'concurrency_file_changed_title' => 'Le fichier à été modifié', + 'concurrency_file_changed_description' => 'Un autre utilisateur a modifié ce fichier sur le disque. Vous pouvez charger à nouveau le fichier depuis le disque et perdre vos modifications) ou écraser le fichier sur le disque.', + 'return_to_list' => 'Retourner à la liste' + ], + 'recordfinder' => [ + 'find_record' => 'Trouver un enregistrement', + 'cancel' => 'Annuler', + ], + 'pagelist' => [ + 'page_link' => 'Lien de page', + 'select_page' => 'Sélectionnez une page...' + ], + 'relation' => [ + 'missing_config' => 'La behavior relation n’a pas de configuration pour ":config".', + 'missing_definition' => 'La behavior relation n’a pas de définition pour le champ ":field".', + 'missing_model' => 'La behavior relation utilisée dans la classe :class n’a pas de modèle défini.', + 'invalid_action_single' => 'Cette action ne peut être effectuée sur une relation unitaire.', + 'invalid_action_multi' => 'Cette action ne peut être effectuée sur une relation multiple.', + 'help' => 'Cliquer sur un élément pour l’ajouter', + 'related_data' => 'Donnée :name liée', + 'add' => 'Ajouter', + 'add_selected' => 'Ajouter la sélection', + 'add_a_new' => 'Ajouter un(e) :name', + 'link_selected' => 'Lier la sélection', + 'link_a_new' => 'Lier un(e) :name', + 'cancel' => 'Annuler', + 'close' => 'Fermer', + 'add_name' => 'Ajouter un(e) :name', + 'create' => 'Créer', + 'create_name' => 'Créer un(e) :name', + 'update' => 'Mettre à jour', + 'update_name' => 'Mise à jour d’un(e) :name', + 'preview' => 'Aperçu', + 'preview_name' => 'Aperçu d’un(e) :name', + 'remove' => 'Retirer', + 'remove_name' => 'Retirer un(e) :name', + 'delete' => 'Supprimer', + 'delete_name' => 'Suppression d’un(e) :name', + 'delete_confirm' => 'Êtes vous sûr(e) ?', + 'link' => 'Lier', + 'link_name' => 'Lier un(e) :name', + 'unlink' => 'Détacher', + 'unlink_name' => 'Détacher un(e) :name', + 'unlink_confirm' => 'Êtes vous sûr(e) ?', + ], + 'reorder' => [ + 'default_title' => 'Réorganiser les enregistrements', + 'no_records' => 'Il n’y a aucun enregistrement à trier.', + ], + 'model' => [ + 'name' => 'Modèle', + 'not_found' => 'Aucun modèle ":class" ne correspond à l’ID :id', + 'missing_id' => 'Il manque l’ID de l’enregistrement.', + 'missing_relation' => 'Le modèle ":class" ne contient pas de définition ":relation".', + 'missing_method' => 'Le modèle ":class" ne contient pas de méthode ":method".', + 'invalid_class' => 'Le modèle :model utilisé dans la classe :class est invalide, il doit hériter de la classe \Model.', + 'mass_assignment_failed' => 'L’affectation de masse a échoué pour l’attribut ":attribute" du modèle.' + ], + 'warnings' => [ + 'tips' => 'Astuces de configuration du système', + 'tips_description' => 'Il y a des éléments à prendre en compte pour configurer le système correctement.', + 'permissions' => 'PHP ne peut pas écrire dans le répertoire :name et ses sous-dossiers. Veuillez modifier les permissions en écriture du serveur web pour ce répertoire.', + 'extension' => 'L’extension PHP :name n’est pas installée. Veuillez installer la librairie et activer l’extension.', + 'plugin_missing' => 'Le plugin :name est une dépendance mais n\'est pas installé. Veuillez installer le plugin.', + ], + 'editor' => [ + 'menu_label' => 'Préférences de l’éditeur de code', + 'menu_description' => 'Personnaliser la configuration de l’éditeur de code, telle que la taille de la police ou la coloration syntaxique.', + 'font_size' => 'Taille de la police', + 'tab_size' => 'Taille de la tabulation', + 'use_hard_tabs' => 'Indentation par tabulation', + 'code_folding' => 'Replier le code', + 'code_folding_begin' => 'Marquer le début', + 'code_folding_begin_end' => 'Marquer le début et la fin', + 'autocompletion' => 'Auto-complétion', + 'word_wrap' => 'Retour à la ligne', + 'highlight_active_line' => 'Sélectionner la ligne active', + 'auto_closing' => 'Fermer Automatiquement les tags', + 'show_invisibles' => 'Afficher les caractères invisibles', + 'show_gutter' => 'Afficher les numéros de ligne', + 'basic_autocompletion'=> 'Auto-complétion basique (Ctrl + Espace)', + 'live_autocompletion'=> 'Auto-complétion en temps réel', + 'enable_snippets'=> 'Activer les extraits de code (Tab)', + 'display_indent_guides'=> 'Afficher les guides d’indentation', + 'show_print_margin'=> 'Afficher les marges d’impression', + 'mode_off' => 'Désactivé', + 'mode_fluid' => 'Fluide', + '40_characters' => '40 caractères', + '80_characters' => '80 caractères', + 'theme' => 'Coloration syntaxique', + 'markup_styles' => 'Styles du balisage', + 'custom_styles' => 'Feuille de styles personnalisée', + 'custom styles_comment' => 'Styles personnalisés à inclure dans l’editeur HTML.', + 'markup_classes' => 'Classes de style', + 'paragraph' => 'Paragraphe', + 'link' => 'Lien', + 'table' => 'Tableau', + 'table_cell' => 'Cellule d’un tableau', + 'image' => 'Image', + 'label' => 'Libellé', + 'class_name' => 'Nom de la classe', + 'markup_tags' => 'Balises', + 'allowed_empty_tags' => 'Autoriser les balises vides', + 'allowed_empty_tags_comment' => 'Liste des balises qui ne sont pas supprimées lorsqu’elles sont vides.', + 'allowed_tags' => 'Balises autorisées', + 'allowed_tags_comment' => 'Liste des balises autorisées.', + 'no_wrap' => 'Balises non encadrées', + 'no_wrap_comment' => 'Liste des balises qui ne doivent pas être encadrées dans par des balises de bloc.', + 'remove_tags' => 'Balises supprimées', + 'remove_tags_comment' => 'Liste des balises qui sont supprimées ainsi que leur contenu.', + 'line_breaker_tags' => 'Balise de saut de ligne', + 'line_breaker_tags_comment' => 'La liste des balises qui sont utilisés pour mettre des sauts de ligne.', + 'toolbar_buttons' => 'Boutons de la barre d\'outils', + 'toolbar_buttons_comment' => 'Les boutons de la barre d\'outils a afficher par défaut dans l\'éditeur de texte enrichi.', + ], + 'tooltips' => [ + 'preview_website' => 'Aperçu du site' + ], + 'mysettings' => [ + 'menu_label' => 'Mes paramètres', + 'menu_description' => 'Paramètres de votre compte administrateur' + ], + 'myaccount' => [ + 'menu_label' => 'Mon compte', + 'menu_description' => 'Modifier les informations de votre compte comme le nom, l’adresse e-mail ou le mot de passe.', + 'menu_keywords' => 'security login sécurité authentification identification' + ], + 'branding' => [ + 'menu_label' => 'Personnaliser l’interface d’administration', + 'menu_description' => 'Personnaliser l’interface d’administration comme le nom, les couleurs ou le logo.', + 'brand' => 'Marque', + 'logo' => 'Logo', + 'logo_description' => 'Envoyer un logo personnalisé à utiliser dans l’interface d’administration.', + 'app_name' => 'Nom de l’application', + 'app_name_description' => 'Ce nom est affiché comme titre dans l’interface d’administration.', + 'app_tagline' => 'Slogan de l’application', + 'app_tagline_description' => 'Ce slogan est affiché sur la page d’inscription à l’interface d’administration.', + 'colors' => 'Couleurs', + 'primary_color' => 'Couleur principale', + 'secondary_color' => 'Couleur secondaire', + 'accent_color' => 'Couleur d’accentuation', + 'styles' => 'Styles', + 'custom_stylesheet' => 'Feuille de styles personnalisée', + 'navigation' => 'Navigation', + 'menu_mode' => 'Style du menu', + 'menu_mode_inline' => 'Horizontal', + 'menu_mode_tile' => 'Tuiles', + 'menu_mode_collapsed' => 'Replié', + ], + 'backend_preferences' => [ + 'menu_label' => 'Préférences d’administration', + 'menu_description' => 'Gérer les préférences de votre compte telles que la langue utilisée.', + 'region' => 'Région', + 'code_editor' => 'Éditeur de code', + 'timezone' => 'Fuseau horaire', + 'timezone_comment' => 'Ajuster les dates affichées à ce fuseau horaire.', + 'locale' => 'Langue', + 'locale_comment' => 'Choisir une langue.' + ], + 'access_log' => [ + 'hint' => 'Ce journal affiche la liste des tentatives d’authentification réussies des administrateurs. Les données sont sauvegardées pendant :days jours.', + 'menu_label' => 'Journal des accès', + 'menu_description' => 'Affiche la liste des authentifications réussies des utilisateurs de l’interface d’administration.', + 'id' => 'ID', + 'created_at' => 'Date et heure', + 'type' => 'Type', + 'login' => 'Identifiant', + 'ip_address' => 'Adresse IP', + 'first_name' => 'Prénom', + 'last_name' => 'Nom', + 'email' => 'Adresse e-mail' + ], + 'filter' => [ + 'all' => 'tous', + 'options_method_not_exists' => "La classe du modèle :model doit définir une méthode :method() qui retourne les options pour le filtre ':filter'.", + 'date_all' => 'toute la période', + 'number_all' => 'tout les nombres', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Envoyer un fichier CSV', + 'import_file' => 'Importer un fichier', + 'row' => 'Ligne :row', + 'first_row_contains_titles' => 'La première ligne contient les titres des colonnes', + 'first_row_contains_titles_desc' => 'Laissez coché si la première ligne du fichier CSV contient les titres des colonnes.', + 'match_columns' => '2. Faire correspondre les colonnes du fichier avec les champs du modèle de données', + 'file_columns' => 'Colonnes du fichier', + 'database_fields' => 'Champs de la base de données', + 'set_import_options' => '3. Fixer les options d’importation', + 'export_output_format' => '1. Format de sortie de l’export', + 'file_format' => 'Format du fichier', + 'standard_format' => 'Format Standard', + 'custom_format' => 'Format Personnalisé', + 'delimiter_char' => 'Caractère séparateur', + 'enclosure_char' => 'Caractère d’encadrement', + 'escape_char' => 'Caractère d’échappement', + 'select_columns' => '2. Choisissez les colonnes à exporter', + 'column' => 'Colonne', + 'columns' => 'Colonnes', + 'set_export_options' => '3. Définir les options d’exportation', + 'show_ignored_columns' => 'Voir les colonnes ignorées', + 'auto_match_columns' => 'Correspondance automatique des colonnes', + 'created' => 'Créés', + 'updated' => 'Mis à jour', + 'skipped' => 'Ignorés', + 'warnings' => 'Alertes', + 'errors' => 'Erreurs', + 'skipped_rows' => 'Lignes ignorées', + 'import_progress' => 'Progression de l’import', + 'processing' => 'Traitement', + 'import_error' => 'Erreur d’import', + 'upload_valid_csv' => 'Veuillez envoyer un fichier CSV valide.', + 'drop_column_here' => 'Déposez les colonnes ici...', + 'ignore_this_column' => 'Ignorer cette colonne', + 'processing_successful_line1' => 'Le processus d’export du fichier s’est terminé avec succès !', + 'processing_successful_line2' => 'Le navigateur devrait automatiquement vous rediriger vers le téléchargement du fichier.', + 'export_progress' => 'Progression de l’export', + 'export_error' => 'Erreur d’export', + 'column_preview' => 'Prévisualisation des colonnes', + 'file_not_found_error' => 'Fichier non trouvé', + 'empty_error' => 'Il n‘y a aucune donnée à exporter', + 'empty_import_columns_error' => 'Veuillez indiquer quelques colonnes à importer.', + 'match_some_column_error' => 'Veuillez d’abord faire correspondre quelques colonnes.', + 'required_match_column_error' => 'Veuillez faire correspondre la colonne obligatoire :label.', + 'empty_export_columns_error' => 'Veuillez indiquer quelques colonnes à exporter.', + 'behavior_missing_uselist_error' => 'Vous devez implémenter le behavior ListController avec l’option d’export "useList" activée.', + 'missing_model_class_error' => 'Veuillez préciser la propriété modelClass pour :type', + 'missing_column_id_error' => 'Identifiant de colonne manquant', + 'unknown_column_error' => 'Colonne inconnue', + 'encoding_not_supported_error' => 'L’encodage de votre fichier source n’est pas reconnu. Veuillez sélectionner le format d’import personnalisé avec l’encodage adapté pour importer votre fichier.', + 'encoding_format' => 'Encodage du fichier', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, européen occidental)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, européen central)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, européen du Sud)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, européen du Nord)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, cyrillique)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, arabe)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, grec)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, hébreu)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, turc)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, nordique)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, thaï)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, balte)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, celtique)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, européen occidental révisé avec le signe euro)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Déposer et gérer les contenus media - images, vidéos, sons, documents' + ], + 'mediafinder' => [ + 'label' => 'Galerie média', + 'default_prompt' => 'Cliquez sur le bouton %s pour trouver un élément média' + ], + 'media' => [ + 'menu_label' => 'Média', + 'upload' => 'Déposer un fichier', + 'move' => 'Déplacer', + 'delete' => 'Supprimer', + 'add_folder' => 'Ajouter un répertoire', + 'search' => 'Rechercher', + 'display' => 'Affichage', + 'filter_everything' => 'Tout', + 'filter_images' => 'Images', + 'filter_video' => 'Vidéo', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Documents', + 'library' => 'Librairie', + 'size' => 'Taille', + 'title' => 'Titre', + 'last_modified' => 'Dernière modification', + 'public_url' => 'Adresse URL publique', + 'click_here' => 'Cliquer ici', + 'thumbnail_error' => 'Erreur lors de la création de la miniature.', + 'return_to_parent' => 'Retourner au répertoire parent', + 'return_to_parent_label' => 'Monter…', + 'nothing_selected' => 'Aucune sélection.', + 'multiple_selected' => 'Plusieurs éléments sélectionnés.', + 'uploading_file_num' => 'Dépôt de :number fichier(s)…', + 'uploading_complete' => 'Dépôt des fichiers terminé', + 'uploading_error' => 'Le dépôt des fichiers a échoué', + 'type_blocked' => 'Le type de fichier utilisé est bloqué pour des raisons de sécurité.', + 'order_by' => 'Trier par', + 'direction' => 'Direction', + 'direction_asc' => 'Ascendant', + 'direction_desc' => 'Descendant', + 'folder' => 'Répertoire', + 'no_files_found' => 'Aucun fichier trouvé.', + 'delete_empty' => 'Veuillez sélectionner les éléments à supprimer.', + 'delete_confirm' => 'Confirmer la suppression de ces éléments ?', + 'error_renaming_file' => 'Erreur lors du renommage de l’élément.', + 'new_folder_title' => 'Nouveau répertoire', + 'folder_name' => 'Nom du répertoire', + 'error_creating_folder' => 'Erreur lors de la création du répertoire', + 'folder_or_file_exist' => 'Un répertoire ou un fichier portant ce nom existe déjà.', + 'move_empty' => 'Veuillez sélectionner les éléments à déplacer.', + 'move_popup_title' => 'Déplacer des fichiers ou répertoires', + 'move_destination' => 'Répertoire de destination', + 'please_select_move_dest' => 'Veuillez sélectionner un répertoire de destination.', + 'move_dest_src_match' => 'Veuillez sélectionner un autre répertoire de destination.', + 'empty_library' => 'La librairie multimédia est vide. Pour commencer, télécharger des fichiers ou répertoires.', + 'insert' => 'Insérer', + 'crop_and_insert' => 'Rogner et insérer', + 'select_single_image' => 'Veuillez sélectionner une seule image.', + 'selection_not_image' => 'L’élément sélectionné n’est pas une image.', + 'restore' => 'Annuler tous les changements', + 'resize' => 'Redimensionner…', + 'selection_mode_normal' => 'Normal', + 'selection_mode_fixed_ratio' => 'Rapport fixe', + 'selection_mode_fixed_size' => 'Taille fixe', + 'height' => 'Hauteur', + 'width' => 'Largeur', + 'selection_mode' => 'Mode de sélection', + 'resize_image' => 'Redimensionner l’image', + 'image_size' => 'Taille de l’image :', + 'selected_size' => 'Sélectionnée :' + ] +]; diff --git a/modules/backend/lang/hu/lang.php b/modules/backend/lang/hu/lang.php new file mode 100644 index 0000000..9e000b2 --- /dev/null +++ b/modules/backend/lang/hu/lang.php @@ -0,0 +1,646 @@ + [ + 'title' => 'Admin felület', + 'invalid_login' => 'A megadott adatok nem egyeznek. Kérjük ellenőrizze őket és próbálja újra.' + ], + 'field' => [ + 'invalid_type' => 'A(z) :type mezőtípus érvénytelen.', + 'options_method_invalid_model' => "A(z) ':field' tulajdonság nem passzol a modellhez. Próbálja meghatározni a beállítást, ami megfelelő a(z) :model osztály számára.", + 'options_method_not_exists' => "A(z) :model osztálynak egy :method() nevű metódust kell definiálnia a(z) ':field' űrlapmező számára, ami visszaadja a beállításokat.", + 'options_static_method_invalid_value' => "A(z) :class osztályban lévő ':method()' nevű metódus nem ad vissza érvényes tömböt.", + 'colors_method_not_exists' => "A(z) :model modell osztálynak egy :method() nevű metódust kell definiálnia a(z) ':field' űrlapmező számára, ami visszaadja a html HEX kódot." + ], + 'widget' => [ + 'not_registered' => "A(z) ':name' widget osztálynév regisztrálása nem történt meg.", + 'not_bound' => "A(z) ':name' osztálynevű widget kötése nem történt meg a vezérlővel." + ], + 'page' => [ + 'untitled' => 'Névtelen', + '404' => [ + 'label' => 'Az oldal nem található', + 'help' => 'A megadott webcím alatt nem jeleníthető meg tartalom. Kérjük próbálkozzon más címmel.', + 'back_link' => 'Vissza az előző oldalra', + ], + 'access_denied' => [ + 'label' => 'Hozzáférés megtagadva', + 'help' => 'Nem rendelkezik a szükséges engedélyekkel ennek a lapnak a megtekintéséhez.', + 'cms_link' => 'Vissza a látogatói oldalra' + ], + 'no_database' => [ + 'label' => 'Az adatbázis nem elérhető', + 'help' => 'Kérjük ellenőrizze a hozzáférési adatok helyességét majd próbálja újra betölteni az oldalt.', + 'cms_link' => 'Vissza a weboldalra' + ], + ], + 'partial' => [ + 'not_found_name' => "A(z) ':name' részlap nem található.", + 'invalid_name' => 'Helytelen részlap név: :name.' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Helytelen AJAX handler név: :name.', + 'not_found' => "A(z) ':name' AJAX handler nem található." + ], + 'account' => [ + 'impersonate' => 'Átjelentkezés a fiókba', + 'impersonate_confirm' => 'Biztos, hogy átjelentkezik a felhasználó saját fiókjába? Ezáltal a jelenlegi munkamenetből ki lesz jelentkeztetve.', + 'impersonate_success' => 'Sikeresen átjelentkezett a másik fiókba', + 'impersonate_working' => 'Átjelentkezés...', + 'impersonating' => 'Átjelentkezve mint :full_name', + 'stop_impersonating' => 'Visszajelentkezés', + 'unsuspend' => 'Felfüggesztés', + 'unsuspend_confirm' => 'Biztos, hogy felfüggeszti a felhasználót?', + 'unsuspend_success' => 'A felfüggesztés sikeresen megtörtént.', + 'unsuspend_working' => 'Felfüggesztés folyamatban...', + 'signed_in_as' => 'Belépve mint :full_name', + 'sign_out' => 'Kijelentkezés', + 'login' => 'Belépés', + 'reset' => 'Alaphelyzet', + 'restore' => 'Visszaállítás', + 'login_placeholder' => 'felhasználónév', + 'password_placeholder' => 'jelszó', + 'remember_me' => 'Bejelentkezve maradok', + 'forgot_password' => 'Elfelejtette a jelszavát?', + 'enter_email' => 'Adja meg az e-mail címét', + 'enter_login' => 'Adja meg a felhasználói nevét', + 'email_placeholder' => 'e-mail cím', + 'enter_new_password' => 'Adjon meg egy új jelszót', + 'password_reset' => 'Új jelszó kiadása', + 'restore_success' => 'A visszaállítással kapcsolatos utasításokat tartalmazó levél elküldésre került.', + 'restore_error' => "Nem található a(z) ':login' nevű felhasználó.", + 'reset_success' => 'A jelszó átállítása sikerült. Most már bejelentkezhet.', + 'reset_error' => 'A megadott jelszó átállítási adatok érvénytelenek. Próbálja újra!', + 'reset_fail' => 'Nem állítható vissza a jelszava!', + 'apply' => 'Alkalmaz', + 'cancel' => 'Mégsem', + 'delete' => 'Törlés', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Vezérlőpult', + 'widget_label' => 'Widget', + 'widget_width' => 'Szélesség', + 'full_width' => 'teljes szélesség', + 'manage_widgets' => 'Widgetek kezelése', + 'add_widget' => 'Widget hozzáadása', + 'widget_inspector_title' => 'Widget testreszabása', + 'widget_inspector_description' => 'A jelenlegi widgethez tartozó beállítások.', + 'widget_columns_label' => 'Szélesség :columns', + 'widget_columns_description' => 'A widget szélessége, egy 1 és 10 közötti szám.', + 'widget_columns_error' => 'Adja meg a widget szélességét egy 1 és 10 közötti számként.', + 'columns' => '{1} oszlop|[2,Inf] oszlop', + 'widget_new_row_label' => 'Új sorba', + 'widget_new_row_description' => 'A widget új sorba helyezése.', + 'widget_title_label' => 'Megjelenő cím', + 'widget_title_error' => 'A widget címének megadása kötelező.', + 'reset_layout' => 'Elrendezés visszaállítása', + 'reset_layout_confirm' => 'Visszaállítás az alapértelmezettre?', + 'reset_layout_success' => 'A visszaállítás megtörtént.', + 'make_default' => 'Elrendezés mentése', + 'make_default_confirm' => 'A jelenlegi elrendezés legyen az alapértelmezett?', + 'make_default_success' => 'A jelenlegi elrendezés lett az alapértelmezett.', + 'collapse_all' => 'Összes becsukása', + 'expand_all' => 'Összes kibontása', + 'status' => [ + 'widget_title_default' => 'Rendszer állapota', + 'update_available' => '{0} frissítés érhető el!|{1} frissítés érhető el!|[2,Inf] frissítés érhető el!', + 'updates_pending' => 'Függőben lévő frissítések', + 'updates_nil' => 'A weboldal naprakész', + 'updates_link' => 'Frissítés', + 'warnings_pending' => 'Függőben lévő teendők', + 'warnings_nil' => 'Minden rendben van', + 'warnings_link' => 'Megtekintés', + 'core_build' => 'Verzió', + 'event_log' => 'Esemény napló', + 'request_log' => 'Kérelem napló', + 'app_birthday' => 'Telepítve' + ], + 'welcome' => [ + 'widget_title_default' => 'Üdvözöljük!', + 'welcome_back_name' => 'Köszönjük, hogy visszatért a(z) :app weboldalra, :name.', + 'welcome_to_name' => 'Köszöntjük a(z) :app weboldalon, :name.', + 'first_sign_in' => 'Ez az első alkalom, hogy bejelentkezett.', + 'last_sign_in' => 'Legutóbbi bejelentkezése:', + 'view_access_logs' => 'Hozzáférés napló megtekintése', + 'nice_message' => 'Legyen jó napja!' + ] + ], + 'user' => [ + 'name' => 'Admin', + 'menu_label' => 'Adminok', + 'menu_description' => 'Jogosultságok, szerepkörök és csoportok módosítása.', + 'list_title' => 'Adminok kezelése', + 'new' => 'Új admin', + 'login' => 'Felhasználói név', + 'first_name' => 'Vezetéknév', + 'last_name' => 'Keresztnév', + 'full_name' => 'Teljes név', + 'email' => 'E-mail cím', + 'role_field' => 'Szerepkör', + 'role_comment' => 'Meghatározza a felhasználó jogosultságait. Felülbírálható a felhasználó adatlapján, az Engedélyek fülön.', + 'groups' => 'Csoportok', + 'groups_comment' => 'Adja meg, hogy a felhasználó melyik csoport(ok)ba tartozzon.', + 'avatar' => 'Profilkép', + 'password' => 'Jelszó', + 'password_confirmation' => 'Jelszó megerősítése', + 'permissions' => 'Engedélyek', + 'account' => 'Profil', + 'superuser' => 'Szuperadmin', + 'superuser_comment' => 'Korlátlan hozzáférést biztosít az admin felülethez.', + 'send_invite' => 'Meghívó küldése e-mailben', + 'send_invite_comment' => 'Csak a belépéshez szükséges adatokat tartalmazza.', + 'delete_confirm' => 'Valóban törölni akarja ezt a felhasználót?', + 'return' => 'Vissza az adminokhoz', + 'allow' => 'Engedélyezés', + 'inherit' => 'Öröklés', + 'deny' => 'Tiltás', + 'activated' => 'Aktivált', + 'last_login' => 'Bejelentkezve', + 'created_at' => 'Létrehozva', + 'updated_at' => 'Módosítva', + 'deleted_at' => 'Törölve', + 'show_deleted' => 'Töröltek mutatása', + 'group' => [ + 'name' => 'Csoport', + 'name_comment' => 'A név a csoport létrehozásnál és szerkesztésnél jelenik meg.', + 'name_field' => 'Név', + 'description_field' => 'Leírás', + 'is_new_user_default_field_label' => 'Alapértelmezett csoport', + 'is_new_user_default_field_comment' => 'Az új adminisztrátorok hozzáadása ehhez a csoporthoz.', + 'code_field' => 'Kód', + 'code_comment' => 'Adjon meg egy egyedi kódot, ha az API-val kíván hozzáférni.', + 'menu_label' => 'Csoportok', + 'list_title' => 'Csoportok', + 'new' => 'Új csoport', + 'delete_confirm' => 'Valóban törölni akarja az admin csoportot?', + 'return' => 'Vissza a csoportokhoz', + 'users_count' => 'Felhasználók' + ], + 'role' => [ + 'name' => 'Szerepkör', + 'name_field' => 'Név', + 'name_comment' => 'A szerepkör megnevezése, ami a listákban jelenik meg.', + 'description_field' => 'Leírás', + 'code_field' => 'Kód', + 'code_comment' => 'Egyedi értéket adjon meg, amit az API elérés során használhat.', + 'menu_label' => 'Szerepkörök', + 'list_title' => 'Szerepkörök', + 'new' => 'Új szerepkör', + 'delete_confirm' => 'Valóban törölni akarja a szerepkört?', + 'return' => 'Vissza a szerepkörhöz', + 'users_count' => 'Felhasználók' + ], + 'preferences' => [ + 'not_authenticated' => 'Nincs olyan hitelesített felhasználó, aki számára betölthetők vagy menthetők a beállítások.' + ], + 'trashed_hint_title' => 'Ez a fiók törölve lett', + 'trashed_hint_desc' => 'A visszaállításához kattintson a jobb alsó sarokban található ikonra.' + ], + 'list' => [ + 'default_title' => 'Lista', + 'search_prompt' => 'Keresés...', + 'no_records' => 'Nincs megjeleníthető tartalom', + 'missing_model' => 'Nincs modell definiálva a(z) :class osztályban használt lista viselkedéshez.', + 'missing_column' => 'Nincsenek oszlop definíciók a(z) :columns oszlopok számára.', + 'missing_columns' => 'A(z) :class osztályban használt listának nincsenek definiált lista oszlopai.', + 'missing_definition' => "A lista viselkedés nem tartalmaz oszlopot a(z) ':field' mező számára.", + 'missing_parent_definition' => "A lista viselkedés nem tartalmaz definíciót az alábbihoz: ':definition'.", + 'behavior_not_ready' => 'Nem történt meg a lista viselkedés inicializálása. Kérjük ellenőrizze, hogy meghívta-e a makeLists() függvényt a vezérlőben.', + 'invalid_column_datetime' => "A(z) ':column' oszlopérték nem DateTime objektum, hiányzik egy \$dates hivatkozás a modellben?", + 'pagination' => 'Megjelenítve: :from-:to / :total', + 'first_page' => 'Első lap', + 'last_page' => 'Utolsó lap', + 'prev_page' => 'Előző lap', + 'next_page' => 'Következő lap', + 'refresh' => 'Frissítés', + 'updating' => 'Folyamatban...', + 'loading' => 'Betöltés...', + 'setup_title' => 'Lista testreszabása', + 'setup_help' => 'A jelölőnégyzetek használatával válassza ki azokat az oszlopokat, melyeket látni szeretne a listában. Az oszlopok pozícióját felfelé vagy lefelé húzással módosíthatja.', + 'records_per_page' => 'Listázás', + 'records_per_page_help' => 'Adja meg az elemek laponként megjelenítendő számát. Minél nagyobbat választ, annál több időbe kerül a lista frissítése. Az ajánlott érték 20 és 40 közötti.', + 'check' => 'Bejelöl', + 'delete_selected' => 'Eltávolítás', + 'delete_selected_empty' => 'A törléshez előbb ki kell választani elemet.', + 'delete_selected_confirm' => 'Valóban töröljük a kiválasztott elemeket?', + 'delete_selected_success' => 'Sikeresen törölve lettek a kiválasztott elemek.', + 'column_switch_true' => 'Igen', + 'column_switch_false' => 'Nem' + ], + 'fileupload' => [ + 'attachment' => 'Csatolmány', + 'help' => 'Adja meg a csatolmány címét és a leírását.', + 'title_label' => 'Cím', + 'description_label' => 'Leírás', + 'default_prompt' => 'Hozza ide a fájlt vagy kattintson erre: %s', + 'attachment_url' => 'Csatolmány webcíme', + 'upload_file' => 'Fájl feltöltése', + 'upload_error' => 'Feltöltési hiba', + 'remove_confirm' => 'Biztos benne?', + 'remove_file' => 'Fájl eltávolítása' + ], + 'repeater' => [ + 'add_new_item' => 'Új elem hozzáadása', + 'min_items_failed' => 'A(z) :name mező legalább :max elemből állhat. Jelenleg csak :items mező van megadva.', + 'max_items_failed' => 'A(z) :name mező legfeljebb :max elemből állhat. Jelenleg :items mező van megadva.', + ], + 'form' => [ + 'create_title' => 'Új :name', + 'update_title' => ':name szerkesztése', + 'preview_title' => ':name gyorsnézete', + 'create_success' => 'A(z) :name létrehozása sikerült', + 'update_success' => 'A(z) :name módosítása sikerült', + 'delete_success' => 'A(z) :name törlése sikerült', + 'restore_success' => 'A(z) :name visszaállítása sikerült', + 'reset_success' => 'A visszaállítás sikerült', + 'missing_id' => 'Nincs megadva az űrlap rekord azonosítója.', + 'missing_model' => 'A(z) :class osztályban használt űrlap viselkedésének nincs definiált modellje.', + 'missing_definition' => "Az űrlap viselkedés nem tartalmaz mezőt a(z) ':field' mezőhöz.", + 'not_found' => 'A(z) :id azonosítójú űrlap rekord nem található.', + 'action_confirm' => 'Biztos benne?', + 'create' => 'Létrehozás', + 'create_and_close' => 'Létrehozás és bezárás', + 'creating' => 'Létrehozás...', + 'creating_name' => 'A(z) :name létrehozása...', + 'save' => 'Mentés', + 'save_and_close' => 'Mentés és bezárás', + 'saving' => 'Mentés...', + 'saving_name' => 'A(z) :name mentése...', + 'delete' => 'Törlés', + 'deleting' => 'Törlés...', + 'confirm_delete' => 'Biztos, hogy törölhető?', + 'confirm_delete_multiple' => 'Biztos, hogy mindegyik törölhető?', + 'deleting_name' => 'A(z) :name törlése...', + 'restore' => 'Visszaállítás', + 'restoring' => 'Visszaállítás...', + 'confirm_restore' => 'Biztos, hogy állítsuk vissza?', + 'reset_default' => 'Alaphelyzet', + 'resetting' => 'Visszaállítás', + 'resetting_name' => 'A(z) :name visszaállítása', + 'undefined_tab' => 'Egyebek', + 'field_off' => 'Ki', + 'field_on' => 'Be', + 'add' => 'Hozzáadás', + 'apply' => 'Alkalmaz', + 'cancel' => 'Mégsem', + 'close' => 'Bezárás', + 'confirm' => 'Megerősítés', + 'reload' => 'Újratöltés', + 'complete' => 'Befejezés', + 'ok' => 'Rendben', + 'or' => 'vagy', + 'confirm_tab_close' => 'Valóban be akarja zárni a fület? El fognak veszni a nem mentett módosítások.', + 'behavior_not_ready' => 'Nem történt meg az űrlap viselkedésének inicializálása. Kérjük ellenőrizze, hogy meghívta-e az initForm() függvényt a vezérlőben.', + 'preview_no_files_message' => 'Nincs megadva fájl.', + 'preview_no_media_message' => 'Nincs megadva kép.', + 'preview_no_record_message' => 'Nincs megadva mező.', + 'select' => 'Kiválaszt', + 'select_all' => 'mindegyik', + 'select_none' => 'egyik sem', + 'select_placeholder' => 'válasszon', + 'insert_row' => 'Sor beszúrása', + 'insert_row_below' => 'Sor beszúrása alá', + 'delete_row' => 'Sor törlése', + 'concurrency_file_changed_title' => 'A fájl megváltozott', + 'concurrency_file_changed_description' => 'A jelenleg szerkesztett fájlt egy másik felhasználó már módosította. Újratöltheti és elveszti a változtatásait, vagy felülírja a fájlt.', + 'return_to_list' => 'Vissza a listához' + ], + 'recordfinder' => [ + 'find_record' => 'Tartalom keresése', + 'invalid_model_class' => 'A(z) ":modelClass" modell osztály érvénytelen a tartalom kereséshez.', + 'cancel' => 'Mégsem' + ], + 'pagelist' => [ + 'page_link' => 'Lapok', + 'select_page' => '-- válasszon --' + ], + 'relation' => [ + 'missing_config' => "A reláció viselkedésnek nincs semmilyen konfigurációja a következőhöz: ':config'.", + 'missing_definition' => "A reláció viselkedés nem tartalmazza a(z) ':field' mező definícióját.", + 'missing_model' => 'A(z) :class osztályban használt reláció viselkedésnek nincs definiált modellje.', + 'invalid_action_single' => 'Ez a művelet nem hajtható végre egyetlen kapcsolaton.', + 'invalid_action_multi' => 'Ez a művelet nem hajtható végre több kapcsolaton.', + 'help' => 'Kattintson egy elemre a hozzáadásához', + 'related_data' => 'Kapcsolódó :name adatok', + 'add' => 'Hozzáadás', + 'add_selected' => 'Kijelöltek hozzáadása', + 'add_a_new' => 'Új :name hozzáadása', + 'link_selected' => 'Kijelöltek csatolása', + 'link_a_new' => 'Új :name csatolása', + 'cancel' => 'Mégsem', + 'close' => 'Bezárás', + 'add_name' => ':name hozzáadása', + 'create' => 'Létrehozás', + 'create_name' => ':name létrehozása', + 'update' => 'Frissítés', + 'update_name' => 'A(z) :name frissítése', + 'preview' => 'Előnézet', + 'preview_name' => 'Előnézet neve', + 'remove' => 'Eltávolítás', + 'remove_name' => 'A(z) :name eltávolítása', + 'delete' => 'Törlés', + 'delete_name' => 'A(z) :name törlése', + 'delete_confirm' => 'Biztos benne?', + 'link' => 'Csatolás', + 'link_name' => ':name csatolása', + 'unlink' => 'Csatolás megszüntetése', + 'unlink_name' => ':name csatolásának megszüntetése', + 'unlink_confirm' => 'Biztos benne?' + ], + 'reorder' => [ + 'default_title' => 'Elemek újrarendezése', + 'no_records' => 'Nincs elérhető tartalom a rendezéshez.' + ], + 'model' => [ + 'name' => 'Modell', + 'not_found' => "Nem található :id azonosítójú ':class' modell.", + 'missing_id' => 'Nincs azonosító megadva a modell rekord kereséséhez.', + 'missing_relation' => "A(z) ':class' modell nem tartalmaz definíciót a(z) ':relation' reláció számára.", + 'missing_method' => "A(z) ':class' modell nem tartalmaz ':method' metódust.", + 'invalid_class' => "A(z) :class osztályban használt :model modell nem érvényes, örökölnie kell a \Model osztályt.", + 'mass_assignment_failed' => "A tömeges hozzárendelés a(z) ':attribute' modell attribútumhoz nem sikerült." + ], + 'warnings' => [ + 'tips' => 'Beállítási tippek', + 'tips_description' => 'Az alábbi dolgokra figyeljen oda a rendszer megfelelő működése érdekében.', + 'permissions' => 'A(z) :name könyvtár vagy alkönyvtárai a PHP számára nem írhatóak. Adjon megfelelő engedélyeket a kiszolgálónak erre a könyvtárra.', + 'extension' => 'A(z) :name PHP kiterjesztés nincs telepítve. Telepítse ezt a függvénytárat és aktiválja a kiterjesztést.', + 'plugin_missing' => 'A(z) :name bővítményre szükség van, de nincs telepítve. Kérjük telepítse ezt a bővítményt.', + 'debug' => 'A hibakeresési mód engedélyezve van. Ez nem ajánlott éles weboldal esetén.', + 'decompileBackendAssets' => 'Az admin felülethez tartozó fájlok nem véglegesek. Ez nem ajánlott éles weboldal esetén.' + ], + 'editor' => [ + 'menu_label' => 'Szövegszerkesztő', + 'menu_description' => 'A megjelenésének és működésének testreszabása.', + 'preview' => 'Előnézet', + 'font_size' => 'Betűméret', + 'tab_size' => 'Tabulátor mérete', + 'use_hard_tabs' => 'Behúzás tabulátorokkal', + 'code_folding' => 'Kód összecsukása', + 'code_folding_begin' => 'Jelzés elejénél', + 'code_folding_begin_end' => 'Jelzés elejénél és végénél', + 'autocompletion' => 'Automatikus kiegészítés', + 'word_wrap' => 'Tördelés', + 'highlight_active_line' => 'Aktív sor kiemelése', + 'auto_closing' => 'Automatikus kódlezárás', + 'show_invisibles' => 'Láthatatlan karakterek mutatása', + 'show_gutter' => 'Margó megjelenítése', + 'basic_autocompletion'=> 'Egyszerű mód (Ctrl + Szóköz)', + 'live_autocompletion'=> 'Intelligens mód', + 'enable_snippets'=> 'Kódrészletek engedélyezése (Tab)', + 'display_indent_guides'=> 'Bekezdés megjelenítése', + 'show_print_margin'=> 'Nyomtatási margó mutatása', + 'mode_off' => 'Nincs', + 'mode_fluid' => 'Folytonos', + '40_characters' => '40 karakter', + '80_characters' => '80 karakter', + 'theme' => 'Színséma', + 'markup_styles' => 'Stílusok', + 'custom_styles' => 'Egyéni megjelenés', + 'custom styles_comment' => 'Saját stílusok és megjelenések megadása.', + 'markup_classes' => 'Értékek', + 'paragraph' => 'Bekezdés', + 'link' => 'Hivatkozás', + 'table' => 'Táblázat', + 'table_cell' => 'Táblázat cella', + 'image' => 'Kép', + 'label' => 'Megnevezés', + 'class_name' => 'CSS osztály', + 'markup_tags' => 'Szabályok', + 'markup_tag' => 'Szabály', + 'allowed_empty_tags' => 'Engedélyezett üres elemek', + 'allowed_empty_tags_comment' => 'Azon HTML elemek, amik üres érték esetén sem lesznek eltávolítva.', + 'allowed_tags' => 'Engedélyezett elemek', + 'allowed_tags_comment' => 'Azon HTML elemek, amik használata megengedett.', + 'no_wrap' => 'Nem tördelhető elemek', + 'no_wrap_comment' => 'Azon HTML elemek, amik tartalma nem tördelhető.', + 'remove_tags' => 'Eltávolítható elemek', + 'remove_tags_comment' => 'Azon HTML elemek, amik a tartalmukkal együtt törölhetőek.', + 'line_breaker_tags' => 'Sortörő elemek', + 'line_breaker_tags_comment' => 'Azon HTML elemek, amik végén kötelezően egy új sor jelenik meg.', + 'toolbar_options' => 'Eszköztár', + 'toolbar_buttons' => 'Saját konfiguráció', + 'toolbar_buttons_comment' => 'Az alapértelmezetten megjelenő eszközök listája.', + 'toolbar_buttons_preset' => 'Előre beállított konfigurációk:', + 'toolbar_buttons_presets' => [ + 'default' => 'Alapértelmezett', + 'minimal' => 'Minimális', + 'full' => 'Teljes', + ], + 'paragraph_formats' => 'Bekezdés formátumok', + 'paragraph_formats_comment' => 'Az ehhez tartozó lenyíló listában fognak megjelenni.', + ], + 'tooltips' => [ + 'preview_website' => 'Weboldal megtekintése' + ], + 'mysettings' => [ + 'menu_label' => 'Beállításaim', + 'menu_description' => 'A fiókkal kapcsolatos beállítások' + ], + 'myaccount' => [ + 'menu_label' => 'Fiókom', + 'menu_description' => 'A felhasználói adatok módosítása.', + 'menu_keywords' => 'biztonságos bejelentkezés' + ], + 'branding' => [ + 'menu_label' => 'Testreszabás', + 'menu_description' => 'Az admin felület megjelenésének egyedivé tétele.', + 'brand' => 'Márka', + 'logo' => 'Logó', + 'logo_description' => 'Legalább közepes méretű legyen.', + 'favicon' => 'Favicon', + 'favicon_description' => 'Egyedi ikon az admin felülethez.', + 'app_name' => 'Név', + 'app_name_description' => 'A honlap megnevezése.', + 'app_tagline' => 'Szlogen', + 'app_tagline_description' => 'A weboldal mottója.', + 'colors' => 'Színek', + 'primary_color' => 'Alap szín', + 'secondary_color' => 'Másodlagos szín', + 'accent_color' => 'Hangsúlyos szín', + 'styles' => 'Stílusok', + 'custom_stylesheet' => 'Egyéni megjelenés', + 'navigation' => 'Navigáció', + 'menu_mode' => 'Menü stílusa', + 'menu_mode_inline' => 'Egysoros', + 'menu_mode_inline_no_icons' => 'Egysoros (nincs ikon)', + 'menu_mode_tile' => 'Csempés', + 'menu_mode_collapsed' => 'Összezárt' + ], + 'backend_preferences' => [ + 'menu_label' => 'Beállításaim', + 'menu_description' => 'A működésének testreszabása.', + 'region' => 'Régió', + 'code_editor' => 'Kódszerkesztő', + 'timezone' => 'Időzóna', + 'timezone_comment' => 'Válassza ki az alapértelmezett időzónát.', + 'locale' => 'Nyelv', + 'locale_comment' => 'Válassza ki az alapértelmezett nyelvet.' + ], + 'access_log' => [ + 'hint' => 'Ez a napló a felhasználók sikeres bejelentkezési kísérleteit listázza ki. A bejegyzéseket :days napig őrzi meg a rendszer.', + 'menu_label' => 'Hozzáférés napló', + 'menu_description' => 'A felhasználók sikeres bejelentkezéseinek megtekintése.', + 'id' => 'ID', + 'created_at' => 'Időpont', + 'type' => 'Típus', + 'login' => 'Felhasználónév', + 'ip_address' => 'IP cím', + 'first_name' => 'Keresztnév', + 'last_name' => 'Vezetéknév', + 'email' => 'E-mail cím' + ], + 'filter' => [ + 'all' => 'mind', + 'options_method_not_exists' => "A(z) :model osztálynak kötelező definiálni a(z) :method() metódust a(z) ':filter' szűrő feltételhez.", + 'date_all' => 'minden időszak', + 'number_all' => 'minden szám' + ], + 'import_export' => [ + 'upload_csv_file' => '1. CSV fájl', + 'import_file' => 'Fájl feltöltése', + 'row' => ':row sor', + 'first_row_contains_titles' => 'Az első sor tartalmazza az oszlop neveit', + 'first_row_contains_titles_desc' => 'Hagyja bejelölve, amennyiben a CSV fájl első sora az oszlop neveket tartalmazza.', + 'match_columns' => '2. Oszlopok párosítása', + 'file_columns' => 'Fájl oszlopok', + 'database_fields' => 'Adatbázis oszlopok', + 'set_import_options' => '3. További beállítások', + 'export_output_format' => '1. CSV fájl', + 'file_format' => 'Fájl formátuma', + 'standard_format' => 'Szabvány formátum', + 'custom_format' => 'Egyedi formátum', + 'delimiter_char' => 'Határoló karakter', + 'enclosure_char' => 'Elválasztó karakter', + 'escape_char' => 'Végjel karakter', + 'select_columns' => '2. Oszlopok kiválasztása', + 'column' => 'Oszlop', + 'columns' => 'Oszlopok', + 'set_export_options' => '3. Exportálási beállítások', + 'show_ignored_columns' => 'Figyelmen kívül hagyott oszlopok mutatása', + 'auto_match_columns' => 'Automatikus oszlop párosítás', + 'created' => 'Létrehozva', + 'updated' => 'Frissítve', + 'skipped' => 'Kihagyva', + 'warnings' => 'Figyelmeztetések', + 'errors' => 'Hibák', + 'skipped_rows' => 'Kihagyott sorok', + 'import_progress' => 'Importálás folyamatban...', + 'processing' => 'Folyamatban', + 'import_error' => 'Importálási hiba', + 'upload_valid_csv' => 'Kérjük töltsön fel érvényes CSV fájlt.', + 'drop_column_here' => 'Húzza ide az oszlopot...', + 'ignore_this_column' => 'Figyelmen kívül hagyott oszlop', + 'processing_successful_line1' => 'Az exportálási folyamat sikeresen lezárult!', + 'processing_successful_line2' => 'A böngésző elkezdi a fájl letöltését.', + 'export_progress' => 'Exportálás folyamatban', + 'export_error' => 'Exportálási hiba', + 'column_preview' => 'Oszlop előnézete', + 'file_not_found_error' => 'A fájl nem található', + 'empty_error' => 'Nincs adat az exportáláshoz.', + 'empty_import_columns_error' => 'Kérjük adjon meg néhány oszlopot az importáláshoz.', + 'match_some_column_error' => 'Kérjük elsőként párosítson össze oszlopokat.', + 'required_match_column_error' => 'Kérjük adja meg a párosítást ehhez a kötelező mezőhöz: :label.', + 'empty_export_columns_error' => 'Kérjük adjon meg néhány oszlopot az exportáláshoz.', + 'behavior_missing_uselist_error' => 'Szükséges implementálni a ListController vezérlőt a "useList" engedélyezése esetén.', + 'missing_model_class_error' => 'Kérjük adja meg a modelClass tulajdonságát ehhez: :type', + 'missing_column_id_error' => 'Hiányzó oszlop azonosító', + 'unknown_column_error' => 'Ismeretlen oszlop', + 'encoding_not_supported_error' => 'A forrásfájl kódolása nem felismerhető. Kérjük válassza ki a listából a megfelelő kódolást.', + 'encoding_format' => 'Fájl kódolása', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Nyugat-európai)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Közép-európai)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, Dél-európai)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, Észak-európai)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cirill)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arab)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Görög)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Héber)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Török)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Északi)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Balti)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Kelta)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Nyugat-európai Euró jellel)', + 'windows_1250' => 'Windows-1250 (CP1250, Közép- és kelet-európai)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Média kezelése', + 'allow_unsafe_markdown' => 'Nem biztonságos szerkesztő használata', + ], + 'mediafinder' => [ + 'label' => 'Média', + 'default_prompt' => 'Kattintson a(z) %s gombra új média fájl kereséséhez.', + 'no_image' => 'A kép nem található' + ], + 'media' => [ + 'menu_label' => 'Média', + 'upload' => 'Feltöltés', + 'move' => 'Áthelyezés', + 'delete' => 'Törlés', + 'add_folder' => 'Könyvtár létrehozása', + 'search' => 'Keresés...', + 'display' => 'Megjelenítés', + 'filter_everything' => 'Összes', + 'filter_images' => 'Kép', + 'filter_video' => 'Videó', + 'filter_audio' => 'Audió', + 'filter_documents' => 'Dokumentum', + 'library' => 'Média', + 'size' => 'Méret', + 'title' => 'Név', + 'last_modified' => 'Módosítva', + 'public_url' => 'Webcím', + 'click_here' => 'Megtekintés', + 'thumbnail_error' => 'Hiba a bélyegkép létrehozásánál.', + 'return_to_parent' => 'Vissza a szülő könyvtárhoz', + 'return_to_parent_label' => 'Eggyel vissza ..', + 'nothing_selected' => 'Nincs kiválasztva fájl.', + 'multiple_selected' => 'Több fájl kiválasztva.', + 'uploading_file_num' => 'Feltöltve :number fájl...', + 'uploading_complete' => 'Feltöltés sikeresen befejezve', + 'uploading_error' => 'Feltöltés sikertelen', + 'type_blocked' => 'A fájltípus blokkolva lett biztonsági okokból.', + 'order_by' => 'Rendezés', + 'direction' => 'Irány', + 'direction_asc' => 'Növekvő', + 'direction_desc' => 'Csökkenő', + 'folder' => 'Könyvtár', + 'no_files_found' => 'Nem található fájl a lekérésben.', + 'delete_empty' => 'Kérjük válassza ki a törölni kívánt fájlokat.', + 'delete_confirm' => 'Valóban törölni akarja a kiválasztott fájlokat?', + 'error_renaming_file' => 'Hiba a fájl átnevezésében.', + 'new_folder_title' => 'Új könyvtár', + 'folder_name' => 'Könyvtár neve', + 'error_creating_folder' => 'Hiba a könyvtár létrehozásánál', + 'folder_or_file_exist' => 'Már létezik ilyen nevű fájl vagy könyvtár.', + 'move_empty' => 'Kérjük válasszon ki fájlt az áthelyezéshez.', + 'move_popup_title' => 'Fájlok vagy könyvtárak áthelyezése', + 'move_destination' => 'Célkönyvtár', + 'please_select_move_dest' => 'Kérjük válasszon célkönyvtárat.', + 'move_dest_src_match' => 'Kérjük válasszon másik célkönyvtárat.', + 'empty_library' => 'Kezdésként hozzon létre könyvtárat és töltsön fel fájlokat.', + 'insert' => 'Beillesztés', + 'crop_and_insert' => 'Vágás és beillesztés', + 'select_single_image' => 'Kérjük válasszon ki egy képet.', + 'selection_not_image' => 'A kiválasztott fájl nem kép.', + 'restore' => 'Összes változtatás visszavonása', + 'resize' => 'Átméretezés...', + 'selection_mode_normal' => 'Normál', + 'selection_mode_fixed_ratio' => 'Rögzített képarány', + 'selection_mode_fixed_size' => 'Rögzített méret', + 'height' => 'Magasság', + 'width' => 'Szélesség', + 'selection_mode' => 'Kiválasztás módja', + 'resize_image' => 'Kép átméretezése', + 'image_size' => 'Kép mérete:', + 'selected_size' => 'Kiválasztva:' + ] +]; diff --git a/modules/backend/lang/id/lang.php b/modules/backend/lang/id/lang.php new file mode 100644 index 0000000..b3e7ce4 --- /dev/null +++ b/modules/backend/lang/id/lang.php @@ -0,0 +1,301 @@ + [ + 'title' => 'Area Administrasi' + ], + 'field' => [ + 'invalid_type' => 'Jenis medan tidak valid digunakan :type.', + 'options_method_not_exists' => "Kelas model :model harus menentukan metode :method() yang mengembalikan opsi untuk borang medan ':field'." + ], + 'widget' => [ + 'not_registered' => "Kelas gawit bernama ':name' belum terdaftar", + 'not_bound' => "Gawit dengan kelas bernama ':name' belum terikat pada controller" + ], + 'page' => [ + 'untitled' => 'Tak Berjudul', + 'access_denied' => [ + 'label' => 'Akses ditolak', + 'help' => "Anda tidak memiliki izin untuk melihat laman ini.", + 'cms_link' => 'Kembali ke back-end' + ] + ], + 'partial' => [ + 'not_found' => "Potongan ':name' tidak ditemukan." + ], + 'account' => [ + 'sign_out' => 'Keluar', + 'login' => 'Catat Masuk', + 'reset' => 'Atur Ulang', + 'restore' => 'Pulihkan', + 'login_placeholder' => 'Nama Pengguna', + 'password_placeholder' => 'Sandi Lewat', + 'forgot_password' => 'Lupa sandi lewat Anda?', + 'enter_email' => 'Masukan surel Anda', + 'enter_login' => 'Masukan nama pengguna Anda', + 'email_placeholder' => 'Surel', + 'enter_new_password' => 'Masukan sandi lewat baru', + 'password_reset' => 'Atur Ulang Sandi Lewat', + 'restore_success' => 'Sebuah surat berisi petunjuk pemulihan telah dikirim ke alamat surat elektronik Anda.', + 'restore_error' => "Pengguna dengan nama pengguna ':login' tidak ditemukan", + 'reset_success' => 'Sandi lewat Anda telah diatur ulang. Anda dapat catat masuk sekarang.', + 'reset_error' => 'Data atur ulang sandi lewat yang diberikan tidak valid. Silakan ulangi lagi!', + 'reset_fail' => 'Tidak dapat mengatur ulang sandi lewat Anda!', + 'apply' => 'Terapkan', + 'cancel' => 'Urung', + 'delete' => 'Hapus', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Dasbor', + 'widget_label' => 'Gawit', + 'widget_width' => 'Lebar', + 'full_width' => 'lebar penuh', + 'add_widget' => 'Tambah gawit', + 'widget_inspector_title' => 'Penyusunan gawit', + 'widget_inspector_description' => 'Susun gawit laporan', + 'widget_columns_label' => 'Lebar :columns', + 'widget_columns_description' => 'Lebar gawit, angka antara 1 sampai 10.', + 'widget_columns_error' => 'Silakan masukan angka lebar gawit antara 1 sampai 10.', + 'columns' => '{1} kolom|[2,Inf] kolom', + 'widget_new_row_label' => 'Paksa baris baru', + 'widget_new_row_description' => 'Letakkan gawit pada baris baru.', + 'widget_title_label' => 'Tajuk gawit', + 'widget_title_error' => 'Tajuk gawit diperlukan.', + 'status' => [ + 'widget_title_default' => 'Status sistem', + 'update_available' => '{0} pembaruan tersedia!|{1} pembaruan tersedia!|[2,Inf] pembaruan tersedia!' + ] + ], + 'user' => [ + 'name' => 'Administrator', + 'menu_label' => 'Administrator', + 'menu_description' => 'Kelola pengguna adminstrator back-end, grup, dan perizinan.', + 'list_title' => 'Kelola Administrator', + 'new' => 'Administrator Baru', + 'login' => 'Nama Pengguna', + 'first_name' => 'Name Depan', + 'last_name' => 'Name Belakang', + 'full_name' => 'Nama Lengkap', + 'email' => 'Surel', + 'groups' => 'Grup', + 'groups_comment' => 'Tentukan grup yang dimiliki pengguna ini.', + 'avatar' => 'Avatar', + 'password' => 'Sandi lewat', + 'password_confirmation' => 'Tegaskan sandi lewat', + 'permissions' => 'Izin', + 'superuser' => 'Pengguna Super', + 'superuser_comment' => 'Centang kotak ini untuk memperkenankan pengguna ini mengakses semua area.', + 'send_invite' => 'Kirim undangan dengan surel', + 'send_invite_comment' => 'Gunakan kotak cek ini untuk mengirimi pengguna undangan surel', + 'delete_confirm' => 'Anda yakin akan menghapus administrator ini?', + 'return' => 'Kembali ke senarai administrator', + 'allow' => 'Boleh', + 'inherit' => 'Mewarisi', + 'deny' => 'Tolak', + 'group' => [ + 'name' => 'Grup', + 'name_field' => 'Nama', + 'description_field' => 'Jabaran', + 'is_new_user_default_field' => 'Tambahkan administrator baru pada grup ini secara asali', + 'code_field' => 'Kode', + 'code_comment' => 'Masukkan kode unik jika Anda ingin mengakses ini dengan API.', + 'menu_label' => 'Grup', + 'list_title' => 'Kelola Grup', + 'new' => 'Grup Administrator Baru', + 'delete_confirm' => 'Anda yakin akan menghapus grup administrator ini?', + 'return' => 'Kembali ke senarai grup', + ], + 'preferences' => [ + 'not_authenticated' => 'Tidak ada pengguna berotentikasi untuk memuat atau menyimpan pengaturan.' + ] + ], + 'list' => [ + 'default_title' => 'Senarai', + 'search_prompt' => 'Pencarian...', + 'no_records' => 'Tidak ada rekam dalam tampilan ini.', + 'missing_model' => 'Behavior Senarai yang digunakan dalam :class tidak memiliki tetapan model.', + 'missing_column' => 'Tidak ada tetapan untuk kolom :columns.', + 'missing_columns' => 'Senarai yang digunakan dalam :class tidak memiliki tetapan kolom senarai.', + 'missing_definition' => "Behavior Senarai tidak berisi kolom untuk ':field'.", + 'behavior_not_ready' => 'Behavior Senarai belum diinisialisasi, periksa apakah Anda telah memanggil makeLists() pada controller Anda.', + 'invalid_column_datetime' => "Nilai kolom ':column' bukan objek DateTime, apakah Anda lupa merujukkan \$dates dalam Model?", + 'pagination' => 'Menampilkan rekam: :from s/d :to dari :total', + 'prev_page' => 'Sebelumnya', + 'next_page' => 'Berikutnya', + 'loading' => 'Memuat...', + 'setup_title' => 'Pengaturan Senarai', + 'setup_help' => 'Gunakan kotak cek untuk memilih kolom yang ingin ditampilkan pada senarai. Anda dapat mengubah posisi kolom dengan menyeretnya naik atau turun.', + 'records_per_page' => 'Rekam per laman', + 'records_per_page_help' => 'Pilih jumlah rekam per laman untuk ditampilkan. Mohon diingat, jumlah rekam yang banyak dalam satu halaman dapat menurunkan kinerja.', + 'delete_selected' => 'Hapus yang terpilih', + 'delete_selected_empty' => 'Tidak ada rekam terpilih untuk dihapus.', + 'delete_selected_confirm' => 'Hapus rekam terpilih?', + 'delete_selected_success' => 'Berhasil menghapus rekam terpilih.', + ], + 'fileupload' => [ + 'attachment' => 'Lampiran', + 'help' => 'Tambah judul dan jabaran untuk lampiran ini.', + 'title_label' => 'Judul', + 'description_label' => 'Jabaran' + ], + 'form' => [ + 'create_title' => ':name Baru', + 'update_title' => 'Sunting :name', + 'preview_title' => 'Tinjau :name', + 'create_success' => ':name berhasil dibuat', + 'update_success' => ':name berhasil diperbarui', + 'delete_success' => ':name berhasil dihapus', + 'missing_id' => 'Borang ID rekam belum ditentukan.', + 'missing_model' => 'Behavior borang yang digunakan dalam :class tidak memiliki ketentuan model.', + 'missing_definition' => "Behavior borang tidak berisi medan untuk ':field'.", + 'not_found' => 'Borang untuk rekam dengan ID :id tidak ditemukan.', + 'action_confirm' => 'Anda yakin?', + 'create' => 'Buat', + 'create_and_close' => 'Buat dan tutup', + 'creating' => 'Membuat...', + 'creating_name' => 'Membuat :name...', + 'save' => 'Simpan', + 'save_and_close' => 'Simpan dan tutup', + 'saving' => 'Menyimpan...', + 'saving_name' => 'Menyimpan :name...', + 'delete' => 'Menghapus', + 'deleting' => 'Menghapus...', + 'deleting_name' => 'Menghapus :name...', + 'reset_default' => 'Atur ulang ke asali', + 'resetting' => 'Pengaturan ulang', + 'resetting_name' => 'Pengaturan ulang :name', + 'undefined_tab' => 'Lain-lain', + 'field_off' => 'Off', + 'field_on' => 'On', + 'add' => 'Tambah', + 'apply' => 'Terapkan', + 'cancel' => 'Urung', + 'close' => 'Tutup', + 'confirm' => 'Tetapkan', + 'reload' => 'Muat ulang', + 'ok' => 'OK', + 'or' => 'atau', + 'confirm_tab_close' => 'Anda yakin akan menutup tab? Perubahan belum tersimpan akan hilang.', + 'behavior_not_ready' => 'Behavior borang belum diinisialisasi, periksa apakah Anda telah memanggil initForm() pada controller Anda.', + 'preview_no_files_message' => 'Berkas tidak terunggah', + 'select' => 'Pilih', + 'select_all' => 'Pilih Semua', + 'select_none' => 'Pilih tidak ada', + 'select_placeholder' => 'silakan pilih', + 'insert_row' => 'Sisipkan Baris', + 'delete_row' => 'Hapus Baris', + 'concurrency_file_changed_title' => 'Berkas telah diubah', + 'concurrency_file_changed_description' => "Berkas yang Anda sunting telah diubah pada diska oleh pengguna lain. Anda dapat memuat ulang berkas dan kehilangan perubahan yang telah Anda buat atau menimpa berkas pada diska." + ], + 'relation' => [ + 'missing_config' => "Behavior hubungan tidak memiliki pengaturan untuk ':config'.", + 'missing_definition' => "Behavior hubungan tidak berisi tentuan untuk ':field'.", + 'missing_model' => "Behavior hubungan yang digunakan dalam :class tidak memiliki ketentuan model.", + 'invalid_action_single' => "Aksi ini tidak dapat dilaksanakan di dalam perhubungan tungal.", + 'invalid_action_multi' => "Aksi ini tidak dapat dilaksanakan di dalam perhubungan banyak.", + 'help' => "Klik pada butir untuk menambah", + 'related_data' => "Terhubung data :name", + 'add' => "Tambah", + 'add_selected' => "Tambah terpilih", + 'add_a_new' => "Tambah :name baru", + 'link_selected' => "Taut terpilih", + 'link_a_new' => "Taut :name baru", + 'cancel' => "Urung", + 'close' => "Tutup", + 'add_name' => "Tambah :name", + 'create' => "Buat", + 'create_name' => "Buat :name", + 'update' => "Perbarui", + 'update_name' => "Perbarui :name", + 'preview' => "Tinjau", + 'preview_name' => "Tinjau :name", + 'remove' => "Lepas", + 'remove_name' => "Lepas :name", + 'delete' => "Hapus", + 'delete_name' => "Hapus :name", + 'delete_confirm' => "Anda yakin?", + 'link' => "Taut", + 'link_name' => "Taut :name", + 'unlink' => "Buka Taut", + 'unlink_name' => "Buka Taut :name", + 'unlink_confirm' => "Anda yakin?", + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => "Model ':class' dengan ID :id tidak dapat ditemukan", + 'missing_id' => 'Tidak ada ID ditentukan untuk mencari rekam model.', + 'missing_relation' => "Model ':class' tidak berisi tentuan untuk ':relation'.", + 'missing_method' => "Model ':class' tidak berisi metode ':method'.", + 'invalid_class' => "Model :model yang digunakan pada :class tidak valid, model harus turunan kelas \Model.", + 'mass_assignment_failed' => "Penetapan masal gagal untuk atribut Model ':attribute'." + ], + 'warnings' => [ + 'tips' => 'Kiat pengaturan sistem', + 'tips_description' => 'Ada masalah yang perlu Anda perhatikan untuk mengatur sistem dengan tepat.', + 'permissions' => 'Direktori :name atau direktori di bawahnya tidak dapat ditulis oleh PHP. Silakan atur hak akses webserver yang sesuai pada direktori ini.', + 'extension' => 'Ekstensi PHP :name tidak terpasang. Silakan pasang pustaka ini dan aktifkan ekstensi.' + ], + 'editor' => [ + 'menu_label' => 'Penyesuaian Penyunting Kode', + 'menu_description' => 'Penyesuaian penyunting kode dengan keinginan Andan, seperti ukuran fonta dan skema warna.', + 'font_size' => 'Ukuran fonta', + 'tab_size' => 'Ukuran tab', + 'use_hard_tabs' => 'Inden dengan tabs', + 'code_folding' => 'Pelipat kode', + 'word_wrap' => 'Bungkus kata', + 'highlight_active_line' => 'Sorot baris aktif', + 'show_invisibles' => 'Tampilkan karakter tak terlihat', + 'show_gutter' => 'Tampilkan parit', + 'theme' => 'Skema warna' + ], + 'tooltips' => [ + 'preview_website' => 'Tinjau website' + ], + 'mysettings' => [ + 'menu_label' => 'Pengaturanku', + 'menu_description' => 'Pengaturan yang berkaitan dengan akun administrasi Anda' + ], + 'myaccount' => [ + 'menu_label' => 'Akunku', + 'menu_description' => 'Perbarui rincian akun Anda seperti nama, alamat surel dan sandi lewat.', + 'menu_keywords' => 'security login' + ], + 'branding' => [ + 'menu_label' => 'Penyesuaian back-end', + 'menu_description' => 'Penyesuaian area administrasi seperti nama, warna dan logo.', + 'brand' => 'Brand', + 'logo' => 'Logo', + 'logo_description' => 'Unggah logo ubah suai untuk digunakan pada back-end.', + 'app_name' => 'Nama Apl', + 'app_name_description' => 'Nama ini ditampilkan pada area judul back-end.', + 'app_tagline' => 'Slogan Apl', + 'app_tagline_description' => 'Nama ini akan ditampilkan pada layar masuk back-end.', + 'colors' => 'Warna', + 'primary_color' => 'Primer color', + 'secondary_color' => 'Sekunder color', + 'accent_color' => 'Accent color', + 'styles' => 'Gaya', + 'custom_stylesheet' => 'Lembar gaya ubah suai' + ], + 'backend_preferences' => [ + 'menu_label' => 'Penyesuaian Back-end', + 'menu_description' => 'Kelola penyesuaian akun Anda seperti bahasa yang diinginkan.', + 'locale' => 'Bahasa', + 'locale_comment' => 'Pilih bahasa lokal yang ingin digunakan.' + ], + 'access_log' => [ + 'hint' => 'Catatan ini menampilkan senarai percobaan masuk yang berhasil oleh administrator. Rekam akan disimpan selama :days hari.', + 'menu_label' => 'Catatan akses', + 'menu_description' => 'Tampilan senarai pengguna back-end yang berhasil masuk.', + 'created_at' => 'Tanggal & Waktu', + 'login' => 'Nama Pengguna', + 'ip_address' => 'Alamat IP', + 'first_name' => 'Nama depan', + 'last_name' => 'Nama belakang', + 'email' => 'Surel' + ], + 'filter' => [ + 'all' => 'semua' + ] +]; diff --git a/modules/backend/lang/it/lang.php b/modules/backend/lang/it/lang.php new file mode 100644 index 0000000..e0dab8b --- /dev/null +++ b/modules/backend/lang/it/lang.php @@ -0,0 +1,540 @@ + [ + 'title' => 'Area di Amministrazione' + ], + 'field' => [ + 'invalid_type' => 'Il tipo di campo :type non è valido.', + 'options_method_not_exists' => 'La classe :model deve definire un metodo :method() che ritorni le opzioni per il campo ":field".' + ], + 'widget' => [ + 'not_registered' => "Nessun widget ':name' è stato registrato", + 'not_bound' => "Nessun widget ':name' è stato legato al controller", + ], + 'page' => [ + 'untitled' => 'Senza titolo', + 'access_denied' => [ + 'label' => 'Accesso negato', + 'help' => "Non hai le autorizzazioni necessarie per accedere a questa pagina.", + 'cms_link' => 'Ritorna al pannello di controllo' + ], + ], + 'partial' => [ + 'not_found_name' => "La vista parziale ':name' non è stata trovata." + ], + 'account' => [ + 'sign_out' => 'Esci', + 'login' => 'Accedi', + 'reset' => 'Reimposta', + 'restore' => 'Ripristina', + 'login_placeholder' => 'login', + 'password_placeholder' => 'password', + 'forgot_password' => 'Password dimenticata?', + 'enter_email' => 'Inserisci in tuo indirizzo e-mail', + 'enter_login' => 'Inserisci il tuo username.', + 'email_placeholder' => 'email', + 'enter_new_password' => 'Inserisci una nuova password', + 'password_reset' => 'Reimposta password', + 'restore_success' => 'Le istruzioni per reimpostare la password sono state inviate al tuo indirizzo e-mail.', + 'restore_error' => "Nessun utente con username ':login' è stato trovato.", + 'reset_success' => 'La tua password è stata reimpostata con successo. Ora puoi effettuare l\'accesso.', + 'reset_error' => 'I dati forniti per la reimpostazione della password non sono validi. Riprova!', + 'reset_fail' => 'Impossibile ripristinare la password!', + 'apply' => 'Applica', + 'cancel' => 'Annulla', + 'delete' => 'Elimina', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Dashboard', + 'widget_label' => 'Widget', + 'widget_width' => 'Larghezza', + 'full_width' => 'intera larghezza', + 'manage_widgets' => 'Gestisci widget', + 'add_widget' => 'Aggiungi widget', + 'widget_inspector_title' => 'Configurazione widget', + 'widget_inspector_description' => 'Configura il widget', + 'widget_columns_label' => 'Larghezza :columns', + 'widget_columns_description' => 'La larghezza del widget, un numero compreso tra 1 e 10.', + 'widget_columns_error' => 'La larghezza del widget deve essere un numero compreso tra 1 e 10.', + 'columns' => '{1} colonna|[2,Inf] colonne', + 'widget_new_row_label' => 'Forza nuova riga', + 'widget_new_row_description' => 'Inserisci il widget su una nuova riga.', + 'widget_title_label' => 'Titolo del widget', + 'widget_title_error' => 'Il titolo del widget è obbligatorio.', + 'reset_layout' => 'Reimposta layout', + 'reset_layout_confirm' => 'Reimpostare il layout ai valori predefiniti?', + 'reset_layout_success' => 'Il layout è stato reimpostato', + 'make_default' => 'Rendi predefinito', + 'make_default_confirm' => 'Impostare il layout corrente come predefinito?', + 'make_default_success' => 'Il layout corrente è ora il predefinito', + 'status' => [ + 'widget_title_default' => 'Stato del sistema', + 'update_available' => '{0} aggiornamenti disponibili!|{1} aggiornamento disponibile!|[2,Inf] aggiornamenti disponibili!', + 'updates_pending' => 'Aggiornamenti software in attesa', + 'updates_nil' => 'Il software è aggiornato', + 'updates_link' => 'Aggiorna', + 'warnings_pending' => 'Alcuni problemi hanno bisogno di attenzione', + 'warnings_nil' => 'Nessun avviso da visualizzare', + 'warnings_link' => 'Visualizza', + 'core_build' => 'Build di sistema', + 'event_log' => 'Log eventi', + 'request_log' => 'Log richieste', + 'app_birthday' => 'Online dal', + ], + 'welcome' => [ + 'widget_title_default' => 'Benvenuto', + 'welcome_back_name' => 'Bentornato su :app, :name.', + 'welcome_to_name' => 'Benvenuto su :app, :name.', + 'first_sign_in' => 'Questa è la prima volta che hai eseguito l\'accesso.', + 'last_sign_in' => 'Il tuo ultimo accesso è stato ', + 'view_access_logs' => 'Visualizza log accessi', + 'nice_message' => 'Buona giornata!', + ] + ], + 'user' => [ + 'name' => 'Amministratore', + 'menu_label' => 'Amministratori', + 'menu_description' => 'Gestisci gli utenti amministratori, i gruppi e le autorizzazioni.', + 'list_title' => 'Gestisci amministratori', + 'new' => 'Nuovo amministratore', + 'login' => 'Login', + 'first_name' => 'Nome', + 'last_name' => 'Cognome', + 'full_name' => 'Nome completo', + 'email' => 'Indirizzo e-mail', + 'groups' => 'Gruppi', + 'groups_comment' => 'Seleziona i gruppi a cui appartiene l\'utente.', + 'avatar' => 'Avatar', + 'password' => 'Password', + 'password_confirmation' => 'Conferma password', + 'permissions' => 'Autorizzazioni', + 'account' => 'Account', + 'superuser' => 'Super User', + 'superuser_comment' => 'Seleziona per consentire all\'utente di accedere a tutte le aree.', + 'send_invite' => 'Invia invito tramite e-mail', + 'send_invite_comment' => 'Invia un messaggio di benvenuto contenente le credenziali per l\'accesso.', + 'delete_confirm' => 'Vuoi davvero eliminare questo amministratore?', + 'return' => 'Ritorna alla lista degli amministratori', + 'allow' => 'Consenti', + 'inherit' => 'Eredita', + 'deny' => 'Nega', + 'group' => [ + 'name' => 'Gruppo', + 'name_comment' => 'Il nome viene visualizzato nell\'elenco dei gruppi del form di Creazione/Modifica Amministratore ', + 'name_field' => 'Nome', + 'description_field' => 'Descrizione', + 'is_new_user_default_field_label' => 'Gruppo predefinito', + 'is_new_user_default_field_comment' => 'Aggiungi i nuovi amministratori a questo gruppo per impostazione predefinita.', + 'code_field' => 'Codice', + 'code_comment' => 'Inserisci un codice univoco se vuoi accedere a questo elementro tramite API.', + 'menu_label' => 'Gruppi', + 'list_title' => 'Gestisci gruppi', + 'new' => 'Nuovo gruppo', + 'delete_confirm' => 'Vuoi davvero eliminare questo gruppo amministratore?', + 'return' => 'Ritorna alla lista dei gruppi', + 'users_count' => 'Utenti' + ], + 'preferences' => [ + 'not_authenticated' => 'Non c\'è nessun utente autenticato per cui caricare o salvare le preferenze.' + ] + ], + 'list' => [ + 'default_title' => 'Elenco', + 'search_prompt' => 'Cerca...', + 'no_records' => 'Nessun risultato trovato.', + 'missing_model' => 'L\'elenco utilizzato nella classe :class non ha un modello definito.', + 'missing_column' => 'Non ci sono colonne definite per :columns.', + 'missing_columns' => 'L\'elenco utilizzato nella classe :class non ha un elenco di colonne definito.', + 'missing_definition' => "L'elenco non contiene una colonna per il campo ':field'.", + 'missing_parent_definition' => "L\'elenco non contiene una definizione per ':definition'.", + 'behavior_not_ready' => 'Il comportamento "elenco" non è stato inizializzato, controlla di aver chiamato il metodo makeLists() nel controller.', + 'invalid_column_datetime' => "Il valore della colonna ':column' non è un oggetto di tipo DateTime, hai dimenticato un riferimento a \$dates nel modello?", + 'pagination' => 'Record visualizzati: :from-:to di :total', + 'prev_page' => 'Pagina precedente', + 'next_page' => 'Pagina successiva', + 'refresh' => 'Ricarica', + 'updating' => 'Aggiornamento in corso...', + 'loading' => 'Caricamento...', + 'setup_title' => 'Configura elenco', + 'setup_help' => 'Utilizza le checkbox per selezionare le colonne che vuoi visualizzare nell\'elenco. Puoi cambiare la posizione delle colonne trascinandole verso l\'alto o il basso.', + 'records_per_page' => 'Record per pagina', + 'records_per_page_help' => 'Seleziona il numero di record da visualizzare su ogni pagina. Ricorda che un numero elevato di record in una singola pagina può ridurre le prestazioni.', + 'check' => 'Spunta', + 'delete_selected' => 'Elimina selezionati', + 'delete_selected_empty' => 'Non hai selezionato nessun record da eliminare.', + 'delete_selected_confirm' => 'Elimina i record selezionati?', + 'delete_selected_success' => 'I record selezionati sono stati eliminati con successo.', + 'column_switch_true' => 'Sì', + 'column_switch_false' => 'No' + ], + 'fileupload' => [ + 'attachment' => 'Allegato', + 'help' => 'Aggiungi un titolo e una descrizione per questo allegato.', + 'title_label' => 'Titolo', + 'description_label' => 'Descrizione', + 'default_prompt' => 'Fai clic su %s o trascina un file qui per eseguire il caricamento', + 'attachment_url' => 'URL Allegato', + 'upload_file' => 'Carica file', + 'upload_error' => 'Errore nel caricamento', + 'remove_confirm' => 'Sei sicuro?', + 'remove_file' => 'Rimuovi file' + ], + 'form' => [ + 'create_title' => 'Crea :name', + 'update_title' => 'Modifica :name', + 'preview_title' => 'Anteprima :name', + 'create_success' => ':name creato con successo', + 'update_success' => ':name modificato con successo', + 'delete_success' => ':name eliminato con successo', + 'reset_success' => 'Reimpostazione completata', + 'missing_id' => 'L\'ID del record non è stato specificato.', + 'missing_model' => 'Il form utilizzato nella classe :class non ha un modello definito.', + 'missing_definition' => "Il form non contiene il campo ':field'.", + 'not_found' => 'Nessun record con ID :id è stato trovato.', + 'action_confirm' => 'Sei sicuro?', + 'create' => 'Crea', + 'create_and_close' => 'Crea e chiudi', + 'creating' => 'Creazione in corso...', + 'creating_name' => 'Creazione :name in corso...', + 'save' => 'Salva', + 'save_and_close' => 'Salva e chiudi', + 'saving' => 'Salvataggio in corso...', + 'saving_name' => 'Salvataggio :name in corso...', + 'delete' => 'Elimina', + 'deleting' => 'Eliminazione in corso...', + 'confirm_delete' => 'Elimina record?', + 'confirm_delete_multiple' => 'Elimina i record selezionati?', + 'deleting_name' => 'Eliminazione :name in corso...', + 'reset_default' => 'Ripristina predefiniti', + 'resetting' => 'Ripristino in corso', + 'resetting_name' => 'Ripristino :name in corso', + 'undefined_tab' => 'Varie', + 'field_off' => 'Off', + 'field_on' => 'On', + 'add' => 'Aggiungi', + 'apply' => 'Applica', + 'cancel' => 'Annulla', + 'close' => 'Chiudi', + 'confirm' => 'Conferma', + 'reload' => 'Ricarica', + 'complete' => 'Completo', + 'ok' => 'OK', + 'or' => 'o', + 'confirm_tab_close' => 'Vuoi davvero chiudere il tab? Le modifiche non salvate andranno perse.', + 'behavior_not_ready' => 'Il comportamento del form non è stato inizializzato, verifica di aver chiamato il metodo initForm() nel controller.', + 'preview_no_files_message' => 'Non ci sono file caricati.', + 'preview_no_record_message' => 'Nessun record selezionato.', + 'select' => 'Seleziona', + 'select_all' => 'seleziona tutto', + 'select_none' => 'deseleziona tutto', + 'select_placeholder' => 'seleziona', + 'insert_row' => 'Inserisci riga', + 'insert_row_below' => 'Inserisci riga sotto', + 'delete_row' => 'Elimina riga', + 'concurrency_file_changed_title' => 'Il file è stato cambiato', + 'concurrency_file_changed_description' => "Il file che stavi modificando è stato cambiato da un altro utente. Puoi ricaricare il file e perdere le tue modifiche oppure sovrascrivere il file sul disco.", + 'return_to_list' => 'Ritorna all\'elenco' + ], + 'recordfinder' => [ + 'find_record' => 'Trova record' + ], + 'relation' => [ + 'missing_config' => "La relazione non ha nessuna configurazione per ':config'.", + 'missing_definition' => "La relazione non contiene una definizione per il campo ':field'.", + 'missing_model' => 'La relazione utilizzata nella classe :class non ha un modello definito.', + 'invalid_action_single' => 'L\'azione non può essere eseguita su una relazione singola.', + 'invalid_action_multi' => 'L\'azione non può essere eseguita su una relazione multipla.', + 'help' => 'Fai clic su un elemento per aggiungere', + 'related_data' => 'Dati :name correlati', + 'add' => 'Aggiungi', + 'add_selected' => 'Aggiungi selezionati', + 'add_a_new' => 'Aggiungi nuovo :name', + 'link_selected' => 'Collega selezionati', + 'link_a_new' => 'Collega nuovo :name', + 'cancel' => 'Annulla', + 'close' => 'Chiudi', + 'add_name' => 'Aggiungi :name', + 'create' => 'Crea', + 'create_name' => 'Crea :name', + 'update' => 'Aggiorna', + 'update_name' => 'Aggiorna :name', + 'preview' => 'Visualizza', + 'preview_name' => 'Visualizza :name', + 'remove' => 'Rimuovi', + 'remove_name' => 'Rimuovi :name', + 'delete' => 'Elimina', + 'delete_name' => 'Elimina :name', + 'delete_confirm' => 'Sei sicuro?', + 'link' => 'Collega', + 'link_name' => 'Collega :name', + 'unlink' => 'Scollega', + 'unlink_name' => 'Scollega :name', + 'unlink_confirm' => 'Sei sicuro?' + ], + 'reorder' => [ + 'default_title' => 'Riordina record', + 'no_records' => 'Non ci sono record disponibili per ordinare.' + ], + 'model' => [ + 'name' => 'Modello', + 'not_found' => "Nessun modello ':class' con ID :id trovato.", + 'missing_id' => 'Nessun ID specificato per la ricerca.', + 'missing_relation' => "Il modello ':class' non contiene una definizione per la relazione ':relation'.", + 'missing_method' => "Il modello ':class' non contiene un metodo ':method'.", + 'invalid_class' => "Il modello :model utilizzato nella classe :class non è valido, deve ereditare la classe \Model.", + 'mass_assignment_failed' => "Assegnazione massiva fallita per l'attributo ':attribute' del modello.", + ], + 'warnings' => [ + 'tips' => 'Suggerimenti per la configurazione del sistema', + 'tips_description' => 'Ci sono elementi a cui è necessario prestare attenzione al fine di configurare il sistema in maniera corretta.', + 'permissions' => 'La cartella :name o le sue sottocartelle non sono scrivibili da PHP. Imposta le corrette autorizzazioni per il server web su questa cartella.', + 'extension' => 'L\'estensione di PHP :name non è installata. Installa questa libreria ed attiva l\'estensione.' + ], + 'editor' => [ + 'menu_label' => 'Preferenze editor di codice', + 'menu_description' => 'Personalizza le impostazioni dell\'editor, come la dimensione del carattere e lo schema di colori.', + 'font_size' => 'Dimensione carattere', + 'tab_size' => 'Dimensione Tab', + 'use_hard_tabs' => 'Indenta utilizzando i Tab', + 'code_folding' => 'Raggruppa il codice', + 'code_folding_begin' => 'Evidenzia inizio', + 'code_folding_begin_end' => 'Evidenzia inizio e fine', + 'autocompletion' => 'Completamento automatico', + 'word_wrap' => 'A capo automatico', + 'highlight_active_line' => 'Evidenzia la linea attiva', + 'auto_closing' => 'Chiudi automaticamente i tag', + 'show_invisibles' => 'Mostra caratteri invisibili', + 'show_gutter' => 'Visualizza numeri di linea', + 'basic_autocompletion'=> 'Completamento automatico di base (Ctrl + Spazio)', + 'live_autocompletion'=> 'Completamento automatico in tempo reale', + 'enable_snippets'=> 'Abilita frammenti di codice (Tab)', + 'display_indent_guides'=> 'Visualizza guide di indentazione', + 'show_print_margin'=> 'Visualizza margini di stampa', + 'mode_off' => 'No', + 'mode_fluid' => 'Fluido', + '40_characters' => '40 Caratteri', + '80_characters' => '80 Caratteri', + 'theme' => 'Schema di colori', + 'markup_styles' => 'Stili di markup', + 'custom_styles' => 'Foglio di stile personalizzato', + 'custom styles_comment' => 'Stili personalizzati da includere nell\'editor HTML.', + 'markup_classes' => 'Classi di markup', + 'paragraph' => 'Paragrafo', + 'link' => 'Collegamento', + 'table' => 'Tabella', + 'table_cell' => 'Cella di una tabella', + 'image' => 'Immagine', + 'label' => 'Etichetta', + 'class_name' => 'Nome della classe', + 'markup_tags' => 'Tag di markup', + 'allowed_empty_tags' => 'Tag vuoti consentiti', + 'allowed_empty_tags_comment' => 'L\'elenco dei tag che non sono rimossi quando non hanno nessun contenuto.', + 'allowed_tags' => 'Tag consentiti', + 'allowed_tags_comment' => 'L\'elenco dei tag consentiti.', + 'no_wrap' => 'Tag da non includere in blocchi', + 'no_wrap_comment' => 'L\'elenco dei tag che non devono essere contenuti all\'interno di blocchi di tag.', + 'remove_tags' => 'Tag da rimuovere', + 'remove_tags_comment' => 'L\'elenco dei tag che sono rimossi insieme al loro contenuto.' + ], + 'tooltips' => [ + 'preview_website' => 'Anteprima del sito web' + ], + 'mysettings' => [ + 'menu_label' => 'Impostazioni personali', + 'menu_description' => 'Impostazioni legate al tuo account amministratore' + ], + 'myaccount' => [ + 'menu_label' => 'Il mio account', + 'menu_description' => 'Aggiorna i dettagli del tuo account, come il nome, l\'indirizzo e-mail e la password.', + 'menu_keywords' => 'sicurezza login' + ], + 'branding' => [ + 'menu_label' => 'Personalizza pannello di controllo', + 'menu_description' => 'Personalizza l\'area di amministrazione, come il nome, i colori ed il logo.', + 'brand' => 'Marchio', + 'logo' => 'Logo', + 'logo_description' => 'Carica un logo personalizzato da utilizzare nel pannello di controllo.', + 'app_name' => 'Nome dell\'applicazione', + 'app_name_description' => 'Questo campo verrà visualizzato nella barra del titolo del pannello di controllo.', + 'app_tagline' => 'Slogan dell\'applicazione', + 'app_tagline_description' => 'Questo campo verrà visualizzato nella schermata di login del pannello di controllo.', + 'colors' => 'Colori', + 'primary_color' => 'Principale color', + 'secondary_color' => 'Secondario color', + 'accent_color' => 'Accent color', + 'styles' => 'Stili', + 'custom_stylesheet' => 'Foglio di stile personalizzato', + 'navigation' => 'Navigazione', + 'menu_mode' => 'Stile menu', + 'menu_mode_inline' => 'In linea', + 'menu_mode_tile' => 'Piastrelle', + 'menu_mode_collapsed' => 'Compresso' + ], + 'backend_preferences' => [ + 'menu_label' => 'Preferenze pannello di controllo', + 'menu_description' => 'Gestisci le preferenze del tuo account, come la lingua.', + 'region' => 'Regione', + 'code_editor' => 'Editor di codice', + 'timezone' => 'Fuso orario', + 'timezone_comment' => 'Regola le date visualizzate su questo fuso orario.', + 'locale' => 'Lingua', + 'locale_comment' => 'Seleziona la lingua da utilizzare.', + ], + 'access_log' => [ + 'hint' => 'Questo registro visualizza un elenco dei tentativi di accesso di un amministratore avvenuti con successo. I record sono mantenuti per un totale di :days giorni.', + 'menu_label' => 'Registro accessi', + 'menu_description' => 'Visualizza una lista degli accessi da parte degli amministratori.', + 'created_at' => 'Data e ora', + 'login' => 'Login', + 'ip_address' => 'Indirizzo IP', + 'first_name' => 'Nome', + 'last_name' => 'Cognome', + 'email' => 'Indirizzo e-mail', + ], + 'filter' => [ + 'all' => 'tutto', + 'options_method_not_exists' => "Il modello :model deve definire un metodo :method() che ritorni le opzioni per il filtro ':filter'.", + 'date_all' => 'tutte' + ], + 'import_export' => [ + 'upload_csv_file' => '1. Carica un file CSV', + 'import_file' => 'Importa file', + 'first_row_contains_titles' => 'La prima riga contiene i titoli delle colonne', + 'first_row_contains_titles_desc' => 'Lasciare selezionato se la prima riga nel file CSV è utilizzata come nome di colonna.', + 'match_columns' => '2. Abbina le colonne del file ai campi del database', + 'file_columns' => 'Colonne del file', + 'database_fields' => 'Campi del database', + 'set_import_options' => '3. Imposta opzioni di importazione', + 'export_output_format' => '1. Formato di output dell\'esportazione', + 'file_format' => 'Formato del file', + 'standard_format' => 'Formato standard', + 'custom_format' => 'Formato personalizzato', + 'delimiter_char' => 'Carattere delimitatore', + 'enclosure_char' => 'Qualificatore di testo', + 'escape_char' => 'Carattere di escape', + 'select_columns' => '2. Seleziona le colonne da esportare', + 'column' => 'Colonna', + 'columns' => 'Colonne', + 'set_export_options' => '3. Imposta opzioni di esportazione', + 'show_ignored_columns' => 'Visualizza colonne ignorate', + 'auto_match_columns' => 'Abbinamento automatico colonne', + 'created' => 'Creati', + 'updated' => 'Aggiornati', + 'skipped' => 'Saltati', + 'warnings' => 'Avvisi', + 'errors' => 'Errori', + 'skipped_rows' => 'Righe saltate', + 'import_progress' => 'Progresso importazione', + 'processing' => 'Elaborazione', + 'import_error' => 'Errore di importazione', + 'upload_valid_csv' => 'Si prega di caricare un file CSV valido.', + 'drop_column_here' => 'Rilascia qui la colonna...', + 'ignore_this_column' => 'Ignora questa colonna', + 'processing_successful_line1' => 'Processo di esportazione del file completato!', + 'processing_successful_line2' => 'Il browser ora ti reindirizzerà al download del file.', + 'export_progress' => 'Progresso esportazione', + 'export_error' => 'Errore di esportazione', + 'column_preview' => 'Anteprima colonna', + 'file_not_found_error' => 'File non trovato', + 'empty_error' => 'Nessun dato fornito per l\'esportazione.', + 'empty_import_columns_error' => 'Si prega di specificare alcune colonne da importare.', + 'match_some_column_error' => 'Si prega di abbinare alcune colonne prima di procedere.', + 'required_match_column_error' => 'Si prega di specificare un abbinamento per il campo obbligatorio :label.', + 'empty_export_columns_error' => 'Si prega di specificare alcune colonne da esportare.', + 'behavior_missing_uselist_error' => 'Devi implementare il comportamento del controller ListController con l\'opzione di esportazione "useList" abilitata.', + 'missing_model_class_error' => 'Si prega di specificare la proprietà modelClass per :type', + 'missing_column_id_error' => 'Identificatore di colonna mancante', + 'unknown_column_error' => 'Colonna sconosciuta', + 'encoding_not_supported_error' => 'La codifica del file di origine non è stata riconosciuta. Si prega di selezionare l\'opzione di formato personalizzato con la codifica corretta per importare il file.', + 'encoding_format' => 'Codifica del file', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latino-1, Europa Occidentale)', + 'iso_8859_2' => 'ISO-8859-2 (Latino-2, Europa Centrale)', + 'iso_8859_3' => 'ISO-8859-3 (Latino-3, Europa Meridionale)', + 'iso_8859_4' => 'ISO-8859-4 (Latino-4, Europa Settentrionale)', + 'iso_8859_5' => 'ISO-8859-5 (Latino, Cirillico)', + 'iso_8859_6' => 'ISO-8859-6 (Latinp, Arabo)', + 'iso_8859_7' => 'ISO-8859-7 (Latino, Greco)', + 'iso_8859_8' => 'ISO-8859-8 (Latino, Ebraico)', + 'iso_8859_0' => 'ISO-8859-9 (Latino-5, Turco)', + 'iso_8859_10' => 'ISO-8859-10 (Latino-6, Nordico)', + 'iso_8859_11' => 'ISO-8859-11 (Latino, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latino-7, Baltico)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtico)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Revisione di Europa Occidentale con il simbolo dell\'euro)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Gestisci elementi multimediali' + ], + 'mediafinder' => [ + 'label' => 'Media Finder', + 'default_prompt' => 'Fai clic sul pulsante %s per trovare un elemento multimediale' + ], + 'media' => [ + 'menu_label' => 'Elementi multimediali', + 'upload' => 'Carica', + 'move' => 'Sposta', + 'delete' => 'Elimina', + 'add_folder' => 'Aggiungi cartella', + 'search' => 'Cerca', + 'display' => 'Visualizza', + 'filter_everything' => 'Tutto', + 'filter_images' => 'Immagini', + 'filter_video' => 'Video', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Documenti', + 'library' => 'Libreria', + 'size' => 'Dimensione', + 'title' => 'Titolo', + 'last_modified' => 'Ultima modifica', + 'public_url' => 'URL pubblico', + 'click_here' => 'Fai clic qui', + 'thumbnail_error' => 'Errore durante la generazione dell\'anteprima.', + 'return_to_parent' => 'Ritorna alla cartella superiore', + 'return_to_parent_label' => 'Torna su ..', + 'nothing_selected' => 'Nessun elemento selezionato.', + 'multiple_selected' => 'Elementi multipli selezionati.', + 'uploading_file_num' => 'Caricamento in corso di :number file(s)...', + 'uploading_complete' => 'Caricamento completato', + 'uploading_error' => 'Caricamento fallito', + 'type_blocked' => 'Il tipo di file utilizzato è bloccato per questioni di sicurezza.', + 'order_by' => 'Ordina per', + 'folder' => 'Cartella', + 'no_files_found' => 'Nessun file corrisponde alla tua richiesta.', + 'delete_empty' => 'Seleziona elementi da eliminare.', + 'delete_confirm' => 'Vuoi davvero eliminare gli elementi selezionati?', + 'error_renaming_file' => 'Errore durante la rinominazione dell\'elemento', + 'new_folder_title' => 'Nuova cartella', + 'folder_name' => 'Nome della cartella', + 'error_creating_folder' => 'Errore durante la creazione della cartella', + 'folder_or_file_exist' => 'Una cartella o un file con il nome specificato è già esistente.', + 'move_empty' => 'Selezione elementi da spostare.', + 'move_popup_title' => 'Sposta file o cartelle', + 'move_destination' => 'Cartella di destinazione', + 'please_select_move_dest' => 'Seleziona una cartella di destinazione.', + 'move_dest_src_match' => 'Seleziona un\'altra cartella di destinazione.', + 'empty_library' => 'La libreria è vuota. Carica dei files o crea delle cartelle per iniziare.', + 'insert' => 'Inserisci', + 'crop_and_insert' => 'Ritaglia e inserisci', + 'select_single_image' => 'Seleziona una singola immagine.', + 'selection_not_image' => 'L\'elemento selezionato non è un\'immagine.', + 'restore' => 'Annulla tutte le modifiche', + 'resize' => 'Ridimensiona...', + 'selection_mode_normal' => 'Normale', + 'selection_mode_fixed_ratio' => 'Rapporto fisso', + 'selection_mode_fixed_size' => 'Dimensione fissa', + 'height' => 'Altezza', + 'width' => 'Larghezza', + 'selection_mode' => 'Metodo di selezione', + 'resize_image' => 'Ridimensiona immagine', + 'image_size' => 'Dimensione immagine:', + 'selected_size' => 'Selezionati:' + ] +]; diff --git a/modules/backend/lang/ja/lang.php b/modules/backend/lang/ja/lang.php new file mode 100644 index 0000000..affe10b --- /dev/null +++ b/modules/backend/lang/ja/lang.php @@ -0,0 +1,297 @@ + [ + 'title' => 'システム管理者領域' + ], + 'field' => [ + 'invalid_type' => '無効なフィールドタイプ :type が使用されています。', + 'options_method_not_exists' => 'モデルクラスの:modelは、":field"フォームフィールドのためにオプションを返す、:method()メソッドを定義しなくてはなりません。', + ], + 'widget' => [ + 'not_registered' => "':name'は、ウィジット名として登録されていません。", + 'not_bound' => "ウィジットクラス名の':name'は、コントローラーと結び付けられていません。", + ], + 'page' => [ + 'untitled' => "タイトル無し", + 'access_denied' => [ + 'label' => "アクセスが拒否されました", + 'help' => "このページを表示するために必要な権限がありません。", + 'cms_link' => "CMSのバックエンドに行く", + ], + ], + 'partial' => [ + 'not_found_name' => "':name'パーシャルは見つかりません。", + ], + 'account' => [ + 'sign_out' => 'ログアウト', + 'login' => 'ログイン', + 'reset' => 'リセット', + 'restore' => '元に戻す', + 'login_placeholder' => 'ユーザー名', + 'password_placeholder' => 'パスワード', + 'forgot_password' => "パスワードを忘れましたか?", + 'enter_email' => "メールアドレスを入力してください", + 'enter_login' => "ユーザー名を入力してください", + 'email_placeholder' => "メールアドレス", + 'enter_new_password' => "新しいパスワードを入力してください", + 'password_reset' => "パスワードリセット", + 'restore_success' => "パスワードを元に戻すための手順を説明したメールを送信しました。", + 'restore_error' => "':login'というユーザーは登録されていません。", + 'reset_success' => "パスワードがリセットされました。", + 'reset_error' => "間違ったパスワードリセットデータが送信されました。再実行してください。", + 'reset_fail' => "パスワードをリセットできませんでした。", + 'apply' => '適用', + 'cancel' => 'キャンセル', + 'delete' => '削除', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => 'ダッシュボード', + 'widget_label' => 'ウィジェット', + 'widget_width' => 'ウィジェット幅', + 'full_width' => '全幅', + 'add_widget' => 'ウィジェットの追加', + 'widget_inspector_title' => 'ウィジェットの設定', + 'widget_inspector_description' => 'リポートウィジェットを設定します。', + 'widget_columns_label' => '幅 :columns', + 'widget_columns_description' => 'ウィジェット幅は1〜10の数字で指定してします。', + 'widget_columns_error' => 'ウィジェット幅は1〜10の数字で指定してください。', + 'columns' => '{1} カラム|[2,Inf] カラム', + 'widget_new_row_label' => '次の行に配置', + 'widget_new_row_description' => 'ウィジェットを次の行に配置します。', + 'widget_title_label' => 'ウィジェットタイトル', + 'widget_title_error' => 'ウィジェットタイトルを指定してください。', + 'status' => [ + 'widget_title_default' => 'システム状態', + 'update_available' => '{0}個のアップデートが見つかりました。|{1} 個のアップデートが見つかりました。|[2,Inf] 個のアップデートが見つかりました。' + ], + ], + 'user' => [ + 'name' => 'システム管理者', + 'menu_label' => 'システム管理者', + 'menu_description' => 'バックエンドの管理ユーザーとグループ、権限の管理。', + 'list_title' => 'システム管理者の管理', + 'new' => '新規システム管理者', + 'login' => "ログイン", + 'first_name' => "名", + 'last_name' => "姓", + 'full_name' => "姓名", + 'email' => "メールアドレス", + 'groups' => "グループ", + 'groups_comment' => "このユーザーが所属するグループを指定してください。", + 'avatar' => "アバター", + 'password' => "パスワード", + 'password_confirmation' => "パスワード確認", + 'permissions' => '権限', + 'superuser' => "スーパーユーザー", + 'superuser_comment' => "全領域へのアクセスをこのユーザーに許可する場合、ボックスをチェックしてください。", + 'send_invite' => 'メールにより招待送信', + 'send_invite_comment' => 'このユーザーに、メールで招待状を送る場合、ボックスをチェックしてください。', + 'delete_confirm' => 'この管理者を本当に削除しますか?', + 'return' => 'システム管理者リストに戻る', + 'allow' => '許可', + 'inherit' => '継承', + 'deny' => '拒否', + 'group' => [ + 'name' => 'グループ', + 'name_field' => '名前', + 'description_field' => '説明', + 'is_new_user_default_field' => 'デフォルトで新しいシステム管理者をこのグループに追加する。', + 'code_field' => 'コード', + 'code_comment' => 'もしあなたがAPIでアクセスしたい場合は、ユニークなコードを入力してください。', + 'menu_label' => 'グループ', + 'list_title' => 'グループ管理', + 'new' => '新規グループ', + 'delete_confirm' => '本当にこの管理者グループを削除しますか?', + 'return' => 'グループリストへ戻る', + ], + 'preferences' => [ + 'not_authenticated' => '設定を読み込み/保存する、認証されたユーザーが存在していません。' + ] + ], + 'list' => [ + 'default_title' => 'リスト', + 'search_prompt' => '検索...', + 'no_records' => 'このビューにはレコードがありません。', + 'missing_model' => ':classクラスの中のリストビヘイビアーにモデルがありません。', + 'missing_column' => ':columnsに対する、カラム定義がありません。', + 'missing_columns' => ':classクラスの中のリストには、リストするカラムが定義されていません。', + 'missing_definition' => "リストビヘイビアーは、':field'に対するカラムを持っていません。", + 'behavior_not_ready' => 'リストビヘイビアーは初期化されていません。コントローラーで、makeLists()を呼び出しているか確認してください。', + 'invalid_column_datetime' => "カラムの値 ':column' はDateTimeオブジェクトではありません。モデル内の \$dates に指定していますか?", + 'pagination' => '表示中のレコード: :from-:to / :total', + 'prev_page' => '前のページ', + 'next_page' => '次のページ', + 'loading' => 'ロード中...', + 'setup_title' => 'リストのセットアップ', + 'setup_help' => 'リストの表示したいカラムをチェックボックスで選択してください。カラムの位置は上下にドラッグして変更できます。', + 'records_per_page' => 'ページ中のレコード数', + 'records_per_page_help' => 'ページあたりの表示レコード数を選択してください。1ページにたくさん表示するとパフォーマンスに影響があるので留意してください。' + ], + 'fileupload' => [ + 'attachment' => '添付', + 'help' => 'この添付のタイトルと説明を追加します。', + 'title_label' => 'タイトル', + 'description_label' => '説明' + ], + 'form' => [ + 'create_title' => "新規 :name", + 'update_title' => "編集 :name", + 'preview_title' => "プレビュー :name", + 'create_success' => ':nameを作成しました。', + 'update_success' => ':nameを更新しました。', + 'delete_success' => ':nameを削除しました。', + 'missing_id' => "フォームのレコードIDが指定されていません。", + 'missing_model' => ':classクラスで使用している、フォームビヘイビアーは、モデル定義を持っていません。', + 'missing_definition' => "フォームビヘイビアーは、':field'フィールドを持っていません。", + 'not_found' => 'IDが:idのフォームレコードが見つかりません。', + 'action_confirm' => '削除していいですか?', + 'create' => '作成', + 'create_and_close' => '作成後閉じる', + 'creating' => '作成中...', + 'creating_name' => ':name を作成中...', + 'save' => '保存', + 'save_and_close' => '保存後閉じる', + 'saving' => '保存中...', + 'saving_name' => ':name を保存中...', + 'delete' => '削除', + 'deleting' => '削除中...', + 'deleting_name' => ':name を削除中...', + 'reset_default' => '初期値にリセット', + 'resetting' => 'リセット', + 'resetting_name' => ':name を初期値にリセット中...', + 'undefined_tab' => 'その他', + 'field_off' => '無効', + 'field_on' => '', // MEMO あえて空文字列にしています。 + 'add' => 'Add', + 'apply' => '適用', + 'cancel' => 'キャンセル', + 'close' => '閉じる', + 'confirm' => '確認', + 'reload' => 'リロード', + 'ok' => 'OK', + 'or' => 'または', + 'confirm_tab_close' => '本当にタブを閉じますか? 保存されていない変更は消えてしまいます。', + 'behavior_not_ready' => 'フォームビヘイビアーは初期化されていません。コントローラーでinitForm()を呼び出しているか確認してください。', + 'preview_no_files_message' => 'ファイルはアップロードされません。', + 'select' => '選択', + 'select_all' => 'すべて選択', + 'select_none' => 'どれも選択しない', + 'select_placeholder' => '選択してください', + 'insert_row' => '行を挿入', + 'delete_row' => '行を削除', + 'concurrency_file_changed_title' => 'ファイルは変更されていません。', + 'concurrency_file_changed_description' => '編集中のファイルが他のユーザーにより変更されました。リロードして加えた変更を破棄するか、そのまま上書きできます。', + ], + 'relation' => [ + 'missing_config' => "リレーションビヘイビアは、':config'に対する設定を持っていません。", + 'missing_definition' => "リレーションビヘイビアは、':field'フィールドに対する定義を持っていません。", + 'missing_model' => ":classクラスで使用している、リレーションビヘイビアは、モデル定義を持っていません。", + 'invalid_action_single' => "このアクションは、単一リレーションでは実行できません。", + 'invalid_action_multi' => "このアクションは、複数リレーションでは実行できません。", + 'help' => '項目をクリックすると追加されます。', + 'related_data' => "関連するデータ :name", + 'add' => "追加", + 'add_name' => "追加 :name", + 'add_selected' => "追加は選択されています", + 'add_a_new' => "新しい追加 :name", + 'link_selected' => "リンクは選択されています", + 'link_a_new' => "新しいリンク :name", + 'cancel' => "キャンセル", + 'close' => "閉じる", + 'create' => "作成", + 'create_name' => "作成 :name", + 'update' => "更新", + 'update_name' => "更新 :name", + 'preview' => "プレビュー", + 'preview_name' => "プレビュー :name", + 'remove' => "削除", + 'remove_name' => "削除 :name", + 'delete' => "削除", + 'delete_name' => "削除 :name", + 'delete_confirm' => "削除していいですか?", + 'link' => "リンク", + 'link_name' => "リンク :name", + 'unlink' => "リンク解除", + 'unlink_name' => "リンク解除 :name", + 'unlink_confirm' => "リンクを解除していいですか?", + ], + 'model' => [ + 'name' => "モデル", + 'not_found' => "IDが:idの、':class'モデルは見つかりません。", + 'missing_id' => "モデルレコードを探すためのIDが、指定されていません。", + 'missing_relation' => "':class'モデルは、':relation'の定義を持っていません。", + 'missing_method' => "モデル ':class' にメソッド ':method' は定義されていません。", + 'invalid_class' => ":classクラスで使用している、:modelモデルは正しくありません。\Modelクラスを継承してください。", + 'mass_assignment_failed' => "モデル属性':attribute'の一括設定に失敗しました。", + ], + 'warnings' => [ + 'tips' => 'システム構成のチップス', + 'tips_description' => 'あなたが、システムを適切に設定するために注意を払う必要がある問題があります。', + 'permissions' => 'ディレクトリ":name"またはそのサブディレクトリは、PHPから書き込みできません。このディレクトリのパーミッションを設定してください。', + 'extension' => 'PHP拡張":name"はインストールされていません。PHP拡張をインストールして有効にしてください。', + ], + 'editor' => [ + 'menu_label' => 'エディタ', + 'menu_description' => 'コードエディタ設定の管理', + 'font_size' => 'フォントサイズ', + 'tab_size' => 'タブサイズ', + 'use_hard_tabs' => 'インデントにタブを使用する', + 'code_folding' => 'コード折りたたみ', + 'word_wrap' => 'ワードラップ', + 'highlight_active_line' => '選択行のハイライト', + 'show_invisibles' => '見えない文字を表示する', + 'show_gutter' => '行番号を表示する', + 'theme' => 'カラーテーマ', + ], + 'tooltips' => [ + 'preview_website' => 'Webサイトをプレビューする' + ], + 'mysettings' => [ + 'menu_label' => 'マイ設定', + 'menu_description' => 'この管理者アカウントの設定をします。' + ], + 'myaccount' => [ + 'menu_label' => 'アカウント', + 'menu_description' => '名前、電子メールアドレス、パスワードなどのあなたのアカウント詳細をアップデートしてください。', + 'menu_keywords' => 'セキュリティ ログイン' + ], + 'branding' => [ + 'menu_label' => 'バックエンドのカスタマイズ', + 'menu_description' => 'システム管理者領域を設定します。例えば、名前や色、ロゴ。', + 'brand' => 'ブランド', + 'logo' => 'ロゴ', + 'logo_description' => 'バックエンドで使用するロゴをアップロードします。', + 'app_name' => 'アプリ名', + 'app_name_description' => 'この名前はバックエンドのタイトル領域に表示されます。', + 'app_tagline' => 'アプリタグライン', + 'app_tagline_description' => 'この名前はバックエンドのサインインページに表示されます。', + 'colors' => '配色', + 'primary_color' => 'プライマリ color', + 'secondary_color' => 'セカンダリ color', + 'accent_color' => 'Accent color', + 'styles' => 'スタイル', + 'custom_stylesheet' => 'カスタムスタイルシート' + ], + 'backend_preferences' => [ + 'menu_label' => 'バックエンド', + 'menu_description' => '言語の設定などを行います。', + 'locale' => 'ロケール', + 'locale_comment' => '使用する言語のロケールを選択してください。' + ], + 'access_log' => [ + 'hint' => 'このログは管理者のサインインが成功したリストです。記録は:days日間保持されます。', + 'menu_label' => 'アクセスログ', + 'menu_description' => 'サインインに成功したバックエンドユーザーを表示します。', + 'created_at' => '日時', + 'login' => 'ログイン', + 'ip_address' => 'IPアドレス', + 'first_name' => '名', + 'last_name' => '姓', + 'email' => 'メール' + ], + 'filter' => [ + 'all' => 'すべて' + ], +]; diff --git a/modules/backend/lang/kr/lang.php b/modules/backend/lang/kr/lang.php new file mode 100644 index 0000000..4a152dc --- /dev/null +++ b/modules/backend/lang/kr/lang.php @@ -0,0 +1,560 @@ + [ + 'title' => '시스템관리자영역' + ], + 'field' => [ + 'invalid_type' => '유효하지 않은 필드타입 사용 :type ', + 'options_method_invalid_model' => "':field' 속성은 리졸브 될 수 없습니다. :model 모델 클래스의 특정 옵션 메소드를 명시적으로 사용해 보세요.", + 'options_method_not_exists' => ':model 모델 클래스는 ":field" 폼 필드의 옵션들을 반환하기위한 :method() 메소드를 정의해야 합니다.', + ], + 'widget' => [ + 'not_registered' => "':name' 위젯 클래스로 등록되지 않았습니다.", + 'not_bound' => "':name' 위젯 클래스는 컨트롤러와 바인드되지 않았습니다.", + ], + 'page' => [ + 'untitled' => "타이틀 없음", + 'access_denied' => [ + 'label' => "액세스가 거부되었습니다", + 'help' => "이 페이지를 표시하기위한 권한이 없습니다.", + 'cms_link' => "CMS의 백엔드로 가기", + ], + 'no_database' => [ + 'label' => 'DB를 찾을 수 없습니다', + 'help' => "백엔드에 접속하기 위해선 DB가 필요합니다. 다시 접속하시기 전에 DB가 정상적으로 설정및 이전되었는지 확인해주세요.", + 'cms_link' => '홈페이지로 돌아가기' + ], + ], + 'partial' => [ + 'not_found_name' => "':name' 페이지를 찾을 수 없습니다.", + ], + 'account' => [ + 'sign_out' => '로그아웃', + 'login' => '로그인', + 'reset' => '리셋', + 'restore' => '되돌리기', + 'login_placeholder' => '아이디', + 'password_placeholder' => '비밀번호', + 'forgot_password' => "비밀번호를 잊어버리셨습니까?", + 'enter_email' => "이메일 주소를 입력해주세요", + 'enter_login' => "아이디를 입력해 주세요", + 'email_placeholder' => "이메일 주소", + 'enter_new_password' => "변경할 비밀번호를 입력해주세요", + 'password_reset' => "비밀번호 재설정", + 'restore_success' => "비밀번호를 복구하기 위한 절차를 설명한 메일을 발송합니다.", + 'restore_error' => "':login' 아이디는 등록되어있지 않습니다.", + 'reset_success' => "비밀번호가 재설정 되었습니다.", + 'reset_error' => "잘못된 비밀번호 재설정 데이터가 발송되었습니다. 다시 해주세요.", + 'reset_fail' => "비밀번호를 재설정 할 수 없습니다.", + 'apply' => '적용', + 'cancel' => '취소', + 'delete' => '삭제', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => '대시보드', + 'widget_label' => '위젯', + 'widget_width' => '위젯 넓이', + 'full_width' => '전체 넓이', + 'manage_widgets' => '위젯 관리', + 'add_widget' => '위젯 추가', + 'widget_inspector_title' => '위젯 환경설정', + 'widget_inspector_description' => '리포트 위젯', + 'widget_columns_label' => '넓이 :columns', + 'widget_columns_description' => '위젯 넓이는 1에서 10까지 숫자입니다.', + 'widget_columns_error' => '위젯 넓이는 1에서 10까지의 숫자로 입력해주세요.', + 'columns' => '{1} 열|[2,Inf] 열', + 'widget_new_row_label' => '신규 행', + 'widget_new_row_description' => '신규 행에 위젯을 놓습니다.', + 'widget_title_label' => '위젯 제목', + 'widget_title_error' => '위젯 제목이 필요합니다.', + 'reset_layout' => '레이아웃 재설정', + 'reset_layout_confirm' => '초기값으로 레이아웃을 재설정할까요?', + 'reset_layout_success' => '레이아웃이 초기화 되었습니다', + 'make_default' => '기본값으로', + 'make_default_confirm' => '현재 레이아웃을 기본값으로 할까요?', + 'make_default_success' => '현재 레이아웃을 기본값으로 설정했습니다', + 'collapse_all' => '전체 접기', + 'expand_all' => '전체 펼치기', + 'status' => [ + 'widget_title_default' => '시스템 상태', + 'update_available' => '{0} 업데이트 가능!|{1} 업데이트 가능!|[2,Inf] 업데이트 가능!', + 'updates_pending' => 'SW 업데이트 보류', + 'updates_nil' => 'SW가 업데이트 되었습니다', + 'updates_link' => '업데이트', + 'warnings_pending' => '몇몇 이슈는 주의가 필요합니다', + 'warnings_nil' => '표시할 경고가 없습니다', + 'warnings_link' => '보기', + 'core_build' => '시스템 빌드', + 'event_log' => '이벤트 로그', + 'request_log' => '요청 로그', + 'app_birthday' => '온라인시간 ', + ], + 'welcome' => [ + 'widget_title_default' => '환영합니다', + 'welcome_back_name' => ':app로 돌아오신것을 환영합니다, :name님', + 'welcome_to_name' => ':app로 오신것을 환영합니다, :name님', + 'first_sign_in' => '이번이 최초접속입니다.', + 'last_sign_in' => '당신의 최종 접속은 ', + 'view_access_logs' => '접속 로그 보기', + 'nice_message' => '좋은 하루 되세요!', + ] + ], + 'user' => [ + 'name' => '사용자관리', + 'menu_label' => '사용자관리', + 'menu_description' => '백엔드 관리, 사용자,그룹 및 권한 관리.', + 'list_title' => '사용자 관리', + 'new' => '신규사용자', + 'login' => "아이디", + 'first_name' => "이름", + 'last_name' => "성", + 'full_name' => "성명", + 'email' => "이메일주소", + 'groups' => "그룹", + 'groups_comment' => "이 사용자가 소속될 그룹을 선택해 주세요.", + 'avatar' => "아바타", + 'password' => "비밀번호", + 'password_confirmation' => "비밀번호 확인", + 'permissions' => '권한', + 'superuser' => "수퍼유저", + 'superuser_comment' => "전영역의 접속을 이사용자에게 허가하길 원할경우 체크해주세요.", + 'send_invite' => '이메일로 초대장 발송', + 'send_invite_comment' => '이 사용자에 초대장을 발송하길 원할경우 체크해주세요.', + 'delete_confirm' => '이 사용자를 정말로 삭제하시겠습니까?', + 'return' => '사용자관리로 돌아가기', + 'allow' => '허가', + 'inherit' => '상속', + 'deny' => '거부', + 'activated' => '활성화됨', + 'last_login' => '최종접속', + 'created_at' => '생성일시', + 'updated_at' => '변경일시', + 'group' => [ + 'name' => '그룹', + 'name_comment' => '사용자 관리폼에 표시될 그룹목록에 표시됩니다.', + 'name_field' => '이름', + 'description_field' => '설명', + 'is_new_user_default_field_label' => '기본 그룹', + 'is_new_user_default_field_comment' => '신규 사용자를 이 그룹에 자동으로 소속시킵니다.', + 'code_field' => '코드', + 'code_comment' => 'API로 그룹 오브젝트에 접근하길 원할경우 고유한 코드를 입력해주세요.', + 'menu_label' => '그룹 관리', + 'list_title' => '그룹 관리', + 'new' => '신규 그룹', + 'delete_confirm' => '이 사용자 그룹을 삭제하시겠습니까?', + 'return' => '그룹 관리로 돌아가기', + 'users_count' => '명' + ], + 'preferences' => [ + 'not_authenticated' => '설정을 저장하기 위한 권한확인이 되지 않았습니다.' + ] + ], + 'list' => [ + 'default_title' => '목록', + 'search_prompt' => '검색...', + 'no_records' => '표시할 기록이 없습니다.', + 'missing_model' => ':class 클래스의 목록 행동이 모델 정의를 가지고 있지 않습니다.', + 'missing_column' => ':columns 를 위한 칼럼정의가 없습니다.', + 'missing_columns' => ':class 클래스에서 사용하는 List에 칼럼정의가 없습니다.', + 'missing_definition' => "목록 행동이 ':field' 칼럼을 포함하지 않습니다.", + 'missing_parent_definition' => "목록 행동 ':definition' 정의를 포함하지 않습니다.", + 'behavior_not_ready' => '목록 행동이 초기화되지 않았습니다. 컨트롤러의 makeLists() 를 체크해주세요.', + 'invalid_column_datetime' => "':column' 칼럼값이 DateTime 객체가 아닙니다. 모델에서 \$dates 참조를 잊어버리지 않았습니까?", + 'pagination' => '총 :total 중 표시된 기록: :from-:to', + 'first_page' => '처음', + 'last_page' => '마지막', + 'prev_page' => '이전', + 'next_page' => '다음', + 'refresh' => '새로고침', + 'updating' => '변경중...', + 'loading' => '로딩중...', + 'setup_title' => '목록 설정', + 'setup_help' => '목록에 표시하길 원하는 열에 체크하세요. 위아래로 드래그해서 위치를 변경할 수 있습니다.', + 'records_per_page' => '페이지당 목록갯수', + 'records_per_page_help' => '페이지당 표시할 목록 갯수를 선택하세요. 많이 설정할수록 페이지 표시속도가 느려질 수 있습니다.', + 'check' => '체크', + 'delete_selected' => '선택삭제', + 'delete_selected_empty' => '삭제할 기록이 없습니다.', + 'delete_selected_confirm' => '선택하신 기록을 삭제하시겠습니까?', + 'delete_selected_success' => '선택하신 기록을 삭제했습니다.', + 'column_switch_true' => 'Y', + 'column_switch_false' => 'N' + ], + 'fileupload' => [ + 'attachment' => '첨부', + 'help' => '이 첨부에 대한 제목과 설명을 추가.', + 'title_label' => '제목', + 'description_label' => '설명', + 'default_prompt' => '여기에 %s 클릭하거나 파일 드래그하여 업로드', + 'attachment_url' => '첨부 URL', + 'upload_file' => '파일 업로드', + 'upload_error' => '업로드 오류', + 'remove_confirm' => '삭제하시겠습니까?', + 'remove_file' => '파일 삭제' + ], + 'form' => [ + 'create_title' => '신규 :name', + 'update_title' => '수정 :name', + 'preview_title' => '미리보기 :name', + 'create_success' => ':name 생성됨', + 'update_success' => ':name 변경됨', + 'delete_success' => ':name 삭제됨', + 'reset_success' => '재설정 완료', + 'missing_id' => 'Form 기록의 ID가 특정되지 않았습니다.', + 'missing_model' => ':class 에서 사용하는 폼 행동이 모델정의를 가지고 있지 않습니다.', + 'missing_definition' => "폼 행동 ':field' 를 위한 필드를 가지고 있지 않습니다.", + 'not_found' => ':id 아이디의 Form 레코드를 찾을 수 없습니다.', + 'action_confirm' => '진행하시겠습니까?', + 'create' => '생성', + 'create_and_close' => '생성후 닫기', + 'creating' => '생성중...', + 'creating_name' => '생성중 :name...', + 'save' => '저장', + 'save_and_close' => '저장후 닫기', + 'saving' => '저장중...', + 'saving_name' => '저장중 :name...', + 'delete' => '삭제', + 'deleting' => '삭제중...', + 'confirm_delete' => '삭제하시겠습니까?', + 'confirm_delete_multiple' => '선택하신 기록을 삭제하시겠습니까?', + 'deleting_name' => '삭제중 :name...', + 'reset_default' => '초기값으로 재설정', + 'resetting' => '재설정중', + 'resetting_name' => '재설정 :name', + 'undefined_tab' => '기타', + 'field_off' => '끔', + 'field_on' => '켬', + 'add' => '추가', + 'apply' => '적용', + 'cancel' => '취소', + 'close' => '닫기', + 'confirm' => '확인', + 'reload' => '갱신', + 'complete' => '완료', + 'ok' => 'OK', + 'or' => 'or', + 'confirm_tab_close' => '탭을 닫으시겠습니까? 저장하지 않은 내용은 잃게됩니다.', + 'behavior_not_ready' => '폼 행동이 초기화되지 않았습니다. 컨트롤러에서 initForm()을 체크해보세요.', + 'preview_no_files_message' => '업로드할 파일이 없습니다.', + 'preview_no_media_message' => '선택하신 미디어가 없습니다.', + 'preview_no_record_message' => '선택하신 기록이 없습니다.', + 'select' => '선택', + 'select_all' => '모두 선택', + 'select_none' => '없음을 선택하십시오', + 'select_placeholder' => '선택해주세요', + 'insert_row' => '행 추가', + 'insert_row_below' => '아래 행 추가', + 'delete_row' => '행 삭제', + 'concurrency_file_changed_title' => '파일이 변경되었습니다', + 'concurrency_file_changed_description' => "다른 사용자에의해 파일이 변경되었습니다. 갱신하여 변경내용을 버리거나 덮어쓰기를 하실 수 있습니다.", + 'return_to_list' => '목록으로 돌아가기' + ], + 'recordfinder' => [ + 'find_record' => '기록 찾기', + 'cancel' => '취소', + ], + 'pagelist' => [ + 'page_link' => '페이지 링크', + 'select_page' => '페이지를 선택...' + ], + 'relation' => [ + 'missing_config' => "릴레이션 행동은 ':config' 설정을 가지고 있지 않습니다.", + 'missing_definition' => "릴레이션 행동이 ':field' 필드에 대한 정의를 가지고 있지 않습니다.", + 'missing_model' => ":class 클래스에서 사용하는 릴레이션 행동은 모델정의를 가지고 있지 않습니다.", + 'invalid_action_single' => "이 동작은 단 릴레이션에서는 실행하실 수 없습니다.", + 'invalid_action_multi' => "이 동작은 복수 릴레이션에서는 실행하실 수 없습니다.", + 'help' => '항목을 클릭하시면 추가합니다.', + 'related_data' => "관련데이터 :name", + 'add' => "추가", + 'add_name' => "추가 :name", + 'add_selected' => "추가가 선택되어 있습니다", + 'add_a_new' => "신규추가 :name", + 'link_selected' => "링크가 선택되어 있습니다", + 'link_a_new' => "신규링크 :name", + 'cancel' => "취소", + 'close' => "닫기", + 'create' => "생성", + 'create_name' => "생성 :name", + 'update' => "변경", + 'update_name' => "변경 :name", + 'preview' => "미리보기", + 'preview_name' => "미리보기 :name", + 'remove' => "삭제", + 'remove_name' => "삭제 :name", + 'delete' => "삭제", + 'delete_name' => "삭제 :name", + 'delete_confirm' => "삭제해도 될까요?", + 'link' => "링크", + 'link_name' => "링크 :name", + 'unlink' => "링크삭제", + 'unlink_name' => "링크삭제 :name", + 'unlink_confirm' => "링크를 삭제해도 될까요?", + ], + 'reorder' => [ + 'default_title' => '기록순서변경', + 'no_records' => '분류할 기록이 없습니다.' + ], + 'model' => [ + 'name' => "모델", + 'not_found' => "ID가 :id인 ':class' 모델을 찾을 수 없습니다.", + 'missing_id' => "모델 레코드를 찾기위한 ID 설정되어 있지 않습니다.", + 'missing_relation' => "':class' 모델은 ':relation'의 정의를 가지고있지 않습니다.", + 'missing_method' => "':class' 모델에 ':method' 메소드가 정의되어있지 않습니다.", + 'invalid_class' => ":class 로 사용되는 :model 모델이 올바르지 않습니다. \Model 클래스를 상속해주세요.", + 'mass_assignment_failed' => "':attribute' 모델속성의 일괄설정에 실패하였습니다.", + ], + 'warnings' => [ + 'tips' => '시스템설정 팁', + 'tips_description' => '당신이 시스템을 적절하게 설정하기위해 명심해야할 이슈들이 있습니다.', + 'permissions' => '":name" 디렉토리 또는 서브디렉토리는 PHP에서 쓸 수 없습니다. 이 디렉토리의 퍼미션을 설정해주세요.', + 'extension' => '":name" PHP 익스텐션이 설치되어있지 않습니다. 설치후 활성화해주세요.', + 'plugin_missing' => ':name 플러그인에 의존성이 해결되지 않았습니다. 이 플러그인을 설치해주세요.', + ], + 'editor' => [ + 'menu_label' => '에디터 설정', + 'menu_description' => '폰트 사이즈나 컬러 스키마등의 전역 에디터의 설정.', + 'font_size' => '폰트크기', + 'tab_size' => '텝사이즈', + 'use_hard_tabs' => '텝으로 들여쓰기사용', + 'code_folding' => '코드 접기', + 'code_folding_begin' => '마크사용', + 'code_folding_begin_end' => '마크사용과 종료', + 'autocompletion' => '자동완성', + 'word_wrap' => '줄바꿈', + 'highlight_active_line' => '현재라인강조', + 'auto_closing' => '자동 테그닫기', + 'show_invisibles' => '보이지않는 문자 보기', + 'show_gutter' => '라인넘버보기', + 'basic_autocompletion'=> '기본 자동완성 (Ctrl + Space)', + 'live_autocompletion'=> '라이브 자동완성', + 'enable_snippets'=> '코드 스니핏 사용 (Tab)', + 'display_indent_guides'=> '들여쓰기 가이드 표시', + 'show_print_margin'=> '출력마진 보기', + 'mode_off' => 'Off', + 'mode_fluid' => 'Fluid', + '40_characters' => '40 문자', + '80_characters' => '80 문자', + 'theme' => '색상 스키마', + 'markup_styles' => '마크업 스타일', + 'custom_styles' => '별도의 스타일시트', + 'custom styles_comment' => '에디터에 별도의 스타일시트를 포함시킨다.', + 'markup_classes' => '마크업 클래스', + 'paragraph' => '단락', + 'link' => '링크', + 'table' => '테이블', + 'table_cell' => '셀', + 'image' => '이미지', + 'label' => '라벨', + 'class_name' => '클래스 이름', + 'markup_tags' => '마크업 테그들', + 'allowed_empty_tags' => '빈테그 허용', + 'allowed_empty_tags_comment' => '내용이 없어도 제거하지 않을 테그목록', + 'allowed_tags' => '허용된 테그들', + 'allowed_tags_comment' => '허용된 테그목록', + 'no_wrap' => '테그를 줄바꿈하지 않음', + 'no_wrap_comment' => '블록 테그안에서 줄바꿈 하지않을 테그목록', + 'remove_tags' => '테그제거', + 'remove_tags_comment' => '내용과 함께 제거할 테그목록' + ], + 'tooltips' => [ + 'preview_website' => '웹사이트 미리보기' + ], + 'mysettings' => [ + 'menu_label' => '내 설정', + 'menu_description' => '사용자 계정의 설정을 합니다.' + ], + 'myaccount' => [ + 'menu_label' => '계정', + 'menu_description' => '이름, 이메일주소, 비밀번호 등의 계정 세부정보를 변경해주세요.', + 'menu_keywords' => '보안 로그인' + ], + 'branding' => [ + 'menu_label' => '백엔드 설정변경', + 'menu_description' => '앱 이름이나 색, 로고 등의 시스템 설정을 변경합니다.', + 'brand' => '브랜드', + 'logo' => '로고', + 'logo_description' => '백엔드에서 사용하는 로고를 업로드합니다.', + 'app_name' => '앱 이름', + 'app_name_description' => '이 이름은 백엔드의 타이틀영역에 표시됩니다.', + 'app_tagline' => '앱 테그라인', + 'app_tagline_description' => '이 이름은 백엔드의 로그인 페이지에 표시됩니다.', + 'colors' => '색상', + 'primary_color' => '주요 색상', + 'secondary_color' => '부수적인 색상', + 'accent_color' => '강조 색상', + 'styles' => '스타일', + 'custom_stylesheet' => '별도의 스타일시트', + 'navigation' => '네비게이션', + 'menu_mode' => '메뉴 스타일', + 'menu_mode_inline' => '인라인', + 'menu_mode_tile' => '타일', + 'menu_mode_collapsed' => '접힘' + ], + 'backend_preferences' => [ + 'menu_label' => '백엔드 환경설정', + 'menu_description' => '당신 계정의 사용언어 등의 환경설정', + 'region' => '지역', + 'code_editor' => '코드 에디터', + 'timezone' => '타임존', + 'timezone_comment' => '타임존에 맞는 날짜 조정.', + 'locale' => '로케일', + 'locale_comment' => '사용언어에 맞는 로케일을 선택해주세요.' + ], + 'access_log' => [ + 'hint' => '이 로그는 사용자들의 성공적인 로그인 접속 기록 목록을 표시합니다. 총 :days일보관함.', + 'menu_label' => '접속 로그', + 'menu_description' => '백엔드 계정의 성공 로그인 기록보기', + 'created_at' => '일시', + 'login' => '계정', + 'ip_address' => 'IP주소', + 'first_name' => '이름', + 'last_name' => '성', + 'email' => '이메일' + ], + 'filter' => [ + 'all' => '전체', + 'options_method_not_exists' => ":model 모델클래스는 ':filter' 필터옵션을 리턴하기위해서 반드시 :method() 메소드를 정의해야합니다.", + 'date_all' => '전체기간' + ], + 'import_export' => [ + 'upload_csv_file' => '1. CSV 파일 업로드', + 'import_file' => '파일 가져오기', + 'first_row_contains_titles' => '첫 행에 열 제목을 담기', + 'first_row_contains_titles_desc' => '첫 행을 CSV의 열 타이틀로 쓰려면 이 항목을 체크해주세요.', + 'match_columns' => '2. DB필드와 파일열을 일치', + 'file_columns' => '파일 열', + 'database_fields' => 'DB 필드', + 'set_import_options' => '3. 가져오기 옵션 설정', + 'export_output_format' => '1. 내보내기 출력 형식', + 'file_format' => '파일 형식', + 'standard_format' => '표준 형식', + 'custom_format' => '다른 형식', + 'delimiter_char' => '구분자 문자', + 'enclosure_char' => '종결 문자', + 'escape_char' => '회피 문자', + 'select_columns' => '2. 내보낼 열을 선택', + 'column' => '열', + 'columns' => '열들', + 'set_export_options' => '3. 내보내기 옵션 설정', + 'show_ignored_columns' => '무시한 열들 표시', + 'auto_match_columns' => '자동 일치 열', + 'created' => '생성됨', + 'updated' => '변경됨', + 'skipped' => '건너뜀', + 'warnings' => '경고', + 'errors' => '오류', + 'skipped_rows' => '건너뛴 행', + 'import_progress' => '가져오기 처리', + 'processing' => '처리중', + 'import_error' => '가져오기 오류', + 'upload_valid_csv' => '유효한 CSV파일을 업로드하세요.', + 'drop_column_here' => '이곳에 열을 떨굼...', + 'ignore_this_column' => '이 열을 무시', + 'processing_successful_line1' => '파일 내보내기 과정이 완료되었습니다!', + 'processing_successful_line2' => '브라우저가 파일다운로드 화면으로 이동합니다.', + 'export_progress' => '내보내기 처리', + 'export_error' => '내보내기 오류', + 'column_preview' => '열 미리보기', + 'file_not_found_error' => '파일을 찾을 수 없습니다', + 'empty_error' => '내보내기 위한 데이터가 없습니다', + 'empty_import_columns_error' => '가져올 열을 정해주세요.', + 'match_some_column_error' => '먼저 일치시킬 열을 선택해주세요.', + 'required_match_column_error' => '필요한 :label 필드에 일치시킬 짝을 선택해주세요.', + 'empty_export_columns_error' => '내보낼 열을 선택해주세요.', + 'behavior_missing_uselist_error' => '컨트롤러 행동 ListController를 useList 옵션을 켜고 내보내기를 시행해야만합니다.', + 'missing_model_class_error' => ':type 타입을 위한 모델 성질을 선택해주세요.', + 'missing_column_id_error' => '잃은 열의 식별자', + 'unknown_column_error' => '모르는 열', + 'encoding_not_supported_error' => '원본 파일의 인코딩을 인식할 수 없습니다. 가져오기를 위해선 정당한 인코딩의 자체파일포멧을 선택해주세요.', + 'encoding_format' => '파일 인코딩', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => '미디어관리와 업로드 - 이미지, 동영상, 소리, 문서' + ], + 'mediafinder' => [ + 'label' => '미디어 탐색기', + 'default_prompt' => '%s 버튼 클릭하여 미디어 아이템 찾기' + ], + 'media' => [ + 'menu_label' => '미디어', + 'upload' => '업로드', + 'move' => '이동', + 'delete' => '삭제', + 'add_folder' => '폴더 추가', + 'search' => '검색', + 'display' => '표시방법', + 'filter_everything' => '전체표시', + 'filter_images' => '이미지', + 'filter_video' => '동영상', + 'filter_audio' => '소리', + 'filter_documents' => '문서', + 'library' => '라이브러리', + 'size' => '용량', + 'title' => '제목', + 'last_modified' => '최종변경', + 'public_url' => '다운로드 URL', + 'click_here' => '클릭해주세요', + 'thumbnail_error' => '썸네일 생성 오류.', + 'return_to_parent' => '상위 폴더로 돌아가기', + 'return_to_parent_label' => '상위 폴더 ..', + 'nothing_selected' => '선택없음.', + 'multiple_selected' => '여러개 선택됨.', + 'uploading_file_num' => ':number 파일 업로드중...', + 'uploading_complete' => '업로드 완료', + 'uploading_error' => '업로드 실패', + 'type_blocked' => '보안문제로 해당 파일타입은 불가능합니다.', + 'order_by' => '정렬방법', + 'folder' => '폴더', + 'no_files_found' => '요청하신 파일을 찾을 수 없습니다.', + 'delete_empty' => '삭제할 대상을 선택해 주세요.', + 'delete_confirm' => '선택하신 대상을 삭제하시겠습니까?', + 'error_renaming_file' => '이름변경 오류.', + 'new_folder_title' => '신규 폴더', + 'folder_name' => '폴더 이름', + 'error_creating_folder' => '폴더 생성 오류', + 'folder_or_file_exist' => '해당 이름의 파일이나 폴더가 이미 존재합니다.', + 'move_empty' => '이동할 대상을 선택하세요.', + 'move_popup_title' => '파일이나 폴더를 이동', + 'move_destination' => '목적지 폴더', + 'please_select_move_dest' => '목적지 폴더를 선택하세요.', + 'move_dest_src_match' => '다른 목적지 폴더를 선택하세요.', + 'empty_library' => '라이브러리가 비어있습니다. 파일을 업로드하거나 폴더를 생성하여 시작해보세요.', + 'insert' => '삽입', + 'crop_and_insert' => '자르기 & 삽입', + 'select_single_image' => '한개의 이미지를 선택해주세요.', + 'selection_not_image' => '선택하신 것은 이미지가 아닙니다.', + 'restore' => '모든 변경 되돌리기', + 'resize' => '크기변경...', + 'selection_mode_normal' => '일반', + 'selection_mode_fixed_ratio' => '고정 비율', + 'selection_mode_fixed_size' => '고정 크기', + 'height' => '높이', + 'width' => '넓이', + 'selection_mode' => '선택 모드', + 'resize_image' => '이미지 크기 변경', + 'image_size' => '이미지 크기:', + 'selected_size' => '선택크기:' + ], +]; diff --git a/modules/backend/lang/lt/lang.php b/modules/backend/lang/lt/lang.php new file mode 100644 index 0000000..cd8ffc1 --- /dev/null +++ b/modules/backend/lang/lt/lang.php @@ -0,0 +1,558 @@ + [ + 'title' => 'Administracijos zona' + ], + 'field' => [ + 'invalid_type' => 'Netinkamas laukelio tipas :type.', + 'options_method_invalid_model' => "Artributas ':field' nenuskaito tinkamo modelio. Bandykite nurodyti parinkties metodą išskirtinai modelio klasei :model", + 'options_method_not_exists' => "Modelio klasė :model turi nurodyti metodą :method() gražinantį parinktis ':field' formos laukeliui." + ], + 'widget' => [ + 'not_registered' => "Valdiklio klasės pavadinimas ':name' neiregistruotas", + 'not_bound' => "Valdiklio klasės pavadinimas ':name' nepriskirtas kontroleriui" + ], + 'page' => [ + 'untitled' => 'Neužvardintas', + 'access_denied' => [ + 'label' => 'Prieiga atmesta', + 'help' => "Neturite reikiamų prieigos teisių šio puslapio peržiūrai.", + 'cms_link' => 'Grįžti į administraciją' + ], + 'no_database' => [ + 'label' => 'Truksta duombazės', + 'help' => "Duomenų bazė reikalinga administracijos prieigai. Patikrinkite duomenų bazės konfigūraciją bei migracijas ir bandykite dar kartą.", + 'cms_link' => 'Grįžti į svetainę' + ], + ], + 'partial' => [ + 'not_found_name' => "Priedėlis ':name' nerastas." + ], + 'account' => [ + 'sign_out' => 'Atsijungti', + 'login' => 'Prisijungti', + 'reset' => 'Perstatyti', + 'restore' => 'Atstatyti', + 'login_placeholder' => 'vartotojas', + 'password_placeholder' => 'slaptažodis', + 'forgot_password' => 'Pamiršote slaptažodį?', + 'enter_email' => 'Įveskite savo el.paštą', + 'enter_login' => 'Įveskite savo vartotojo vardą', + 'email_placeholder' => 'el.paštas', + 'enter_new_password' => 'Įveskite naują slaptažodį', + 'password_reset' => 'Slaptažodžio Keitimas', + 'restore_success' => 'Išsiuntėme Jums laišką el.paštu su tolimesnėmis instrukcijomis.', + 'restore_error' => "Vartotojas prisijungimo vardu ':login' nerastas", + 'reset_success' => 'Slaptažodį pakeitėme. Dabar galite prisijungti.', + 'reset_error' => 'Peteikėte netinkamą slaptažodžio atstatymo informaciją. Bandykite dar kartą!', + 'reset_fail' => 'Slaptažodžio pakeisti nepavyko!', + 'apply' => 'Taikyti', + 'cancel' => 'Atšaukti', + 'delete' => 'trinti', + 'ok' => 'GERAI' + ], + 'dashboard' => [ + 'menu_label' => 'Valdymas', + 'widget_label' => 'Skydelis', + 'widget_width' => 'Plotis', + 'full_width' => 'pilnas proltis', + 'manage_widgets' => 'Tvarkyti skydelius', + 'add_widget' => 'Pridėti skydelį', + 'widget_inspector_title' => 'Skydelio konfigūracija', + 'widget_inspector_description' => 'Konfigūruoti ataskaitų skydelį', + 'widget_columns_label' => 'Plotis :columns', + 'widget_columns_description' => 'Skydelio plotis, skaitmuo nuo 1 iki 10.', + 'widget_columns_error' => 'Įveskite skydelio plotį skaitmenimisnuo 1 iki 10.', + 'columns' => '{1} stulpelis|[2,Inf] stulpeliai', + 'widget_new_row_label' => 'Priverstina nauja eilė', + 'widget_new_row_description' => 'Kelti skydelį į naują eilę.', + 'widget_title_label' => 'Skydelio pavadinimas', + 'widget_title_error' => 'Skydelio pavadinimas yra būtinas.', + 'reset_layout' => 'Atstatyti išdėstymą', + 'reset_layout_confirm' => 'Atstatyti išdėstymą į pirminę?', + 'reset_layout_success' => 'Išdėstymą atstatėme', + 'make_default' => 'Įrašyti kaip pagrindinį', + 'make_default_confirm' => 'Nustatyti dabartinį išdėstymą kaip pagrindinį?', + 'make_default_success' => 'Dabartinis išdėstymas dabar yra pagrindinis', + 'collapse_all' => 'Suskleisti visus', + 'expand_all' => 'Išskleisti visus', + 'status' => [ + 'widget_title_default' => 'Sistemos būsena', + 'update_available' => '{0} galimų naujinimų!|{1} galimas naujinimas!|[2,Inf] galimi naujinimai!', + 'updates_pending' => 'Laukiantys programos naujinimai', + 'updates_nil' => 'Sistema yra pilnai atnaujinta', + 'updates_link' => 'Naujinti', + 'warnings_pending' => 'Tam tikros problemos reikalauja peržiūros', + 'warnings_nil' => 'Įspėjimų nėra', + 'warnings_link' => 'Žiūrėti', + 'core_build' => 'Sistemos sudėtis', + 'event_log' => 'Įvykių registras', + 'request_log' => 'Užklausų registras', + 'app_birthday' => 'Veikia nuo', + ], + 'welcome' => [ + 'widget_title_default' => 'Sveiki!', + 'welcome_back_name' => 'Sveiki sugrįžę į :app, :name.', + 'welcome_to_name' => 'Prisijungėte į :app, :name.', + 'first_sign_in' => 'Tai yra pirmas kartas kai prisijungiate.', + 'last_sign_in' => 'Paskutinį kartą prisijungėte', + 'view_access_logs' => 'Žiurėti prieigos registrą', + 'nice_message' => 'Geros Jums dienos!', + ] + ], + 'user' => [ + 'name' => 'Administratorius', + 'menu_label' => 'Administratoriai', + 'menu_description' => 'Tvarkyti administracinius vartotojus, grupes ir prieigos leidimus.', + 'list_title' => 'Tvarkyti Administratorius', + 'new' => 'Naujas Administratorius', + 'login' => 'Prisijungimo vardas', + 'first_name' => 'Vardas', + 'last_name' => 'Pavardė', + 'full_name' => 'Pilnas vardas', + 'email' => 'El.paštas', + 'groups' => 'Grupės', + 'groups_comment' => 'Priskirkite vartotoją grupėms. Grupės nurodo prieigos leidimus, kurie gali būti perrašyti redaguojant vartotoją, Prieigų lentelėje.', + 'avatar' => 'Avataras/Foto', + 'password' => 'Slaptažodis', + 'password_confirmation' => 'Patvirtinti Slaptažodį', + 'permissions' => 'Prieigos leidimai', + 'account' => 'Vartotojas', + 'superuser' => 'Super Vartotojas', + 'superuser_comment' => 'Suteikia šiam vartotojui neribojamą prieigą į visus nustatymus sistemojeG. Super vartotojai gali pridėti bei tvarkyti vartotojus. ', + 'send_invite' => 'Siųsti pakvietimą el.paštu', + 'send_invite_comment' => 'Siunčia informuojantį laišką su prisijungimo informacija.', + 'delete_confirm' => 'Trinti šį administratorių?', + 'return' => 'Grįžti į administratorių sąrašą', + 'allow' => 'Leisti', + 'inherit' => 'Paveldima', + 'deny' => 'Neleisti', + 'activated' => 'Aktyvuotas', + 'last_login' => 'Paskutinis Prisijungimas', + 'created_at' => 'Sukurtas', + 'updated_at' => 'Atnaujintas', + 'group' => [ + 'name' => 'Grupė', + 'name_comment' => 'Pavadinimas rodomas Administratoriaus pridėjimo formos grupių sąraše.', + 'name_field' => 'Pavadinimas', + 'description_field' => 'Aprašymas', + 'is_new_user_default_field_label' => 'Pagrindinė grupė', + 'is_new_user_default_field_comment' => 'Naujus administratorius priskirti šiai grupei automatiškai', + 'code_field' => 'Kodas', + 'code_comment' => 'Įveskite unikalų grupės kodą jei norėsite pasiekti šią grupę per API.', + 'menu_label' => 'Tvarkyti Grupes', + 'list_title' => 'Tvarkyti Grupes', + 'new' => 'Nauja Grupė', + 'delete_confirm' => 'Ištrinti šią administratorių grupę?', + 'return' => 'Grįžti į grupių sąrašą', + 'users_count' => 'Vartotojai(ų)' + ], + 'preferences' => [ + 'not_authenticated' => 'Nėra prisijungusio vartotojo, kurio nustatymus būtų galima užkrauti arba išsaugoti.' + ] + ], + 'list' => [ + 'default_title' => 'Sąrašas', + 'search_prompt' => 'Ieškoti...', + 'no_records' => 'Kolkas nėra jokių įrašų.', + 'missing_model' => 'Sąrašo elgsenos nustatymai naudojami :class klasėje, neturi nurodyto modelio.', + 'missing_column' => 'Nėra stulpelio aprašų :columns stulpeliui.', + 'missing_columns' => 'Sąrašas naudojamas klasėje :class neturi nurodytų stulpelių.', + 'missing_definition' => "Sąrašo elgsena neturi stulpelio ':field'.", + 'missing_parent_definition' => "Sąrašo elgsena neturi nurodymo laukeliui ':definition'.", + 'behavior_not_ready' => 'Sąrašo elgsena neinicijuota. Pasitikrinkite ar naudojate funckiją makeLists() savo kontroleryje.', + 'invalid_column_datetime' => "Stulpelio reikšmė ':column' nėra DateTime objektas, galbūt nenurodėte \$dates kvietinio modelyje?", + 'pagination' => 'Rodomi įrašai: :from-:to iš :total', + 'first_page' => 'Pirmas puslapis', + 'last_page' => 'Paskutinis puslapis', + 'prev_page' => 'Ankstesnis puslapis', + 'next_page' => 'Sekantis puslapis', + 'refresh' => 'Perkrauti', + 'updating' => 'Atnaujinama...', + 'loading' => 'Kraunama...', + 'setup_title' => 'Sąrašo nustatymai', + 'setup_help' => 'Pažymėkite varnelėmis stulpelius, kuriuos norite matyti šąraše. Taip pat galite nustatyti stulpelių eiliškumą rikiuojant juos palės pagalba aukštyn ir žemyn.', + 'records_per_page' => 'Įrašų puslapyje', + 'records_per_page_help' => 'Pasirinkite norimą įrašų skaičių puslapyje. Primename, kad didelis kiekis įrašų viename puslapyje įtakos užkrovimo našumą.', + 'check' => 'Žymėti', + 'delete_selected' => 'Trinti pasirinktus', + 'delete_selected_empty' => 'Nepažymėjote nieko trynimui.', + 'delete_selected_confirm' => 'Ištrinti pasirinktus įrašus?', + 'delete_selected_success' => 'Pasirinktus įrašus ištrynėme.', + 'column_switch_true' => 'Taip', + 'column_switch_false' => 'Ne' + ], + 'fileupload' => [ + 'attachment' => 'Priedas', + 'help' => 'Įrašykite pavadinimą ir aprašymą šiam priedui.', + 'title_label' => 'Pavadinimas', + 'description_label' => 'Aprašymas', + 'default_prompt' => 'Spauskite %s arba įtempkite failus čia', + 'attachment_url' => 'Priedo URL', + 'upload_file' => 'Įkelti failą', + 'upload_error' => 'Įkėlimo klaida', + 'remove_confirm' => 'Ar tikrai?', + 'remove_file' => 'Pašalinti failą' + ], + 'form' => [ + 'create_title' => 'Naujas :name', + 'update_title' => 'Redaguoti :name', + 'preview_title' => 'Peržiūrėti :name', + 'create_success' => ':name sukurtas', + 'update_success' => ':name atnaujintas', + 'delete_success' => ':name ištrintas', + 'reset_success' => 'Atstatymas baigtas', + 'missing_id' => 'Formos įrašo ID nenurodytas.', + 'missing_model' => 'Formos elgsena naudojama klasėje :class neturi nurodyto modelio.', + 'missing_definition' => "Formos elgsena neturi laukelio reikšmei ':field'.", + 'not_found' => 'Formos įrašas su ID :id nebuvo rastas.', + 'action_confirm' => 'Ar tikrai?', + 'create' => 'Kurti', + 'create_and_close' => 'Kurti ir uždaryti', + 'creating' => 'Kuriama...', + 'creating_name' => 'Kuriama :name...', + 'save' => 'Saugoti', + 'save_and_close' => 'Saugoti ir uždaryti', + 'saving' => 'Saugome...', + 'saving_name' => 'Saugome :name...', + 'delete' => 'Trinti', + 'deleting' => 'Triname...', + 'confirm_delete' => 'Trinti įrašą?', + 'confirm_delete_multiple' => 'Trinti pasirinktus įrašus?', + 'deleting_name' => 'Triname :name...', + 'reset_default' => 'Atstatyti į pradžią', + 'resetting' => 'Atstatome', + 'resetting_name' => 'Atstatome :name', + 'undefined_tab' => 'Įvairus', + 'field_off' => 'Išjungta', + 'field_on' => 'Įjungta', + 'add' => 'Pridėti', + 'apply' => 'Taikyti', + 'cancel' => 'Atšaukti', + 'close' => 'Uždaryti', + 'confirm' => 'Patvirtinti', + 'reload' => 'Perkrauti', + 'complete' => 'Užbaigti', + 'ok' => 'GERAI', + 'or' => 'arba', + 'confirm_tab_close' => 'Uždaryti kortelę? Neišsaugoti pakeitimai bus prarasti.', + 'behavior_not_ready' => 'Formos elgsena nebuvo inicijuota, pasitikrinkite ar užklausėte funkciją initForm() savo kontroleryje.', + 'preview_no_files_message' => 'Nėra įkeltų failų.', + 'preview_no_record_message' => 'Nėra pasirinktų įrašų.', + 'select' => 'Pasirinkti', + 'select_all' => 'pasirinkti viską', + 'select_none' => 'neišsirinkite nė vieno', + 'select_placeholder' => 'prašome pasirinkti', + 'insert_row' => 'Pridėti Eilutę', + 'insert_row_below' => 'Pridėti Eilutę Žemiau', + 'delete_row' => 'Trinti Eilutę', + 'concurrency_file_changed_title' => 'Failas buvo pakeistas', + 'concurrency_file_changed_description' => "Jūsų redaguojamą failą diske pakeitė kitas vartotojas. Galite perkrauti failą prarasdami pakeitimus arba perrašyti failą diske.", + 'return_to_list' => 'Grįžti į sąrašą' + ], + 'recordfinder' => [ + 'find_record' => 'Rasti Įrašą' + ], + 'pagelist' => [ + 'page_link' => 'Puslapio nuoroda', + 'select_page' => 'Pasirinkti puslapį...' + ], + 'relation' => [ + 'missing_config' => "Subendrinimo elgsena neturi konfigūracijos ':config'.", + 'missing_definition' => "Subendrinimo elgsena neturi nustatymo ':field' laukeliui.", + 'missing_model' => 'Subendrinimo elgsena naudojama klasėje :class neturi nustatyto modelio.', + 'invalid_action_single' => 'Šis veiksmas negalimas pavieniam subendrinimui.', + 'invalid_action_multi' => 'Šis veiksmas negalimas daugialypiui subendrinimui.', + 'help' => 'Spauskite elementą pridėjimui', + 'related_data' => 'Giminingi :name duomenys', + 'add' => 'Pridėti', + 'add_selected' => 'Pridėti pasirinktus', + 'add_a_new' => 'Pridėti naują :name', + 'link_selected' => 'Pasirinkta nuoroda', + 'link_a_new' => 'Jungti naują :name', + 'cancel' => 'Atšaukti', + 'close' => 'Uždaryti', + 'add_name' => 'Pridėti :name', + 'create' => 'Kurti', + 'create_name' => 'Kurti :name', + 'update' => 'Atnaujinti', + 'update_name' => 'Atnaujinti :name', + 'preview' => 'Peržiūrėti', + 'preview_name' => 'Peržiūrėti :name', + 'remove' => 'Pašalinti', + 'remove_name' => 'Pašalinti :name', + 'delete' => 'Ištrinti', + 'delete_name' => 'Ištrinti :name', + 'delete_confirm' => 'Ar tikrai?', + 'link' => 'Nuoroda', + 'link_name' => 'Nuoroda :name', + 'unlink' => 'Atjungti', + 'unlink_name' => 'Atjungti :name', + 'unlink_confirm' => 'Ar tikrai?' + ], + 'reorder' => [ + 'default_title' => 'Rūšiuoti įrašus', + 'no_records' => 'Nėra įrašų galimų rūšiavimui.' + ], + 'model' => [ + 'name' => 'Modelis', + 'not_found' => "Modelis ':class' su ID :id nerastas", + 'missing_id' => 'Nenurodytas ID modelio įrašui ieškoti.', + 'missing_relation' => "Modelis ':class' neturi nustatymo ':relation'.", + 'missing_method' => "Modelis ':class' neturi metodo ':method'.", + 'invalid_class' => "Modelis :model naudojamas klasėje :class yra netinkamas. Jis turi kreiptis į \Model klasę.", + 'mass_assignment_failed' => "Masinis priskyrimas nepavyko Modelio atributui ':attribute'." + ], + 'warnings' => [ + 'tips' => 'Sistemos konfigūracijos patarimai', + 'tips_description' => 'Yra problemų į kurias turėtumėte atkreipti dėmesį norėdami sukonfigūruoti sistemą tinkamai.', + 'permissions' => 'Direktorija :name arba jos subdirektorijos nėra įrašomos naudojant PHP. Prašome nustatyti rašymo prieigą serveryje šiai direktorijai.', + 'extension' => 'PHP priedas :name nėra įdiegtas. Prašome įdiegti ir aktyvuoti šį priedą.' + ], + 'editor' => [ + 'menu_label' => 'Redaktoriaus nustatymai', + 'menu_description' => 'Redaguoti bendrąsias redaktoriaus savybes, tokias kaip šrifto dydis ir spalvų schema.', + 'font_size' => 'Šrifto dydis', + 'tab_size' => 'Kortelės dydis', + 'use_hard_tabs' => 'Pastūmimas naudojant TAB', + 'code_folding' => 'Kodo suskleidimas', + 'code_folding_begin' => 'Žymėti pradžią', + 'code_folding_begin_end' => 'Žymėti pradžią ir pabaigą', + 'autocompletion' => 'Autopildymas', + 'word_wrap' => 'Perkėlimas', + 'highlight_active_line' => 'Paryškiti aktyvią eilutę', + 'auto_closing' => 'Automatiškai uždaryti žymas', + 'show_invisibles' => 'Rodyti nematomus simbolius', + 'show_gutter' => 'Rodyti paraštę', + 'basic_autocompletion'=> 'Paprastas autopildymas (Ctrl + Space)', + 'live_autocompletion'=> 'Autopildymas gyvai', + 'enable_snippets'=> 'Įjungti kodo fragmentus (Tab)', + 'display_indent_guides'=> 'Rodyti pastūmimo gidą', + 'show_print_margin'=> 'Rodyti spausdinimo ribą', + 'mode_off' => 'Išjungta', + 'mode_fluid' => 'Paslankus', + '40_characters' => '40 Simbolių', + '80_characters' => '80 Simbolių', + 'theme' => 'Spalvų schema', + 'markup_styles' => 'Markup Styles', + 'custom_styles' => 'Custom stylesheet', + 'custom styles_comment' => 'Custom styles to include in the HTML editor.', + 'markup_classes' => 'Žymėjimo Klasės', + 'paragraph' => 'Pastraipa', + 'link' => 'Nuoroda', + 'table' => 'Lentelė', + 'table_cell' => 'Lentelės Langelis', + 'image' => 'Paveiksliukas', + 'label' => 'Žymeklis', + 'class_name' => 'Klasės pavadinimas', + 'markup_tags' => 'Žymėjimo tagai', + 'allowed_empty_tags' => 'Leisti tuščius tagus', + 'allowed_empty_tags_comment' => 'Tagų sąrašas, kurie nepašalinami kai juose nėra turinio.', + 'allowed_tags' => 'Leidžiami tagai', + 'allowed_tags_comment' => 'Leidžiamų tagų sąrašas.', + 'no_wrap' => 'Neperkelti tagų', + 'no_wrap_comment' => 'Tagų sąrašas, kurie nebus perkeliami blokuose.', + 'remove_tags' => 'Pašalinti tagus', + 'remove_tags_comment' => 'Tagų sąrašas, kurie šalinami su esančiu turiniu juose.' + ], + 'tooltips' => [ + 'preview_website' => 'Peržiūrėti svetainę' + ], + 'mysettings' => [ + 'menu_label' => 'Mano nustatymai', + 'menu_description' => 'Nustatymai susieto su Jūsų administracine anketa' + ], + 'myaccount' => [ + 'menu_label' => 'Mano anketa', + 'menu_description' => 'Atnaujinkite savo anketos informaciją tokią kaip vardas, el.paštas ir slaptažodis.', + 'menu_keywords' => 'saugus prisijungimas' + ], + 'branding' => [ + 'menu_label' => 'Redaguoti posistemę', + 'menu_description' => 'Redaguoti adminsitracinės zonos pavadinimą, spalvas bei logotipą.', + 'brand' => 'Prekės ženklas', + 'logo' => 'Logotipas', + 'logo_description' => 'Įkelkite logotipą, kurį norite naudoti posistemėje.', + 'app_name' => 'Programos Pavadinimas', + 'app_name_description' => 'Šis pavadinimas bus rodomas naršyklės kortelėje naudojant administracinę zoną.', + 'app_tagline' => 'Programos Antraštė', + 'app_tagline_description' => 'Šią antraštę matysite prisijungimo į administracinę zoną puslapyje.', + 'colors' => 'Spalvos', + 'primary_color' => 'Pirminė spalva', + 'secondary_color' => 'Antrinė spalva', + 'accent_color' => 'Akcento spalva', + 'styles' => 'Stiliai', + 'custom_stylesheet' => 'Individualus stiliaus planas (CSS)', + 'navigation' => 'Navigacija', + 'menu_mode' => 'Meniu stilius', + 'menu_mode_inline' => 'Linijoje', + 'menu_mode_tile' => 'Langeliais', + 'menu_mode_collapsed' => 'Sutraukta' + ], + 'backend_preferences' => [ + 'menu_label' => 'Posistemės savybės', + 'menu_description' => 'Tvarkykite savo anketos savybes tokias kaip norima kalba.', + 'region' => 'Regionas', + 'code_editor' => 'Kodo redaktorius', + 'timezone' => 'Laiko Juosta', + 'timezone_comment' => 'Pritaikyti rodomas datas šiai laiko juostai.', + 'locale' => 'Kalba', + 'locale_comment' => 'Pasirinkite norimą kalbą.' + ], + 'access_log' => [ + 'hint' => 'Šis registras rodo sėkmingų administratoriaus prisijungimų sąrašą. Įrašai yra saugomi viso :days dienų.', + 'menu_label' => 'Prieigos registras', + 'menu_description' => 'Žiūrėti sėkmingų administratoriaus prisijungimų sąrašą.', + 'created_at' => 'Data ir Laikas', + 'login' => 'Prisijungimas', + 'ip_address' => 'IP adresas', + 'first_name' => 'Vardas', + 'last_name' => 'Pavardė', + 'email' => 'El.paštas' + ], + 'filter' => [ + 'all' => 'viską', + 'options_method_not_exists' => "Modelio klasė :model turi nurodyti metodą :method() gražinantš parinktis ':filter' filtrui.", + 'date_all' => 'visas periodas' + ], + 'import_export' => [ + 'upload_csv_file' => '1. Įkelkite CSV failą', + 'import_file' => 'Importuoti failą', + 'first_row_contains_titles' => 'Pirma eilutė nurodo stulpelių pavadinimus', + 'first_row_contains_titles_desc' => 'Palikite pažymėtą jeigu norite naudoti pirmą eilutę kaip stulpelių pavadinimus.', + 'match_columns' => '2. Suderinkite failo stulpelius su duomenų bazės laukeliais', + 'file_columns' => 'Failo stulpeliai', + 'database_fields' => 'Duombazės laukeliai', + 'set_import_options' => '3. Nurodykite importavimo nustatymus', + 'export_output_format' => '1. Eksportavimo formatas', + 'file_format' => 'Failo formatas', + 'standard_format' => 'Standartinis formatas', + 'custom_format' => 'Individualus formatas', + 'delimiter_char' => 'Skirtuko simbolis', + 'enclosure_char' => 'Aptvėrimo simbolis', + 'escape_char' => 'Išėjimo simbolis', + 'select_columns' => '2. Pasirinkite stulpelius eksportavimui', + 'column' => 'Stulpelis', + 'columns' => 'Stulpeliai', + 'set_export_options' => '3. Nurodykite eksportavimo nustatymus', + 'show_ignored_columns' => 'Rodyti ignoruotus stulpelius', + 'auto_match_columns' => 'Automatiškai suderinti stulpelius', + 'created' => 'Sukurta', + 'updated' => 'Atnaujinta', + 'skipped' => 'Praleista', + 'warnings' => 'Įspėjimai', + 'errors' => 'Klaidos', + 'skipped_rows' => 'Praleistos Eilutės', + 'import_progress' => 'Importavimo progresas', + 'processing' => 'Vykdoma', + 'import_error' => 'Importavimo klaida', + 'upload_valid_csv' => 'Prašome įkelti tinkamą CSV failą.', + 'drop_column_here' => 'Ikelkite stulpelį čia...', + 'ignore_this_column' => 'Ignoruoti šį stulpelį', + 'processing_successful_line1' => 'Failo eksportavimas sėkmingai užbaigtas!', + 'processing_successful_line2' => 'Nukreipiame naršyklę į failo parsiuntimą.', + 'export_progress' => 'Eksportavimo progresas', + 'export_error' => 'Eksportavimo klaida', + 'column_preview' => 'Stulpelio peržiūra', + 'file_not_found_error' => 'Failas nerastas', + 'empty_error' => 'Nėra pateiktų duomenų eksportavimui', + 'empty_import_columns_error' => 'Prašome pasirinkti stulpelius, kuriuos norite eksportuoti.', + 'match_some_column_error' => 'Prašome suderinti stulpelius.', + 'required_match_column_error' => 'Prašome nurodyti atitikmenį laukeliui :label.', + 'empty_export_columns_error' => 'Prašome pasirinkti stulpelius, kuriuos norite eksportuoti.', + 'behavior_missing_uselist_error' => 'Turite įterpti kontrolerio elgesną ListController su aktyvuotu eksportavimo "useList" pasirinkimu.', + 'missing_model_class_error' => 'Prašome nurodyti modelClass atributą tipui :type', + 'missing_column_id_error' => 'Truksta stulpelių identifikatoriaus', + 'unknown_column_error' => 'Nežinomas stulpelis', + 'encoding_not_supported_error' => 'Nežinoma failo koduotė. Pasirinkite individualaus formato failą su tinkama koduote.', + 'encoding_format' => 'Failo koduotė', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Įkelti ir tvarkyti media elementus - paveiksliukus, video, garsus, dokumentus' + ], + 'mediafinder' => [ + 'label' => 'Failų Tvarkyklė', + 'default_prompt' => 'Spauskite %s mygtuką media failų paieškai' + ], + 'media' => [ + 'menu_label' => 'Media', + 'upload' => 'Įkelti', + 'move' => 'Perkelti', + 'delete' => 'Trinti', + 'add_folder' => 'Pridėti katalogą', + 'search' => 'Ieškoti', + 'display' => 'Rodyti', + 'filter_everything' => 'Viskas', + 'filter_images' => 'Paveiksliukai', + 'filter_video' => 'Video', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Dokumentai', + 'library' => 'Biblioteka', + 'size' => 'Dydis', + 'title' => 'Pavadinimas', + 'last_modified' => 'Redaguotas', + 'public_url' => 'Viešas URL', + 'click_here' => 'Spauskite čia', + 'thumbnail_error' => 'Nepavyko atvaizduoti miniatiūros.', + 'return_to_parent' => 'Grįžti į pirminį katalogą', + 'return_to_parent_label' => 'Eiti aukštyn ..', + 'nothing_selected' => 'Nieko nepasirinkote.', + 'multiple_selected' => 'Pasirinkote keletą elementų.', + 'uploading_file_num' => 'Įkeliama :number failai(as)...', + 'uploading_complete' => 'Įkėlimas įvykdytas', + 'uploading_error' => 'Įkėlimas nepavyko', + 'type_blocked' => 'Failo tipas yra blokuojamas saugumo sumetimais.', + 'order_by' => 'Rūšiuoti pagal', + 'folder' => 'Katalogas', + 'no_files_found' => 'Pagal Jūsų paiešką failų neradome.', + 'delete_empty' => 'Pasirinkite emelentus trynimui.', + 'delete_confirm' => 'Trinti pasirinktus elementus?', + 'error_renaming_file' => 'Klaida pervadinant elementą.', + 'new_folder_title' => 'Naujas katalogas', + 'folder_name' => 'Katalogo pavadinimas', + 'error_creating_folder' => 'Klaida sukuriant katalogą', + 'folder_or_file_exist' => 'Katalogas ar failas šiuo pavadinimu jau yra.', + 'move_empty' => 'Pasirinkite elementus perkėlimui.', + 'move_popup_title' => 'Perkelti failus ar katalogus', + 'move_destination' => 'Paskirties katalogas', + 'please_select_move_dest' => 'Pasirinkite paskirties katalogą.', + 'move_dest_src_match' => 'Prašome pasirinkti kitą paskirties katalogą.', + 'empty_library' => 'Media biblioteka tuščiay. Pradžiai įkelkite failus ar sukurkite katalogus.', + 'insert' => 'Įterpti', + 'crop_and_insert' => 'Apkirpti ir Įterpti', + 'select_single_image' => 'Pasirinkite vieną paveiksliuką.', + 'selection_not_image' => 'pasirinktas elementas nėra paveiksliukas.', + 'restore' => 'Atstatyti visus pakeitimus', + 'resize' => 'Keisti išmatavimus...', + 'selection_mode_normal' => 'Normalus', + 'selection_mode_fixed_ratio' => 'Fiksuotas sdantykis', + 'selection_mode_fixed_size' => 'Fiksuotas dydis', + 'height' => 'Aukštis', + 'width' => 'Plotis', + 'selection_mode' => 'Pasirinkimo būdas', + 'resize_image' => 'Keisti paveiksliuko išmatavimus', + 'image_size' => 'Paveiksliuko dydis:', + 'selected_size' => 'Pasirinkta:' + ] +]; diff --git a/modules/backend/lang/lv/lang.php b/modules/backend/lang/lv/lang.php new file mode 100644 index 0000000..f707376 --- /dev/null +++ b/modules/backend/lang/lv/lang.php @@ -0,0 +1,459 @@ + [ + 'title' => 'Administrācijas vide' + ], + 'field' => [ + 'invalid_type' => 'Nederīgs lauka tips :type.', + 'options_method_not_exists' => "Moduļa klasei :model jādefinē metodi :method() atgrieztās vērtības ':field' formas laukam." + ], + 'widget' => [ + 'not_registered' => "Logrīka klases nosaukums ':name' nav reģistrēts", + 'not_bound' => "Logrīks ar klases nosaukumu ':name' nav piesaistīts kontrolierim" + ], + 'page' => [ + 'untitled' => 'Bez nosaukuma', + 'access_denied' => [ + 'label' => 'Piekļuve liegta', + 'help' => "Jums nav piekļuves tiesību, lai skatītu šo lapu.", + 'cms_link' => 'Atgriezties back-end' + ], + ], + 'partial' => [ + 'not_found_name' => "Daļa ':name' nav atrasta." + ], + 'account' => [ + 'sign_out' => 'Izrakstīties', + 'login' => 'Login', + 'reset' => 'Atiestatīt', + 'restore' => 'Atjaunot', + 'login_placeholder' => 'vārds', + 'password_placeholder' => 'parole', + 'forgot_password' => 'Aizmirsāt paroli?', + 'enter_email' => 'Ievadiet epastu', + 'enter_login' => 'Ievadiet lietotājvārdu', + 'email_placeholder' => 'epasts', + 'enter_new_password' => 'Ievadiet jauno paroli', + 'password_reset' => 'Paroles atiestatīšana', + 'restore_success' => 'Epasts tika nosūtīts uz norādīto adresi ar paroles atiestatīšanas norādēm.', + 'restore_error' => "Lietotājs ar norādīto lietotājvārdu neeksistē ':login'", + 'reset_success' => 'Jūsu parole tika veiksmīgi atiestatīta. Varat pieslēgties.', + 'reset_error' => 'Nederīgi paroles atiestatīšanas dati. Mēģiniet vēlreiz!', + 'reset_fail' => 'Nebija iespējams atiestatīt paroli!', + 'apply' => 'Apstiprināt', + 'cancel' => 'Atcelt', + 'delete' => 'Dzēst', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Mērinstrumentu panelis', + 'widget_label' => 'Logrīks', + 'widget_width' => 'Platums', + 'full_width' => 'pilns platums', + 'add_widget' => 'Pievienot logrīku', + 'widget_inspector_title' => 'Logrīka konfigurācija', + 'widget_inspector_description' => 'Konfigurējiet logrīku', + 'widget_columns_label' => 'Platums :columns', + 'widget_columns_description' => 'Logrīka platums, skaitlis starp 1 un 10.', + 'widget_columns_error' => 'Lūdzu ievadiet logrīka platumu kā skaitli starp 1 un 10.', + 'columns' => '{1} kolonna|[2,Inf] kolonnas', + 'widget_new_row_label' => 'Piespiedu jauna rinda', + 'widget_new_row_description' => 'Novietot logrīku jaunā rindā.', + 'widget_title_label' => 'Logrīka virsraksts', + 'widget_title_error' => 'Logrīka virsraksts ir obligāts.', + 'status' => [ + 'widget_title_default' => 'Sistēmas statuss', + 'update_available' => '{0} atjauninājumi pieejami!|{1} atjauninājums pieejams!|[2,Inf] atjauninājumi pieejami!' + ] + ], + 'user' => [ + 'name' => 'Administrātors', + 'menu_label' => 'Administrātori', + 'menu_description' => 'Pārvaldiet back-end administrēšanas lietotājus, grupas un tiesības.', + 'list_title' => 'Pārvaldīt Administrātorus', + 'new' => 'Jauns Administrātors', + 'login' => 'Lietotājvārds', + 'first_name' => 'Vārds', + 'last_name' => 'Uzvārds', + 'full_name' => 'Pilnais vārds', + 'email' => 'Epasts', + 'groups' => 'Grupas', + 'groups_comment' => 'Norādiet, kurai grupai šī persona pieder.', + 'avatar' => 'Avatar', + 'password' => 'Parole', + 'password_confirmation' => 'Apstiprināt Paroli', + 'permissions' => 'Tiesības', + 'account' => 'Konts', + 'superuser' => 'Super Lietotājs', + 'superuser_comment' => 'Atķeksējiet šo aili, lai atļautu šai personai neierobežotu piekļuvi.', + 'send_invite' => 'Nosūtīt uzaicinājumu pa Epastu', + 'send_invite_comment' => 'Atķeksējiet šo aili, lai nosūtītu uzaicinājumu pa Epastu', + 'delete_confirm' => 'Vai tiešām vēlaties dzēst šo administrātoru?', + 'return' => 'Atgriezties administratoru sarakstā', + 'allow' => 'Atļaut', + 'inherit' => 'Pārmantot', + 'deny' => 'Aizliegt', + 'group' => [ + 'name' => 'Grupa', + 'name_comment' => 'Nosaukums tiek attēlots Administratora Pievienošanas/Labošanas lapu grupu sarakstā.', + 'name_field' => 'Nosaukums', + 'description_field' => 'Apraksts', + 'is_new_user_default_field_label' => 'Noklusējama grupa', + 'is_new_user_default_field_comment' => 'Pievienot jaunos administrātorus šai grupai pēc noklusējuma', + 'code_field' => 'Kods', + 'code_comment' => 'Norādiet unikālu piekļuves kodu, ja vēlaties to sasniegt caur API.', + 'menu_label' => 'Grupas', + 'list_title' => 'Pārvaldīt Grupas', + 'new' => 'Jauna Administrātoru Grupa', + 'delete_confirm' => 'Vai tiešām vēlaties dzēst šo administrātoru grupu?', + 'return' => 'Atgriezties grupu sarakstā', + 'users_count' => 'Lietotāji' + ], + 'preferences' => [ + 'not_authenticated' => 'Nav autentificēts lietotājs, kuram ielādēt vai saglabāt iestatījumus.' + ] + ], + 'list' => [ + 'default_title' => 'Saraksts', + 'search_prompt' => 'Meklēt...', + 'no_records' => 'Nav ierakstu šajā skatā.', + 'missing_model' => 'Saraksta uzvedībai definētai :class nav definēts modulis.', + 'missing_column' => 'Nav kolonnu definīciju :columns.', + 'missing_columns' => 'Sarakstam definētam :class nav definētas kolonnas.', + 'missing_definition' => "Sarakstā nav kolonnas ':field'.", + 'missing_parent_definition' => "Saraksts nesatur uzvedības definīciju priekš ':definition'.", + 'behavior_not_ready' => 'Saraksts nav inicializēts, pārbaudiet vai saucāt makeLists() jūsu kontrolierī.', + 'invalid_column_datetime' => "Kolonnas vērtība ':column' nav DateTime objekts, vai esat definējis \$dates savā modulī?", + 'pagination' => 'Attēloti ieraksti: :from-:to no :total', + 'prev_page' => 'Iepriekšējā lapa', + 'next_page' => 'Nākamā lapa', + 'refresh' => 'Atsvaidzināt', + 'updating' => 'Atjaunināšana...', + 'loading' => 'Ielādējam...', + 'setup_title' => 'Saraksta iestatīšana', + 'setup_help' => 'Izmantojiet rūtiņas lai izvēlētos kolonnas kuras vēlaties redzēt sarakstā. Varat mainīt kolonnu pozīcijas pārnesot tās augšup vai lejup.', + 'records_per_page' => 'Ieraksti uz lapu', + 'records_per_page_help' => 'Izvēlieties cik ierakstus rādīt vienā lapā. Ņemiet vēra, ka daudz ierakstu var bremzēt lapas ielādi.', + 'delete_selected' => 'Dzēst izvēlētos', + 'delete_selected_empty' => 'Dzēšanai nav izvēlēts neviens ieraksts.', + 'delete_selected_confirm' => 'Dzēst izvēlētos ierakstus?', + 'delete_selected_success' => 'Izvēlētie ieraksti veiksmīgi dzēsti.', + 'column_switch_true' => 'Jā', + 'column_switch_false' => 'Nē' + ], + 'fileupload' => [ + 'attachment' => 'Pielikums', + 'help' => 'Pievienojiet virsrakstu un aprakstu šim pielikumam.', + 'title_label' => 'Vrisraksts', + 'description_label' => 'Apraksts', + 'default_prompt' => 'Uzklikšķiniet uz %s vai nesiet failu šeit', + 'attachment_url' => 'Pielikuma URL', + 'upload_file' => 'Augšupielādēt failu', + 'upload_error' => 'Augšupielādes kļūda', + 'remove_confirm' => 'Vai esat pārliecināts?', + 'remove_file' => 'Noņemt failu' + ], + 'form' => [ + 'create_title' => 'Jauns :name', + 'update_title' => 'Labot :name', + 'preview_title' => 'Priekšskatīt :name', + 'create_success' => ':name tika veiksmīgi izveidots', + 'update_success' => ':name tika veiksmīgi atjaunināts', + 'delete_success' => ':name tika veiksmīgi izdzēsts', + 'missing_id' => 'Formas ieraksta ID netika norādīts.', + 'missing_model' => 'Formai iekš :class nav definēts modulis.', + 'missing_definition' => "Forma nesatur ':field'.", + 'not_found' => 'Formas ieraksts ar ID :id netika atrasts.', + 'action_confirm' => 'Vai esat pārliecināts?', + 'create' => 'Izveidot', + 'create_and_close' => 'Izveidot un aizvērt', + 'creating' => 'Izveidojam...', + 'creating_name' => 'Izveidojam :name...', + 'save' => 'Saglabāt', + 'save_and_close' => 'Saglabāt un aizvērt', + 'saving' => 'Saglabājam...', + 'saving_name' => 'Saglabājam :name...', + 'delete' => 'Dzēst', + 'deleting' => 'Dzēšam...', + 'confirm_delete' => 'Vai tiešām vēlaties dzēst šo ierakstu?', + 'confirm_delete_multiple' => 'Vai tiešām vēlaties dzēst šos ierakstus?', + 'deleting_name' => 'Dzēšam :name...', + 'reset_default' => 'Atiestatīt uz noklusējumu', + 'resetting' => 'Atiestatam', + 'resetting_name' => 'Atiestatam :name', + 'undefined_tab' => 'Izvēles', + 'field_off' => 'Izsl.', + 'field_on' => 'Iesl.', + 'add' => 'Pievienot', + 'apply' => 'Apstiprināt', + 'cancel' => 'Atcelt', + 'close' => 'Aizvērt', + 'confirm' => 'Apstiprināt', + 'reload' => 'Pārlādēt', + 'complete' => 'Pabeigt', + 'ok' => 'OK', + 'or' => 'vai', + 'confirm_tab_close' => 'Vai tiešām vēlaties aizvērt šo cilni? Nesaglabātās izmaiņas būs zudušas.', + 'behavior_not_ready' => 'Forma nav tikusi inicializēta, pārbaudiet vai izsaucāt initForm() savā kontrolierī.', + 'preview_no_files_message' => 'Faili nav augšupielādēti', + 'preview_no_record_message' => 'Nav izvēlētu ierakstu.', + 'select' => 'Izvēlēties', + 'select_all' => 'izvēlēties visus', + 'select_none' => 'neizvēlēties nevienu', + 'select_placeholder' => 'lūdzu izvēlieties', + 'insert_row' => 'Ievietot rindu', + 'insert_row_below' => 'Ievietot riendu zemāk', + 'delete_row' => 'Dzēst rindu', + 'concurrency_file_changed_title' => 'Fails tika modificēts', + 'concurrency_file_changed_description' => "Fails, kuru labojat ir ticis modificēts no cita lietotāja puses. Jūs varat pārlādēt failu un zaudēt savas izmaiņas vai arī pārrakstīt esošo failu uz diska.", + 'return_to_list' => 'Atgriezties uz sarakstu' + ], + 'recordfinder' => [ + 'find_record' => 'Atrast ierakstu' + ], + 'relation' => [ + 'missing_config' => "Relācijām nav norādīta nekāda konfigurācija ':config'.", + 'missing_definition' => "Relācijām nav definēts lauks ':field'.", + 'missing_model' => "Relācijās izmantotajai klasei :class nav moduļa definīcijas.", + 'invalid_action_single' => "Šī darbība nevar tikt veikta ar vienmoduļa relāciju.", + 'invalid_action_multi' => "Šī darbība nevar tikt veikta ar daudzmoduļu relāciju.", + 'help' => "Spiediet uz vienuma, lai pievienotu", + 'related_data' => "Saistītie :name dati", + 'add' => "Pievienot", + 'add_selected' => "Pievienot izvēlētos", + 'add_a_new' => "Pievienot jaunu :name", + 'link_selected' => "Saite izvēlēta", + 'link_a_new' => "Saistīt jaunu :name", + 'cancel' => "Atcelt", + 'close' => "Aizvērt", + 'add_name' => "Pievienot :name", + 'create' => "Izveidot", + 'create_name' => "Izveidot :name", + 'update' => "Atjaunot", + 'update_name' => "Atjaunot :name", + 'preview' => "Priekšskatīt", + 'preview_name' => "Priekšskatīt :name", + 'remove' => "Noņemt", + 'remove_name' => "Noņemt :name", + 'delete' => "Dzēst", + 'delete_name' => "Dzēst :name", + 'delete_confirm' => "Vai esat pārliecināts?", + 'link' => "Saistīt", + 'link_name' => "Saistīt :name", + 'unlink' => "Atsaistīt", + 'unlink_name' => "Atsaistīt :name", + 'unlink_confirm' => "Vai esat pārliecināts?", + ], + 'reorder' => [ + 'default_title' => 'Pārkārtot ierakstus', + 'no_records' => 'Nav pieejami ieraksti, ko pārkārtot.', + ], + 'model' => [ + 'name' => 'Modulis', + 'not_found' => "Modulis ':class' ar ID :id netika atrasts", + 'missing_id' => 'Nav ticis norādīts ID, lai meklētu ierakstu.', + 'missing_relation' => "Modulis ':class' nesniedz informāciju par ':relation'.", + 'missing_method' => "Modulis ':class' nesatur metodi ':method'.", + 'invalid_class' => "Modulis :model lietots :class ir nederīgs, tam jābūt mantotam no \Moduļa klases.", + 'mass_assignment_failed' => "Masveida saistīšana neizdevās Moduļa atribūtam ':attribute'." + ], + 'warnings' => [ + 'tips' => 'Sistēmas konfigurācijas padomi', + 'tips_description' => 'Ir lietas, kurām vajadzētu pievērst uzmanību, lai konfigurētu sistēmu pareizi.', + 'permissions' => 'Mape :name vai tās apakšmapes nav ierakstāmas ar PHP. Lūdzu iestatiet pareizas tiesības web serverim šajā mapē.', + 'extension' => 'PHP paplašinājums :name nav instalēts. Lūdzu instalējiet šo papildinājumu un aktivizējiet to.' + ], + 'editor' => [ + 'menu_label' => 'Koda labotāja iestatījumi', + 'menu_description' => 'Pielāgojiet sava kodu labotāja iestatījumus, tādus kā fontu izmēru un krāsu shēmu.', + 'font_size' => 'Fonta izmērs', + 'tab_size' => 'Tabulācijas platums', + 'use_hard_tabs' => 'Kārtot lietojot Tab', + 'code_folding' => 'Koda savilkšana', + 'word_wrap' => 'Vārdu aplaušana', + 'highlight_active_line' => 'Iekrāsot aktīvo līniju', + 'auto_closing' => 'Automātiski aizvērt birkas un īpašos simbolus', + 'show_invisibles' => 'Rādīt slēptos simbolus', + 'show_gutter' => 'Rādīt līniju numurus', + 'enable_basic_autocompletion'=> 'Iespējot pamata automātisko pabeigšanu (Ctrl+Space)', + 'enable_snippets'=> 'Rādīt koda fragmentus automātiskajā pabeigšanā', + 'enable_live_autocompletion'=> 'Iespējot dzīvo automātisko pabeigšanu', + 'display_indent_guides'=> 'Rādīt atkāpju ceļvežus', + 'show_print_margin'=> 'Rādīt printēšanas rezervi', + 'theme' => 'Krāsu shēma' + ], + 'tooltips' => [ + 'preview_website' => 'Priekšskatīt web lapu' + ], + 'mysettings' => [ + 'menu_label' => 'Mani Iestatījumi', + 'menu_description' => 'Iestatījumi saistībā ar jūsu administrātora kontu' + ], + 'myaccount' => [ + 'menu_label' => 'Mans konts', + 'menu_description' => 'Atjaunojiet sava konta detaļas, piemēram, vārdu, epastu un paroli.', + 'menu_keywords' => 'drošība login' + ], + 'branding' => [ + 'menu_label' => 'Back-end pielāgošana', + 'menu_description' => 'Pielāgojiet administratīvo vidi, piemēram nosaukumu, krāsas un logo.', + 'brand' => 'Brends', + 'logo' => 'Logo', + 'logo_description' => 'Augšupielādējiet pielāgotu logo lai izmantotu back-end.', + 'app_name' => 'Nosaukums', + 'app_name_description' => 'Šis nosaukums tiek rādīts augšpusē iekš back-end.', + 'app_tagline' => 'Apraksts', + 'app_tagline_description' => 'Šis apraksts tiek rādīts back-end auteintificēšanās lapā.', + 'colors' => 'Krāsas', + 'primary_color' => 'Primārā krāsa', + 'secondary_color' => 'Sekundārā krāsa', + 'accent_color' => 'Akcenta / Uzsvara krāsa', + 'styles' => 'Stili', + 'custom_stylesheet' => 'Pielāgots css', + 'navigation' => 'Navigācija', + 'menu_mode' => 'Izvēlnes stils', + 'menu_mode_inline' => 'Rindā (Inline)', + 'menu_mode_tile' => 'Flīzes (Tiles)', + 'menu_mode_collapsed' => 'Collapsed', + ], + 'backend_preferences' => [ + 'menu_label' => 'Back-end iestatījumi', + 'menu_description' => 'Pārvaldiet sava konta iestatījumus, piemēram, valodu.', + 'region' => 'Regions', + 'code_editor' => 'Koda redaktors', + 'timezone' => 'Laika josla', + 'locale' => 'Valoda', + 'locale_comment' => 'Izvēlieties kādu valodu izmantosiet.' + ], + 'access_log' => [ + 'hint' => 'Šis žurnāls rāda sarakstu ar vieksmīgajiem ielogošanās mēģinājumiem no administrātoriem. Ieraksti tiek saglabāti :days dienas.', + 'menu_label' => 'Autorizēšanās žurnāls', + 'menu_description' => 'Rāda sarakstu ar veiksmīgajiem back-end autorizēšanās mēģinājumiem.', + 'created_at' => 'Datums & Laiks', + 'login' => 'Lietotājvārds', + 'ip_address' => 'IP adrese', + 'first_name' => 'Vārds', + 'last_name' => 'Uzvārds', + 'email' => 'Epasts' + ], + 'filter' => [ + 'all' => 'visi' + ], + 'import_export' => [ + 'upload_csv_file' => '1. Augšupielādējiet CSV failu', + 'import_file' => 'Importa fails', + 'first_row_contains_titles' => 'Pirmā rinda satur kolonnu nosaukumus / virsrakstus', + 'first_row_contains_titles_desc' => 'Atstājiet šo izvēles aili aktīvu, ja pirmā rinda Jūsu CSV failā satur kolonnu nosaukumus / virsrakstus.', + 'match_columns' => '2. Saskanējiet faila kolonnas ar datubāzes laukiem', + 'file_columns' => 'Faila kolonnas', + 'database_fields' => 'Datubāzes lauki / kolonnas', + 'set_import_options' => '3. Iestatiet importa opcijas', + 'export_output_format' => '1. Eksporta izvades formāts', + 'file_format' => 'Faila formāts', + 'standard_format' => 'Standarta formāts', + 'custom_format' => 'Pielāgots formāts', + 'delimiter_char' => 'Delimiter rakstzīme (simbols)', + 'enclosure_char' => 'Enclosure rakstzīme (simbols)', + 'escape_char' => 'Escape rakstzīme (simbols)', + 'select_columns' => '2. Izvēlieties kolonnas, kuras ir jāeksportē', + 'column' => 'Kolonna', + 'columns' => 'Kolonnas', + 'set_export_options' => '3. Iestatiet eksporta opcijas', + 'show_ignored_columns' => 'Parādīt ignorētās kolonnas', + 'auto_match_columns' => 'Automātiski saskanēt kolonnas', + 'created' => 'Izveidoti', + 'updated' => 'Atjaunināti', + 'skipped' => 'Izlaisti', + 'warnings' => 'Brīdinājumi', + 'errors' => 'Kļūdas', + 'skipped_rows' => 'Izlaistas rindas', + 'import_progress' => 'Importa progress', + 'processing' => 'Apstrāde', + 'import_error' => 'Importa kļūda', + 'upload_valid_csv' => 'Lūdzu, augšupielādējiet derīgu CSV failu.', + 'drop_column_here' => 'Nesiet datubāzes lauku šeit...', + 'ignore_this_column' => 'Ignorēt šo kolonnu', + 'processing_successful_line1' => 'Faila eksporta process ir sekmīgi pabeigts!', + 'processing_successful_line2' => 'Tagad pārlūks automātiski novirzīs uz faila lejupielādi.', + 'export_progress' => 'Eksporta progress', + 'export_error' => 'Eksporta kļūda', + 'column_preview' => 'Kolonnas priekšskatījums', + 'file_not_found_error' => 'Fails nav atrasts', + 'empty_error' => 'Dati eksportam netika sniegti', + 'empty_import_columns_error' => 'Lūdzu, norādiet kādas kolonnas ir jāimportē.', + 'match_some_column_error' => 'Lūdzu, vispirms saskanējiet kolonnas.', + 'required_match_column_error' => 'Lūdzu, norādiet attiecīgu datubāzes lauku obligātam laukam :label.', + 'empty_export_columns_error' => 'Lūdzu, norādiet kādas kolonnas ir jāeksportē.', + 'behavior_missing_uselist_error' => 'Jums ir jāisteno kontroliera uzvedība ListController Jūsu kontrolierī un jāiestata "useList: true" opcija Importa un Eksporta konfigurācijā.', + 'missing_model_class_error' => 'Lūdzu, norādiet modelClass īpašību priekš :type', + 'missing_column_id_error' => 'Trūkstošs kolonnas identifikators', + 'unknown_column_error' => 'Nezināma kolonna', + 'encoding_not_supported_error' => 'Izvēlētā faila kodējums nav atpazīts. Lūdzu, izvēlieties Pielāgota formāta opciju ar pareizu kodējumu lai Jūsu fails tiktu ieimportēts.', + 'encoding_format' => 'Faila kodējums', + ], + 'permissions' => [ + 'manage_media' => 'Pārvaldīt multividi' + ], + 'mediafinder' => [ + 'default_prompt' => 'Klikšķiniet uz %s pogas, lai atrastu multividi' + ], + 'media' => [ + 'menu_label' => 'Multimēdija', + 'upload' => 'Augšupielādēt', + 'move' => 'Pārvietot', + 'delete' => 'Dzēst', + 'add_folder' => 'Pievienot mapi', + 'search' => 'Meklēt', + 'display' => 'Attēlot', + 'filter_everything' => 'Viss', + 'filter_images' => 'Attēli', + 'filter_video' => 'Video', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Dokumenti', + 'library' => 'Bibliotēka', + 'size' => 'Izmērs', + 'title' => 'Virsraksts', + 'last_modified' => 'Pēdējoreiz modificēts', + 'public_url' => 'Publiskā URL', + 'click_here' => 'Spiest šeit', + 'thumbnail_error' => 'Kļūda ģenerējot priekšskatījumu.', + 'return_to_parent' => 'Atgriezties vecākmapē', + 'return_to_parent_label' => 'Doties augšup ..', + 'nothing_selected' => 'Nekas nav izvēlēts.', + 'multiple_selected' => 'Vairāki izvēlēti objekti.', + 'uploading_file_num' => 'Augšupielādējam :number failu(us)...', + 'uploading_complete' => 'Augšupielāde pabeigta', + 'order_by' => 'Kārtot pēc', + 'folder' => 'Mape', + 'no_files_found' => 'Jūsu pieprasītie faili netika atrasti.', + 'delete_empty' => 'Lūdzu izvēlaties objektus, kurus dzēst.', + 'delete_confirm' => 'Vai tiešām vēlaties izdzēst izvēlēto objektu(us)?', + 'error_renaming_file' => 'Kļūda pārdēvējot objektu.', + 'new_folder_title' => 'Jauna mape', + 'folder_name' => 'Mapes nosaukums', + 'error_creating_folder' => 'Kļūda izveidojot mapi', + 'folder_or_file_exist' => 'Mape vai fails ar izvēlēto nosaukumu jau eksistē.', + 'move_empty' => 'Izvēlēties objektus, kurus pārvietot.', + 'move_popup_title' => 'Pārvietot failus vai mapes', + 'move_destination' => 'Mērķdirektorija', + 'please_select_move_dest' => 'Lūdzu izvēlieties mērķdirektoriju.', + 'move_dest_src_match' => 'Lūdzu izvēlieties citu mērķdirektoriju.', + 'empty_library' => 'Multimēdijas bibliotēka ir tukša. Augšupielādējiet failus vai izveidojat mapes, lai sāktu.', + 'insert' => 'Ievietot', + 'crop_and_insert' => 'Apgriezt un Ievietot', + 'select_single_image' => 'Lūdzu izvēlieties vienu attēlu.', + 'selection_not_image' => 'Izvēlētais objekts nav attēls.', + 'restore' => 'Atcelt visas izmaiņas', + 'resize' => 'Mērogot...', + 'selection_mode_normal' => 'Normāls', + 'selection_mode_fixed_ratio' => 'Fiksēta attiecība', + 'selection_mode_fixed_size' => 'Fiksēts izmērs', + 'height' => 'Augstums', + 'width' => 'Platums', + 'selection_mode' => 'Iezīmēšanas režīms', + 'resize_image' => 'Mērogot attēlu', + 'image_size' => 'Attēla izmērs:', + 'selected_size' => 'Izvēlēts:' + ] +]; diff --git a/modules/backend/lang/nb-no/lang.php b/modules/backend/lang/nb-no/lang.php new file mode 100644 index 0000000..7174185 --- /dev/null +++ b/modules/backend/lang/nb-no/lang.php @@ -0,0 +1,548 @@ + [ + 'title' => 'Administrasjonsområde' + ], + 'field' => [ + 'invalid_type' => 'Ugyldig felttype brukt :type.', + 'options_method_not_exists' => "Modellklassen :model må definere en metode :method() som returnerer vilkår for formfeltet ':field'." + ], + 'widget' => [ + 'not_registered' => "En widget med klassenavnet ':name' har ikke blitt registrert", + 'not_bound' => "En widget med klassenavnet ':name' er ikke bundet til kontrolleren" + ], + 'page' => [ + 'untitled' => 'Uten navn', + 'access_denied' => [ + 'label' => 'Ingen tilgang', + 'help' => "Du har ikke nødvendig tilgang til å se denne siden.", + 'cms_link' => 'Tilbake til backend' + ], + 'no_database' => [ + 'label' => 'Database mangler', + 'help' => "En database kreves for å koble til backend. Sjekk at databasetilgang er konfigurert og migrert før du prøver igjen.", + 'cms_link' => 'Tilbake til hovedsiden' + ], + ], + 'partial' => [ + 'not_found_name' => "En partial ved navn ':name' ble ikke funnet." + ], + 'account' => [ + 'sign_out' => 'Logg ut', + 'login' => 'Logg inn', + 'reset' => 'Nullstill', + 'restore' => 'Gjenopprett', + 'login_placeholder' => 'brukernavn', + 'password_placeholder' => 'passord', + 'forgot_password' => 'Glemt passordet ditt?', + 'enter_email' => 'Din e-postadresse', + 'enter_login' => 'Ditt brukernavn', + 'email_placeholder' => 'e-postadresse', + 'enter_new_password' => 'Skriv inn nytt passord', + 'password_reset' => 'Gjenopprett passord', + 'restore_success' => 'En e-post har blitt sendt til din e-postadresse med informasjon om gjenoppretting av passord.', + 'restore_error' => "Brukernavnet ':login' eksisterer ikke.", + 'reset_success' => 'Ditt passord har blitt gjenopprettet. Du kan nå logge inn.', + 'reset_error' => 'Ugyldig data. Vennligst prøv igjen!', + 'reset_fail' => 'Kunne ikke gjenopprette passord!', + 'apply' => 'Fortsett', + 'cancel' => 'Avbryt', + 'delete' => 'Slett', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Dashboard', + 'widget_label' => 'Widget', + 'widget_width' => 'Bredde', + 'full_width' => 'full bredde', + 'manage_widgets' => 'Administrer widgets', + 'add_widget' => 'Legg til widget', + 'widget_inspector_title' => 'Widget-konfigurasjon', + 'widget_inspector_description' => 'Konfigurer widgeten', + 'widget_columns_label' => 'Bredde :columns', + 'widget_columns_description' => 'Bredden på widgeten. Tall mellom 1 og 10.', + 'widget_columns_error' => 'Vennligst spesifiser bredden på weidgeten som et tall mellom 1 og 10.', + 'columns' => '{1} kolonne|[2,Inf] kolonner', + 'widget_new_row_label' => 'Tving ny rad', + 'widget_new_row_description' => 'Plasserer widgeten i en ny rad.', + 'widget_title_label' => 'Widget-tittel', + 'widget_title_error' => 'Tittel er obligatorisk.', + 'reset_layout' => 'Tilbakestill layout', + 'reset_layout_confirm' => 'Tilbakestille layout til originalen?', + 'reset_layout_success' => 'Layout er tilbakestilt', + 'make_default' => 'Sett som standard', + 'make_default_confirm' => 'Sett nåværende layout som standard?', + 'make_default_success' => 'Nåværende layout er nå standard', + 'status' => [ + 'widget_title_default' => 'System status', + 'update_available' => '{0} oppdateringer tilgjengelig!|{1} oppdatering tilgjengelig!|[2,Inf] oppdateringer tilgjengelig!', + 'updates_pending' => 'Ventende oppdateringer', + 'updates_nil' => 'Programvaren er oppdatert', + 'updates_link' => 'Oppdater', + 'warnings_pending' => 'Noen snubletråder du må se på', + 'warnings_nil' => 'Ingen advarsler å vise', + 'warnings_link' => 'Vis', + 'core_build' => 'System build', + 'event_log' => 'Event logg', + 'request_log' => 'Request logg', + 'app_birthday' => 'Online siden', + ], + 'welcome' => [ + 'widget_title_default' => 'Velkommen', + 'welcome_back_name' => 'Velkommen til :app, :name.', + 'welcome_to_name' => 'Velkommen til :app, :name.', + 'first_sign_in' => 'Dette er første gangen du har logget inn.', + 'last_sign_in' => 'Forrige innlogging var', + 'view_access_logs' => 'Vis adgangslogg', + 'nice_message' => 'Ha en fantastisk dag!!', + ] + ], + 'user' => [ + 'name' => 'Administrator', + 'menu_label' => 'Administratorer', + 'menu_description' => 'Administrer backend-administratorer, grupper og tilganger.', + 'list_title' => 'Håndter administratorer', + 'new' => 'Ny administrator', + 'login' => 'Brukernavn', + 'first_name' => 'Fornavn', + 'last_name' => 'Etternavn', + 'full_name' => 'Fullt navn', + 'email' => 'E-postadresse', + 'groups' => 'Grupper', + 'groups_comment' => 'Spesifiser hvilke grupper personen tilhører.', + 'avatar' => 'Avatar', + 'password' => 'Passord', + 'password_confirmation' => 'Bekreft passord', + 'permissions' => 'Tilganger', + 'account' => 'konto', + 'superuser' => 'Superbruker', + 'superuser_comment' => 'Kryss av denne boksen for å gi personen tilgang til alle områder.', + 'send_invite' => 'Send invitasjon via e-post', + 'send_invite_comment' => 'Kryss av denne boksen for å sende personen en invitasjon via e-post', + 'delete_confirm' => 'Vil du virkelig slette denne administratoren?', + 'return' => 'Tilbake til administratoroversikten', + 'allow' => 'Tillat', + 'inherit' => 'Arv', + 'deny' => 'Nekt', + 'activated' => 'Aktivert', + 'last_login' => 'Forrige innlogging', + 'created_at' => 'Opprettet', + 'updated_at' => 'Oppdatert', + 'group' => [ + 'name' => 'Gruppe', + 'name_comment' => 'Navnet vises i gruppelisten under valget for å opprette og redigere administratorer.', + 'name_field' => 'Navn', + 'description_field' => 'Beskrivelse', + 'is_new_user_default_field_label' => 'Standardgruppe', + 'is_new_user_default_field_comment' => 'Legg nye administratorer til denne gruppen som standard', + 'code_field' => 'Kode', + 'code_comment' => 'Fyll inn en unik kode for å bruke API-en.', + 'menu_label' => 'Grupper', + 'list_title' => 'Administrere grupper', + 'new' => 'Ny gruppe', + 'delete_confirm' => 'Vil du virkelig slette denne administratorgruppen?', + 'return' => 'Tilbake til gruppeoversikten', + 'users_count' => 'Antall brukere' + ], + 'preferences' => [ + 'not_authenticated' => 'Det er ingen autentiserte brukere å laste eller lagre innstillinger for.' + ] + ], + 'list' => [ + 'default_title' => 'Liste', + 'search_prompt' => 'Søk...', + 'no_records' => 'Det er ingen treff i denne visningen.', + 'missing_model' => 'Listeegenskapen brukt i :class mangler en modelldefinisjon.', + 'missing_column' => 'Det er ingen kolonnedefinisjoner for :columns.', + 'missing_columns' => 'Liste brukt i :class har ingen definerte kolonner.', + 'missing_definition' => "Listeegenskapen inneholder ingen kolonner for ':field'.", + 'missing_parent_definition' => "Listeegenskapen mangler definisjon for ':definition'.", + 'behavior_not_ready' => 'Listeegenskapen har ikke blir initialisert, sjekk at du har kalt makeList() i kontrolleren.', + 'invalid_column_datetime' => "Kolonneverdien ':column' er ikke et DateTime-objekt, mangler du en \$date-referanse i modellen?", + 'pagination' => 'Viser rader: :from-:to av :total', + 'prev_page' => 'Forrige side', + 'next_page' => 'Neste side', + 'refresh' => 'Oppdater', + 'updating' => 'Oppdaterer...', + 'loading' => 'Laster...', + 'setup_title' => 'Listeinnstillinger', + 'setup_help' => 'Kryss av sjekkboksene for å velge hvilke kolonner du vil ha i listen. Du kan sortere kolonnene ved å dra sjekkboksene opp eller ned.', + 'records_per_page' => 'Rader per side', + 'records_per_page_help' => 'Velg antall rader som skal vises på hver side. Vær oppmerksom på at et høyt antall kan redusere ytelsen på siden.', + 'check' => 'Velg', + 'delete_selected' => 'Slett valgte', + 'delete_selected_empty' => 'Det er ingen valgte rader å slette.', + 'delete_selected_confirm' => 'Vil du slette valgte rader?', + 'delete_selected_success' => 'Rader har blitt slettet.', + 'column_switch_true' => 'Ja', + 'column_switch_false' => 'Nei' + ], + 'fileupload' => [ + 'attachment' => 'Vedlegg', + 'help' => 'Legg til tittel og beskrivelse for dette vedlegget.', + 'title_label' => 'Tittel', + 'description_label' => 'Beskrivelse', + 'default_prompt' => 'Klikk %s eller dra filen hit for å laste opp', + 'attachment_url' => 'URL til vedlegg', + 'upload_file' => 'Last opp fil', + 'upload_error' => 'Feil ved opplasting', + 'remove_confirm' => 'Er du sikker?', + 'remove_file' => 'Fjern filen' + ], + 'form' => [ + 'create_title' => 'Ny :name', + 'update_title' => 'Endre :name', + 'preview_title' => 'Forhåndsvis :name', + 'create_success' => ':name har blitt opprettet', + 'update_success' => ':name har blitt endret', + 'delete_success' => ':name har blitt slettet', + 'reset_success' => 'Tilbakestilling fullført', + 'missing_id' => 'Record ID for skjemaet har ikke blitt spesifisert.', + 'missing_model' => 'Skjemaegenskapen brukt i :class mangler en modell.', + 'missing_definition' => "Skjemaegenskapen mangler et felt for ':field'.", + 'not_found' => 'Record ID :id ble ikke funnet.', + 'action_confirm' => 'Er du sikker?', + 'create' => 'Opprett', + 'create_and_close' => 'Opprett og lukk', + 'creating' => 'Oppretter...', + 'creating_name' => 'Oppretter :name...', + 'save' => 'Lagre', + 'save_and_close' => 'Lagre og lukk', + 'saving' => 'Lagrer...', + 'saving_name' => 'Lagrer :name...', + 'delete' => 'Slett', + 'deleting' => 'Sletter...', + 'confirm_delete' => 'Slett oppføring?', + 'confirm_delete_multiple' => 'Slett valgte oppføringer?', + 'deleting_name' => 'Sletter :name...', + 'reset_default' => 'Tilbakestill', + 'resetting' => 'Tilbakestiller', + 'resetting_name' => 'Tilbakestiller :name', + 'undefined_tab' => 'Div.', + 'field_off' => 'Av', + 'field_on' => 'På', + 'add' => 'Legg til', + 'apply' => 'Fortsett', + 'cancel' => 'Avbryt', + 'close' => 'Lukk', + 'confirm' => 'Bekreft', + 'reload' => 'Last på nytt', + 'complete' => 'Fullført', + 'ok' => 'OK', + 'or' => 'eller', + 'confirm_tab_close' => 'Vil du virkelig lukke fanen? Endringer som ikke er lagret vil gå tapt.', + 'behavior_not_ready' => 'Skjemaegenskap har ikke blitt initialisert, sjekk at du har kalt initForm() i kontrolleren.', + 'preview_no_files_message' => 'Filer er ikke opplastet', + 'preview_no_record_message' => 'Det er ingen valgte oppføringer.', + 'select' => 'Velg', + 'select_all' => 'Velg alle', + 'select_none' => 'Velg ingen', + 'select_placeholder' => 'velg', + 'insert_row' => 'Sett inn rad', + 'insert_row_below' => 'Sett inn rad under', + 'delete_row' => 'Slett rad', + 'concurrency_file_changed_title' => 'Filen er endret', + 'concurrency_file_changed_description' => "Filen du endrer på har blitt endret på disken av en annen bruker. Du kan enten oppdatere filen og tape endret data, eller overskrive filen på disken.", + 'return_to_list' => 'Tilbake til listen' + ], + 'recordfinder' => [ + 'find_record' => 'Finn oppføring' + ], + 'relation' => [ + 'missing_config' => "Relasjonen mangler en konfigurasjon for ':config'.", + 'missing_definition' => "Relasjonen mangler en definisjon for ':field'.", + 'missing_model' => "Relasjonen brukt i :class har ingen definert modell.", + 'invalid_action_single' => "Denne handlingen kan ikke brukes på en enkel relasjon.", + 'invalid_action_multi' => "Denne relasjonen kan ikke brukes på fler-relasjoner.", + 'help' => "Klikk på et element for å legge til", + 'related_data' => "Relatert :name data", + 'add' => "Legg til", + 'add_selected' => "Legg til valgte", + 'add_a_new' => "Legg til ny :name", + 'link_selected' => "Link valgte", + 'link_a_new' => "Link en ny :name", + 'cancel' => "Avbryt", + 'close' => "Lukk", + 'add_name' => "Legg til :name", + 'create' => "Opprett", + 'create_name' => "Opprett :name", + 'update' => "Oppdater", + 'update_name' => "Oppdater :name", + 'preview' => "Forhåndsvis", + 'preview_name' => "Forhåndsvis :name", + 'remove' => "Fjern", + 'remove_name' => "Fjern :name", + 'delete' => "Slett", + 'delete_name' => "Slett :name", + 'delete_confirm' => "Er du sikker?", + 'link' => "Link", + 'link_name' => "Link :name", + 'unlink' => "Fjern link", + 'unlink_name' => "Fjern link :name", + 'unlink_confirm' => "Er du sikker?", + ], + 'reorder' => [ + 'default_title' => 'Sortere oppføringer', + 'no_records' => 'Det er ingen tilgjengelige oppføringer å sortere.' + ], + 'model' => [ + 'name' => 'Modell', + 'not_found' => "Modellen ':class' med ID-en :id ble ikke funnet", + 'missing_id' => 'Det er ingen ID spesifisert for å se opp modellen.', + 'missing_relation' => "Modellen ':class' mangler en definisjon for ':relation'.", + 'missing_method' => "Modellen ':class' mangler metoden ':method'.", + 'invalid_class' => "Modellen :model som brukes i :class er ugyldig, den må arve \Model-klassen.", + 'mass_assignment_failed' => "Mass assignment feilet for modell-attributten ':attribute'." + ], + 'warnings' => [ + 'tips' => 'Tips for systemkonfigurasjon', + 'tips_description' => 'Det er problemer du må være oppmerksom på for å konfigurere systemet riktig.', + 'permissions' => 'Mappen :name eller dens undermapper kan ikke skrives på av PHP. Vennligst sjekk skrivetilganger på serveren.', + 'extension' => 'PHP-extensionen :name er ikke installert..' + ], + 'editor' => [ + 'menu_label' => 'Teksteditor-innstillinger', + 'menu_description' => 'Endre teksteditor-innstillingene dine, for eksemplem tekststørrelse og fargevalg.', + 'font_size' => 'Tekststørrelse', + 'tab_size' => 'Tab-størrelse', + 'use_hard_tabs' => 'Inntrykk med tabs', + 'code_folding' => 'Code folding', + 'code_folding_begin' => 'Merk start av code folding', + 'code_folding_begin_end' => 'Merk start og slutt av code folding', + 'autocompletion' => 'Automatisk fullføring', + 'word_wrap' => 'Orddeling', + 'highlight_active_line' => 'Fremhev aktiv linje', + 'auto_closing' => 'Lukk tager automatisk', + 'show_invisibles' => 'Vis usynlige tegn', + 'show_gutter' => 'Vis linjenummer', + 'basic_autocompletion'=> 'Enkel autofullføring (Ctrl + Space)', + 'live_autocompletion'=> 'Live autofullføring', + 'enable_snippets'=> 'Aktivér kodesnippets (Tab)', + 'display_indent_guides'=> 'Vis innrykk', + 'show_print_margin'=> 'Vis utskriftsmargin', + 'mode_off' => 'Av', + 'mode_fluid' => 'Flytende', + '40_characters' => '40 tegn', + '80_characters' => '80 tegn', + 'theme' => 'Fargetema', + 'markup_styles' => 'Markup-stiler', + 'custom_styles' => 'Tilpasset stilsett (CSS)', + 'custom styles_comment' => 'Tilpassede CSS-stilregler å inkludere i HTML-editoren.', + 'markup_classes' => 'Markup-klasser', + 'paragraph' => 'Avsnitt', + 'link' => 'Link', + 'table' => 'Tabell', + 'table_cell' => 'Celle', + 'image' => 'Bilde', + 'label' => 'Label', + 'class_name' => 'Navn på klasse', + 'markup_tags' => 'Markup-tagger', + 'allowed_empty_tags' => 'Tillatte tomme tagger', + 'allowed_empty_tags_comment' => 'Liste av tagger som ikke fjernes til tross for at de ikke har innhold.', + 'allowed_tags' => 'Tillatte tagger', + 'allowed_tags_comment' => 'Liste over tillatte tagger.', + 'no_wrap' => 'Ikke pakk inn tagger', + 'no_wrap_comment' => 'Liste av tagger som ikke kan puttes inne i block-tagger.', + 'remove_tags' => 'Fjern tagger', + 'remove_tags_comment' => 'Liste over tagger som fjernes med innholdet.' + ], + 'tooltips' => [ + 'preview_website' => 'Forhåndsvis nettsiden' + ], + 'mysettings' => [ + 'menu_label' => 'Mine innstillinger', + 'menu_description' => 'Innstillinger relatert til din administratorkonto' + ], + 'myaccount' => [ + 'menu_label' => 'Min konto', + 'menu_description' => 'Oppdater dine kontodetaljer, som navn, e-postadresse og passord.', + 'menu_keywords' => 'sikkerhetsinnlogging' + ], + 'branding' => [ + 'menu_label' => 'Tilpass backend', + 'menu_description' => 'Tilpass administratorområdet, for eksempel navn, farger og logo.', + 'brand' => 'Merkevare', + 'logo' => 'Logo', + 'logo_description' => 'Last opp logo for å bruke backend.', + 'app_name' => 'App-navn', + 'app_name_description' => 'Dette navnet vises i tittelområdet backend.', + 'app_tagline' => 'App Tagline', + 'app_tagline_description' => 'Denne teksten vises på innloggingssiden backend.', + 'colors' => 'Farger', + 'primary_color' => 'Primærfarge', + 'secondary_color' => 'Sekundærfarge', + 'accent_color' => 'Accentfarge', + 'styles' => 'Stilsett', + 'custom_stylesheet' => 'Eget stilsett', + 'navigation' => 'Navigasjon', + 'menu_mode' => 'Menystyil', + 'menu_mode_inline' => 'Inline', + 'menu_mode_tile' => 'Fliser', + 'menu_mode_collapsed' => 'Kollapset' + ], + 'backend_preferences' => [ + 'menu_label' => 'Backend-innstillinger', + 'menu_description' => 'Administrer kontoinnstillinger som for eksempel språk.', + 'region' => 'Region', + 'code_editor' => 'Kodeeditor', + 'timezone' => 'Tidssone', + 'timezone_comment' => 'Formatér viste datoer til gjeldende tidssone.', + 'locale' => 'Språk', + 'locale_comment' => 'Velg ønsket språk.' + ], + 'access_log' => [ + 'hint' => 'Denne loggen viser en liste over vellykkede administratorinnlogginger. Innloggingene blir lagret i 60 dager.', + 'menu_label' => 'Aksesslogg', + 'menu_description' => 'Se en liste over vellykkede innlogginger på backend.', + 'created_at' => 'Tid', + 'login' => 'Brukernavn', + 'ip_address' => 'IP-adresse', + 'first_name' => 'Fornavn', + 'last_name' => 'Etternavn', + 'email' => 'E-postadresse' + ], + 'filter' => [ + 'all' => 'alle', + 'options_method_not_exists' => "Modellen :model må definere en metode :method() som sender tilbake regler for ':filter' filteret.", + 'date_all' => 'hele perioden' + ], + 'import_export' => [ + 'upload_csv_file' => '1. Last opp en CSV-fil', + 'import_file' => 'Importere fil', + 'first_row_contains_titles' => 'Første raden inneholder kolonnetitler', + 'first_row_contains_titles_desc' => 'La denne være valgt hvis den første raden i CSV-filen inneholder titler på kolonnene.', + 'match_columns' => '2. Koble kolonner til felter i databasen', + 'file_columns' => 'Filkolonner', + 'database_fields' => 'Databasefelter', + 'set_import_options' => '3. Valg for import', + 'export_output_format' => '1. Eksport-format', + 'file_format' => 'Filformat', + 'standard_format' => 'Standard format', + 'custom_format' => 'Tilpasset format', + 'delimiter_char' => 'Deletegn', + 'enclosure_char' => 'Innhegningstegn', + 'escape_char' => 'Escape-tegn', + 'select_columns' => '2. Velg kolonner å eksportere', + 'column' => 'Kolonne', + 'columns' => 'Kolonner', + 'set_export_options' => '3. Valg for eksport', + 'show_ignored_columns' => 'Vis ignorerte kolonner', + 'auto_match_columns' => 'Auto-match kolonner', + 'created' => 'Opprettet', + 'updated' => 'Oppdatert', + 'skipped' => 'Ignorert', + 'warnings' => 'Advarsler', + 'errors' => 'Feil', + 'skipped_rows' => 'Ignorerte rader', + 'import_progress' => 'Status for import', + 'processing' => 'Behandler', + 'import_error' => 'Feil under import', + 'upload_valid_csv' => 'Vennligst last opp en gyldig CSV-fil.', + 'drop_column_here' => 'Dropp kolonne her...', + 'ignore_this_column' => 'Ignorer denne kolonnen', + 'processing_successful_line1' => 'Eksport fullført!', + 'processing_successful_line2' => 'Nettleseren vil nå gå til nedlasting av fil.', + 'export_progress' => 'Status for eksport', + 'export_error' => 'Feil under eksport', + 'column_preview' => 'Forhåndsvid kolonne', + 'file_not_found_error' => 'Filen ikke funnet', + 'empty_error' => 'Ingen data å eksportere', + 'empty_import_columns_error' => 'Vennligst velg kolonner å importere.', + 'match_some_column_error' => 'Vennligst match kolonner først.', + 'required_match_column_error' => 'Vennligst finn match for påkrevet felt :label.', + 'empty_export_columns_error' => 'Vennligst velg kolonner å eksportere.', + 'behavior_missing_uselist_error' => 'Du må implemnetere controlleren med ListController-egenskapen "useList" aktivert for eksport.', + 'missing_model_class_error' => 'Vennligst spesifisér modelClass for :type', + 'missing_column_id_error' => 'Mangler kolonne', + 'unknown_column_error' => 'Ukjent kolonne', + 'encoding_not_supported_error' => 'Formatet i filen er ukjent. Vennligst velg tilpasset format med riktig enkodingvalg for å importere filen.', + 'encoding_format' => 'Filenkoding', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Last opp og behandle media - bilder, video, lydfiler, dokumenter', + ], + 'mediafinder' => [ + 'default_prompt' => 'Klikk på %s knappen for å hente media' + ], + 'media' => [ + 'menu_label' => 'Media', + 'upload' => 'Last opp', + 'move' => 'Flytt', + 'delete' => 'Slett', + 'add_folder' => 'Ny mappe', + 'search' => 'Søk', + 'display' => 'Vis', + 'filter_everything' => 'Alle filer', + 'filter_images' => 'Bilder', + 'filter_video' => 'Video', + 'filter_audio' => 'Lyd', + 'filter_documents' => 'Dokumenter', + 'library' => 'Bibliotek', + 'size' => 'Størrelse', + 'title' => 'Tittel', + 'last_modified' => 'Sist endret', + 'public_url' => 'URL', + 'click_here' => 'Klikk her', + 'thumbnail_error' => 'Kunne ikke lage thumbnail.', + 'return_to_parent' => 'Gå til forrige mappe', + 'return_to_parent_label' => 'Gå opp ..', + 'nothing_selected' => 'Ingenting er valgt.', + 'multiple_selected' => 'Flere filer er valgt.', + 'uploading_file_num' => 'Laster opp :number fil(er)...', + 'uploading_complete' => 'Opplasting fullført', + 'uploading_error' => 'Opplasting feilet', + 'type_blocked' => 'Filtypen er blokkert av sikkerhetsgrunner.', + 'order_by' => 'Sorter etter', + 'folder' => 'Mappe', + 'no_files_found' => 'Ingen filer ble funnet.', + 'delete_empty' => 'Ingen filer er valgt.', + 'delete_confirm' => 'Vil du virkelig slette valgte fil(er)?', + 'error_renaming_file' => 'Kunne ikke gi filen nytt navn.', + 'new_folder_title' => 'Ny mappe', + 'folder_name' => 'Mappenavn', + 'error_creating_folder' => 'Kunne ikke opprette ny mappe', + 'folder_or_file_exist' => 'En fil eller mappe med det navnet eksisterer allerede.', + 'move_empty' => 'Vennligst velg filer å flytte.', + 'move_popup_title' => 'Flytt filer eller mapper', + 'move_destination' => 'Målmappe', + 'please_select_move_dest' => 'Vennligst velg en målmappe.', + 'move_dest_src_match' => 'Please select another destination folder.', + 'empty_library' => 'Mediabiblioteket er tomt. Last opp filer eller opprett mapper for å komme i gang.', + 'insert' => 'Insert', + 'crop_and_insert' => 'Crop & Insert', + 'select_single_image' => 'Vennligst velg ett enkelt bilde.', + 'selection_not_image' => 'Valgte fil er ikke et bilde.', + 'restore' => 'Angre endringer', + 'resize' => 'Endre størrelse...', + 'selection_mode_normal' => 'Normal', + 'selection_mode_fixed_ratio' => 'Fast forhold', + 'selection_mode_fixed_size' => 'Fast størrelse', + 'height' => 'Høyde', + 'width' => 'Bredde', + 'selection_mode' => 'Valgmodus', + 'resize_image' => 'Endre bildestørrelse', + 'image_size' => 'Bildestørrelse:', + 'selected_size' => 'Valgt:' + ] +]; diff --git a/modules/backend/lang/nl/lang.php b/modules/backend/lang/nl/lang.php new file mode 100644 index 0000000..4c8375b --- /dev/null +++ b/modules/backend/lang/nl/lang.php @@ -0,0 +1,646 @@ + [ + 'title' => 'Beheeromgeving', + 'invalid_login' => 'De ingevoerde gegevens leveren geen resultaat. Controleer je invoer en probeer het opnieuw.', + ], + 'field' => [ + 'invalid_type' => 'Ongeldig type veld: :type.', + 'options_method_invalid_model' => "Het attribuut ':field' levert geen geldig model op. Probeer de opties methode expliciet te specifieren voor modelklasse :model.", + 'options_method_not_exists' => 'De modelklasse :model moet de methode :method() definiëren met daarin opties voor het veld ":field".', + 'options_static_method_invalid_value' => "De statische methode ':method()' in :class leverde geen geldige array met opties op.", + 'colors_method_not_exists' => 'De modelklasse :model moet de methode :method() definiëren met daarin html HEX kleurcodes voor het veld ":field".', + ], + 'widget' => [ + 'not_registered' => "Een widget met klassenaam ':name' is niet geregistreerd", + 'not_bound' => "Een widget met klassenaam ':name' is niet gekoppeld aan de controller", + ], + 'page' => [ + 'untitled' => 'Naamloos', + '404' => [ + 'label' => 'Sorry, we kunnen deze pagina niet meer vinden.', + 'help' => "We hebben ons best gedaan, maar het lijkt erop dat deze pagina niet (meer) bestaat of misschien verhuisd is.", + 'back_link' => 'Terug naar de homepagina.', + ], + 'access_denied' => [ + 'label' => 'Toegang geweigerd', + 'help' => 'Je hebt niet de benodigde rechten om deze pagina te bekijken.', + 'cms_link' => 'Terug naar CMS', + ], + 'no_database' => [ + 'label' => 'Database niet gevonden', + 'help' => 'Een database is nodig om toegang te krijgen tot de back-end. Controleer of de database juist is geconfigureerd en probeer het opnieuw.', + 'cms_link' => 'Terug naar homepagina', + ], + ], + 'partial' => [ + 'not_found_name' => "Het sjabloon (partial) ':name' is niet gevonden.", + 'invalid_name' => 'Ongeldige sjabloon (partial) naam: :name.', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Ongeldige AJAX verzoek met naam: :name.', + 'not_found' => "Het AJAX verzoek ':name' kon niet worden gevonden.", + ], + 'account' => [ + 'impersonate' => 'Inloggen als', + 'impersonate_confirm' => 'Je gaat inloggen als deze gebruiker. Weet je het zeker? Keer terug door uit te loggen.', + 'impersonate_success' => 'Je bent nu ingelogd als deze gebruiker', + 'impersonate_working' => 'Inloggen als...', + 'impersonating' => 'Inloggen als :full_name', + 'stop_impersonating' => 'Terugkeren', + 'unsuspend' => 'Blokkering opheffen', + 'unsuspend_confirm' => 'Weet je zeker dat je de blokkering voor deze gebruiker wilt opheffen?', + 'unsuspend_success' => 'De blokkade voor deze gebruiker is opgeheven.', + 'unsuspend_working' => 'Blokkering opheffen...', + 'signed_in_as' => 'Ingelogd als :full_name', + 'sign_out' => 'Uitloggen', + 'login' => 'Inloggen', + 'reset' => 'Wijzigen', + 'restore' => 'Herstellen', + 'login_placeholder' => 'Gebruikersnaam', + 'password_placeholder' => 'Wachtwoord', + 'remember_me' => 'Blijf ingelogd', + 'forgot_password' => 'Wachtwoord vergeten?', + 'enter_email' => 'Vul e-mailadres in', + 'enter_login' => 'Vul gebruikersnaam in', + 'email_placeholder' => 'E-mailadres', + 'enter_new_password' => 'Vul een nieuw wachtwoord in', + 'password_reset' => 'Herstel wachtwoord', + 'restore_success' => 'Een e-mail met instructies om het wachtwoord te herstellen is verzonden naar jouw e-mailadres.', + 'restore_error' => "Een gebruiker met de gebruikersnaam ':login' is niet gevonden", + 'reset_success' => 'Het wachtwoord is succesvol hersteld. Je kunt nu inloggen', + 'reset_error' => 'Ongeldige herstelinformatie aangeboden. Probeer het opnieuw!', + 'reset_fail' => 'Het is niet mogelijk het wachtwoord te herstellen!', + 'apply' => 'Toepassen', + 'cancel' => 'Annuleren', + 'delete' => 'Verwijderen', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => 'Overzicht', + 'widget_label' => 'Widget', + 'widget_width' => 'Breedte', + 'full_width' => 'Volledige breedte', + 'manage_widgets' => 'Beheer widgets', + 'add_widget' => 'Widget toevoegen', + 'widget_inspector_title' => 'Widget configuratie', + 'widget_inspector_description' => 'Configureer de rapportage widget', + 'widget_columns_label' => 'Breedte :columns', + 'widget_columns_description' => 'De widget breedte, een getal tussen 1 en 10.', + 'widget_columns_error' => 'Voer een getal tussen 1 en 10 in als widget breedte.', + 'columns' => '{1} kolom|[2,Inf] kolommen', + 'widget_new_row_label' => 'Forceer nieuwe rij', + 'widget_new_row_description' => 'Plaats de widget in een nieuwe rij.', + 'widget_title_label' => 'Widget titel', + 'widget_title_error' => 'Een widget titel is verplicht.', + 'reset_layout' => 'Layout resetten', + 'reset_layout_confirm' => 'Layout resetten naar standaard?', + 'reset_layout_success' => 'Layout is ge-reset', + 'make_default' => 'Als standaard instellen', + 'make_default_confirm' => 'Huidige layout als standaard instellen?', + 'make_default_success' => 'Huidige layout is nu als standaard ingesteld.', + 'collapse_all' => 'Alles inklappen', + 'expand_all' => 'Alles uitklappen', + 'status' => [ + 'widget_title_default' => 'Systeemstatus', + 'update_available' => '{0} updates beschikbaar!|{1} update beschikbaar!|[2,Inf] updates beschikbaar!', + 'updates_pending' => 'Er staan updates klaar', + 'updates_nil' => 'De software is up-to-date', + 'updates_link' => 'Updates installeren', + 'warnings_pending' => 'Sommige problemen hebben aandacht nodig', + 'warnings_nil' => 'Alles OK', + 'warnings_link' => 'Weergeven', + 'core_build' => 'Systeem build', + 'event_log' => 'Gebeurtenis logboek', + 'request_log' => 'Verzoek logboek', + 'app_birthday' => 'Online sinds', + ], + 'welcome' => [ + 'widget_title_default' => 'Welkom', + 'welcome_back_name' => 'Welkom terug bij :app, :name.', + 'welcome_to_name' => 'Welkom bij :app, :name.', + 'first_sign_in' => 'Dit is de eerste keer dat je bent ingelogd.', + 'last_sign_in' => 'Je laatste login was', + 'view_access_logs' => 'Toon toegangslogboek', + 'nice_message' => 'Een fijne dag!', + ], + ], + 'user' => [ + 'name' => 'Beheerder', + 'menu_label' => 'Beheerders', + 'menu_description' => 'Beheer beheerders, groepen en rechten.', + 'list_title' => 'Beheer beheerders', + 'new' => 'Nieuwe beheerder', + 'login' => 'Gebruikersnaam', + 'first_name' => 'Voornaam', + 'last_name' => 'Achternaam', + 'full_name' => 'Volledige naam', + 'email' => 'E-mailadres', + 'role_field' => 'Rol', + 'role_comment' => 'Rollen definiëren gebruikerspermissies die overschreven kunnen worden op gebruikersniveau (zie tabblad Rechten).', + 'groups' => 'Groepen', + 'groups_comment' => 'Selecteer de groepen waar deze gebruiker bij hoort.', + 'avatar' => 'Avatar', + 'password' => 'Wachtwoord', + 'password_confirmation' => 'Bevestig wachtwoord', + 'permissions' => 'Rechten', + 'account' => 'Account', + 'superuser' => 'Supergebruiker', + 'superuser_comment' => 'Vink deze optie aan om de gebruiker volledige rechten tot het systeem te geven.', + 'send_invite' => 'Stuur uitnodiging per e-mail', + 'send_invite_comment' => 'Vink deze optie aan om de gebruiker een uitnodiging per e-mail te sturen', + 'delete_confirm' => 'Weet je zeker dat je deze beheerder wilt verwijderen?', + 'return' => 'Terug naar het beheerdersoverzicht', + 'allow' => 'Toestaat', + 'inherit' => 'Overerven', + 'deny' => 'Weigeren', + 'activated' => 'Geactiveerd', + 'last_login' => 'Laatste login', + 'created_at' => 'Aangemaakt op', + 'updated_at' => 'Gewijzigd op', + 'deleted_at' => 'Verwijderd op', + 'show_deleted' => 'Toon verwijderd', + 'group' => [ + 'name' => 'Groep', + 'name_field' => 'Naam', + 'name_comment' => 'De naam die wordt weergegeven in de groepenlijst bij het aanmaken of bewerken van een beheerder.', + 'description_field' => 'Omschrijving', + 'is_new_user_default_field_label' => 'Standaard groep', + 'is_new_user_default_field_comment' => 'Voeg nieuwe beheerders automatisch toe aan deze groep.', + 'code_field' => 'Code', + 'code_comment' => 'Voer een unieke code in als je deze met de API wilt gebruiken.', + 'menu_label' => 'Groepen', + 'list_title' => 'Beheer groepen', + 'new' => 'Nieuwe beheerdersgroep', + 'delete_confirm' => 'Weet je zeker dat je deze beheerdersgroep wilt verwijderen?', + 'return' => 'Terug naar het groepenoverzicht', + 'users_count' => 'Gebruikers', + ], + 'role' => [ + 'name' => 'Rol', + 'name_field' => 'Naam', + 'name_comment' => 'De naam wordt weergegeven in de rollenlijst in het Beheerders formulier.', + 'description_field' => 'Omschrijving', + 'code_field' => 'Code', + 'code_comment' => 'Voer een unieke code in als je deze met de API wilt gebruiken.', + 'menu_label' => 'Beheer rollen', + 'list_title' => 'Beheer rollen', + 'new' => 'Nieuwe rol', + 'delete_confirm' => 'Verwijder deze beheerdersrol?', + 'return' => 'Terug naar het rollenoverzicht', + 'users_count' => 'Gebruikers', + ], + 'preferences' => [ + 'not_authenticated' => 'Er is geen geauthenticeerde gebruiker om gegevens voor te laden of op te slaan.', + ], + 'trashed_hint_title' => 'Dit account is verwijderd', + 'trashed_hint_desc' => 'Dit account is verwijderd en kan dus niet meer op ingelogd worden. Klik op het icoontje rechts onderin als je het account te herstellen.', + ], + 'list' => [ + 'default_title' => 'Lijst', + 'search_prompt' => 'Zoeken...', + 'no_records' => 'Er zijn geen resultaten gevonden.', + 'missing_model' => 'Geen model opgegeven voor het gedrag (behavior) van de lijst gebruikt in :class.', + 'missing_column' => 'Er zijn geen kolomdefinities voor :columns.', + 'missing_columns' => 'De gebruikte lijst in :class heeft geen kolommen gedefineerd.', + 'missing_definition' => "De behavior van de lijst bevat geen kolom voor ':field'.", + 'missing_parent_definition' => "De lijst behavior bevat geen definitie voor ':definition'.", + 'behavior_not_ready' => 'Behavior van de lijst is niet geladen. Controleer of makeLists() in de controller is aangeroepen.', + 'invalid_column_datetime' => "De waarde van kolom ':column' is geen DateTime object, mist er een \$dates referentie in het Model?", + 'pagination' => 'Getoonde resultaten: :from-:to van :total', + 'first_page' => 'Eerste pagina', + 'last_page' => 'Laatste pagina', + 'prev_page' => 'Vorige pagina', + 'next_page' => 'Volgende pagina', + 'refresh' => 'Vernieuwen', + 'updating' => 'Bijwerken...', + 'loading' => 'Laden...', + 'setup_title' => 'Lijst instellingen', + 'setup_help' => 'Selecteer door middel van vinkjes de kolommen welke je in de lijst wilt zien. Je kunt de volgorde van kolommen veranderen door ze omhoog of omlaag te slepen.', + 'records_per_page' => 'Resultaten per pagina', + 'records_per_page_help' => 'Selecteer het aantal resultaten dat per pagina getoond moet worden. Let op: een hoog getal kan voor prestatieproblemen zorgen.', + 'check' => 'Ingeschakeld', + 'delete_selected' => 'Verwijder geselecteerde', + 'delete_selected_empty' => 'Geen geselecteerde records om te verwijderen.', + 'delete_selected_confirm' => 'Verwijder geselecteerde records?', + 'delete_selected_success' => 'De geselecteerde records zijn succesvol verwijderd.', + 'column_switch_true' => 'Ja', + 'column_switch_false' => 'Nee', + ], + 'fileupload' => [ + 'attachment' => 'Bijlage', + 'help' => 'Voeg een titel en omschrijving toe aan deze bijlage.', + 'title_label' => 'Titel', + 'description_label' => 'Omschrijving', + 'default_prompt' => 'Klik op %s of sleep hier een bestand naar toe om te uploaden', + 'attachment_url' => 'Bijlage URL', + 'upload_file' => 'Upload bestand', + 'upload_error' => 'Upload fout', + 'remove_confirm' => 'Weet je het zeker?', + 'remove_file' => 'Verwijder bestand', + ], + 'repeater' => [ + 'add_new_item' => 'Nieuw item toevoegen', + 'min_items_failed' => ':name vereist minimaal :min items, er zijn :items opgegeven', + 'max_items_failed' => ':name vereist maximaal :max items, er zijn :items opgegeven', + ], + 'form' => [ + 'create_title' => 'Nieuwe :name', + 'update_title' => 'Bewerk :name', + 'preview_title' => 'Bekijk :name', + 'create_success' => ':name is succesvol aangemaakt', + 'update_success' => ':name is succesvol bijgewerkt', + 'delete_success' => ':name is succesvol verwijderd', + 'restore_success' => ':name is succesvol hersteld', + 'reset_success' => 'Resetten voltooid', + 'missing_id' => 'Record ID van het formulier is niet opgegeven.', + 'missing_model' => 'Geen model opgegeven voor het gedrag (behavior) van het formulier gebruikt in :class.', + 'missing_definition' => "Het gedrag (behavior) van het formulier bevat geen kolom voor ':field'.", + 'not_found' => 'Het formulier met record ID :id is niet gevonden.', + 'action_confirm' => 'Weet je het zeker?', + 'create' => 'Maken', + 'create_and_close' => 'Maken en sluiten', + 'creating' => 'Maken...', + 'creating_name' => ':name maken...', + 'save' => 'Opslaan', + 'save_and_close' => 'Opslaan en sluiten', + 'saving' => 'Opslaan...', + 'saving_name' => ':name opslaan...', + 'delete' => 'Verwijderen', + 'deleting' => 'Verwijderen...', + 'confirm_delete' => 'Weet je zeker dat je dit record wilt verwijderen?', + 'confirm_delete_multiple' => 'Weet je zeker dat je de geselecteerde records wilt verwijderen?', + 'deleting_name' => ':name verwijderen...', + 'restore' => 'Herstellen', + 'restoring' => 'Herstellen...', + 'confirm_restore' => 'Weet je zeker dat je dit record wil herstellen?', + 'reset_default' => 'Terug naar standaard instellingen', + 'resetting' => 'Bezig met terugzetten', + 'resetting_name' => ':name terugzetten', + 'undefined_tab' => 'Overig', + 'field_off' => 'Uit', + 'field_on' => 'Aan', + 'add' => 'Toevoegen', + 'apply' => 'Toepassen', + 'cancel' => 'Annuleren', + 'close' => 'Sluiten', + 'confirm' => 'Bevestigen', + 'reload' => 'Herladen', + 'complete' => 'Voltooid', + 'ok' => 'OK', + 'or' => 'of', + 'confirm_tab_close' => 'Weet je zeker dat je dit tabblad wilt sluiten? Niet opgeslagen wijzigingen gaan verloren.', + 'behavior_not_ready' => 'Gedrag (behavior) van het formulier is niet geladen. Controleer of initForm() in de controller is aangeroepen.', + 'preview_no_files_message' => 'Bestanden zijn niet geüpload.', + 'preview_no_media_message' => 'Er zijn geen media geselecteerd.', + 'preview_no_record_message' => 'Er zijn geen records geselecteerd.', + 'select' => 'Selecteer', + 'select_all' => 'selecteer alles', + 'select_none' => 'selecteer niets', + 'select_placeholder' => 'selecteer', + 'insert_row' => 'Rij invoegen', + 'insert_row_below' => 'Rij onder invoegen', + 'delete_row' => 'Rij verwijderen', + 'concurrency_file_changed_title' => 'Bestand is gewijzigd', + 'concurrency_file_changed_description' => 'Heb bestand wat je aan het bewerken bent is gewijzigd door een andere gebruiker. Je kunt het bestand opnieuw inladen (en wijzigingen verliezen) of het bestand te overschrijven.', + 'return_to_list' => 'Terug naar lijst', + ], + 'recordfinder' => [ + 'find_record' => 'Zoek record', + 'invalid_model_class' => 'Het opgegeven model klasse ":modelClass" voor de recordfinder is ongeldig', + 'cancel' => 'Annuleren', + ], + 'pagelist' => [ + 'page_link' => 'Pagina link', + 'select_page' => 'Selecteer een pagina...', + ], + 'relation' => [ + 'missing_config' => "Het gedrag (behavior) van deze relatie bevat geen instellingen voor ':config'.", + 'missing_definition' => "Het gedrag (behavior) van de relatie bevat geen kolom voor ':field'.", + 'missing_model' => 'Geen model opgegeven voor het gedrag (behavior) van relatie gebruikt in :class.', + 'invalid_action_single' => 'Deze actie kan niet worden uitgevoerd op een enkele (singular) relatie.', + 'invalid_action_multi' => 'Deze actie kan niet worden uitgevoerd op meerdere (multiple) relatie.', + 'help' => 'Klik op een item om toe te voegen', + 'related_data' => 'Gerelateerde :name data', + 'add' => 'Toevoegen', + 'add_selected' => 'Selectie toevoegen', + 'add_a_new' => 'Nieuwe :name toevoegen', + 'link_selected' => 'Koppel geselecteerde', + 'link_a_new' => 'Koppel een nieuwe :name', + 'cancel' => 'Annuleer', + 'close' => 'Sluiten', + 'add_name' => ':name toevoegen', + 'create' => 'Maken', + 'create_name' => 'Maak :name', + 'update' => 'Wijzigen', + 'update_name' => 'Wijzig :name', + 'preview' => 'Voorbeeldweergave', + 'preview_name' => 'Voorbeeldweergave :name', + 'remove' => 'Verwijder', + 'remove_name' => 'Verwijder :name', + 'delete' => 'Wissen', + 'delete_name' => 'Wis :name', + 'delete_confirm' => 'Weet je het zeker?', + 'link' => 'Koppel', + 'link_name' => 'Koppel :name', + 'unlink' => 'Ontkoppel', + 'unlink_name' => 'Ontkoppel :name', + 'unlink_confirm' => 'Weet je het zeker?', + ], + 'reorder' => [ + 'default_title' => 'Rangschik records', + 'no_records' => 'Er zijn geen records beschikbaar om te rangschikken.', + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => "Model ':class' met ID :id is niet gevonden", + 'missing_id' => 'Record ID van het model is niet opgegeven.', + 'missing_relation' => "Model ':class' bevat geen definitie voor ':relation'.", + 'missing_method' => "Model ':class' bevat geen ':method' methode.", + 'invalid_class' => 'Model :model gebruikt in :class is ongeldig. Het moet van de \Model klasse erven (inherit).', + 'mass_assignment_failed' => "Massa toewijzing voor Model attribute ':attribute' mislukt.", + ], + 'warnings' => [ + 'tips' => 'Systeem configuratie tips', + 'tips_description' => 'Er zijn problemen gevonden waar je aandacht aan moet besteden om uw systeem goed te configureren.', + 'permissions' => 'De map :name of de submappen zijn niet schrijfbaar voor PHP. Zet de bijhorende rechten voor de webserver in deze map.', + 'extension' => 'De PHP extensie :name is niet geïnstalleerd. Installeer deze bibliotheek en activeer de extensie.', + 'plugin_missing' => 'De plugin :name is een afhankelijkheid maar is niet geïnstalleerd. Installeer deze plugin a.u.b.', + 'debug' => 'Debug modus is ingeschakeld. Dit wordt niet aanbevolen op een productie-omgeving.', + 'decompileBackendAssets' => 'Assets van de back-end worden momenteel gedecompileerd. Dit wordt niet aanbevolen op een productie-omgeving.', + ], + 'editor' => [ + 'menu_label' => 'Editor instellingen', + 'menu_description' => 'Beheer editor instellingen, zoals lettergrootte en kleurschema.', + 'preview' => 'Voorbeeldweergave', + 'font_size' => 'Lettergrootte', + 'tab_size' => 'Tab grootte', + 'use_hard_tabs' => 'Inspringen met tabs', + 'code_folding' => 'Code invouwing', + 'code_folding_begin' => 'Markeer begin', + 'code_folding_begin_end' => 'Markeer begin en einde', + 'autocompletion' => 'Automatisch aanvullen', + 'word_wrap' => 'Tekstterugloop', + 'highlight_active_line' => 'Markeer actieve lijnen', + 'auto_closing' => 'Sluit tags en speciale karakters automatisch', + 'show_invisibles' => 'Toon verborgen karakters', + 'show_gutter' => 'Toon "goot"', + 'basic_autocompletion' => 'Basis automatische aanvulling (Ctrl + Spatie)', + 'live_autocompletion' => 'Live automatische aanvulling', + 'enable_snippets' => 'Inschakelen van code snippets (Tab)', + 'display_indent_guides' => 'Toon inspringing hulp', + 'show_print_margin' => 'Toon printmarges', + 'mode_off' => 'Uit', + 'mode_fluid' => 'Vloeiend', + '40_characters' => '40 karakters', + '80_characters' => '80 karakters', + 'theme' => 'Kleurschema', + 'markup_styles' => 'Opmaakstijlen', + 'custom_styles' => 'Eigen stylesheet', + 'custom styles_comment' => 'Eigen stijlen die in de HTML-editor gebruikt moeten worden.', + 'markup_classes' => 'Opmaak classes', + 'paragraph' => 'Paragraaf', + 'link' => 'Link', + 'table' => 'Tabel', + 'table_cell' => 'Tabel cel', + 'image' => 'Afbeelding', + 'label' => 'Label', + 'class_name' => 'Class naam', + 'markup_tags' => 'Opmaak HTML-tags', + 'markup_tag' => 'Opmaak HTML-tag', + 'allowed_empty_tags' => 'Toegestane lege HTML-tags', + 'allowed_empty_tags_comment' => 'Een lijst van HTML-tags die niet worden verwijderd als ze leeg zijn.', + 'allowed_tags' => 'Toegestane HTML-tags', + 'allowed_tags_comment' => 'Een lijst van toegestane HTML-tags.', + 'no_wrap' => 'HTML-tags niet afbreken', + 'no_wrap_comment' => 'Een lijst van tags die niet worden afgebroken.', + 'remove_tags' => 'Te verwijderen HTML-tags', + 'remove_tags_comment' => 'Een lijst van HTML-tags die samen met hun inhoud worden verwijderd.', + 'line_breaker_tags' => 'Line breaker tags', + 'line_breaker_tags_comment' => 'Een lijst van HTML-tags waartussen een line breaker element wordt geplaatst.', + 'toolbar_options' => 'Toolbar opties', + 'toolbar_buttons' => 'Toolbar knoppen', + 'toolbar_buttons_comment' => 'De toolbar knoppen die standaard getoond worden door de Rich Editor.', + 'toolbar_buttons_preset' => 'Voeg preset toe voor toolbar knoppen:', + 'toolbar_buttons_presets' => [ + 'default' => 'Standaard', + 'minimal' => 'Minimaal', + 'full' => 'Volledig', + ], + 'paragraph_formats' => 'Paragraaf formaten', + 'paragraph_formats_comment' => 'De opties die in de "Paragraaf formaat" lijst zullen verschijnen.', + ], + 'tooltips' => [ + 'preview_website' => 'Voorbeeldweergave website', + ], + 'mysettings' => [ + 'menu_label' => 'Mijn instellingen', + 'menu_description' => 'Instellingen gerelateerd aan jouw beheeraccount', + ], + 'myaccount' => [ + 'menu_label' => 'Mijn account', + 'menu_description' => 'Werk accountinstellingen zoals naam, e-mailadres en wachtwoord bij.', + 'menu_keywords' => 'security login', + ], + 'branding' => [ + 'menu_label' => 'Aanpassen back-end', + 'menu_description' => 'Pas de beheeromgeving aan zoals de naam, kleuren en logo.', + 'brand' => 'Uitstraling', + 'logo' => 'Logo', + 'logo_description' => 'Upload een logo om te gebruiken in de beheeromgeving.', + 'favicon' => 'Favicon', + 'favicon_description' => 'Upload een favicon om te gebruiken in de beheeromgeving', + 'app_name' => 'Applicatie naam', + 'app_name_description' => 'Deze naam wordt weergegeven bij de titel van de beheeromgeving.', + 'app_tagline' => 'Applicatie slogan', + 'app_tagline_description' => 'Deze slogan wordt weergegeven in het aanmeldvenster van de beheeromgeving.', + 'colors' => 'Kleuren', + 'primary_color' => 'Primaire kleur', + 'secondary_color' => 'Secundaire kleur', + 'accent_color' => 'Accentkleur', + 'styles' => 'Stijlen', + 'custom_stylesheet' => 'Aangepaste stylesheet', + 'navigation' => 'Navigatie', + 'menu_mode' => 'Menustijl', + 'menu_mode_inline' => 'Inline-mode', + 'menu_mode_inline_no_icons' => 'Inline-mode (zonder iconen)', + 'menu_mode_tile' => 'Tegels', + 'menu_mode_collapsed' => 'Ingeklapt', + ], + 'backend_preferences' => [ + 'menu_label' => 'CMS voorkeuren', + 'menu_description' => 'Beheer taalvoorkeur en de weergave van het CMS.', + 'region' => 'Regio', + 'code_editor' => 'Code editor', + 'timezone' => 'Tijdzone', + 'timezone_comment' => 'Weer te geven datums overal aanpassen naar deze tijdzone.', + 'locale' => 'Taal', + 'locale_comment' => 'Selecteer jouw gewenste taal.', + ], + 'access_log' => [ + 'hint' => 'Dit logboek toont een lijst met succesvolle inlogpogingen door beheerders. Registraties blijven :days dagen bewaard.', + 'menu_label' => 'Toegangslogboek', + 'menu_description' => 'Bekijk een lijst met succesvolle inlogpogingen van gebruikers.', + 'id' => 'ID', + 'created_at' => 'Datum & tijd', + 'type' => 'Type', + 'login' => 'Gebruikersnaam', + 'ip_address' => 'IP-adres', + 'first_name' => 'Voornaam', + 'last_name' => 'Achternaam', + 'email' => 'E-mailadres', + ], + 'filter' => [ + 'all' => 'alle', + 'options_method_not_exists' => "De model class :model moet de methode :method() gedefinieerd hebben die de opties voor de filter ':filter' teruggeeft.", + 'date_all' => 'alle periodes', + 'number_all' => 'alle nummers', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Upload een CSV bestand', + 'import_file' => 'Importeer bestand', + 'row' => 'Rij :row', + 'first_row_contains_titles' => 'De eerste regel bevat kolomtitels', + 'first_row_contains_titles_desc' => 'Vink aan als de eerste regel kolomtitels bevat die gebruikt moeten worden.', + 'match_columns' => '2. Vergelijk de kolommen met de database velden', + 'file_columns' => 'Bestand kolommen', + 'database_fields' => 'Database velden', + 'set_import_options' => '3. Importeer opties', + 'export_output_format' => '1. Export uitvoerformaat', + 'file_format' => 'Bestandsformaat', + 'standard_format' => 'Standaard formaat', + 'custom_format' => 'Aangepast formaat', + 'delimiter_char' => 'Scheidingsteken', + 'enclosure_char' => 'Tekstscheidingsteken', + 'escape_char' => 'Escape karakter', + 'select_columns' => '2. Selecteer kolommen om te exporteren', + 'column' => 'Kolom', + 'columns' => 'Kolommen', + 'set_export_options' => '3. Exporteer opties', + 'show_ignored_columns' => 'Toon genegeerde kolommen', + 'auto_match_columns' => 'Automatisch matchen van kolommen', + 'created' => 'Aangemaakt', + 'updated' => 'Bijgewerkt', + 'skipped' => 'Overgeslagen', + 'warnings' => 'Waarschuwingen', + 'errors' => 'Fouten', + 'skipped_rows' => 'Overgeslagen rijen', + 'import_progress' => 'Voortgang importeren', + 'processing' => 'Bezig met verwerken', + 'import_error' => 'Importeer fout', + 'upload_valid_csv' => 'Upload een geldig CSV bestand.', + 'drop_column_here' => 'Sleep kolom hierheen...', + 'ignore_this_column' => 'Negeer deze kolom', + 'processing_successful_line1' => 'Bestandsexport is succesvol voltooid!', + 'processing_successful_line2' => 'De browser zal je direct doorsturen naar de download.', + 'export_progress' => 'Voortgang exporteren', + 'export_error' => 'Fout bij exporteren', + 'column_preview' => 'Kolom voorbeeldweergave', + 'file_not_found_error' => 'Bestand niet gevonden', + 'empty_error' => 'Er was geen data beschikbaar om te exporteren', + 'empty_import_columns_error' => 'Selecteer een aantal kolommen om te importeren.', + 'match_some_column_error' => 'Match eerst een aantal kolommen.', + 'required_match_column_error' => 'Specifieer een match voor het verplicht veld :label.', + 'empty_export_columns_error' => 'Selecteer een aantal kolommen om te exporteren.', + 'behavior_missing_uselist_error' => 'Je moet de controller behavior ListController implementeren met de export "useList" optie ingeschakeld.', + 'missing_model_class_error' => 'Specifieer de `modelClass` eigenschap voor type :type', + 'missing_column_id_error' => 'Kolom ID mist', + 'unknown_column_error' => 'Onbekende kolom', + 'encoding_not_supported_error' => 'De codering van bronbestand wordt niet herkend. Selecteer de juiste bestandscodering om het bestand te importeren.', + 'encoding_format' => 'Bestandscodering', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1250' => 'Windows-1250 (CP1250, Central and Eastern European)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)', + ], + ], + 'permissions' => [ + 'manage_media' => 'Beheer media (afbeeldingen, videos, geluiden, documenten)', + 'allow_unsafe_markdown' => 'Gebruik onveilige Markdown (Kan Javascript bevatten)', + ], + 'mediafinder' => [ + 'label' => 'Media zoeker', + 'default_prompt' => 'Klik op de %s knop om een media item te vinden', + 'no_image' => 'De afbeelding kan niet gevonden worden', + ], + 'media' => [ + 'menu_label' => 'Media', + 'upload' => 'Uploaden', + 'move' => 'Verplaatsen', + 'delete' => 'Verwijderen', + 'add_folder' => 'Map toevoegen', + 'search' => 'Zoeken', + 'display' => 'Weergeven', + 'filter_everything' => 'Alles', + 'filter_images' => 'Afbeeldingen', + 'filter_video' => 'Video\'s', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Documenten', + 'library' => 'Bibliotheek', + 'size' => 'Grootte', + 'title' => 'Titel', + 'last_modified' => 'Laatst gewijzigd', + 'public_url' => 'URL', + 'click_here' => 'Klik hier', + 'thumbnail_error' => 'Fout opgetreden bij genereren miniatuurweergave.', + 'return_to_parent' => 'Terug naar bovenliggende map', + 'return_to_parent_label' => 'Naar bovenliggende ...', + 'nothing_selected' => 'Er is niets geselecteerd.', + 'multiple_selected' => 'Meerdere items geselecteerd.', + 'uploading_file_num' => 'Uploaden van :number bestanden...', + 'uploading_complete' => 'Uploaden voltooid', + 'uploading_error' => 'Upload mislukt', + 'type_blocked' => 'Het bestandstype is i.v.m. veiligheidsredenen geblokkeerd.', + 'order_by' => 'Sorteer op', + 'direction' => 'Sorteervolgorde', + 'direction_asc' => 'Oplopend', + 'direction_desc' => 'Aflopend', + 'folder' => 'Map', + 'no_files_found' => 'Er zijn geen bestanden gevonden.', + 'delete_empty' => 'Selecteer items om te verwijderen.', + 'delete_confirm' => 'Weet je zeker dat je de geselecteerde items wilt verwijderen?', + 'error_renaming_file' => 'Fout bij wijzigen naam.', + 'new_folder_title' => 'Nieuwe map', + 'folder_name' => 'Mapnaam', + 'error_creating_folder' => 'Fout bij maken van map', + 'folder_or_file_exist' => 'Er bestaat reeds een map of bestand met deze naam.', + 'move_empty' => 'Selecteer de items om te verplaatsen.', + 'move_popup_title' => 'Verplaats bestanden of mappen', + 'move_destination' => 'Doelmap', + 'please_select_move_dest' => 'Selecteer een doelmap.', + 'move_dest_src_match' => 'Selecteer een andere doelmap.', + 'empty_library' => 'De media bibliotheek is leeg. Upload bestanden of maak mappen aan om te beginnen.', + 'insert' => 'Invoegen', + 'crop_and_insert' => 'Uitsnijden & Invoegen', + 'select_single_image' => 'Selecteer één afbeelding.', + 'selection_not_image' => 'Het geselecteerde item is geen afbeelding.', + 'restore' => 'Alle wijzigingen ongedaan maken', + 'resize' => 'Wijzig grootte...', + 'selection_mode_normal' => 'Normaal', + 'selection_mode_fixed_ratio' => 'Vaste ratio', + 'selection_mode_fixed_size' => 'Vaste grootte', + 'height' => 'Hoogte', + 'width' => 'Breedte', + 'selection_mode' => 'Selectie modus', + 'resize_image' => 'Wijzig grootte van afbeelding', + 'image_size' => 'Grootte afbeelding:', + 'selected_size' => 'Geselecteerd:', + ], +]; diff --git a/modules/backend/lang/pl/lang.php b/modules/backend/lang/pl/lang.php new file mode 100644 index 0000000..12a4190 --- /dev/null +++ b/modules/backend/lang/pl/lang.php @@ -0,0 +1,627 @@ + [ + 'title' => 'Panel Administracyjny', + 'invalid_login' => 'Podane dane logowania są niepoprawne. Sprawdź je i spróbuj ponownie.', + ], + 'field' => [ + 'invalid_type' => 'Użyto nieprawidłowego typu pola :type.', + 'options_method_invalid_model' => 'Atrybut \':field\' nie jest poprawnym modelem. Spróbuj zdefiniować metodę zwracającą opcje dla modelu :model.', + 'options_method_not_exists' => 'Model :model musi definiować metodę :method() zwracając opcję z pola \':field\' formularza.', + 'colors_method_not_exists' => 'Model :model musi definiować metodę :method() zwracającą kolor zakodowany dla pola formularza \':field\'.', + ], + 'widget' => [ + 'not_registered' => 'Nazwa klasy widgetu \':name\' nie została zarejestrowana', + 'not_bound' => 'Nazwa klasy widgetu \':name\' nie została przepisana do kontrolera', + ], + 'page' => [ + 'untitled' => 'Bez nazwy', + 404 => [ + 'label' => 'Nie znaleziono strony', + 'help' => 'Szukaliśmy i szukaliśmy, ale dla podanego adresu URL nic nie daliśmy rady znaleźć. Może szukałeś czegoś innego?', + 'back_link' => 'Wróć na poprzednią stronę', + ], + 'access_denied' => [ + 'label' => 'Odmowa dostępu', + 'help' => 'Nie posiadasz odpowiednich uprawnień, aby zobaczyć tą stronę.', + 'cms_link' => 'Powrót do panelu back-end', + ], + 'no_database' => [ + 'label' => 'Brak bazy danych', + 'help' => 'Baza danych jest wymagana do dostępu do panelu administracyjnego. Sprawdz czy baza danych jest prawidłowo skonfigurowana i zmigrowana przed ponowną próbą.', + 'cms_link' => 'Powrót do strony głównej', + ], + ], + 'partial' => [ + 'not_found_name' => 'Blok \':name\' nie został odnaleziony.', + 'invalid_name' => 'Niepoprawny fragment o nazwie: :name.', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Niepoprawna nazwa AJAX handlera: :name.', + 'not_found' => 'AJAX handler o nazwie \':name\' nie został znaleziony.', + ], + 'account' => [ + 'impersonate' => 'Wciel się w użytkownika', + 'impersonate_confirm' => 'Czy na pewno chcesz wcielić się w tego użytkownika? Możesz wrócić do poprzedniego stanu przez wylogowanie się.', + 'impersonate_success' => 'Wcieliłeś się w użytkownika', + 'impersonate_working' => 'Wcielanie się', + 'impersonating' => 'Wcielanie się w :full_name', + 'stop_impersonating' => 'Zakończ wcielanie się w użytkownika', + 'signed_in_as' => 'Zalogowany jako :full_name', + 'sign_out' => 'Wyloguj', + 'login' => 'Zaloguj', + 'reset' => 'Reset', + 'restore' => 'Odzyskaj', + 'login_placeholder' => 'login', + 'password_placeholder' => 'hasło', + 'remember_me' => 'Zapamiętaj mnie', + 'forgot_password' => 'Zapomniałeś hasła?', + 'enter_email' => 'Wpisz swój email', + 'enter_login' => 'Wpisz swój login', + 'email_placeholder' => 'email', + 'enter_new_password' => 'Wpisz swoje hasło', + 'password_reset' => 'Zmień hasło', + 'restore_success' => 'Wysłano wiadomość na Twój adres email z hasłem oraz instrukcjami odzyskania.', + 'restore_error' => 'Nie znaleziono użytkownika z loginem \':login\'', + 'reset_success' => 'Twoje hasło zostało prawidłowo zresetowane. Możesz się teraz zalogować.', + 'reset_error' => 'Nieprawidłowe dane zmiany hasła. Spróbuj ponownie!', + 'reset_fail' => 'Nie można zmienić Twojego hasła!', + 'apply' => 'Zastosuj', + 'cancel' => 'Anuluj', + 'delete' => 'Usuń', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => 'Kokpit', + 'widget_label' => 'Widget', + 'widget_width' => 'Szerokość', + 'full_width' => 'pełna szerokość', + 'manage_widgets' => 'Zarządzaj widgetami', + 'add_widget' => 'Dodaj widget', + 'widget_inspector_title' => 'Konfiguracja widgetu', + 'widget_inspector_description' => 'Konfiguruj widget', + 'widget_columns_label' => 'Szerokość: :columns', + 'widget_columns_description' => 'Szerokość widgetu, cyfra pomiędzy 1 a 10.', + 'widget_columns_error' => 'Proszę podać szerokość widgetu jako cyfrę pomiędzy 1 a 10.', + 'columns' => '{1} kolumna|[2,Inf] kolumny', + 'widget_new_row_label' => 'Wymuś nowy wiersz', + 'widget_new_row_description' => 'Umieść widget w nowym wierszu.', + 'widget_title_label' => 'Nazwa widgetu', + 'widget_title_error' => 'Nazwa widgetu jest wymagana.', + 'reset_layout' => 'Resetuj układ', + 'reset_layout_confirm' => 'Ustawić domyślny układ?', + 'reset_layout_success' => 'Został przywrócony domyślny układ', + 'make_default' => 'Ustaw jako domyślny', + 'make_default_confirm' => 'Ustawić obecny układ jako domyślny?', + 'make_default_success' => 'Obecny układ jest teraz domyślny', + 'collapse_all' => 'Zwiń wszystkie', + 'expand_all' => 'Rozwiń wszystkie', + 'status' => [ + 'widget_title_default' => 'Status systemu', + 'update_available' => '{0} dostępnych aktualizacji!|{1} dostępna aktualizacja!|[2,Inf] dostępne aktualizacje!', + 'updates_pending' => 'Oczekujące aktualizacje', + 'updates_nil' => 'Wersja systemu jest aktualna', + 'updates_link' => 'Aktualizuj', + 'warnings_pending' => 'Niektóre kwestie wymagają uwagi', + 'warnings_nil' => 'Brak ostrzeżeń do wyświetlenia', + 'warnings_link' => 'Wyświetl', + 'core_build' => 'Wersja systemu', + 'event_log' => 'Dziennik zdarzeń', + 'request_log' => 'Log żądań', + 'app_birthday' => 'Online od', + ], + 'welcome' => [ + 'widget_title_default' => 'Witaj', + 'welcome_back_name' => 'Witaj z powrotem w :app, :name.', + 'welcome_to_name' => 'Witaj w :app, :name.', + 'first_sign_in' => 'To jest twoje pierwsze logowanie.', + 'last_sign_in' => 'Data ostatniego logowania', + 'view_access_logs' => 'Zobacz dziennik zdarzeń', + 'nice_message' => 'Miłego dnia!', + ], + ], + 'user' => [ + 'name' => 'Administrator', + 'menu_label' => 'Administratorzy', + 'menu_description' => 'Zarządzaj administratorami, użytkownikami, grupami i uprawnieniami.', + 'list_title' => 'Zarządzaj Administratorami', + 'new' => 'Nowy Administrator', + 'login' => 'Login', + 'first_name' => 'Imię', + 'last_name' => 'Nazwisko', + 'full_name' => 'Imię i nazwisko', + 'email' => 'E-mail', + 'role_field' => 'Rola', + 'role_comment' => 'Role definiują uprawnienia użytkowników, które mogą być nadpisane na poziomie użytkownika w zakładce Uprawnienia.', + 'groups' => 'Grupa', + 'groups_comment' => 'Określ, do której grupy należy ten użytkownik', + 'avatar' => 'Awatar', + 'password' => 'Hasło', + 'password_confirmation' => 'Potwierdź hasło', + 'permissions' => 'Uprawnienia', + 'account' => 'Konto', + 'superuser' => 'Super Użytkownik', + 'superuser_comment' => 'Zaznacz to pole jeżeli chcesz zezwolić temu użytkownikowi na pełny dostęp do panelu.', + 'send_invite' => 'Wyślij zaproszenie wiadomością email', + 'send_invite_comment' => 'Zaznacz to pole, aby wysłać zaproszenie wiadomością email do tego użytkownika', + 'delete_confirm' => 'Czy jesteś pewny, że chcesz usunąć tego administratora', + 'return' => 'Wróc do listy administratorów', + 'allow' => 'Zezwól', + 'inherit' => 'Dziedzicz', + 'deny' => 'Odmów', + 'activated' => 'Aktywowany', + 'last_login' => 'Ostatnie zalogowanie', + 'created_at' => 'Stworzony', + 'updated_at' => 'Zaktualizowany', + 'deleted_at' => 'Usunięty', + 'show_deleted' => 'Pokaż usunięte', + 'group' => [ + 'name' => 'Grupa', + 'name_field' => 'Nazwa', + 'name_comment' => 'Nazwa wyświetlana na liście grup oraz w formularzu dodawania/edycji administratora.', + 'description_field' => 'Opis', + 'is_new_user_default_field_label' => 'Domyslna grupa', + 'is_new_user_default_field_comment' => 'Dodaj nowych administratorów domyślnie do tej grupy', + 'code_field' => 'Kod', + 'code_comment' => 'Wpisz unikalny kod, jeżeli chcesz mieć do niego dostęp poprzez API.', + 'menu_label' => 'Grupy', + 'list_title' => 'Zarządzaj grupami', + 'new' => 'Nowa grupa Administratorów', + 'delete_confirm' => 'Jesteś pewny, że chcesz usunąć tą grupę administratorów?', + 'return' => 'Wróć do listy grup', + 'users_count' => 'Użytkowników', + 'is_new_user_default_field' => 'Dodawaj nowych administratorów do tej grupy jako domyślnej.', + ], + 'role' => [ + 'name' => 'Rola', + 'name_field' => 'Nazwa', + 'name_comment' => 'Nazwa wyświetlana na liście ról w formularzu administratora.', + 'description_field' => 'Opis', + 'code_field' => 'Kod', + 'code_comment' => 'Wprowadź unikalny kod, umożliwiający dostęp do obiektu roli przez API.', + 'menu_label' => 'Zarządzaj Rolami', + 'list_title' => 'Zarządzaj Rolami', + 'new' => 'Nowa Rola', + 'delete_confirm' => 'Czy na pewno?', + 'return' => 'Powrót do listy ról', + 'users_count' => 'Użytkownicy', + ], + 'preferences' => [ + 'not_authenticated' => 'Nie znaleziono uwierzytelnionego użytkownika, aby załadować lub zapisać ustawienia.', + ], + 'trashed_hint_title' => 'To konto zostało usunięte', + 'trashed_hint_desc' => 'To konto zostało usunięte i nie da się na nie zalogować. Żeby przywrócić normalne zachowanie użyj przycisku w prawym dolnym rogu.', + ], + 'list' => [ + 'default_title' => 'Lista', + 'search_prompt' => 'Szukaj...', + 'no_records' => 'Brak rekordów w tym widoku.', + 'missing_model' => 'Zachowanie listy użyte w :class nie ma zdefiniowanego modelu.', + 'missing_column' => 'Brak definicji kolumn dla :columns.', + 'missing_columns' => 'Lista użyta w :class nie posiada zdefiniowanej listy kolumn.', + 'missing_definition' => 'Zachowanie listy nie posiada kolumn dla \':field\'.', + 'missing_parent_definition' => 'Zachowanie listy nie zawiera definicji dla \':definition\'.', + 'behavior_not_ready' => 'Zachowanie listy nie zostało zainicjowane, sprawdź czy wywołałeś makeLists() w swoim kontrolerze.', + 'invalid_column_datetime' => 'Wartość kolumny \':column\' nie jest objektem typu DateTime, czy nie brakuje Ci referencji $dates w Modelu?', + 'pagination' => 'Wyświetlono rekordy: :from-:to z :total', + 'first_page' => 'First page', + 'last_page' => 'Last page', + 'prev_page' => 'Poprzednia strona', + 'next_page' => 'Następna strona', + 'refresh' => 'Odśwież', + 'updating' => 'Aktualizowanie...', + 'loading' => 'Wczytywanie...', + 'setup_title' => 'Ustawienia listy', + 'setup_help' => 'Użyj pól wyboru, aby wybrać kolumny, które chcesz zobaczyć w liście. Możesz zmienić pozycję kolumny przeciągająć ją w dół lub w górę.', + 'records_per_page' => 'Rekordy na stronę', + 'records_per_page_help' => 'Wybierz liczbnę rekordów do wyświetlenia na stronę. Wyższa liczba rekordów na jedną stronę może zmniejszyć wydajność.', + 'check' => 'Sprawdź', + 'delete_selected' => 'Usuń zaznaczone', + 'delete_selected_empty' => 'Nie wybrano elementów do usunięcia.', + 'delete_selected_confirm' => 'Usunąć zaznaczone elementy?', + 'delete_selected_success' => 'Pomyślnie usunięto zaznaczone elementy.', + 'column_switch_true' => 'Tak', + 'column_switch_false' => 'Nie', + ], + 'fileupload' => [ + 'attachment' => 'Załącznik', + 'help' => 'Dodaj tytuł oraz opis załącznika.', + 'title_label' => 'Tytuł', + 'description_label' => 'Opis', + 'default_prompt' => 'Kliknij %s lub upuść plik aby przesłać', + 'attachment_url' => 'URL załącznika', + 'upload_file' => 'Prześlij plik', + 'upload_error' => 'Błąd przesyłania', + 'remove_confirm' => 'Jesteś pewien?', + 'remove_file' => 'Usuń plik', + ], + 'repeater' => [ + 'add_new_item' => 'Dodaj nowy element', + 'min_items_failed' => ':name wymaga conajmniej :min elementów, a wprowadzono :items', + 'max_items_failed' => ':name wymaga maksymalnie :max elementów, a wprowadzono :items', + ], + 'form' => [ + 'create_title' => 'Nowy :name', + 'update_title' => 'Edytuj :name', + 'preview_title' => 'Podgląd :name', + 'create_success' => ':name został stworzony pomyślnie', + 'update_success' => ':name został zaktualizowany pomyślnie', + 'delete_success' => ':name został usunięty pomyślnie', + 'restore_success' => ':name został przywrócony pomyślnie', + 'reset_success' => 'Resetowanie zostało zakończone', + 'missing_id' => 'ID rekordu formularza nie zostało znalezione.', + 'missing_model' => 'Zachowanie formularza w klasie :class nie ma zadefiniowanego Modelu.', + 'missing_definition' => 'Zachowanie formularza nie posiada pola dla \':field\'.', + 'not_found' => 'Rekord formularza o ID :id nie został znaleziony.', + 'action_confirm' => 'Czy jesteś pewny?', + 'create' => 'Stwórz', + 'create_and_close' => 'Stwórz i zamknij', + 'creating' => 'Tworzenie...', + 'creating_name' => 'Tworzenie :name...', + 'save' => 'Zapisz', + 'save_and_close' => 'Zapisz i zamknij', + 'saving' => 'Zapisywanie...', + 'saving_name' => 'Zapisywanie :name...', + 'delete' => 'Usuń', + 'deleting' => 'Usuwanie...', + 'confirm_delete' => 'Usunąć rekord?', + 'confirm_delete_multiple' => 'Usunąć zaznaczone rekordy?', + 'deleting_name' => 'Usuwanie :name...', + 'restore' => 'Przywróć', + 'restoring' => 'Przywracanie...', + 'confirm_restore' => 'Czy na pewno chcesz przywrócić ten rekord?', + 'reset_default' => 'Resetuj do domyślnych', + 'resetting' => 'Resetowanie', + 'resetting_name' => 'Resetowanie :name', + 'undefined_tab' => 'Różne', + 'field_off' => 'Wył.', + 'field_on' => 'Wł.', + 'add' => 'Dodaj', + 'apply' => 'Zastosuj', + 'cancel' => 'Anuluj', + 'close' => 'Zamknij', + 'confirm' => 'Potwierdź', + 'reload' => 'Przeładuj', + 'complete' => 'Zakończ', + 'ok' => 'OK', + 'or' => 'lub', + 'confirm_tab_close' => 'Czy naprawdę chcesz zamknąć tą kartę? Wszystkie niezapisane zmiany zostaną utracone.', + 'behavior_not_ready' => 'Zachowanie formularza nie zostało zainicjowane, sprawdź czy wywołałeś initForm() w swoim kontrolerze.', + 'preview_no_files_message' => 'Brak wgranych plików.', + 'preview_no_media_message' => 'Nie wybrano żadnych mediów.', + 'preview_no_record_message' => 'Brak zaznaczonych elementów.', + 'select' => 'Zaznacz', + 'select_all' => 'Zaznacz wszystko', + 'select_none' => 'Wybierz brak', + 'select_placeholder' => 'proszę zaznacz', + 'insert_row' => 'Wstaw wiersz', + 'insert_row_below' => 'Wstaw wiersz poniżej', + 'delete_row' => 'Usuń wiersz', + 'concurrency_file_changed_title' => 'Plik został zmieniony.', + 'concurrency_file_changed_description' => 'Plik, który edytujesz został zmieniony na dysku przez innego użytkownika. Możesz przeładować plik i stracić swoje zmiany lub nadpisać plik na dysku.', + 'return_to_list' => 'Powrót do listy', + ], + 'recordfinder' => [ + 'find_record' => 'Znajdź Rekord', + 'invalid_model_class' => 'Klasa ":modelClass" dla recordfinder jest niepoprawna', + 'cancel' => 'Anuluj', + ], + 'pagelist' => [ + 'page_link' => 'Link do strony', + 'select_page' => 'Wybierz stronę...', + ], + 'relation' => [ + 'missing_config' => 'Zachowanie relacji nie zawiera konfiguracji dla pola \':config\'.', + 'missing_definition' => 'Zachowanie relacji nie zawiera definicji dla pola \':field\'.', + 'missing_model' => 'Zachowanie relacji użyte w klasie :class nie zawiera definicji modelu.', + 'invalid_action_single' => 'Ta akcja nie może zostać wykonana na pojedynczej zależności.', + 'invalid_action_multi' => 'Ta akcja nie może zostać wykonana na wielokrotnej zależności.', + 'help' => 'Kliknij element, aby dodać.', + 'related_data' => 'Pokrewne :name dane', + 'add' => 'Dodaj', + 'add_selected' => 'Dodaj zaznaczony', + 'add_a_new' => 'Dodaj nowy :name', + 'link_selected' => 'Dołącz zaznaczone', + 'link_a_new' => 'Dołącz nowy :name', + 'cancel' => 'Anuluj', + 'close' => 'Zamknij', + 'add_name' => 'Dodaj :name', + 'create' => 'Stwórz', + 'create_name' => 'Stwórz :name', + 'update' => 'Aktualizuj', + 'update_name' => 'Aktualizuj :name', + 'preview' => 'Podgląd', + 'preview_name' => 'Podgląd :name', + 'remove' => 'Usuń', + 'remove_name' => 'Usuń :name', + 'delete' => 'Usuń', + 'delete_name' => 'Usuń :name', + 'delete_confirm' => 'Na pewno?', + 'link' => 'Dołącz', + 'link_name' => 'Dołącz :name', + 'unlink' => 'Odłącz', + 'unlink_name' => 'Odłącz :name', + 'unlink_confirm' => 'Jesteś pewien?', + ], + 'reorder' => [ + 'default_title' => 'Zmień kolejność', + 'no_records' => 'Brak dostępnych rekordów do sortowania.', + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => 'Model \':class\' o ID :id nie został znaleziony', + 'missing_id' => 'Nie istnieje sprecyzowane ID dla szukania rekordu modelu.', + 'missing_relation' => 'Model \':class\' nie zawiera definicji dla \':relation\'.', + 'missing_method' => 'Model \':class\' nie zawiera metody \':method\'.', + 'invalid_class' => 'Model :model użyty w klasie :class jest nieprawidłowy i musi dziedziczyć klasę \\Model.', + 'mass_assignment_failed' => 'Masowe przydzielanie nie powiodło się dla atrybutu \':attribute\'.', + ], + 'warnings' => [ + 'tips' => 'Konfiguracja Systemu - Porady', + 'tips_description' => 'Istnieją pewne problemy, na które należy zwrócić uwagę, aby skonfigurować sytem poprawnie.', + 'permissions' => 'PHP nie może zapisać danych w katalogu :name lub jego podkatalogach. Prosimy o przydzielenie odpowiednich uprawnień na serwerze.', + 'extension' => 'Rozszerzenie PHP :name nie jest zainstalowane. Prosimy o instalację i aktywację rozszerzenia.', + 'plugin_missing' => 'Plugin :name jest wymagany, ale nie został zainstalowany.', + 'debug' => 'Tryb debugowania jest włączony. To nie jest zalecane dla środowisk produkcyjnych.', + 'decompileBackendAssets' => 'Assety w Backendzie są zdekompilowane. To nie jest zalecane dla środowisk produkcyjnych.', + ], + 'editor' => [ + 'menu_label' => 'Ustawienia edytora kodu', + 'menu_description' => 'Personalizuj ustawienia edytora kodu, takie jak wielkość czcionki oraz kolorostyka.', + 'font_size' => 'Wielkość czcionki', + 'tab_size' => 'Wielkość karty', + 'use_hard_tabs' => 'Wcięcie tabulaturą', + 'code_folding' => 'Zawijanie kodu', + 'code_folding_begin' => 'Oznacz początek', + 'code_folding_begin_end' => 'Oznacz początek i koniec', + 'autocompletion' => 'Autouzupełnianie', + 'word_wrap' => 'Zawijanie wierszy', + 'highlight_active_line' => 'Podświetl aktywne linie', + 'auto_closing' => 'Automatycznie zamykaj tagi i specjalne znaki', + 'show_invisibles' => 'Pokaż niewidzialne znaki', + 'show_gutter' => 'Pokaż gutter', + 'basic_autocompletion' => 'Podstawowe autouzupełnianie (Ctrl + Space)', + 'live_autocompletion' => 'Autouzupełnianie na żywo', + 'enable_snippets' => 'Włącz code snippets (Tab)', + 'display_indent_guides' => 'Pokaż wskazówki dla wcięcia', + 'show_print_margin' => 'Pokaż margines wydruku', + 'mode_off' => 'Off', + 'mode_fluid' => 'Fluid', + '40_characters' => '40 Znaków', + '80_characters' => '80 Znaków', + 'theme' => 'Schemat kolorów', + 'markup_styles' => 'Style znaczników', + 'custom_styles' => 'Niestandardowy arkusz stylów', + 'custom styles_comment' => 'Niestandardowe style do dołączenia w edytorze HTML.', + 'markup_classes' => 'Klasy znaczników', + 'paragraph' => 'Paragraf', + 'link' => 'Link', + 'table' => 'Tabela', + 'table_cell' => 'Komórka Tabeli', + 'image' => 'Obraz', + 'label' => 'Etykieta', + 'class_name' => 'Nazwa klasy', + 'markup_tags' => 'Znaczniki', + 'allowed_empty_tags' => 'Zezwól na puste znaczniki', + 'allowed_empty_tags_comment' => 'Lista znaczników, które nie będą usunięte w przypadku braku zawartości.', + 'allowed_tags' => 'Dozwolone znaczniki', + 'allowed_tags_comment' => 'Lista dozwolonych znaczników.', + 'no_wrap' => 'Nie zawijaj znaczników', + 'no_wrap_comment' => 'Lista znaczników, które nie powinny być zawinięte w znacznik blokowy.', + 'remove_tags' => 'Usuń znaczniki', + 'remove_tags_comment' => 'Lista znaczników, które zostaną usunięte wraz z zawartością.', + 'line_breaker_tags' => 'Tagi przełamania linii', + 'line_breaker_tags_comment' => 'Lista tagów, pomiędzy którymi zostanie wstawiony znak przełamania linii.', + 'toolbar_buttons' => 'Przyciski paska narzędzi', + 'toolbar_buttons_comment' => 'Przyciski domyślnie wyświetlane na pasku narzędzi Rich Editora. [fullscreen, bold, italic, underline, strikeThrough, subscript, superscript, fontFamily, fontSize, |, color, emoticons, inlineStyle, paragraphStyle, |, paragraphFormat, align, formatOL, formatUL, outdent, indent, quote, insertHR, -, insertLink, insertImage, insertVideo, insertAudio, insertFile, insertTable, undo, redo, clearFormatting, selectAll, html]', + ], + 'tooltips' => [ + 'preview_website' => 'Podgląd strony', + ], + 'mysettings' => [ + 'menu_label' => 'Moje Ustawienia', + 'menu_description' => 'Ustawienia związane z Twoim kontem administratora.', + ], + 'myaccount' => [ + 'menu_label' => 'Moje konto', + 'menu_description' => 'Zmień informacje o koncie jak imię, email czy hasło.', + 'menu_keywords' => 'security login', + ], + 'branding' => [ + 'menu_label' => 'Personalizuj back-end', + 'menu_description' => 'Personalizuj panel administracyjny, kolory, logo.', + 'brand' => 'Marka', + 'logo' => 'Logo', + 'logo_description' => 'Wyślij własne logo do użycia w panelu administracyjnym.', + 'favicon' => 'Favicon', + 'favicon_description' => 'Wgraj faviconę, która zostanie użyta w backendzie', + 'app_name' => 'Nazwa aplikacji', + 'app_name_description' => 'Ta nazwa jest pokazywana w obszarze tytułu w kokpicie.', + 'app_tagline' => 'Podpis aplikacji', + 'app_tagline_description' => 'Ten podpis jest wyświetlany na ekranie logowania do back-endu', + 'colors' => 'Kolory', + 'primary_color' => 'Podstawowy kolor', + 'secondary_color' => 'Dodatkowy kolor', + 'accent_color' => 'Akcentowany kolor', + 'styles' => 'Style', + 'custom_stylesheet' => 'Własne style', + 'navigation' => 'Nawigacja', + 'menu_mode' => 'Styl menu', + 'menu_mode_inline' => 'W linii', + 'menu_mode_inline_no_icons' => 'W linii (bez ikon)', + 'menu_mode_tile' => 'Kafelki', + 'menu_mode_collapsed' => 'Zwinięte', + ], + 'backend_preferences' => [ + 'menu_label' => 'Ustawienia Back-end', + 'menu_description' => 'Zarządzaj swoimi ustawieniami konta, jak język panelu.', + 'region' => 'Region', + 'code_editor' => 'Edytor kodu', + 'timezone' => 'Strefa czasowa', + 'timezone_comment' => 'Dopasuj wyświetlanie dat do tej strefy czasowej.', + 'locale' => 'Język', + 'locale_comment' => 'Wybierz język, którego chciałbyś używać.', + ], + 'access_log' => [ + 'hint' => 'Ten log wyświetla listę udanych logowań administratorów. Dane są przechowywane przez :days dni.', + 'menu_label' => 'Dziennik zdarzeń', + 'menu_description' => 'Zobacz listę pomyślnych zalogowań do panelu administracyjnego.', + 'id' => 'ID', + 'created_at' => 'Data & Czas', + 'type' => 'Typ', + 'login' => 'Login', + 'ip_address' => 'Adres IP', + 'first_name' => 'Imię', + 'last_name' => 'Nazwisko', + 'email' => 'Email', + ], + 'filter' => [ + 'all' => 'wszystkie', + 'options_method_not_exists' => 'Klasa modelu :model musi definiować metodę :method() zwracającą listę opcji dla filtru \':filter\'.', + 'date_all' => 'Cały okres', + 'number_all' => 'wszystkie liczby', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Wgraj plik CSV', + 'import_file' => 'Importuj Plik', + 'row' => 'Wiersz :row', + 'first_row_contains_titles' => 'Pierwszy wiersz zawiera nazwy kolumn', + 'first_row_contains_titles_desc' => 'Zostaw to pole zaznaczone, jeżeli pierwszy wiersz w pliku CSV zawiera tytuły kolumn.', + 'match_columns' => '2. Przypisz kolumny z pliku do pól w bazie danych', + 'file_columns' => 'Kolumny w pliku', + 'database_fields' => 'Pola w bazie', + 'set_import_options' => '3. Ustaw opcje importu', + 'export_output_format' => '1. Format eksportowanego pliku', + 'file_format' => 'Format pliku', + 'standard_format' => 'Standardowy', + 'custom_format' => 'Niestandardowy', + 'delimiter_char' => 'Znak rozdzielający (delimiter)', + 'enclosure_char' => 'Znak zawierający (enclosure)', + 'escape_char' => 'Znak unikania (escape)', + 'select_columns' => '2. Wybierz kolumny do eksportu', + 'column' => 'Kolumna', + 'columns' => 'Kolumny', + 'set_export_options' => '3. Ustaw opcje eksportu', + 'show_ignored_columns' => 'Pokaż ignorowane kolumny', + 'auto_match_columns' => 'Automatycznie przypisz kolumny', + 'created' => 'Stworzono', + 'updated' => 'Zaktualizowano', + 'skipped' => 'Pominięto', + 'warnings' => 'Ostrzeżenia', + 'errors' => 'Błędy', + 'skipped_rows' => 'Pominięte wiersze', + 'import_progress' => 'Postęp importu', + 'processing' => 'Przetwarzanie', + 'import_error' => 'Błąd importu', + 'upload_valid_csv' => 'Wgraj prawidłowy plik CSV.', + 'drop_column_here' => 'Upuść kolumnę tutaj...', + 'ignore_this_column' => 'Ignoruj tą kolumnę', + 'processing_successful_line1' => 'Procedura eksportu zakończyła się powodzeniem!', + 'processing_successful_line2' => 'Przeglądarka automatycznie zaproponuje Ci pobranie pliku.', + 'export_progress' => 'Postęp eksportu', + 'export_error' => 'Błąd eksportu', + 'column_preview' => 'Podgląd kolumny', + 'file_not_found_error' => 'Nie znaleziono pliku', + 'empty_error' => 'Brak danych do wyeksportowania', + 'empty_import_columns_error' => 'Określ kolumny do importu.', + 'match_some_column_error' => 'Najpierw przypisz jakieś kolumny.', + 'required_match_column_error' => 'Przypisz kolumnę dla wymaganego pola :label.', + 'empty_export_columns_error' => 'Określ kolumny do eksportu.', + 'behavior_missing_uselist_error' => 'Musisz zaimplementować zachowanie ListController z włączoną opcją "useList".', + 'missing_model_class_error' => 'Określ klasę modelu dla typu :type', + 'missing_column_id_error' => 'Brak identyfikatora kolumny', + 'unknown_column_error' => 'Nieznana kolumna', + 'encoding_not_supported_error' => 'Nie rozpoznano kodowania pliku źródłowego. Proszę wybrać opcję niestandardowego formatu pliku z poprawnym kodowaniem, aby zaimportować plik.', + 'encoding_format' => 'Kodowanie', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Europa Zachodnia)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Europa Centralna)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, Europa Południowa)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, Europa Północna)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrylica)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabski)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Grecki)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrajski)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turecki)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordycki)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Tajski)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Kraje Nadbałtyckie)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtycki)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Europa Zachodnia wersja ze znakiem euro)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)', + ], + ], + 'permissions' => [ + 'manage_media' => 'Manage mediami', + ], + 'mediafinder' => [ + 'label' => 'Media Finder', + 'default_prompt' => 'Kliknij przycisk %s aby znaleźć element', + 'no_image' => 'Obraz nie został znaleziony', + ], + 'media' => [ + 'menu_label' => 'Media', + 'upload' => 'Prześlij', + 'move' => 'Przenieś', + 'delete' => 'Usuń', + 'add_folder' => 'Dodaj folder', + 'search' => 'Szukaj', + 'display' => 'Pokaż', + 'filter_everything' => 'Wszystko', + 'filter_images' => 'Obrazki', + 'filter_video' => 'Filmy', + 'filter_audio' => 'Dźwięki', + 'filter_documents' => 'Dokumenty', + 'library' => 'Biblioteka', + 'size' => 'Rozmiar', + 'title' => 'Tytuł', + 'last_modified' => 'Data modyfikacji', + 'public_url' => 'Publiczny URL', + 'click_here' => 'Kliknij tutaj', + 'thumbnail_error' => 'Wystąpił błąd przy tworzeniu miniatury.', + 'return_to_parent' => 'Wróć do folderu nadrzędnego', + 'return_to_parent_label' => 'Idź w górę ..', + 'nothing_selected' => 'Nic nie zaznaczono.', + 'multiple_selected' => 'Wybrano wiele elementów.', + 'uploading_file_num' => 'Przesyłanie :number pliku(ów)...', + 'uploading_complete' => 'Przesyłanie zakończone', + 'uploading_error' => 'Błąd przesyłania pliku', + 'type_blocked' => 'Typ pliku jest zablokowany ze względów bezpieczeństwa.', + 'order_by' => 'Sortowanie', + 'direction' => 'Kierunek', + 'direction_asc' => 'Rosnąco', + 'direction_desc' => 'Malejąco', + 'folder' => 'Folder', + 'no_files_found' => 'Nie znaleziono żadnych pasujących elementów.', + 'delete_empty' => 'Wybierz elementy do usunięcia.', + 'delete_confirm' => 'Czy na pewno chcesz usunąć wybrane elementy?', + 'error_renaming_file' => 'Wystąpił błąd przy zmianie nazwy elementu.', + 'new_folder_title' => 'Nowy folder', + 'folder_name' => 'Nazwa folderu', + 'error_creating_folder' => 'Wystąpił błąd przy tworzeniu folderu', + 'folder_or_file_exist' => 'Folder lub plik o podanej nazwie już istnieje.', + 'move_empty' => 'Wybierz elementy do przeniesienia.', + 'move_popup_title' => 'Przenieś pliki lub foldery', + 'move_destination' => 'Folder docelowy', + 'please_select_move_dest' => 'Wybierz folder docelowy.', + 'move_dest_src_match' => 'Wybierz inny folder docelowy.', + 'empty_library' => 'Biblioteka Mediów jest pusta. Na początek prześlij pliki lub utwórz foldery.', + 'insert' => 'Wstaw', + 'crop_and_insert' => 'Przytnij lub wstaw', + 'select_single_image' => 'Wybierz pojedynczy obrazek.', + 'selection_not_image' => 'Wybrany element nie jest obrazkiem.', + 'restore' => 'Cofnij wszystkie zmiany', + 'resize' => 'Skaluj...', + 'selection_mode_normal' => 'Normalny', + 'selection_mode_fixed_ratio' => 'Zablokuj proporcje', + 'selection_mode_fixed_size' => 'Zablokuj rozmiar', + 'height' => 'Wysokość', + 'width' => 'Szerokość', + 'selection_mode' => 'Tryb zaznaczenia', + 'resize_image' => 'Zmień rozmiar obrazka', + 'image_size' => 'Rozmiar obrazka:', + 'selected_size' => 'Wybrano:', + ], +]; diff --git a/modules/backend/lang/pt-br/lang.php b/modules/backend/lang/pt-br/lang.php new file mode 100644 index 0000000..a7947d2 --- /dev/null +++ b/modules/backend/lang/pt-br/lang.php @@ -0,0 +1,646 @@ + [ + 'title' => 'Área Administrativa', + 'invalid_login' => 'Os dados digitados não correspondem aos nossos registros. Por favor, verifique e tente novamente.' + ], + 'field' => [ + 'invalid_type' => 'Tipo de campo inválido :type.', + 'options_method_invalid_model' => 'O atributo ":field" não resolve a classe. Tente especificar as opções do método para o modelo :model.', + 'options_method_not_exists' => 'A classe :model deve definir um método :method() retornando opções para o campo ":field".', + 'options_static_method_invalid_value' => "O método estático ':method()' na :class não retornou um array de opções válidas.", + 'colors_method_not_exists' => 'A classe de modelo :model deve definir um método :method() retornando códigos HEX de cor html para o campo de formulário ":field".' + ], + 'widget' => [ + 'not_registered' => 'Uma classe de widget com o nome ":name" não foi definida', + 'not_bound' => 'Um widget da classe ":name" não foi ligado ao controlador', + ], + 'page' => [ + 'untitled' => 'Sem Título', + '404' => [ + 'label' => 'Página não encontrada', + 'help' => "Pesquisamos e pesquisamos, mas a URL solicitada simplesmente não foi encontrada. Será que você estava procurando outra coisa?", + 'back_link' => 'Volte para a página anterior', + ], + 'access_denied' => [ + 'label' => 'Acesso negado', + 'help' => 'Você não tem as permissões necessárias para visualizar esta página.', + 'cms_link' => 'Retornar à área administrativa', + ], + 'no_database' => [ + 'label' => 'Banco de dados ausente', + 'help' => "Um banco de dados é necessário para acessar o back-end. Verifique se o banco de dados está configurado e migrou antes de tentar novamente.", + 'cms_link' => 'Retornar para a página inicial', + ], + ], + 'partial' => [ + 'not_found_name' => 'O bloco ":name" não foi encontrado.', + 'invalid_name' => 'Nome do bloco é inválido: :name.', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Nome do manipulador AJAX inválido: :name.', + 'not_found' => "Manipulador AJAX ':name' não foi encontrado." + ], + 'account' => [ + 'impersonate' => 'Representar usuário', + 'impersonate_confirm' => 'Tem certeza de que deseja se passar por esse usuário? Você pode reverter para o seu estado original fazendo logout.', + 'impersonate_success' => 'Você está se passando por esse usuário', + 'impersonate_working' => 'Representando...', + 'impersonating' => 'Representando :full_name', + 'stop_impersonating' => 'Pare de representar', + 'unsuspend' => 'Reativar', + 'unsuspend_confirm' => 'Tem certeza de que deseja reativar este usuário?', + 'unsuspend_success' => 'O usuário foi reativado.', + 'unsuspend_working' => 'Reativando...', + 'signed_in_as' => 'Assinado como :full_name', + 'sign_out' => 'Sair', + 'login' => 'Entrar', + 'reset' => 'Redefinir', + 'restore' => 'Restaurar', + 'login_placeholder' => 'Usuário', + 'password_placeholder' => 'Senha', + 'remember_me' => 'Permaneça logado', + 'forgot_password' => 'Esqueceu sua senha?', + 'enter_email' => 'Entre com seu email', + 'enter_login' => 'Entre com seu nome de usuário', + 'email_placeholder' => 'E-mail', + 'enter_new_password' => 'Entre com uma nova senha', + 'password_reset' => 'Redefinir sua senha', + 'restore_success' => 'Um e-mail com instruções para redefinir sua senha foi enviado ao seu endereço de e-mail.', + 'restore_error' => 'O usuário ":login" não foi encontrado', + 'reset_success' => 'Sua senha foi redefinida com sucesso. Você já pode entrar novamente.', + 'reset_error' => 'A senha redefinida é inválida. Por favor, tente de novo!', + 'reset_fail' => 'Falha ao redefinir sua senha!', + 'apply' => 'Aplicar', + 'cancel' => 'Cancelar', + 'delete' => 'Excluir', + 'ok' => 'Ok', + ], + 'dashboard' => [ + 'menu_label' => 'Painel', + 'widget_label' => 'Widget', + 'widget_width' => 'Largura', + 'full_width' => 'Largura total', + 'manage_widgets' => 'Gerenciar widget', + 'add_widget' => 'Adicionar widget', + 'widget_inspector_title' => 'Configurações do widget', + 'widget_inspector_description' => 'Configurar widget de relatório', + 'widget_columns_label' => 'Largura :columns', + 'widget_columns_description' => 'Largura do widget, um número entre 1 e 10.', + 'widget_columns_error' => 'Por favor, entre com a largura do widget. Deve ser um número entre 1 e 10.', + 'columns' => '{1} coluna|[2,Inf] colunas', + 'widget_new_row_label' => 'Forçar uma nova linha', + 'widget_new_row_description' => 'Colocar o widget em uma nova linha.', + 'widget_title_label' => 'Título do widget', + 'widget_title_error' => 'O título do widget é necessário.', + 'reset_layout' => 'Reiniciar painel', + 'reset_layout_confirm' => 'Reiniciar o painel para a configuração padrão?', + 'reset_layout_success' => 'Painel foi reinicializado', + 'make_default' => 'Definir como padrão', + 'make_default_confirm' => 'Definir o painel atual como padrão?', + 'make_default_success' => 'Painel atual agora é o padrão', + 'collapse_all' => 'Recolher tudo', + 'expand_all' => 'Expandir tudo', + 'status' => [ + 'widget_title_default' => 'Status do Sistema', + 'update_available' => '{0} atualizações disponíveis!|{1} atualização disponível!|[2,Inf] atualizações disponíveis!', + 'updates_pending' => 'Atualizações de softwares pendentes', + 'updates_nil' => 'Software já está atualizado', + 'updates_link' => 'Atualizar', + 'warnings_pending' => 'Algumas questões precisam de atenção', + 'warnings_nil' => 'Nenhuma advertência para exibir', + 'warnings_link' => 'Visualizar', + 'core_build' => 'Versão do sistema', + 'event_log' => 'Registro de eventos', + 'request_log' => 'Registro de requisições', + 'app_birthday' => 'No ar desde', + ], + 'welcome' => [ + 'widget_title_default' => 'Seja bem-vindo', + 'welcome_back_name' => 'Seja bem-vindo no seu retorno ao :app, :name.', + 'welcome_to_name' => 'Seja bem-vindo ao :app, :name.', + 'first_sign_in' => 'Esta é a primeira vez que você acessa a área administrativa.', + 'last_sign_in' => 'Seu último acesso foi em', + 'view_access_logs' => 'Visualizar registros de acesso', + 'nice_message' => 'Tenha um excelente dia!', + ] + ], + 'user' => [ + 'name' => 'Administrador', + 'menu_label' => 'Administradores', + 'menu_description' => 'Gerenciar administradores, grupos e permissões.', + 'list_title' => 'Gerenciar administradores', + 'new' => 'Novo administrador', + 'login' => 'Usuário', + 'first_name' => 'Nome', + 'last_name' => 'Sobrenome', + 'full_name' => 'Nome Completo', + 'email' => 'E-mail', + 'role_field' => 'Função', + 'role_comment' => 'As funções definem as permissões do usuário, que podem ser substituídas no nível do usuário, na guia Permissões.', + 'groups' => 'Grupos', + 'groups_comment' => 'Defina a quais grupos essa pessoa pertence.', + 'avatar' => 'Foto', + 'password' => 'Senha', + 'password_confirmation' => 'Confirme a senha', + 'permissions' => 'Permissões', + 'account' => 'Conta', + 'superuser' => 'Super Usuário', + 'superuser_comment' => 'Marque para liberar o acesso irrestrito para este usuário.', + 'send_invite' => 'Enviar convite por e-mail', + 'send_invite_comment' => 'Marque para enviar um convite por e-mail', + 'delete_confirm' => 'Você realmente deseja apagar este administrador?', + 'return' => 'Retornar à lista de administradores', + 'allow' => 'Permitir', + 'inherit' => 'Herdar', + 'deny' => 'Negar', + 'activated' => 'Ativado', + 'last_login' => 'Último login', + 'created_at' => 'Criado em', + 'updated_at' => 'Atualizado em', + 'deleted_at' => 'Excluído em', + 'show_deleted' => 'Mostrar excluído', + 'group' => [ + 'name' => 'Grupo', + 'name_comment' => 'O nome é exibido na lista de grupos ao se criar/alterar um administrador.', + 'name_field' => 'Nome', + 'description_field' => 'Descrição', + 'is_new_user_default_field_label' => 'Grupo padrão', + 'is_new_user_default_field_comment' => 'Adicionar novos administradores a este grupo por padrão', + 'code_field' => 'Código', + 'code_comment' => 'Insira um código exclusivo se você quiser acessá-lo com a API.', + 'menu_label' => 'Grupos', + 'list_title' => 'Gerenciar grupos', + 'new' => 'Novo grupo administrador', + 'delete_confirm' => 'Você realmente deseja excluir este grupo?', + 'return' => 'Voltar para a lista de grupos', + 'users_count' => 'Usuários' + ], + 'role' => [ + 'name' => 'Função', + 'name_field' => 'Nome', + 'name_comment' => 'O nome é exibido na lista de funções no formulário Administrador.', + 'description_field' => 'Descrição', + 'code_field' => 'Código', + 'code_comment' => 'Digite um código exclusivo se quiser acessar o objeto de função com a API.', + 'menu_label' => 'Gerenciar Funções', + 'list_title' => 'Gerenciar Funções', + 'new' => 'Nova Função', + 'delete_confirm' => 'Excluir esta função de administrador?', + 'return' => 'Retornar para lista de funções', + 'users_count' => 'Usuários' + ], + 'preferences' => [ + 'not_authenticated' => 'Nenhum usuário autenticado para carregar as preferências.', + ], + 'trashed_hint_title' => 'Esta conta foi excluída', + 'trashed_hint_desc' => 'Esta conta foi excluida e não poderá ser acessada. Para restaurá-la, clique no ícone de restauração do usuário no canto inferior direito', + ], + 'list' => [ + 'default_title' => 'Lista', + 'search_prompt' => 'Buscar...', + 'no_records' => 'Nenhum registro encontrado.', + 'missing_model' => 'Lista usada em :class não tem um model definido.', + 'missing_column' => 'Não existe definição de coluna para :columns.', + 'missing_columns' => 'Lista utilizada em :class não possui colunas de lista definidas.', + 'missing_parent_definition' => "Comportamento de lista não possui uma definição para ':definition'.", + 'missing_definition' => 'Lista não possui uma coluna para ":field".', + 'behavior_not_ready' => 'Lista não foi inicializada. Confira se você chamou makeLists() no controller.', + 'invalid_column_datetime' => 'Valor da coluna ":column" não é um objeto DateTime, você esqueceu registrar \$dates no Model?', + 'pagination' => 'Registros exibidos: :from-:to de :total', + 'first_page' => 'Primeira página', + 'last_page' => 'Última página', + 'prev_page' => 'Anterior', + 'next_page' => 'Próxima', + 'refresh' => 'Atualizar', + 'updating' => 'Atualizando...', + 'loading' => 'Carregando...', + 'setup_title' => 'Configuração da Lista', + 'setup_help' => 'Selecione as colunas que deseja ver na lista. Você pode alterar as posições das colunas arrastando-as para cima ou para baixo.', + 'records_per_page' => 'Registros por página', + 'records_per_page_help' => 'Selecione o número de registros a serem exibidos por página. Note que um número grande pode prejudicar a performance.', + 'check' => 'Marcar', + 'delete_selected' => 'Excluir selecionado', + 'delete_selected_empty' => 'Não há registros selecionados para excluir.', + 'delete_selected_confirm' => 'Excluir os registros selecionados?', + 'delete_selected_success' => 'Registros selecionados excluídos com sucesso.', + 'column_switch_true' => 'Sim', + 'column_switch_false' => 'Não' + ], + 'fileupload' => [ + 'attachment' => 'Anexo', + 'help' => 'Adicione um título e descrição a este anexo.', + 'title_label' => 'Título', + 'description_label' => 'Descrição', + 'default_prompt' => 'Clique em %s ou arraste um arquivo para cá para enviar', + 'attachment_url' => 'Anexar URL', + 'upload_file' => 'Enviar arquivo', + 'upload_error' => 'Erro ao enviar', + 'remove_confirm' => 'Você tem certeza?', + 'remove_file' => 'Remover arquivo' + ], + 'repeater' => [ + 'add_new_item' => 'Adicionar novo item', + 'min_items_failed' => ':name requer um mínimo de :min itens, apenas :items foram fornecidos', + 'max_items_failed' => ':name requer um máximo de :max itens, apenas :items foram fornecidos', + ], + 'form' => [ + 'create_title' => 'Novo :name', + 'update_title' => 'Editar :name', + 'preview_title' => 'Visualizar :name', + 'create_success' => ':name foi criado com sucesso', + 'update_success' => ':name foi atualizado com sucesso', + 'delete_success' => ':name foi apagado com sucesso', + 'restore_success' => ':name restaurado', + 'reset_success' => 'Reinicialização completada', + 'missing_id' => 'O ID do registro não foi fornecido', + 'missing_model' => 'Formulário utilizado na classe :class não tem um model definido.', + 'missing_definition' => 'Formulário não contém um campo ":field".', + 'not_found' => 'Nenhum registro encontrado com o ID :id', + 'action_confirm' => 'Você tem certeza?', + 'create' => 'Criar', + 'create_and_close' => 'Criar e sair', + 'creating' => 'Criando...', + 'creating_name' => 'Criando :name...', + 'save' => 'Salvar', + 'save_and_close' => 'Salvar e fechar', + 'saving' => 'Salvando...', + 'saving_name' => 'Salvando :name...', + 'delete' => 'Apagar', + 'deleting' => 'Apagando...', + 'confirm_delete' => 'Você realmente deseja apagar este registro?', + 'confirm_delete_multiple' => 'Você realmente deseja apagar os registros selecionados?', + 'deleting_name' => 'Apagando :name...', + 'restore' => 'Restaurar', + 'restoring' => 'Restaurando', + 'confirm_restore' => 'Tem certeza de que deseja restaurar este registro?', + 'reset_default' => 'Redefinir para o padrão', + 'resetting' => 'Redefinindo', + 'resetting_name' => 'Redefinindo :name', + 'undefined_tab' => 'Outros', + 'field_off' => 'Desl', + 'field_on' => 'Lig', + 'add' => 'Adicionar', + 'apply' => 'Aplicar', + 'cancel' => 'Cancelar', + 'close' => 'Fechar', + 'confirm' => 'Confirmar', + 'reload' => 'Recarregar', + 'complete' => 'Concluído', + 'ok' => 'Ok', + 'or' => 'ou', + 'confirm_tab_close' => 'Tem certeza que deseja fechar essa aba? As alterações que não foram salvas serão perdidas', + 'behavior_not_ready' => 'O formulário não foi inicializado. Confira se você chamou initForm() no controller.', + 'preview_no_files_message' => 'Os arquivos não foram carregados', + 'preview_no_media_message' => 'Não há mídia selecionada.', + 'preview_no_record_message' => 'Nenhum registro selecionado.', + 'select' => 'Selecionar', + 'select_all' => 'Selecionar tudo', + 'select_none' => 'Selecione nenhum', + 'select_placeholder' => 'por favor, selecione', + 'insert_row' => 'Inserir linha', + 'insert_row_below' => 'Inserir linha abaixo', + 'delete_row' => 'Excluir linha', + 'concurrency_file_changed_title' => 'O arquivo foi alterado', + 'concurrency_file_changed_description' => 'O arquivo que você está editando foi alterado em disco. Você pode recarregá-lo e perder suas alterações ou sobrescrever o arquivo do disco.', + 'return_to_list' => 'Retornar à lista', + ], + 'recordfinder' => [ + 'find_record' => 'Localizar Registro', + 'invalid_model_class' => 'A classe de modelo fornecida ":modelClass" para o recordfinder é inválida', + 'cancel' => 'Cancelar', + ], + 'pagelist' => [ + 'page_link' => 'Link da página', + 'select_page' => 'Selecione uma página ...', + ], + 'relation' => [ + 'missing_config' => 'Comportamento relation não tem uma configuração para ":config".', + 'missing_definition' => 'Comportamento relation não contém uma definição para ":field".', + 'missing_model' => 'Comportamento relation utilizado na classe :class não possui um model definido.', + 'invalid_action_single' => 'Essa ação não pode ser realizada num relacionamento singular.', + 'invalid_action_multi' => 'Essa ação não pode ser realizada num relacionamento múltiplo.', + 'help' => 'Clique em um item para adicionar', + 'related_data' => 'Dados de :name relacionado', + 'add' => 'Adicionar', + 'add_selected' => 'Adicionar seleção', + 'add_a_new' => 'Adicionar um(a) novo(a) :name', + 'link_selected' => 'Vincular selecionado', + 'link_a_new' => 'Vincular um novo :name', + 'cancel' => 'Cancelar', + 'close' => 'Fechar', + 'add_name' => 'Adicionar :name', + 'create' => 'Criar', + 'create_name' => 'Criar :name', + 'update' => 'Atualizar', + 'update_name' => 'Atualizar :name', + 'preview' => 'Visualizar', + 'preview_name' => 'Visualizar :name', + 'remove' => 'Remover', + 'remove_name' => 'Remover :name', + 'delete' => 'Excluir', + 'delete_name' => 'Excluir :name', + 'delete_confirm' => 'Você tem certeza?', + 'link' => 'Vincular', + 'link_name' => 'Vincular :name', + 'unlink' => 'Desvincular', + 'unlink_name' => 'Desvincular :name', + 'unlink_confirm' => 'Você tem certeza?', + ], + 'reorder' => [ + 'default_title' => 'Reordenar registros', + 'no_records' => 'Não há registros disponíveis para ordenar.', + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => 'Model ":class" com ID :id não foi encontrado', + 'missing_id' => 'ID do registro não especificado.', + 'missing_relation' => 'Model ":class" não contém uma definição para o relacionamento ":relation".', + 'missing_method' => 'Model ":class" não contém o método ":method".', + 'invalid_class' => 'Model :model utilizado na classe :class não é válido. É necessário herdar a classe \Model.', + 'mass_assignment_failed' => 'Falha na atribuição em massa do atributo ":attribute" do Model.', + ], + 'warnings' => [ + 'tips' => 'Dicas de configuração do sistema', + 'tips_description' => 'Há itens que demandam atenção para configurar o sistema corretamente.', + 'permissions' => 'Diretório :name ou seus subdiretórios não são graváveis pelo PHP. Por favor, defina permissões de escrita para o servidor neste diretório.', + 'extension' => 'A extensão PHP :name não está instalada. Por favor, instale esta biblioteca para ativar a extensão.', + 'plugin_missing' => 'O plugin :name é uma dependência, mas não está instalado. Por favor, instale este plugin.', + 'debug' => 'O modo de depuração está ativado. Isso não é recomendado para instalações de produção.', + 'decompileBackendAssets' => 'Os assets no Backend estão atualmente descompilados. Isso não é recomendado para instalações de produção.', + ], + 'editor' => [ + 'menu_label' => 'Definições do Editor', + 'menu_description' => 'Gerenciar configurações do editor.', + 'preview' => 'Prévia', + 'font_size' => 'Tamanho da fonte', + 'tab_size' => 'Tamanho do espaçamento', + 'use_hard_tabs' => 'Recuo usando guias', + 'code_folding' => 'Código flexível', + 'code_folding_begin' => 'Marca de início', + 'code_folding_begin_end' => 'Marca de início e fim', + 'autocompletion' => 'Autocompletar', + 'word_wrap' => 'Quebra de linha', + 'highlight_active_line' => 'Destaque na linha ativa', + 'auto_closing' => 'Auto completar tags e caracteres especiais', + 'show_invisibles' => 'Mostrar caracteres invisíveis', + 'show_gutter' => 'Mostrar numeração de linhas', + 'basic_autocompletion'=> 'Autocompletar básico (Ctrl + Espaço)', + 'live_autocompletion'=> 'Autocompletar em tempo real', + 'enable_snippets'=> 'Habilitar trechos de códigos (Tab)', + 'display_indent_guides'=> 'Exibir guias de indentação', + 'show_print_margin'=> 'Exibir margem de impressão', + 'mode_off' => 'Desligado', + 'mode_fluid' => 'Fluido', + '40_characters' => '40 caracteres', + '80_characters' => '80 caracteres', + 'theme' => 'Esquema de cores', + 'markup_styles' => 'Estilos de marcação', + 'custom_styles' => 'Folha de estilo personalizada', + 'custom styles_comment' => 'Estilos personalizados para incluir no editor HTML.', + 'markup_classes' => 'Classes de marcação', + 'paragraph' => 'Parágrafo', + 'link' => 'Link', + 'table' => 'Tabela', + 'table_cell' => 'Célula de tabela', + 'image' => 'Imagem', + 'label' => 'Rótulo', + 'class_name' => 'Nome da classe', + 'markup_tags' => 'Etiquetas de marcação', + 'markup_tag' => 'Tag de marcação', + 'allowed_empty_tags' => 'Permitir etiquetas vazias', + 'allowed_empty_tags_comment' => 'A lista de etiquetas não é removida quando não há conteúdo.', + 'allowed_tags' => 'Etiquetas permitidas', + 'allowed_tags_comment' => 'Lista de etiquetas permitidas.', + 'no_wrap' => 'Não agrupe as etiquetas', + 'no_wrap_comment' => 'Lista de etiquetas que não devem ser agrupadas.', + 'remove_tags' => 'Excluir etiqueta', + 'remove_tags_comment' => 'Lista de etiquetas que serão exclídas juntas com seu conteúdo.', + 'line_breaker_tags' => 'Tags de quebra de linha', + 'line_breaker_tags_comment' => 'A lista de tags usadas para colocar um elemento em quebra de linha.', + 'toolbar_options' => 'Opções da barra de ferramentas', + 'toolbar_buttons' => 'Botões da barra de ferramentas', + 'toolbar_buttons_comment' => 'Os botões da barra de ferramentas a serem exibidos no Rich Editor por padrão.', + 'toolbar_buttons_preset' => 'Insira uma configuração predefinida de botãos na barra de ferramentas:', + 'toolbar_buttons_presets' => [ + 'default' => 'Padrão', + 'minimal' => 'Mínimo', + 'full' => 'Completo', + ], + 'paragraph_formats' => 'Formatos de parágrafo', + 'paragraph_formats_comment' => 'As opções que aparecerão na lista de Formatos do parágrafo.', + ], + 'tooltips' => [ + 'preview_website' => 'Visualizar a página' + ], + 'mysettings' => [ + 'menu_label' => 'Minhas Configurações', + 'menu_description' => 'Configurações relacionadas à sua conta de administrador', + ], + 'myaccount' => [ + 'menu_label' => 'Minha Conta', + 'menu_description' => 'Atualizar detalhes da sua conta, como nome, e-mail e senha.', + 'menu_keywords' => 'login de segurança' + ], + 'branding' => [ + 'menu_label' => 'Personalização', + 'menu_description' => 'Personalizar detalhes da área administrativa, tais como título, cores e logo.', + 'brand' => 'Marca', + 'logo' => 'Logo', + 'logo_description' => 'Fazer upload de uma logo para usar na área administrativa.', + 'favicon' => 'Favicon', + 'favicon_description' => 'Carregar um favicon personalizado para usar no back-end', + 'app_name' => 'Nome do Aplicativo', + 'app_name_description' => 'Este nome é mostrado no título da área administrativa.', + 'app_tagline' => 'Slogan do Aplicativo', + 'app_tagline_description' => 'Esta frase é mostrada na tela de login administrativo.', + 'colors' => 'Cores', + 'primary_color' => 'Cor primária', + 'secondary_color' => 'Cor secundária', + 'accent_color' => 'Accent color', + 'styles' => 'Estilos', + 'custom_stylesheet' => 'CSS customizado', + 'navigation' => 'Navegação', + 'menu_mode' => 'Estilo de menu', + 'menu_mode_inline' => 'Em linha', + 'menu_mode_inline_no_icons' => 'Em linha (sem ícones)', + 'menu_mode_tile' => 'Blocos', + 'menu_mode_collapsed' => 'Colapsados' + ], + 'backend_preferences' => [ + 'menu_label' => 'Preferências da Administração', + 'menu_description' => 'Gerenciar idiomas e aparência da administração.', + 'region' => 'Região', + 'code_editor' => 'Editor de código', + 'timezone' => 'Fuso horário', + 'timezone_comment' => 'Ajustar datas exibidas para este Fuso horário.', + 'locale' => 'Idioma', + 'locale_comment' => 'Selecione o idioma de sua preferência.', + ], + 'access_log' => [ + 'hint' => 'Este registro mostra a lista de acessos dos administradores. Os registros são mantidos por um período de :days dias.', + 'menu_label' => 'Registro de Acesso', + 'menu_description' => 'Veja a lista de acessos à administração.', + 'id' => 'ID', + 'created_at' => 'Data & Hora', + 'type' => 'Tipo', + 'login' => 'Login', + 'ip_address' => 'Endereço IP', + 'first_name' => 'Nome', + 'last_name' => 'Sobrenome', + 'email' => 'E-mail', + ], + 'filter' => [ + 'all' => 'todos', + 'options_method_not_exists' => "A classe modelo :model deve definir um método :method() retornando opções para o filtro ':filter'.", + 'date_all' => 'todo o período', + 'number_all' => 'todos os números', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Enviar arquivo CSV', + 'import_file' => 'Importar arquivo', + 'row' => 'Linha :row', + 'first_row_contains_titles' => 'Primeira linha contém títulos das colunas', + 'first_row_contains_titles_desc' => 'Deixe marcado se primeira linha do CSV é utilizada como títulos das colunas.', + 'match_columns' => '2. Associar as colunas do arquivo a campos do banco de dados', + 'file_columns' => 'Colunas do arquivo', + 'database_fields' => 'Campos do banco de dados', + 'set_import_options' => '3. Definir opções de importação', + 'export_output_format' => '1. Formato de saída da exportação', + 'file_format' => 'Formato do arquivo', + 'standard_format' => 'Formato padrão', + 'custom_format' => 'Formato personalizado', + 'delimiter_char' => 'Caracter delimitador', + 'enclosure_char' => 'Caracter qualificador', + 'escape_char' => 'Caracter de escape', + 'select_columns' => '2. Selecione colunas para exportar', + 'column' => 'Coluna', + 'columns' => 'Colunas', + 'set_export_options' => '3. Definir opções de exportação', + 'show_ignored_columns' => 'Mostrar colunas ignoradas', + 'auto_match_columns' => 'Auto associar colunas', + 'created' => 'Criados', + 'updated' => 'Atualizados', + 'skipped' => 'Ignorados', + 'warnings' => 'Alertas', + 'errors' => 'Erros', + 'skipped_rows' => 'Registros Ignorados', + 'import_progress' => 'Progresso da Importação', + 'processing' => 'Processando', + 'import_error' => 'Erro de importação', + 'upload_valid_csv' => 'Por favor envie um arquivo CSV válido.', + 'drop_column_here' => 'Soltar coluna aqui...', + 'ignore_this_column' => 'Ignorar esta coluna', + 'processing_successful_line1' => 'Processo de exportação de arquivo concluído com sucesso!', + 'processing_successful_line2' => 'O navegador agora deve redirecionar automaticamente para o download do arquivo.', + 'export_progress' => 'Progresso da exportação', + 'export_error' => 'Erro de exportação', + 'column_preview' => 'Pré-visualizar coluna', + 'file_not_found_error' => 'Arquivo não encontrado', + 'empty_error' => 'Não havia dados fornecidos para exportar', + 'empty_import_columns_error' => 'Por favor, especifique algumas colunas para importar.', + 'match_some_column_error' => 'Por favor, combine algumas colunas primeiro.', + 'required_match_column_error' => 'Por favor, especifique a combinação para o campo requerido :label.', + 'empty_export_columns_error' => 'Por favor, especifique algumas colunas para exportar.', + 'behavior_missing_uselist_error' => 'Você deve implementar o comportamento do controlador ListController com a opção de exportação "useList" habilitada.', + 'missing_model_class_error' => 'Por favor, especifique a propriedade modelo de classe para :type', + 'missing_column_id_error' => 'Identificador de coluna ausente', + 'unknown_column_error' => 'Coluna desconhecida', + 'encoding_not_supported_error' => 'Codificação do arquivo fonte desconhecida. Por favor, selecione a opção "Formato personalizado", com a devida codificação, para importar o arquivo.', + 'encoding_format' => 'Codificação do arquivo', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1250' => 'Windows-1250 (CP1250, Central and Eastern European)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Gerenciar mídias', + 'allow_unsafe_markdown' => 'Usar Markdown inseguro (pode incluir Javascript)', + ], + 'mediafinder' => [ + 'label' => 'Localizador de Mídia', + 'default_prompt' => 'Clique no botão %s para localizar um arquivo de mídia', + 'no_image' => 'A imagem não foi encontrada' + ], + 'media' => [ + 'menu_label' => 'Mídias', + 'upload' => 'Enviar', + 'move' => 'Mover', + 'delete' => 'Excluir', + 'add_folder' => 'Adicionar pasta', + 'search' => 'Buscar', + 'display' => 'Exibir', + 'filter_everything' => 'Tudo', + 'filter_images' => 'Imagens', + 'filter_video' => 'Vídeos', + 'filter_audio' => 'Áudios', + 'filter_documents' => 'Documentos', + 'library' => 'Biblioteca', + 'size' => 'Tamanho', + 'title' => 'Título', + 'last_modified' => 'Última modificação', + 'public_url' => 'URL pública', + 'click_here' => 'Clique aqui', + 'thumbnail_error' => 'Erro ao gerar a miniatura.', + 'return_to_parent' => 'Retornar ao diretório anterior', + 'return_to_parent_label' => 'Vá para ..', + 'nothing_selected' => 'Nenhum item selecionado.', + 'multiple_selected' => 'Múltiplos itens selecionados.', + 'uploading_file_num' => 'Enviando :number arquivo(s)...', + 'uploading_complete' => 'Envio finalizado', + 'uploading_error' => 'Falha no envio', + 'type_blocked' => 'O tipo de arquivo utilizado é bloqueado por motivos de segurança.', + 'order_by' => 'Ordenar por', + 'direction' => 'Direção', + 'direction_asc' => 'Ascendente', + 'direction_desc' => 'Descendente', + 'folder' => 'Pasta', + 'no_files_found' => 'Nenhum arquivo encontrado.', + 'delete_empty' => 'Por favor, selecione um item para excluir.', + 'delete_confirm' => 'Você deseja mesmo excluir o(s) arquivo(s) selecionado(s)?', + 'error_renaming_file' => 'Erro ao renomear o arquivo.', + 'new_folder_title' => 'Nova pasta', + 'folder_name' => 'Nome da pasta', + 'error_creating_folder' => 'Erro ao criar a pasta', + 'folder_or_file_exist' => 'Uma pasta ou arquivo já existe com o nome especificado.', + 'move_empty' => 'Por favor, selecione um item para mover.', + 'move_popup_title' => 'Mover arquivos ou pastas', + 'move_destination' => 'Pasta destino', + 'please_select_move_dest' => 'Por favor, selecione a pasta destino.', + 'move_dest_src_match' => 'Por favor, selecione outra pasta destino.', + 'empty_library' => 'A biblioteca de mídias está vazia. Envie arquivos ou crie pastas para iniciar.', + 'insert' => 'Inserir', + 'crop_and_insert' => 'Cortar & Inserir', + 'select_single_image' => 'Por favor, selecione uma única imagem.', + 'selection_not_image' => 'O arquivo selecionado não é uma imagem.', + 'restore' => 'Desfazer todas as alterações', + 'resize' => 'Redimensionar...', + 'selection_mode_normal' => 'Normal', + 'selection_mode_fixed_ratio' => 'Proporção fixa', + 'selection_mode_fixed_size' => 'Tamanho fixo', + 'height' => 'Altura', + 'width' => 'Largura', + 'selection_mode' => 'Modo de seleção', + 'resize_image' => 'Redimensionar imagem', + 'image_size' => 'Tamanho da imagem:', + 'selected_size' => 'Selecionado:' + ] +]; diff --git a/modules/backend/lang/pt-pt/lang.php b/modules/backend/lang/pt-pt/lang.php new file mode 100644 index 0000000..b0c3e02 --- /dev/null +++ b/modules/backend/lang/pt-pt/lang.php @@ -0,0 +1,627 @@ + [ + 'title' => 'Área Administrativa', + 'invalid_login' => 'As credenciais que introduziu não são válidas. Por favor verifique os seus dados e tente novamente.', + ], + 'field' => [ + 'invalid_type' => 'Invalid field type used :type.', + 'options_method_invalid_model' => "O atributo ':field' não é resolvido para um modelo válidol. Tente especificar o método de opções para a classe de modelo :model explicitamente.", + 'options_method_not_exists' => "A classe de modelo :model deve definir um método :method() que retorne opções para o campo de formulário ':field'.", + 'colors_method_not_exists' => "A classe de modelo :model deve definir um método :method() que retorne códigos de côr hexadecimais html para o campo de formulário':field'.", + ], + 'widget' => [ + 'not_registered' => 'Uma classe de widget com o nome ":name" não foi registada', + 'not_bound' => 'Um widget da classe ":name" não foi ligado ao controlador', + ], + 'page' => [ + 'untitled' => 'Sem título', + '404' => [ + 'label' => 'Página não encontrada', + 'help' => "Por muito que procuremos, o URL pedido não existe. Talvez esteja à procura de outra coisa?", + 'back_link' => 'Voltar à página anterior', + ], + 'access_denied' => [ + 'label' => 'Acesso negado', + 'help' => 'Não tem as permissões necessárias para visualizar esta página.', + 'cms_link' => 'Regressar à área administrativa', + ], + 'no_database' => [ + 'label' => 'Base de dados não existente', + 'help' => "Uma base de dados é necessária para acesso ao back-end. Verifique se a base dados se encontra configurada e migrada antes de tentar novamente.", + 'cms_link' => 'Regressar á página inicial', + ], + ], + 'partial' => [ + 'not_found_name' => 'O bloco parcial ":name" não foi encontrado.', + 'invalid_name' => 'Nome de bloco parcial inválido: :name.', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Nome de processador AJAX inválido: :name.', + 'not_found' => "O processador AJAX ':name' não foi encontrado.", + ], + 'account' => [ + 'impersonate' => 'Personificar utilizador', + 'impersonate_confirm' => 'Tem a certeza de que quer personificar este utilizador? Pode voltar ao seu estado inicial fazendo log out.', + 'impersonate_success' => 'Está agora a personificar este utilizador', + 'impersonate_working' => 'A personificar...', + 'impersonating' => 'A personificar :full_name', + 'stop_impersonating' => 'Parar de personificar', + 'signed_in_as' => 'Sessão iniciada como :full_name', + 'sign_out' => 'Sair', + 'login' => 'Entrar', + 'reset' => 'Redefinir', + 'restore' => 'Restaurar', + 'login_placeholder' => 'Utilizador', + 'password_placeholder' => 'Senha', + 'remember_me' => 'Manter sessão activa', + 'forgot_password' => 'Esqueceu sua senha?', + 'enter_email' => 'Coloque o seu email', + 'enter_login' => 'Coloque o nome de utilizador', + 'email_placeholder' => 'E-mail', + 'enter_new_password' => 'Coloque uma nova senha', + 'password_reset' => 'Redefinir sua senha', + 'restore_success' => 'Um e-mail com instruções para redefinir a sua senha foi enviado ao seu endereço de e-mail.', + 'restore_error' => 'O utilizador ":login" não foi encontrado', + 'reset_success' => 'Sua senha foi redefinida com sucesso. Já pode entrar novamente.', + 'reset_error' => 'A senha redefinida é inválida. Por favor, tente de novo!', + 'reset_fail' => 'Falha ao redefinir sua senha!', + 'apply' => 'Aplicar', + 'cancel' => 'Cancelar', + 'delete' => 'Apagar', + 'ok' => 'Ok', + ], + 'dashboard' => [ + 'menu_label' => 'Painel', + 'widget_label' => 'Widget', + 'widget_width' => 'Largura', + 'full_width' => 'Largura completa', + 'manage_widgets' => 'Gerir widgets', + 'add_widget' => 'Adicionar widget', + 'widget_inspector_title' => 'Configuração de widgets', + 'widget_inspector_description' => 'Configurar o widget', + 'widget_columns_label' => 'Largura :columns', + 'widget_columns_description' => 'A largura do widget, um número entre 1 e 12.', + 'widget_columns_error' => 'Por favor introduza a largura do widget como um número entre 1 e 12.', + 'columns' => '{1} coluna|[2,Inf] colunas', + 'widget_new_row_label' => 'Forçar nova linha', + 'widget_new_row_description' => 'Pôr o widget numa linha nova.', + 'widget_title_label' => 'Título do widget', + 'widget_title_error' => 'O título do widget é obrigatório.', + 'reset_layout' => 'Reinicializar layout', + 'reset_layout_confirm' => 'Reinicializar o layout para a configuração de origem?', + 'reset_layout_success' => 'O layout foi reinicializado', + 'make_default' => 'Guardar como pré-definido', + 'make_default_confirm' => 'Guardar o layout actual como o pré-definido?', + 'make_default_success' => 'O layout actual é agora o pré-definido', + 'collapse_all' => 'Contrair todos', + 'expand_all' => 'Expandir todos ', + 'status' => [ + 'widget_title_default' => 'Estado do Sistema', + 'update_available' => '{0} actualizações disponíveis!|{1} actualização disponível!|[2,Inf] actualizações disponíveis!', + 'updates_pending' => 'Actualizações de softwares pendentes', + 'updates_nil' => 'O software já está actualizado', + 'updates_link' => 'Actualizar', + 'warnings_pending' => 'Algumas questões precisam de atenção', + 'warnings_nil' => 'Nenhuma advertência para mostrar', + 'warnings_link' => 'Visualizar', + 'core_build' => 'Versão do sistema', + 'event_log' => 'Registo de eventos', + 'request_log' => 'Registo de requisições', + 'app_birthday' => 'No ar desde', + ], + 'welcome' => [ + 'widget_title_default' => 'Bem-vindo', + 'welcome_back_name' => 'Seja bem vindo de volta ao :app, :name.', + 'welcome_to_name' => 'Bem vindo ao :app, :name.', + 'first_sign_in' => 'Esta é a primeira vez que acede à área administrativa.', + 'last_sign_in' => 'O último acesso foi em', + 'view_access_logs' => 'Visualizar registos de acesso', + 'nice_message' => 'Tenha um excelente dia!', + ] + ], + 'user' => [ + 'name' => 'Administrador', + 'menu_label' => 'Administradores', + 'menu_description' => 'Gerir utilizadores, grupos, e permissões de administração.', + 'list_title' => 'Gerir Administradores', + 'new' => 'Novo Administrator', + 'login' => 'Login', + 'first_name' => 'Nome Próprio', + 'last_name' => 'Apelido', + 'full_name' => 'Nome Completo', + 'email' => 'Email', + 'role_field' => 'Papel', + 'role_comment' => 'Papéis definem permissões de utilizador, que podem ser sobrepostas para cada utilizador no separador Permissões.', + 'groups' => 'Grupos', + 'groups_comment' => 'Defina os grupos a que esta conta deve pertencer. Os grupos definem permissões, que podem ser sobrepostas para cada utilizador no separador Permissões.', + 'avatar' => 'Avatar', + 'password' => 'Senha', + 'password_confirmation' => 'Confirmar Senha', + 'permissions' => 'Permissões', + 'account' => 'Conta', + 'superuser' => 'Super Utilizador', + 'superuser_comment' => 'Permite accesso completo a todas as àreas do sistema para esta conta. Super utilizadores podem criar e gerir outros utilizadores.', + 'send_invite' => 'Enviar convite por email', + 'send_invite_comment' => 'Envia uma mensagem de boas-vindas com a informação de login e password.', + 'delete_confirm' => 'Apagar este administrador?', + 'return' => 'Voltar à lista de administradores', + 'allow' => 'Permitir', + 'inherit' => 'Herdar', + 'deny' => 'Negar', + 'activated' => 'Activado', + 'last_login' => 'Última entrada', + 'created_at' => 'Criado em', + 'updated_at' => 'Modificado em', + 'deleted_at' => 'Apagado em', + 'show_deleted' => 'Mostrar apagados', + 'group' => [ + 'name' => 'Grupo', + 'name_comment' => 'O nome é exibido na lista de grupos ao criar/alterar um administrador.', + 'name_field' => 'Nome', + 'description_field' => 'Descrição', + 'is_new_user_default_field_label' => 'Grupo padrão', + 'is_new_user_default_field_comment' => 'Adicionar novos administradores a este grupo por padrão', + 'code_field' => 'Código', + 'code_comment' => 'Insira um código exclusivo se quiser utilizar o mesmo com a API.', + 'menu_label' => 'Grupos', + 'list_title' => 'Gerir grupos', + 'new' => 'Novo grupo administrador', + 'delete_confirm' => 'Você realmente deseja apagar este grupo?', + 'return' => 'Voltar para a lista de grupos', + 'users_count' => 'Utilizadores', + ], + 'role' => [ + 'name' => 'Papel', + 'name_field' => 'Nome', + 'name_comment' => 'O nome é exibido na lista de grupos ao criar/alterar um administrador.', + 'description_field' => 'Descrição', + 'code_field' => 'Código', + 'code_comment' => 'Insira um código exclusivo se quiser utilizar o mesmo com a API.', + 'menu_label' => 'Gerir Papéis', + 'list_title' => 'Gerir Papéis', + 'new' => 'Novo Papel', + 'delete_confirm' => 'Você realmente deseja apagar este papel?', + 'return' => 'Voltar para a lista de papéis', + 'users_count' => 'Utilizadores', + ], + 'preferences' => [ + 'not_authenticated' => 'Nenhum utilizador autenticado para carregar as preferências.', + ], + 'trashed_hint_title' => 'Esta conta foi apagada', + 'trashed_hint_desc' => 'Esta conta foi apagada e não pode iniciar sessão. Para a restaurar, clique no botão Restaurar Utilizador no canto inferior direito.', + ], + 'list' => [ + 'default_title' => 'Lista', + 'search_prompt' => 'Pesquisar...', + 'no_records' => 'Nenhum registo encontrado.', + 'missing_model' => 'A lista usada em :class não tem um modelo definido.', + 'missing_column' => 'Não existe definição de coluna para :columns.', + 'missing_columns' => 'A lista utilizada em :class não possui colunas de lista definidas.', + 'missing_parent_definition' => "Comportamento de lista não possui uma definição para ':definition'.", + 'missing_definition' => 'Lista não possui uma coluna para ":field".', + 'behavior_not_ready' => 'Lista não foi inicializada. Verifique se você chamou makeLists() no controlador.', + 'invalid_column_datetime' => 'Valor da coluna ":column" não é um objeto DateTime, esqueceu de referênciar \$dates no modelo?', + 'pagination' => 'Registos exibidos: :from-:to de :total', + 'first_page' => 'Primeira página', + 'last_page' => 'Última página', + 'prev_page' => 'Anterior', + 'next_page' => 'Próxima', + 'refresh' => 'Actualizar', + 'updating' => 'Actualizando...', + 'loading' => 'Carregando...', + 'setup_title' => 'Configuração de Lista', + 'setup_help' => 'Seleccione as colunas que deseja ver na lista. Você pode alterar as posições das colunas arrastando-as para cima ou para baixo.', + 'records_per_page' => 'Registos por página', + 'records_per_page_help' => 'Escolha o número de registos a mostrar por página. Note que um número elevado de registos por página pode reduzir a performance.', + 'check' => 'Marcar', + 'delete_selected' => 'Apagar seleccionado', + 'delete_selected_empty' => 'Não há registos seleccionados para apagar.', + 'delete_selected_confirm' => 'Apagar os registos selecionados?', + 'delete_selected_success' => 'Registos seleccionados apagados com sucesso.', + 'column_switch_true' => 'Sim', + 'column_switch_false' => 'Não', + ], + 'fileupload' => [ + 'attachment' => 'Anexo', + 'help' => 'Adicione um título e descrição a este anexo.', + 'title_label' => 'Título', + 'description_label' => 'Descrição', + 'default_prompt' => 'Clique em %s ou arraste um ficheiro para cá para enviar', + 'attachment_url' => 'Anexar URL', + 'upload_file' => 'Enviar ficheiro', + 'upload_error' => 'Erro ao enviar', + 'remove_confirm' => 'Tem a certeza?', + 'remove_file' => 'Remover ficheiro', + ], + 'repeater' => [ + 'min_items_failed' => ':name requer no mínimo :min itens, apenas :items foram introduzidos', + 'max_items_failed' => ':name requer no máximo :min itens, :items foram introduzidos', + ], + 'form' => [ + 'create_title' => 'Novo :name', + 'update_title' => 'Editar :name', + 'preview_title' => 'Visualizar :name', + 'create_success' => ':name foi criado com sucesso', + 'update_success' => ':name foi actualizado com sucesso', + 'delete_success' => ':name foi apagado com sucesso', + 'restore_success' => ':name foi restaurado com sucesso', + 'reset_success' => 'Reinicialização completa', + 'missing_id' => 'O ID do registo não foi fornecido', + 'missing_model' => 'Formulário utilizado na classe :class não tem um modelo definido.', + 'missing_definition' => 'Formulário não contém um campo ":field".', + 'not_found' => 'Nenhum registo encontrado com o ID :id', + 'action_confirm' => 'Tem a certeza?', + 'create' => 'Criar', + 'create_and_close' => 'Criar e sair', + 'creating' => 'Criando...', + 'creating_name' => 'Criando :name...', + 'save' => 'Guardar', + 'save_and_close' => 'Guardar e fechar', + 'saving' => 'Guardando...', + 'saving_name' => 'Guardando :name...', + 'delete' => 'Apagar', + 'deleting' => 'Apagando...', + 'confirm_delete' => 'Realmente deseja apagar este registo?', + 'confirm_delete_multiple' => 'Realmente deseja apagar os registos seleccionados?', + 'deleting_name' => 'Apagando :name...', + 'restore' => 'Restaurar', + 'restoring' => 'Restaurando', + 'confirm_restore' => 'Realmente deseja restaurar este registo?', + 'reset_default' => 'Redefinir para o padrão', + 'resetting' => 'Redefinindo', + 'resetting_name' => 'Redefinindo :name', + 'undefined_tab' => 'Outros', + 'field_off' => 'Desl', + 'field_on' => 'Lig', + 'add' => 'Adicionar', + 'apply' => 'Aplicar', + 'cancel' => 'Cancelar', + 'close' => 'Fechar', + 'confirm' => 'Confirmar', + 'reload' => 'Recarregar', + 'complete' => 'Concluído', + 'ok' => 'Ok', + 'or' => 'ou', + 'confirm_tab_close' => 'Tem a certeza que deseja fechar esse separador? As alterações que não foram guardadas serão perdidas', + 'behavior_not_ready' => 'O formulário não foi inicializado. Verifique se você chamou initForm() no controlador.', + 'preview_no_files_message' => 'Os ficheiros não foram carregados', + 'preview_no_media_message' => 'Nenhum conteúdo selecionado.', + 'preview_no_record_message' => 'Nenhum registo selecionado.', + 'select' => 'Selecionar', + 'select_all' => 'Selecionar tudo', + 'select_none' => 'Selecione nenhum', + 'select_placeholder' => 'por favor, selecione', + 'insert_row' => 'Inserir linha', + 'insert_row_below' => 'Inserir linha abaixo', + 'delete_row' => 'Apagar linha', + 'concurrency_file_changed_title' => 'O ficheiro foi alterado', + 'concurrency_file_changed_description' => 'O ficheiro que está editando foi alterado em disco. Pode recarregá-lo e perder suas alterações ou sobrescrever o ficheiro do disco.', + 'return_to_list' => 'Regressar à lista', + ], + 'recordfinder' => [ + 'find_record' => 'Localizar Registo', + 'invalid_model_class' => 'A classe modelo ":modelClass" definida para o localizador de registos é inválida.', + 'cancel' => 'Cancelar', + ], + 'pagelist' => [ + 'page_link' => 'Ligação de página', + 'select_page' => 'Escolha uma página...', + ], + 'relation' => [ + 'missing_config' => 'Comportamento da relação não tem uma configuração para ":config".', + 'missing_definition' => 'Comportamento da relação não contém uma definição para ":field".', + 'missing_model' => 'Comportamento da relação utilizado na classe :class não possui um modelo definido.', + 'invalid_action_single' => 'Essa acção não pode ser realizada num relacionamento singular.', + 'invalid_action_multi' => 'Essa acção não pode ser realizada num relacionamento múltiplo.', + 'help' => 'Clique em um item para adicionar', + 'related_data' => 'Dados de :name relacionado', + 'add' => 'Adicionar', + 'add_selected' => 'Adicionar seleção', + 'add_a_new' => 'Adicionar um(a) novo(a) :name', + 'link_selected' => 'Vincular selecionado', + 'link_a_new' => 'Vincular um novo :name', + 'cancel' => 'Cancelar', + 'close' => 'Fechar', + 'add_name' => 'Adicionar :name', + 'create' => 'Criar', + 'create_name' => 'Criar :name', + 'update' => 'Actualizar', + 'update_name' => 'Actualizar :name', + 'preview' => 'Visualizar', + 'preview_name' => 'Visualizar :name', + 'remove' => 'Remover', + 'remove_name' => 'Remover :name', + 'delete' => 'Apagar', + 'delete_name' => 'Apagar :name', + 'delete_confirm' => 'Tem a certeza?', + 'link' => 'Vincular', + 'link_name' => 'Vincular :name', + 'unlink' => 'Desvincular', + 'unlink_name' => 'Desvincular :name', + 'unlink_confirm' => 'Tem a certeza?', + ], + 'reorder' => [ + 'default_title' => 'Reordenar registos', + 'no_records' => 'Não há registos disponíveis para ordenar.', + ], + 'model' => [ + 'name' => 'Modelo', + 'not_found' => 'O modelo ":class" com ID :id não foi encontrado', + 'missing_id' => 'ID do registo não especificado.', + 'missing_relation' => 'O modelo ":class" não contém uma definição para o relacionamento ":relation".', + 'missing_method' => 'O modelo ":class" não contém o método ":method".', + 'invalid_class' => 'O modelo :model utilizado na classe :class não é válido. É necessário herdar a classe \Model.', + 'mass_assignment_failed' => 'Falha na atribuição em massa do atributo ":attribute" do modelo.', + ], + 'warnings' => [ + 'tips' => 'Dicas de configuração do sistema', + 'tips_description' => 'Há itens que requerem atenção para configurar o sistema corretamente.', + 'permissions' => 'Diretoria :name ou suas subdiretorias não são graváveis pelo PHP. Por favor, defina permissões de escrita para o servidor nesta diretoria.', + 'extension' => 'A extensão PHP :name não está instalada. Por favor, instale esta biblioteca para activar a extensão.', + 'plugin_missing' => 'A extensão :name é uma dependência mas não está instalada. Por favor instale esta extensão.', + 'debug' => 'O modo de depuração está activo. Isto não é recomendado em abientes de produção.', + 'decompileBackendAssets' => 'Os recursos do backend não estao compilados. Isto não é recomendado em ambientes de produção.', + ], + 'editor' => [ + 'menu_label' => 'Definições do Editor', + 'menu_description' => 'Gerir configurações globais do editor, como tamanho de fonte ou esquema de cores', + 'font_size' => 'Tamanho da fonte', + 'tab_size' => 'Tamanho do tabulação', + 'use_hard_tabs' => 'Recuo usando guias', + 'code_folding' => 'Código flexível', + 'code_folding_begin' => 'Marca de início', + 'code_folding_begin_end' => 'Marca de início e fim', + 'autocompletion' => 'Autocompletar', + 'word_wrap' => 'Quebra de linha', + 'highlight_active_line' => 'Destaque na linha ativa', + 'auto_closing' => 'Fechar etiquetas automáticamente', + 'show_invisibles' => 'Mostrar caracteres invisíveis', + 'show_gutter' => 'Mostrar guias', + 'basic_autocompletion'=> 'Autocompletar básico (Ctrl + Espaço)', + 'live_autocompletion'=> 'Autocompletar em tempo real', + 'enable_snippets'=> 'Activar trechos de códigos (Tab)', + 'display_indent_guides'=> 'Mostrar guias de indentação', + 'show_print_margin'=> 'Mostrar margem de impressão', + 'mode_off' => 'Desligado', + 'mode_fluid' => 'Fluido', + '40_characters' => '40 caracteres', + '80_characters' => '80 caracteres', + 'theme' => 'Esquema de cores', + 'markup_styles' => 'Estilos de marcação', + 'custom_styles' => 'Folha de estilo personalizada', + 'custom styles_comment' => 'Estilos personalizados para incluir no editor HTML.', + 'markup_classes' => 'Classes de marcação', + 'paragraph' => 'Parágrafo', + 'link' => 'Ligação', + 'table' => 'Tabela', + 'table_cell' => 'Célula de tabela', + 'image' => 'Imagem', + 'label' => 'Rótulo', + 'class_name' => 'Nome da classe', + 'markup_tags' => 'Etiquetas de marcação', + 'allowed_empty_tags' => 'Permitir etiquetas vazias', + 'allowed_empty_tags_comment' => 'A lista de etiquetas que não é removida quando não há conteúdo.', + 'allowed_tags' => 'Etiquetas permitidas', + 'allowed_tags_comment' => 'Lista de etiquetas permitidas.', + 'no_wrap' => 'Não envolva as etiquetas', + 'no_wrap_comment' => 'Lista de etiquetas que não devem ser envolvidas num bloco de etiquetas.', + 'remove_tags' => 'Apagar etiquetas', + 'remove_tags_comment' => 'Lista de etiquetas que serão excluídas incluíndo o conteúdo.', + 'line_breaker_tags' => 'Etiquetas de quebra de linha', + 'line_breaker_tags_comment' => 'Lista de etiquetas entre as quais é inserida uma quebra de linha.', + 'toolbar_buttons' => 'Botões da barra de ferramentas', + 'toolbar_buttons_comment' => 'Botões da barra de ferramentas do editor rico a serem mostradas por defeito.', + ], + 'tooltips' => [ + 'preview_website' => 'Prévisualizar a página', + ], + 'mysettings' => [ + 'menu_label' => 'As minhas configurações', + 'menu_description' => 'Configurações relacionadas com sua conta de administrador', + ], + 'myaccount' => [ + 'menu_label' => 'Minha Conta', + 'menu_description' => 'Actualizar detalhes da sua conta, como nome, e-mail e senha.', + 'menu_keywords' => 'login de segurança', + ], + 'branding' => [ + 'menu_label' => 'Personalização', + 'menu_description' => 'Personalizar detalhes da área administrativa, tais como título, cores e logo.', + 'brand' => 'Marca', + 'logo' => 'Logo', + 'logo_description' => 'Fazer carregamento de um logótipo para usar na área administrativa.', + 'favicon' => 'Favicon', + 'favicon_description' => 'Carrege um favicon personalizado a usar na área administrativa', + 'app_name' => 'Nome da Aplicação', + 'app_name_description' => 'Este nome é mostrado no título da área administrativa.', + 'app_tagline' => 'Slogan do Aplicativo', + 'app_tagline_description' => 'Esta frase é mostrada no ecran de entrada administrativo.', + 'colors' => 'Cores', + 'primary_color' => 'Cor primária', + 'secondary_color' => 'Cor secundária', + 'accent_color' => 'Cor destacada', + 'styles' => 'Estilos', + 'custom_stylesheet' => 'CSS personalizado', + 'navigation' => 'Navegação', + 'menu_mode' => 'Estilo de menu', + 'menu_mode_inline' => 'Em linha', + 'menu_mode_inline_no_icons' => 'Em linha (sem icons)', + 'menu_mode_tile' => 'Blocos', + 'menu_mode_collapsed' => 'Colapsados', + ], + 'backend_preferences' => [ + 'menu_label' => 'Preferências da Administração', + 'menu_description' => 'Gerir idiomas e aparência da administração.', + 'region' => 'Região', + 'code_editor' => 'Editor de código', + 'timezone' => 'Fuso horário', + 'timezone_comment' => 'Ajustar datas exibidas para este fuso horário.', + 'locale' => 'Idioma', + 'locale_comment' => 'Selecione o idioma de sua preferência.', + ], + 'access_log' => [ + 'hint' => 'Este registo mostra a lista de acessos dos administradores. Os registros são mantidos por um período de :days dias.', + 'menu_label' => 'Registo de Acesso', + 'menu_description' => 'Veja a lista de acessos à administração.', + 'id' => 'ID', + 'created_at' => 'Data & Hora', + 'type' => 'Tipo', + 'login' => 'Entrada', + 'ip_address' => 'Endereço IP', + 'first_name' => 'Nome', + 'last_name' => 'Apelido', + 'email' => 'E-mail', + ], + 'filter' => [ + 'all' => 'todos', + 'options_method_not_exists' => "A classe modelo :model deve definir um método :method() retornando opções para o filtro ':filter'.", + 'date_all' => 'todo o período', + 'number_all' => 'todos os números', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Enviar ficheiro CSV', + 'import_file' => 'Importar ficheiro', + 'row' => 'Linha :row', + 'first_row_contains_titles' => 'Primeira linha contém títulos das colunas', + 'first_row_contains_titles_desc' => 'Deixe marcado se primeira linha do CSV é utilizada como títulos das colunas.', + 'match_columns' => '2. Associar as colunas do ficheiro a campos do base de dados', + 'file_columns' => 'Colunas do ficheiro', + 'database_fields' => 'Campos do base de dados', + 'set_import_options' => '3. Definir opções de importação', + 'export_output_format' => '1. Formato de saída da exportação', + 'file_format' => 'Formato do ficheiro', + 'standard_format' => 'Formato padrão', + 'custom_format' => 'Formato personalizado', + 'delimiter_char' => 'Caracter delimitador', + 'enclosure_char' => 'Caracter qualificador', + 'escape_char' => 'Caracter de escape', + 'select_columns' => '2. Selecione colunas para exportar', + 'column' => 'Coluna', + 'columns' => 'Colunas', + 'set_export_options' => '3. Definir opções de exportação', + 'show_ignored_columns' => 'Mostrar colunas ignoradas', + 'auto_match_columns' => 'Auto associar colunas', + 'created' => 'Criados', + 'updated' => 'Atualizados', + 'skipped' => 'Ignorados', + 'warnings' => 'Alertas', + 'errors' => 'Erros', + 'skipped_rows' => 'Registos ignorados', + 'import_progress' => 'Progresso da importação', + 'processing' => 'Processando', + 'import_error' => 'Erro de importação', + 'upload_valid_csv' => 'Por favor envie um ficheiro CSV válido.', + 'drop_column_here' => 'Soltar coluna aqui...', + 'ignore_this_column' => 'Ignorar esta coluna', + 'processing_successful_line1' => 'Processo de exportação de ficheiro concluído com sucesso!', + 'processing_successful_line2' => 'O navegador agora deve redirecionar automaticamente para o descarregar do ficheiro.', + 'export_progress' => 'Progresso da exportação', + 'export_error' => 'Erro de exportação', + 'column_preview' => 'Prévisualizar coluna', + 'file_not_found_error' => 'Ficheiro não encontrado', + 'empty_error' => 'Não havia dados para exportar', + 'empty_import_columns_error' => 'Por favor, especifique algumas colunas para importar.', + 'match_some_column_error' => 'Por favor, combine algumas colunas primeiro.', + 'required_match_column_error' => 'Por favor, especifique a combinação para o campo requerido :label.', + 'empty_export_columns_error' => 'Por favor, especifique algumas colunas para exportar.', + 'behavior_missing_uselist_error' => 'Deve implementar o comportamento do controlador ListController com a opção de exportação "useList" activada.', + 'missing_model_class_error' => 'Por favor, especifique a propriedade modelo de classe para :type', + 'missing_column_id_error' => 'Identificador de coluna ausente', + 'unknown_column_error' => 'Coluna desconhecida', + 'encoding_not_supported_error' => 'Codificação do arquivo fonte desconhecida. Por favor, selecione a opção "Formato personalizado", com a devida codificação, para importar o arquivo.', + 'encoding_format' => 'Codificação do arquivo', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)', + ], + ], + 'permissions' => [ + 'manage_media' => 'Gerir conteúdo multimédia', + ], + 'mediafinder' => [ + 'label' => 'Localizador de multimédia', + 'default_prompt' => 'Clique no botão %s para localizar um ficheiro multimédia', + 'no_image' => 'A imagem não foi encontrada', + ], + 'media' => [ + 'menu_label' => 'Conteúdos', + 'upload' => 'Enviar', + 'move' => 'Mover', + 'delete' => 'Excluir', + 'add_folder' => 'Adicionar pasta', + 'search' => 'Procurar', + 'display' => 'Mostrar', + 'filter_everything' => 'Tudo', + 'filter_images' => 'Imagens', + 'filter_video' => 'Vídeos', + 'filter_audio' => 'Áudios', + 'filter_documents' => 'Documentos', + 'library' => 'Biblioteca', + 'size' => 'Tamanho', + 'title' => 'Título', + 'last_modified' => 'Última modificação', + 'public_url' => 'URL pública', + 'click_here' => 'Clique aqui', + 'thumbnail_error' => 'Erro ao gerar a miniatura.', + 'return_to_parent' => 'Retornar à diretoria anterior', + 'return_to_parent_label' => 'Acima ..', + 'nothing_selected' => 'Nenhum item selecionado.', + 'multiple_selected' => 'Múltiplos itens selecionados.', + 'uploading_file_num' => 'Enviando :number ficheiro(s)...', + 'uploading_complete' => 'Envio finalizado', + 'uploading_error' => 'Falha no envio', + 'type_blocked' => 'O tipo de ficheiro utilizado é bloqueado por motivos de segurança.', + 'order_by' => 'Ordenar por', + 'direction' => 'Direção', + 'direction_asc' => 'Ascendente', + 'direction_desc' => 'Descendente', + 'folder' => 'Pasta', + 'no_files_found' => 'Nenhum ficheiro encontrado.', + 'delete_empty' => 'Por favor, selecione itens para apagar.', + 'delete_confirm' => 'Deseja apagar o(s) ficheiro(s) selecionado(s)?', + 'error_renaming_file' => 'Erro ao renomear o ficheiro.', + 'new_folder_title' => 'Nova pasta', + 'folder_name' => 'Nome da pasta', + 'error_creating_folder' => 'Erro ao criar a pasta', + 'folder_or_file_exist' => 'Uma pasta ou ficheiro já existe com o nome especificado.', + 'move_empty' => 'Por favor, selecione os itens para mover.', + 'move_popup_title' => 'Mover ficheiros ou pastas', + 'move_destination' => 'Pasta destino', + 'please_select_move_dest' => 'Por favor, selecione a pasta de destino.', + 'move_dest_src_match' => 'Por favor, selecione outra pasta de destino.', + 'empty_library' => 'A biblioteca de multimédia, está vazia. Envie ficheiros ou crie pastas para iniciar.', + 'insert' => 'Inserir', + 'crop_and_insert' => 'Cortar & Inserir', + 'select_single_image' => 'Por favor, selecione uma única imagem.', + 'selection_not_image' => 'O ficheiro selecionado não é uma imagem.', + 'restore' => 'Desfazer todas as alterações', + 'resize' => 'Redimensionar...', + 'selection_mode_normal' => 'Normal', + 'selection_mode_fixed_ratio' => 'Proporção fixa', + 'selection_mode_fixed_size' => 'Tamanho fixo', + 'height' => 'Altura', + 'width' => 'Largura', + 'selection_mode' => 'Modo de seleção', + 'resize_image' => 'Redimensionar imagem', + 'image_size' => 'Tamanho da imagem:', + 'selected_size' => 'Selecionado:', + ], +]; diff --git a/modules/backend/lang/ro/lang.php b/modules/backend/lang/ro/lang.php new file mode 100644 index 0000000..294ffb0 --- /dev/null +++ b/modules/backend/lang/ro/lang.php @@ -0,0 +1,228 @@ + [ + 'invalid_type' => 'Tipul campului folosit este invalid - :type.', + 'options_method_not_exists' => 'Clasa model :model trebuie sa defineasca o metoda :method() returnand optiuni pentru campul ":field".', + ], + 'widget' => [ + 'not_registered' => "Un nume de clasa de widget ':name' nu a fost inregistrat", + 'not_bound' => "Un widget cu numele de clasa ':name' nu a fost mapat la controller", + ], + 'page' => [ + 'untitled' => "Fara titlu", + 'access_denied' => [ + 'label' => "Acces restrictionat", + 'help' => "Nu aveti permisiuni pentru a vizualiza aceasta pagina.", + 'cms_link' => "Inapoi in panoul de administrare", + ], + ], + 'partial' => [ + 'not_found_name' => "Partialul ':name' nu a fost gasit.", + ], + 'account' => [ + 'sign_out' => 'Deconectare', + 'login' => 'Login', + 'reset' => 'Resetare', + 'restore' => 'Restaurare', + 'login_placeholder' => 'login', + 'password_placeholder' => 'password', + 'forgot_password' => "Ati uitat parola?", + 'enter_email' => "Introduceti email", + 'enter_login' => "Introduceti login", + 'email_placeholder' => "email", + 'enter_new_password' => "Introduceti o noua parola", + 'password_reset' => "Resetare parola", + 'restore_success' => "Un mesaj a fost trimis catre adresa de email cu instructiuni pentru resetarea parolei.", + 'restore_error' => "Utilizatorul ':login' nu a fost gasit in sistem.", + 'reset_success' => "Parola a fost resetata cu succes. Va puteti conecta.", + 'reset_error' => "Date invalide pentru resetarea parolei. Va rugam incercati din nou!", + 'reset_fail' => "Eroare la resetarea parolei!", + 'apply' => 'Aplicare', + 'cancel' => 'Anulare', + 'delete' => 'Stergere', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => 'Dashboard', + 'widget_label' => 'Widget', + 'widget_width' => 'Latime', + 'add_widget' => 'Adauga widget', + 'widget_inspector_title' => 'Configurare widget', + 'widget_inspector_description' => 'Configurare raport widget', + 'widget_columns_label' => 'Latime :columns', + 'widget_columns_description' => 'Latime widget, un numar intre 1 si 10.', + 'widget_columns_error' => 'Va rugam sa introduceti latimea widget-ului ca un numar intre 1 si 10.', + 'columns' => '{1} coloana|[2,Inf] coloane', + 'widget_new_row_label' => 'Forteaza rand nou', + 'widget_new_row_description' => 'Amplasare widget pe un rand nou.', + 'widget_title_label' => 'Titlu widget', + 'widget_title_error' => 'Titlul widget-ului este necesar.', + 'status' => [ + 'widget_title_default' => 'Status sistem', + 'online' => 'online', + 'update_available' => '{0} actualizari disponibile!|{1} actualizare disponibila!|[2,Inf] actualizari disponibile!', + ] + ], + 'user' => [ + 'name' => 'Administrator', + 'menu_label' => 'Administratori', + 'menu_description' => 'Gestionare administratori, grupuri si permisiuni.', + 'list_title' => 'Gestionare Administratori', + 'new' => 'Administrator nou', + 'login' => "Login", + 'first_name' => "Prenume", + 'last_name' => "Nume", + 'full_name' => "Nume complet", + 'email' => "Email", + 'groups' => "Grupuri", + 'groups_comment' => "Specificati grupurile aferente acestei persoane.", + 'avatar' => "Avatar", + 'password' => "Parola", + 'password_confirmation' => "Confirmare Parola", + 'superuser' => "Super Utilizator", + 'superuser_comment' => "Bifati aceasta bifa pentru a permite acestei persoane sa aiba acces deplin.", + 'send_invite' => 'Trimitere invitatie prin email', + 'send_invite_comment' => 'Folositi aceasta bifa pentru a trimite o invitatie prin email catre utilizator', + 'delete_confirm' => 'Sunteti sigur(a) ca vreti sa stergeti acest administrator?', + 'return' => 'Intoarcere la lista de administratori', + 'group' => [ + 'name' => 'Grup', + 'name_field' => 'Nume', + 'menu_label' => 'Grupuri', + 'list_title' => 'Gestionare Grupuri', + 'new' => 'Grup Nou de Administratori', + 'delete_confirm' => 'Sunteti sigur(a) ca vreti sa stergeti acest grup de administratori?', + 'return' => 'Intoarcere la lista de grupuri', + ], + 'preferences' => [ + 'not_authenticated' => 'Nu exista niciun utilizator autentificat pentru care sa se incarce sau salveze preferinte.' + ] + ], + 'list' => [ + 'default_title' => 'Lista', + 'search_prompt' => 'Cautare...', + 'no_records' => 'Nu exista inregistari pentru aceasta fereastra.', + 'missing_model' => 'Lista folosita in clasa :class nu are un model definit.', + 'missing_column' => 'Nu exista denifitii pentru coloana :columns.', + 'missing_columns' => 'Lista folosita in clasa :class nu are coloane definite.', + 'missing_definition' => "Lista nu contine o coloana pentru campul ':field'.", + 'behavior_not_ready' => 'Setarile initiale ale listei nu au fost definite, verificati existenta functiei makeLists() in controller.', + 'invalid_column_datetime' => "Valoarea coloanei ':column' nu este un obiect de tip DateTime, verificati existenta unei referinte \$dates in Model?", + 'pagination' => 'Afisare inregistrari: :from-:to din :total', + 'setup_title' => 'Setare lista', + 'setup_help' => 'Folositi bife pentru a selecta coloanele pe care doriti sa le vedeti in lista. Puteti modifica pozitia coloanelor glisandu-le in sus sau in jos.', + 'records_per_page' => 'Inregistari pe pagina', + 'records_per_page_help' => 'Selectati numarul de inregistari care sa fie afisat pe pagina. Sa tineti cont de faptul ca un numar mare de inregistari pe o singura pagina poate sa reduca performanta.', + 'apply_changes' => 'Aplicare schimbari', + 'cancel' => 'Anulare' + ], + 'form' => [ + 'create_title' => "Nou :name", + 'update_title' => "Editare :name", + 'preview_title' => "Previzualizare :name", + 'create_success' => ':name a fost creat cu succes', + 'update_success' => ':name a fost actualizat cu succes', + 'delete_success' => ':name a fost sters cu succes', + 'missing_id' => "ID-ul inregistrarii formularului nu a fost specificat.", + 'missing_model' => 'Formularul folosit in clasa :class nu are un model definit.', + 'missing_definition' => "Formularul nu contine un camp pentru campul ':field'.", + 'not_found' => 'Inregistrarea formularului cu ID-ul :id nu a putut fi gasita.', + 'create' => 'Creare', + 'create_and_close' => 'Creare si inchidere', + 'creating' => 'Se creeaza...', + 'save' => 'Salvare', + 'save_and_close' => 'Salvare si inchidere', + 'saving' => 'Se salveaza...', + 'delete' => 'Stergere', + 'deleting' => 'Se sterge...', + 'undefined_tab' => 'Altele', + 'field_off' => 'Dezactivat', + 'field_on' => 'Activat', + 'add' => 'Adaugare', + 'apply' => 'Aplicare', + 'cancel' => 'Anulare', + 'close' => 'Inchidere', + 'ok' => 'OK', + 'or' => 'sau', + 'confirm_tab_close' => 'Sunteti sigur(a) ca doriti sa inchideti acest tab? Modificarile nesalvate vor fi pierdute.', + 'behavior_not_ready' => 'Setarile initiale ale formularului nu au fost definite, verificati existenta functiei initForm() in controller.', + 'preview_no_files_message' => 'Fisierele nu au fost incarcate', + 'select' => 'Selectare', + 'select_all' => 'Selectează tot', + 'select_none' => 'Selectați niciuna', + ], + 'relation' => [ + 'missing_definition' => "Relatia nu contine definitii pentru campul ':field'.", + 'missing_model' => "Relatia folosita in clasa :class nu are un model definit.", + 'invalid_action_single' => "Aceasta actiune nu poate fi realizata pentru o relatie singulara.", + 'invalid_action_multi' => "Aceasta actiune nu poate fi realizata pentru o relatie multipla.", + 'add' => "Adaugare", + 'add_name' => "Adaugare :name", + 'create' => "Creare", + 'create_name' => "Creare :name", + 'update' => "Actualizare", + 'update_name' => "Actualizare :name", + 'remove' => "Inlaturare", + 'remove_name' => "Inlaturare :name", + 'delete' => "Stergere", + 'delete_name' => "Stergere :name", + ], + 'model' => [ + 'name' => "Model", + 'not_found' => "Modelul ':class' cu ID-ul :id nu a putut fi gasit", + 'missing_id' => "Nu exista niciun ID specificat pentru care sa se realizeze cautarea inregistrarii modelului.", + 'missing_relation' => "Modelul ':class' nu contine o definitie pentru relatia ':relation'.", + 'invalid_class' => "Modelul :model folosit in clasa :class nu este valid, trebuie sa mosteneasca clasa \Model.", + 'mass_assignment_failed' => "Atribuirea in masa a esuat pentru atributul modelului ':attribute'.", + ], + 'warnings' => [ + 'tips' => 'Sfaturi pentru configurarea sistemului', + 'tips_description' => 'Exista anumite conditii care necesita atentie pentru a configura sistemul corect.', + 'permissions' => 'Directorul :name si subdirectoarele sale nu au permisiuni de scriere pentru PHP. Va rugam sa setati permisiunile corespunzatoare pentru acest director.', + 'extension' => 'Libraria PHP :name nu este instalata. Va rugam sa instalati aceasta librarie si apoi sa activati extensia.' + ], + 'editor' => [ + 'menu_label' => 'Preferinte Editor Cod', + 'menu_description' => 'Personalizati preferintele editorului de cod, preferinte precum dimensiunea fontului si culorile folosite.', + 'font_size' => 'Dimensiune font', + 'tab_size' => 'Lungime tab', + 'use_hard_tabs' => 'Indentare folosind tab-uri', + 'code_folding' => 'Code folding', + 'word_wrap' => 'Word wrap', + 'highlight_active_line' => 'Evidentiere linie activa', + 'auto_closing' => 'Inchide automat tag-uri si caractere speciale', + 'show_invisibles' => 'Arata caractere invizibile', + 'show_gutter' => 'Afiseaza panou', + 'theme' => 'Schema culori', + ], + 'tooltips' => [ + 'preview_website' => 'Previzualizare site' + ], + 'mysettings' => [ + 'menu_label' => 'Setarile mele', + 'menu_description' => 'Setarile in legatura cu contul de administrare', + ], + 'myaccount' => [ + 'menu_label' => 'Contul meu', + 'menu_description' => 'Actualizati datele contului, precum nume, adresa de email si parola.', + 'menu_keywords' => 'securitate login' + ], + 'backend_preferences' => [ + 'menu_label' => 'Preferinte administrare', + 'menu_description' => 'Gestionati preferinte limba si setari aspect panou de administrare.', + 'locale' => 'Limba', + 'locale_comment' => 'Selectati limba dorita.', + ], + 'access_log' => [ + 'hint' => 'Acest jurnal afiseaza o lista de conectari reusite, realizate de catre administratori. Inregistrarile sunt pastrate pentru un numar total de :days zile.', + 'menu_label' => 'Jurnal acces', + 'menu_description' => 'Vizualizati o lista de conectari reusite, realizate de catre administratori.', + 'created_at' => 'Data & Ora', + 'login' => 'Login', + 'ip_address' => 'Adresa IP', + 'first_name' => 'Prenume', + 'last_name' => 'Nume', + 'email' => 'Email', + ], +]; diff --git a/modules/backend/lang/rs/lang.php b/modules/backend/lang/rs/lang.php new file mode 100644 index 0000000..17a6d63 --- /dev/null +++ b/modules/backend/lang/rs/lang.php @@ -0,0 +1,639 @@ + [ + 'title' => 'Administratorska sekcija', + 'invalid_login' => 'Unešeni detalji se ne podudaraju sa onima u bazi, pokušajte ponovo.', + ], + 'field' => [ + 'invalid_type' => 'Iskorišćen tip polja nije validan :type.', + 'options_method_invalid_model' => "Atribut ':field' ne vraća validni model. Pokušaj da eksplicitno specificiraš metod opcija za model klase :model.", + 'options_method_not_exists' => "Model klase :model mora definisati metod :method() koji vraća opcije za polje obrasca ':field'.", + 'colors_method_not_exists' => "Model klase :model mora da definiše metod :method() koji vraća heksadecimalne kodove boje za polje obrasca ':field'.", + ], + 'widget' => [ + 'not_registered' => "Klasa posredničkog elementa ':name' nije registrovana", + 'not_bound' => "Kalasa posredničkog elementa ':name' nije vezana za kontroler", + ], + 'page' => [ + 'untitled' => 'Bez naziva', + '404' => [ + 'label' => 'Stranica nije pronađena', + 'help' => "Traženi URL nije pronađen. Možda tražiš nešto drugo?", + 'back_link' => 'Nazad na prošlu stranicu', + ], + 'access_denied' => [ + 'label' => 'Pristup odbijen', + 'help' => "Nemaš odgovarajuće dozvole za pristup ovoj stranici.", + 'cms_link' => 'Nazad na pozadinski sistem', + ], + 'no_database' => [ + 'label' => 'Baza podataka nedostaje', + 'help' => "Baza podataka je neophodna za pristup pozadinskom sistemu. Proveri da li je baza podataka konfigurisana kako treba i pokušaj ponovo.", + 'cms_link' => 'Nazad na početnu stranicu', + ], + ], + 'partial' => [ + 'not_found_name' => "Parcijal ':name' nije pronađen.", + 'invalid_name' => 'Naziv parcijala nije validan: :name.', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Naziv AJAX rukovatelja nije validan: :name.', + 'not_found' => "AJAX rukovatelj ':name' nije pronađen.", + ], + 'account' => [ + 'impersonate' => 'Oponašaj korisnika', + 'impersonate_confirm' => 'Da li zaista želiš da oponašaš ovog korisnika? Možeš se vratiti na originalno stanje kada se izloguješ.', + 'impersonate_success' => 'Sada oponašaš ovog korisnika', + 'impersonate_working' => 'Oponašanje...', + 'impersonating' => 'Oponašanje :full_name', + 'stop_impersonating' => 'Prestani sa oponašanjem', + 'unsuspend' => 'Obustavljena suspenzija', + 'unsuspend_confirm' => 'Da li zaista želiš da obustaviš suspenziju za ovog korisnika?', + 'unsuspend_success' => 'Korisnik više nije supsendovan.', + 'unsuspend_working' => 'Obustavljanje suspenzije...', + 'signed_in_as' => 'Ulogovan kao :full_name', + 'sign_out' => 'Izloguj se', + 'login' => 'Logovanje', + 'reset' => 'Resetuj', + 'restore' => 'Povrati', + 'login_placeholder' => 'login', + 'password_placeholder' => 'lozinka', + 'remember_me' => 'Ostani ulogovan', + 'forgot_password' => 'Zaboravljena lozinka?', + 'enter_email' => 'Unesi svoj email', + 'enter_login' => 'Unesi svoj login', + 'email_placeholder' => 'email', + 'enter_new_password' => 'Unesi novu lozinku', + 'password_reset' => 'Resetovanje lozinke', + 'restore_success' => 'Poruka sa instrukcijama je poslata na vašu adresu.', + 'restore_error' => "Korisnik nije pronađen sa navedenom vrednošću: ':login'", + 'reset_success' => 'Lozinka je resetovana, možeš se ulogovati.', + 'reset_error' => 'Priloženi podaci za resetovanje lozinke nisu validni. Pokušaj ponovo!', + 'reset_fail' => 'Resetovanje lozinke nije moguće!', + 'apply' => 'Primeni', + 'cancel' => 'Otkaži', + 'delete' => 'Izbriši', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => 'Kontrolna tabla', + 'widget_label' => 'Posrednički element', + 'widget_width' => 'Širina', + 'full_width' => 'puna širina', + 'manage_widgets' => 'Upravljanje posredničkim elementima', + 'add_widget' => 'Dodaj posrednički element', + 'widget_inspector_title' => 'Konfiguracija posredničkog elementa', + 'widget_inspector_description' => 'Konfiguriši izveštaj za posrednički element', + 'widget_columns_label' => 'Širina :columns', + 'widget_columns_description' => 'Širina posredničkog elementa, broj između 1 i 12.', + 'widget_columns_error' => 'Unesi širinu posredničkog elementa kao broj između 1 i 12.', + 'columns' => '{1} kolona|[2,Inf] kolone', + 'widget_new_row_label' => 'Novi red na silu', + 'widget_new_row_description' => 'Postavi posrednički element u novi red.', + 'widget_title_label' => 'Naslov posredničkog elementa', + 'widget_title_error' => 'Naslov za posrednički element je neophodan.', + 'reset_layout' => 'Resetuj plan', + 'reset_layout_confirm' => 'Resetuj plan na podrazumevani?', + 'reset_layout_success' => 'Plan je resetovan', + 'make_default' => 'Učini podrazumevanim', + 'make_default_confirm' => 'Postavi trenutni plan kao podrazumevani?', + 'make_default_success' => 'Trenutni plan je sada podrazumevani', + 'collapse_all' => 'Sklopi sve', + 'expand_all' => 'Rasklopi sve', + 'status' => [ + 'widget_title_default' => 'Status sistema', + 'update_available' => '{0} ispravki dostupno!|{1} ispravka dostupna!|[2,Inf] ispravke dostupne!', + 'updates_pending' => 'Čekaju se ispravke softvera', + 'updates_nil' => 'Softver je ažuriran', + 'updates_link' => 'Ažuriraj', + 'warnings_pending' => 'Neki problemi zahtevaju vašu pažnju', + 'warnings_nil' => 'Nema upozorenja za prikaz', + 'warnings_link' => 'Pogled', + 'core_build' => 'Verzija sistema', + 'event_log' => 'Log događaja', + 'request_log' => 'Log zahteva', + 'app_birthday' => 'Na mreži od', + ], + 'welcome' => [ + 'widget_title_default' => 'Dobrodošli', + 'welcome_back_name' => 'Dobrodošli nazad na :app, :name.', + 'welcome_to_name' => 'Dobrodošli na :app, :name.', + 'first_sign_in' => 'Prvi put ste se ulogovali.', + 'last_sign_in' => 'Vaše poslednje logovanje je bilo na', + 'view_access_logs' => 'Prikaži logove pristupa', + 'nice_message' => 'Lep dan želim!', + ], + ], + 'user' => [ + 'name' => 'Administrator', + 'menu_label' => 'Administratori', + 'menu_description' => 'Upravljaj administratorima pozadinskog sistema, grupama i dozvolama.', + 'list_title' => 'Upravljanje administratorima', + 'new' => 'Novi administrator', + 'login' => 'Logovanje', + 'first_name' => 'Ime', + 'last_name' => 'Prezime', + 'full_name' => 'Ime i prezime', + 'email' => 'Email', + 'role_field' => 'Rola', + 'role_comment' => 'Role definišu dozvole korisnika, koje mogu biti pregažene na korisničkom nivou ili preko taba za dozvole.', + 'groups' => 'Grupe', + 'groups_comment' => 'Speicificiraj grupe kojima nalog treba pripadati.', + 'avatar' => 'Avatar', + 'password' => 'Lozinka', + 'password_confirmation' => 'Potvrdi lozinku', + 'permissions' => 'Dozvole', + 'account' => 'Nalog', + 'superuser' => 'Super korisnik', + 'superuser_comment' => 'Dozvoli ovom nalogu pristup svim delovima sistema bez ograničenja. Super korisnici mogu dodavati i upravljati drugim korisnicima.', + 'send_invite' => 'Pošalji pozivnicu preko mejla', + 'send_invite_comment' => 'Pošalji poruku dobrodošlice koja sadrži informacije za logovanje.', + 'delete_confirm' => 'Obriši administratora?', + 'return' => 'Nazad na listu administratora', + 'allow' => 'Dozvoli', + 'inherit' => 'Nasledi', + 'deny' => 'Odbij', + 'activated' => 'Aktiviran', + 'last_login' => 'Poslednje logovanje:', + 'created_at' => 'Napravljen:', + 'updated_at' => 'Ažuriran:', + 'deleted_at' => 'Obrisan:', + 'show_deleted' => 'Prikaži izbrisane', + 'group' => [ + 'name' => 'Grupe', + 'name_field' => 'Naziv', + 'name_comment' => 'Naziv je prikazan u listi grupa u administratorskom obrascu.', + 'description_field' => 'Opis', + 'is_new_user_default_field_label' => 'Osnovna grupa', + 'is_new_user_default_field_comment' => 'Podrazumevano dodaj nove administratore ovoj grupi.', + 'code_field' => 'Kod', + 'code_comment' => 'Unesi jedinstveni kod ako želiš da pristupaš objektu grupe preko API-ja.', + 'menu_label' => 'Upravljaj grupama', + 'list_title' => 'Upravljaj grupama', + 'new' => 'Nova grupa', + 'delete_confirm' => 'Izbriši ovu administratorsku grupu?', + 'return' => 'Nazad na listu grupa', + 'users_count' => 'Korisnici', + ], + 'role' => [ + 'name' => 'Rola', + 'name_field' => 'Naziv', + 'name_comment' => 'Naziv je prikazan u listi rola u administratorskom obrascu.', + 'description_field' => 'Opis', + 'code_field' => 'Kod', + 'code_comment' => 'Unesi jedinstveni kod ako želiš da pristupaš objektu role preko API-ja.', + 'menu_label' => 'Upravljaj rolama', + 'list_title' => 'Upravljaj rolama', + 'new' => 'Nova rola', + 'delete_confirm' => 'Izbriši ovu administratorsku rolu?', + 'return' => 'Nazad na listu rola', + 'users_count' => 'Korisnici', + ], + 'preferences' => [ + 'not_authenticated' => 'Nema autentifikovanog korisnika za učitavanje ili čuvanje podeski.', + ], + 'trashed_hint_title' => 'Ovaj nalog je izbrisan', + 'trashed_hint_desc' => 'Ovaj nalog je izbrisan i neće više moći da se koristi za logovanje. Da ga povratiš, klikni na ikonicu u donjem desnom uglu', + ], + 'list' => [ + 'default_title' => 'Lista', + 'search_prompt' => 'Traži...', + 'no_records' => 'Nema zapisa u ovom pogledu.', + 'missing_model' => 'Lista ponašanja korišćena u klasi :class nema definisan model.', + 'missing_column' => 'Nema definicija za sledeće kolone: :columns.', + 'missing_columns' => 'Lista korišćena u klasi :class nema definisane kolone.', + 'missing_definition' => "Lista ponašanja ne sadrži definiciju za ':field'.", + 'missing_parent_definition' => "Lista ponašanja ne sadrži definiciju za ':definition'.", + 'behavior_not_ready' => 'Lista ponašanja nije inicijalizovana, proveri da li je metoda makeLists() pozvana u kontroleru.', + 'invalid_column_datetime' => "Vrednost kolone ':column' nije DateTime objekat, da li ti nedostaje \$dates referenca u modelu?", + 'pagination' => 'Prikazani zapisi: :from-:to od ukupno :total', + 'first_page' => 'Prva strana', + 'last_page' => 'Poslednja strana', + 'prev_page' => 'Prošla strana', + 'next_page' => 'Sledeća strana', + 'refresh' => 'Osveži', + 'updating' => 'Ažuriranje...', + 'loading' => 'Učitavanje...', + 'setup_title' => 'Podešavanje liste', + 'setup_help' => 'Koristi polja za potvrdu za biranje kolona koje želiš da vidiš u listi. Možeš menjati položaj kolona prevlačenjem na gore ili dole.', + 'records_per_page' => 'Zapisa po strani', + 'records_per_page_help' => 'Izaberi broj zapisa za prikazivanje po strani. Imaj samo na umu da veliki broj zapisa po strani može smanjiti performanse.', + 'check' => 'Proveri', + 'delete_selected' => 'Izbriši izabrane', + 'delete_selected_empty' => 'Nema izabranih zapisa za brisanje.', + 'delete_selected_confirm' => 'Izbriši izabrane zapise?', + 'delete_selected_success' => 'Izabrani zapisi su obrisani.', + 'column_switch_true' => 'Da', + 'column_switch_false' => 'Ne', + ], + 'fileupload' => [ + 'attachment' => 'Prilog', + 'help' => 'Dodaj naslov i opis za ovaj prilog.', + 'title_label' => 'Naslov', + 'description_label' => 'Opis', + 'default_prompt' => 'Klikni na %s ili prevuci fajl ovde za otpremanje', + 'attachment_url' => 'URL priloga', + 'upload_file' => 'Otpremi fajl', + 'upload_error' => 'Greška pri otpremanju', + 'remove_confirm' => 'Da li si siguran?', + 'remove_file' => 'Izbriši fajl', + ], + 'repeater' => [ + 'add_new_item' => 'Dodaj novi element', + 'min_items_failed' => 'Ponavljač :name zahteva minimum :min elementa, samo :items je obezbeđeno', + 'max_items_failed' => 'Ponavljač :name može imati maksimum :max elemenata, :items je obezbeđeno', + ], + 'form' => [ + 'create_title' => 'Nova :name', + 'update_title' => 'Izmeni :name', + 'preview_title' => 'Pregledaj :name', + 'create_success' => ':name napravljen', + 'update_success' => ':name ažuriran', + 'delete_success' => ':name obrisan', + 'restore_success' => ':name povraćen', + 'reset_success' => 'Resetovanje završeno', + 'missing_id' => 'ID obrasca nije specificiran.', + 'missing_model' => 'Ponašanje obrasca koje se koristi u klasi :class nema definisan model.', + 'missing_definition' => "Ponašanje obrasca ne sadrži sledeće polje: ':field'.", + 'not_found' => 'Zapis obrasca sa identifikatorom :id nije pronađen.', + 'action_confirm' => 'Da li ste sigurni?', + 'create' => 'Napravi', + 'create_and_close' => 'Napravi i zatvori', + 'creating' => 'Pravljenje...', + 'creating_name' => 'Pravljenje :name...', + 'save' => 'Sačuvaj', + 'save_and_close' => 'Sačuvaj i zatvori', + 'saving' => 'Čuvanje...', + 'saving_name' => 'Čuvanje :name...', + 'delete' => 'Izbriši', + 'deleting' => 'Brisanje...', + 'confirm_delete' => 'Izbriši zapis?', + 'confirm_delete_multiple' => 'Izbriši odabrane zapise?', + 'deleting_name' => 'Brisanje :name...', + 'restore' => 'Povrati', + 'restoring' => 'Vraćanje...', + 'confirm_restore' => 'Da li zaista želite da povratite ovaj zapis?', + 'reset_default' => 'Resetuj na osnovno', + 'resetting' => 'Resetovanje', + 'resetting_name' => 'Resetovanje :name', + 'undefined_tab' => 'Razno', + 'field_off' => 'Isključi', + 'field_on' => 'Uključi', + 'add' => 'Dodaj', + 'apply' => 'Primeni', + 'cancel' => 'Poništi', + 'close' => 'Zatvori', + 'confirm' => 'Potvrdi', + 'reload' => 'Ponovo učitaj', + 'complete' => 'Kompletno', + 'ok' => 'OK', + 'or' => 'ili', + 'confirm_tab_close' => 'Zatvori tab? Nesačuvane promene će biti izgubljene.', + 'behavior_not_ready' => 'Ponašanje obrasca se nije inicijalizovalo, proveri da li je metoda initForm() pozvana.', + 'preview_no_files_message' => 'Nema otpremljenih fajlova.', + 'preview_no_media_message' => 'Nema izabranih medija.', + 'preview_no_record_message' => 'Nema izabranih zapisa.', + 'select' => 'Izaberi', + 'select_all' => 'Izaberi sve', + 'select_none' => 'Ukloni odabire', + 'select_placeholder' => 'izaberi', + 'insert_row' => 'Ubaci red', + 'insert_row_below' => 'Ubaci red ispod', + 'delete_row' => 'Izbriši red', + 'concurrency_file_changed_title' => 'Fajl je izmenjen', + 'concurrency_file_changed_description' => "Fajl nad kojim je rađeno je u međuvremenu promenjen od strane drugog korisnika. Možeš ponovo da ga učitaš i izgubiš svoje promene, ili ga jednostavno pregaziš.", + 'return_to_list' => 'Nazad na listu', + ], + 'recordfinder' => [ + 'find_record' => 'Pronađi zapis', + 'invalid_model_class' => 'Klasa modela ":modelClass" za pretragu nije validna', + 'cancel' => 'Otkaži', + ], + 'pagelist' => [ + 'page_link' => 'Link strane', + 'select_page' => 'Izaberi stranu...', + ], + 'relation' => [ + 'missing_config' => "Relacioni odnos nema konfiguraciju za ':config'.", + 'missing_definition' => "Relacioni odnos ne sadrži definiciju za polje ':field'.", + 'missing_model' => 'Relacioni odnos korišćen u klasi :class nema definisan model.', + 'invalid_action_single' => 'Ova radnja se ne može izvršiti na jednoj vezi.', + 'invalid_action_multi' => 'Ova radnja se ne može izvršiti na više veza.', + 'help' => 'Klikni na element za dodavanje', + 'related_data' => 'Srodni podatak: :name', + 'add' => 'Dodaj', + 'add_selected' => 'Dodaj izabrane', + 'add_a_new' => 'Dodaj novu :name', + 'link_selected' => 'Zakači izabrane', + 'link_a_new' => 'Zakači novu :name', + 'cancel' => 'Otkaži', + 'close' => 'Zatvori', + 'add_name' => 'Dodaj :name', + 'create' => 'Napravi', + 'create_name' => 'Napravi :name', + 'update' => 'Ažuriraj', + 'update_name' => 'Ažuriraj :name', + 'preview' => 'Pregledaj', + 'preview_name' => 'Pregledaj :name', + 'remove' => 'Ukloni', + 'remove_name' => 'Ukloni :name', + 'delete' => 'Izbriši', + 'delete_name' => 'Izbriši :name', + 'delete_confirm' => 'Da li ste sigurni?', + 'link' => 'Zakači', + 'link_name' => 'Zakači :name', + 'unlink' => 'Otkači', + 'unlink_name' => 'Otkači :name', + 'unlink_confirm' => 'Da li ste sigurni?', + ], + 'reorder' => [ + 'default_title' => 'Promeni redosled', + 'no_records' => 'Ne postoje elementi za razmeštanje.', + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => "Model ':class' sa odabranim identifikatorom :id nije pronađen", + 'missing_id' => 'ID za pretragu modela nije specificiran.', + 'missing_relation' => "Model ':class' ne sadrži definiciju za relaciju: ':relation'.", + 'missing_method' => "Model ':class' ne sadrži metod: ':method'.", + 'invalid_class' => "Model :model korišćen u klasi :class nije validan, mora da nasledi klasu \Model.", + 'mass_assignment_failed' => "Greška pri masovnom dodeljivanju za atribut modela: ':attribute'.", + ], + 'warnings' => [ + 'tips' => 'Saveti za konfigurisanje sistema', + 'tips_description' => 'Postoje problemi na koje bi trebalo da obratiš pažnju da bi konfigurisao sistem kako treba.', + 'permissions' => 'PHP ne može pristupiti direktorijumu :name ili njegovim poddirektorijuma zarad upisivanja. Promeni RWX dozvole na serveru za ovaj direktorijum.', + 'extension' => 'Produžetak za PHP :name nije instaliran. Instaliraj ovu biblioteku i produžetak.', + 'plugin_missing' => 'Produžetak :name je obavezan ali nije instaliran. Instaliraj ovaj produžetak.', + 'debug' => 'Uključen je mod za ispravljanje grešaka što nije preporučljivo.', + 'decompileBackendAssets' => 'Sredstva u pozadinskom sistemu trenutno nisu kompajlovana što nije preporučljivo.', + ], + 'editor' => [ + 'menu_label' => 'Podešavanje editora', + 'menu_description' => 'Izmeni postavke globalnog editora, kao što su veličina fonta, boje, itd.', + 'font_size' => 'Veličina fonta', + 'tab_size' => 'Veličina taba', + 'use_hard_tabs' => 'Uvođenje pomoću tabova', + 'code_folding' => 'Presavijanje koda', + 'code_folding_begin' => 'Označi početak', + 'code_folding_begin_end' => 'Označi početak i kraj', + 'autocompletion' => 'Automatsko dovršavanje', + 'word_wrap' => 'Prelomi redove', + 'highlight_active_line' => 'Istakni aktivne linije', + 'auto_closing' => 'Automatski zatvori tagove', + 'show_invisibles' => 'Prikaži nevidljive karaktere', + 'show_gutter' => 'Prikaži margine za povezivanje', + 'basic_autocompletion' => 'Osnovno automatsko dovršavanje (Ctrl + Space)', + 'live_autocompletion' => 'Instant automatsko dovršavanje', + 'enable_snippets' => 'Uključi isečke za kod (Tab)', + 'display_indent_guides' => 'Prikaži pomoćne margine za uvođenje', + 'show_print_margin' => 'Prikaži margine za štampu', + 'mode_off' => 'Isključen mod', + 'mode_fluid' => 'Fluidan mod', + '40_characters' => '40 karaktera', + '80_characters' => '80 karaktera', + 'theme' => 'Boje', + 'markup_styles' => 'Stilovi označavanja', + 'custom_styles' => 'Proizvoljni stilovi', + 'custom styles_comment' => 'Proizvoljni stilovi za uključivanje u HTML editor.', + 'markup_classes' => 'Klase označavanja', + 'paragraph' => 'Paragraf', + 'link' => 'Link', + 'table' => 'Tabela', + 'table_cell' => 'Ćelija tabele', + 'image' => 'Slika', + 'label' => 'Oznaka', + 'class_name' => 'Naziv klase', + 'markup_tags' => 'Tagovi označavanja', + 'allowed_empty_tags' => 'Dozvoljeni prazni tagovi', + 'allowed_empty_tags_comment' => 'Lista tagova koji se ne brišu kada nemaju sadržaj.', + 'allowed_tags' => 'Dozvoljeni tagovi', + 'allowed_tags_comment' => 'Lista dozvoljenih tagova.', + 'no_wrap' => 'Ne umeći tagove', + 'no_wrap_comment' => 'Lista tagova koji se ne trebaju umetati u blokovske tagove.', + 'remove_tags' => 'Ukloni tagove', + 'remove_tags_comment' => 'Lista tagova koji se brišu zajedno sa njihovim sadržajem.', + 'line_breaker_tags' => 'Tagovi za liniju prekida', + 'line_breaker_tags_comment' => 'Lista tagova koji se koriste za postavljanje linije prekida za elemente.', + 'toolbar_buttons' => 'Traka sa alatkama', + 'toolbar_buttons_comment' => 'Traka sa alatkama će obično biti prikazana u editoru.', + 'toolbar_buttons_preset' => 'Ubaci već podešenu konfiguraciju za traku sa alatkama:', + 'toolbar_buttons_presets' => [ + 'default' => 'Osnovna', + 'minimal' => 'Minimalna', + 'full' => 'Kompletna', + ], + ], + 'tooltips' => [ + 'preview_website' => 'Pregledaj sajt', + ], + 'mysettings' => [ + 'menu_label' => 'Moja podešavanja', + 'menu_description' => 'Podešavanja vezana za administratorski nalog', + ], + 'myaccount' => [ + 'menu_label' => 'Moj nalog', + 'menu_description' => 'Ažuriraj detalje svog naloga kao što su ime, prezime, email adresa i lozinka.', + 'menu_keywords' => 'bezbednosno logovanje', + ], + 'branding' => [ + 'menu_label' => 'Izmene pozadinskog sistema', + 'menu_description' => 'Izmene za administratorsku sekciju poput naziva, boja, logoa, itd.', + 'brand' => 'Brend', + 'logo' => 'Logo', + 'logo_description' => 'Otpremi željeni logo za pozadinski sistem.', + 'favicon' => 'Ikonica', + 'favicon_description' => 'Otpremi željenu ikonicu za pozadinski sistem.', + 'app_name' => 'Naziv aplikacije', + 'app_name_description' => 'Ovo ime će se prikazati kao naslov pozadinskog sistema.', + 'app_tagline' => 'Slogan aplikacije', + 'app_tagline_description' => 'Ovaj slogan će se prikazati na strani za logovanje na pozadinski sistem.', + 'colors' => 'Boje', + 'primary_color' => 'Primarne boje', + 'secondary_color' => 'Sekundarne boje', + 'accent_color' => 'Akcentovane boje', + 'styles' => 'Stilovi', + 'custom_stylesheet' => 'Proizvoljni stil', + 'navigation' => 'Navigacija', + 'menu_mode' => 'Stil menija', + 'menu_mode_inline' => 'Uveden', + 'menu_mode_inline_no_icons' => 'Uveden (bez ikonica)', + 'menu_mode_tile' => 'Poređan', + 'menu_mode_collapsed' => 'Sklopljen', + ], + 'backend_preferences' => [ + 'menu_label' => 'Postavke pozadinskog sistema', + 'menu_description' => 'Upravljaj postavkama tvog naloga.', + 'region' => 'Region', + 'code_editor' => 'Editor koda', + 'timezone' => 'Vremenska zona', + 'timezone_comment' => 'Podesi prikazane datume na osnovu ove vremenske zone.', + 'locale' => 'Prevod', + 'locale_comment' => 'Izaberi željeni jezik prevoda.', + ], + 'access_log' => [ + 'hint' => 'Ovaj log prikazuje listu uspešnih logova od strane administratora. Logovi se čuvaju ukupno :days dana.', + 'menu_label' => 'Logovi pristupa', + 'menu_description' => 'Prikaži listu uspešnih logovanja na pozadinski sistem.', + 'id' => 'ID', + 'created_at' => 'Datum & vreme', + 'type' => 'Tip', + 'login' => 'Logovanje', + 'ip_address' => 'IP adresa', + 'first_name' => 'Ime', + 'last_name' => 'Prezime', + 'email' => 'Email', + ], + 'filter' => [ + 'all' => 'svi', + 'options_method_not_exists' => "Model klase :model mora definisati povratne opcije metoda :method() za ':filter' filter.", + 'date_all' => 'svi periodi', + 'number_all' => 'svi brojevi', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Otpremi CSV fajl', + 'import_file' => 'Uvezi fajl', + 'row' => 'Red :row', + 'first_row_contains_titles' => 'Prvi red sadrži naslove kolona', + 'first_row_contains_titles_desc' => 'Ostavite ovo polje označeno ako se prvi red u CSV fajlu koristi za naslove kolona.', + 'match_columns' => '2. Upari kolone fajla sa kolonama baze podataka', + 'file_columns' => 'Kolone fajla', + 'database_fields' => 'Polja u bazi podataka', + 'set_import_options' => '3. Postavi uvozne opcije', + 'export_output_format' => '1. Izvezi izlazni format', + 'file_format' => 'Format fajla', + 'standard_format' => 'Standardni format', + 'custom_format' => 'Proizvoljni format', + 'delimiter_char' => 'Granični znak', + 'enclosure_char' => 'Ogradni znak', + 'escape_char' => 'Komandni znak', + 'select_columns' => '2. Izaberi kolone za izvoz', + 'column' => 'Kolona', + 'columns' => 'Kolone', + 'set_export_options' => '3. Postavi izvozne opcije', + 'show_ignored_columns' => 'Prikaži ignorisane kolone', + 'auto_match_columns' => 'Automatski upari kolone', + 'created' => 'Napravljeni', + 'updated' => 'Ažurirani', + 'skipped' => 'Preskočeni', + 'warnings' => 'Upozorenja', + 'errors' => 'Greške', + 'skipped_rows' => 'Preskočeni redovi', + 'import_progress' => 'Progres uvoza', + 'processing' => 'Procesovanje', + 'import_error' => 'Greška pri uvozu', + 'upload_valid_csv' => 'Otpremi validan CSV fajl.', + 'drop_column_here' => 'Spusti kolonu ovde...', + 'ignore_this_column' => 'Ignoriši ovu kolonu', + 'processing_successful_line1' => 'Proces izvoza fajla je završen!', + 'processing_successful_line2' => 'Pretraživač će sada biti preusmeren na fajl za preuzimanje.', + 'export_progress' => 'Progres izvoza', + 'export_error' => 'Greška pri izvozu', + 'column_preview' => 'Pregled kolone', + 'file_not_found_error' => 'Fajl nije pronađen', + 'empty_error' => 'Nije bilo podataka za izvoz', + 'empty_import_columns_error' => 'Specificiraj neke kolone za uvoz.', + 'match_some_column_error' => 'Upari prvo neke kolone.', + 'required_match_column_error' => 'Specificiraj par za obavezno polje: :label.', + 'empty_export_columns_error' => 'Specificiraj kolone za izvoz.', + 'behavior_missing_uselist_error' => 'Moraš implementirati ponašanje za "ListController" sa omogućenom opcijom izvoza - "useList."', + 'missing_model_class_error' => 'Izaberi svojstvo modela kalse za svojstvo: :type', + 'missing_column_id_error' => 'Identifikator kolone ne postoji', + 'unknown_column_error' => 'Nepoznata kolona', + 'encoding_not_supported_error' => 'Kodiranje izvorne datoteke nije prepoznato. Izaberite opciju prilagođenog formata datoteke sa odgovarajućim kodiranjem da biste uvezli datoteku.', + 'encoding_format' => 'Format enkodovanja', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Zapadnoevropski)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Srednjoevropski)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, Južnoevropski)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, Severnoevropski)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Ćirilični)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arapski)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Grčki)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrejski)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turski)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordijski)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Tajlandski)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltički region)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Keltski)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Zapadnoevropska revizija sa euro znakom)', + 'windows_1250' => 'Windows-1250 (CP1250, Severnoevropski i istočnoevropski)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)', + ], + ], + 'permissions' => [ + 'manage_media' => 'Otpremi i upravljaj medijima - slikama, video i audio zapisima, dokumentima', + ], + 'mediafinder' => [ + 'label' => 'Pretražuj medije', + 'default_prompt' => 'Klikni na %s dugme za traženje elementa', + 'no_image' => 'Slika nije pronađena', + ], + 'media' => [ + 'menu_label' => 'Mediji', + 'upload' => 'Otpremanje', + 'move' => 'Pomeri', + 'delete' => 'Izbriši', + 'add_folder' => 'Dodaj direktorijum', + 'search' => 'Traži', + 'display' => 'Prikaži', + 'filter_everything' => 'Sve', + 'filter_images' => 'Slike', + 'filter_video' => 'Video zapisi', + 'filter_audio' => 'Audio zapisi', + 'filter_documents' => 'Dokumenta', + 'library' => 'Biblioteka', + 'size' => 'Veličina', + 'title' => 'Naslov', + 'last_modified' => 'Poslednja modifikacija', + 'public_url' => 'URL', + 'click_here' => 'Klikni ovde', + 'thumbnail_error' => 'Greška pri generisanju pregledne slike.', + 'return_to_parent' => 'Nazad na nadređeni direktorijum', + 'return_to_parent_label' => 'Idi nazad ..', + 'nothing_selected' => 'Ništa nije izabrano.', + 'multiple_selected' => 'Više elemenata je izabrano.', + 'uploading_file_num' => 'Otpremi :number fajl(ova)...', + 'uploading_complete' => 'Otpremanje završeno', + 'uploading_error' => 'Otpremanje neuspešno', + 'type_blocked' => 'Fajl je blokiran iz bezbednosnih razloga.', + 'order_by' => 'Sortiraj po', + 'direction' => 'Pravac', + 'direction_asc' => 'Uzlazni', + 'direction_desc' => 'Silazni', + 'folder' => 'Direktorijum', + 'no_files_found' => 'Nijedan fajl nije pronađen.', + 'delete_empty' => 'Izaberi elemente za brisanje.', + 'delete_confirm' => 'Izbriši odabran element(e)?', + 'error_renaming_file' => 'Greška pri promeni naziva elementa.', + 'new_folder_title' => 'Novi direktorijum', + 'folder_name' => 'Naziv direktorijuma', + 'error_creating_folder' => 'Greška pri pravljenju direktorijuma', + 'folder_or_file_exist' => 'Direktorijum ili fajl sa navedenim nazivom već postoji.', + 'move_empty' => 'Izaberi elemente za pomeranje.', + 'move_popup_title' => 'Pomeri fajlove ili direktorijume', + 'move_destination' => 'Odredišni direktorijum', + 'please_select_move_dest' => 'Izaberi odredišni direktorijum.', + 'move_dest_src_match' => 'Izaberi drugi odredišni direktorijum.', + 'empty_library' => 'Otpremi fajlove ili napravi direktorijume.', + 'insert' => 'Ubaci', + 'crop_and_insert' => 'Iseci & ubaci', + 'select_single_image' => 'Izaberi jednu sliku.', + 'selection_not_image' => 'Izabrani element nije slika.', + 'restore' => 'Poništi sve promene', + 'resize' => 'Promeni veličinu...', + 'selection_mode_normal' => 'Normalna', + 'selection_mode_fixed_ratio' => 'Fiksirani odnos', + 'selection_mode_fixed_size' => 'Fiksirana veličina', + 'height' => 'Visina', + 'width' => 'Širina', + 'selection_mode' => 'Mod selekcije', + 'resize_image' => 'Promeni veličinu slike', + 'image_size' => 'Veličina slike:', + 'selected_size' => 'Izabrana veličina:', + ], +]; diff --git a/modules/backend/lang/ru/lang.php b/modules/backend/lang/ru/lang.php new file mode 100644 index 0000000..9e4d886 --- /dev/null +++ b/modules/backend/lang/ru/lang.php @@ -0,0 +1,646 @@ + [ + 'title' => 'Панель управления', + 'invalid_login' => 'Вы ввели некорректные данные. Пожалуйста, перепроверьте их и попробуйте ещё раз.' + ], + 'field' => [ + 'invalid_type' => 'Использован неверный тип поля: :type.', + 'options_method_invalid_model' => "Атрибут ':field' не соответствует допустимой модели. Попробуйте явно указать метод параметров для класса :model .", + 'options_method_not_exists' => "Класс модели :model должен содержать метод :method(), возвращающий опции для поля формы ':field'.", + 'options_static_method_invalid_value' => "Статический метод ':method()' в :class не вернул допустимый массив параметров.", + 'colors_method_not_exists' => "Класс модели :model должен содержать метод :method(), возвращающий HTML цвет в HEX для поля формы ':field'.", + ], + 'widget' => [ + 'not_registered' => "Класс виджета ':name' не зарегистрирован.", + 'not_bound' => "Виджет с именем класса ':name' не связан с контроллером.", + ], + 'page' => [ + 'untitled' => 'Без названия', + '404' => [ + 'label' => 'Страница не найдена', + 'help' => 'Мы тщательно искали, но запрошенный URL так и не смогли найти. Может быть вы искали что то ещё?', + 'back_link' => 'Вернуться к предыдущей странице', + ], + 'access_denied' => [ + 'label' => 'Доступ запрещен', + 'help' => 'У вас нет необходимых прав для просмотра этой страницы.', + 'cms_link' => 'Перейти к CMS', + ], + 'no_database' => [ + 'label' => 'Отсутствует база данных', + 'help' => "Для доступа к серверу требуется база данных. Проверьте, что база данных настроена и перенесена, прежде чем повторять попытку.", + 'cms_link' => 'Вернуться на главную страницу', + ], + ], + 'partial' => [ + 'not_found_name' => 'Не удалось найти фрагмент (partial) с именем :name.', + 'invalid_name' => 'Неправильное имя фрагмента: :name.', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Неправильное имя AJAX обработчика: :name.', + 'not_found' => "AJAX обработчик ':name' не найден.", + ], + 'account' => [ + 'impersonate' => 'Имперсонация пользователя', + 'impersonate_confirm' => 'Вы уверены, что хотите имперсонировать себя в качестве этого пользователя? Вы сможете вернуться в исходное состояние выйдя из системы.', + 'impersonate_success' => 'Теперь вы имперсонированы как этот пользователь', + 'impersonate_working' => 'Имперсонация...', + 'impersonating' => 'Имперсонация :full_name', + 'stop_impersonating' => 'Остановить имперсонацию', + 'unsuspend' => 'Приостановлен', + 'unsuspend_confirm' => 'Вы уверены что хотите приостановить данного пользователя?', + 'unsuspend_success' => 'Пользователь был приостановлен.', + 'unsuspend_working' => 'Приостановка...', + 'signed_in_as' => 'Выполнен вход как :full_name', + 'sign_out' => 'Выйти', + 'login' => 'Вход', + 'reset' => 'Сбросить', + 'restore' => 'Восстановить', + 'login_placeholder' => 'пользователь', + 'password_placeholder' => 'пароль', + 'remember_me' => 'Оставаться в системе', + 'forgot_password' => 'Забыли пароль?', + 'enter_email' => 'Введите ваш Email', + 'enter_login' => 'Введите ваш Логин', + 'email_placeholder' => 'email', + 'enter_new_password' => 'Введите новый пароль', + 'password_reset' => 'Сбросить пароль', + 'restore_success' => 'На вашу электронную почту отправлено сообщение с инструкциями для восстановления пароля.', + 'restore_error' => "Пользователь с логином ':login' не найден.", + 'reset_success' => 'Ваш пароль был успешно изменен. Теперь вы можете войти на сайт.', + 'reset_error' => 'Недействительные данные для изменения пароля. Пожалуйста, попробуйте еще раз!', + 'reset_fail' => 'Невозможно изменить пароль!', + 'apply' => 'Применить', + 'cancel' => 'Отменить', + 'delete' => 'Удалить', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => 'Панель управления', + 'widget_label' => 'Виджет', + 'widget_width' => 'Ширина', + 'full_width' => 'полная ширина', + 'manage_widgets' => 'Управление виджетами', + 'add_widget' => 'Добавить виджет', + 'widget_inspector_title' => 'Конфигурации виджета', + 'widget_inspector_description' => 'Настройка отображения виджета', + 'widget_columns_label' => 'Ширина :columns', + 'widget_columns_description' => 'Ширина виджета может варьироваться от 1 до 10.', + 'widget_columns_error' => 'Пожалуйста, выберите ширину виджета.', + 'columns' => '{1} колонка|[2,4] колонки|[5,Inf] колонок', + 'widget_new_row_label' => 'Новая строка', + 'widget_new_row_description' => 'Поставить виджет с новой строки.', + 'widget_title_label' => 'Заголовок', + 'widget_title_error' => 'Заголовок виджета обязателен.', + 'reset_layout' => 'Сбросить расположение', + 'reset_layout_confirm' => 'Сбросить расположение к расположению по умолчанию?', + 'reset_layout_success' => 'Расположение было сброшено', + 'make_default' => 'Сохранить по умолчанию', + 'make_default_confirm' => 'Сделать текущее расположение расположением по умолчанию?', + 'make_default_success' => 'Текущее расположение сохранено как расположение по умолчанию', + 'collapse_all' => 'Свернуть всё', + 'expand_all' => 'Развернуть всё', + 'status' => [ + 'widget_title_default' => 'Статус системы', + 'update_available' => '{0} нет новых обновлений!|{1} доступно новое обновление!|[2,Inf] доступны новые обновления!', + 'updates_pending' => 'Доступны обновления', + 'updates_nil' => 'Используется последняя версия', + 'updates_link' => 'Обновить', + 'warnings_pending' => 'Требуется ваше внимание', + 'warnings_nil' => 'Ошибок нет', + 'warnings_link' => 'Просмотр', + 'core_build' => 'Сборка', + 'event_log' => 'Лог событий', + 'request_log' => 'Лог запросов', + 'app_birthday' => 'Онлайн с', + ], + 'welcome' => [ + 'widget_title_default' => 'Добро пожаловать', + 'welcome_back_name' => 'С возвращением в :app, :name.', + 'welcome_to_name' => 'Добро пожаловать в :app, :name.', + 'first_sign_in' => 'Это первый раз, когда вы вошли в систему.', + 'last_sign_in' => 'Последний раз вы заходили', + 'view_access_logs' => 'Посмотреть лог доступа', + 'nice_message' => 'Хорошего дня!', + ], + ], + 'user' => [ + 'name' => 'Администратора', + 'menu_label' => 'Администраторы', + 'menu_description' => 'Управление группой администраторов, создание групп и разрешений.', + 'list_title' => 'Управление администраторами', + 'new' => 'Добавить администратора', + 'login' => 'Логин', + 'first_name' => 'Имя', + 'last_name' => 'Фамилия', + 'full_name' => 'Полное имя', + 'email' => 'Почта', + 'role_field' => 'Роль', + 'role_comment' => 'Роли определяют уровни доступа пользователей, которые могут быть изменены на уровне пользователя, на вкладке "Разрешения".', + 'groups' => 'Группы', + 'groups_comment' => 'Укажите, к какой группе должен принадлежать этот аккаунт.', + 'avatar' => 'Аватар', + 'password' => 'Пароль', + 'password_confirmation' => 'Подтверждение пароля', + 'permissions' => 'Полномочия', + 'account' => 'Аккаунт', + 'superuser' => 'Суперпользователь', + 'superuser_comment' => 'Предоставляет этому аккаунту неограниченный доступ ко всем областям.', + 'send_invite' => 'Отправить приглашение по электронной почте', + 'send_invite_comment' => 'Отправляет приветственное сообщение, содержащее информацию о логине и пароле.', + 'delete_confirm' => 'Вы действительно хотите удалить этого администратора?', + 'return' => 'Вернуться к списку администраторов', + 'allow' => 'Разрешить', + 'inherit' => 'Наследовать', + 'deny' => 'Запретить', + 'activated' => 'Активирован', + 'last_login' => 'Последний вход', + 'created_at' => 'Создан', + 'updated_at' => 'Обновлен', + 'deleted_at' => 'Удален', + 'show_deleted' => 'Показать удаленных', + 'group' => [ + 'name' => 'Группы', + 'name_field' => 'Название', + 'name_comment' => 'Название отображается в списке групп в форме создания/редактирования администраторов.', + 'description_field' => 'Описание', + 'is_new_user_default_field_label' => 'Группа по умолчанию', + 'is_new_user_default_field_comment' => 'Добавлять новых администраторов в эту группу по умолчанию.', + 'code_field' => 'Уникальный код', + 'code_comment' => 'Введите уникальный код, если вы хотите открыть доступ к нему с помощью API.', + 'menu_label' => 'Группы', + 'list_title' => 'Управление группами', + 'new' => 'Добавить группу', + 'delete_confirm' => 'Вы действительно хотите удалить эту группу администраторов?', + 'return' => 'Вернуться к списку групп', + 'users_count' => 'Пользователи', + ], + 'role' => [ + 'name' => 'Роль', + 'name_field' => 'Название', + 'name_comment' => 'Название отображается в списке ролей в форме "Администратор".', + 'description_field' => 'Описание', + 'code_field' => 'Код', + 'code_comment' => 'Введите уникальный код, если вы хотите получить доступ к объекту роли при помощи API.', + 'menu_label' => 'Управление ролями', + 'list_title' => 'Управление ролями', + 'new' => 'Новая роль', + 'delete_confirm' => 'Удалить эту роль администратора?', + 'return' => 'Вернуться к списку ролей', + 'users_count' => 'Пользователи', + ], + 'preferences' => [ + 'not_authenticated' => 'Невозможно загрузить или сохранить настройки для неавторизованного пользователя.', + ], + 'trashed_hint_title' => 'Этот аккаунт был удален', + 'trashed_hint_desc' => 'Этот аккаунт был удален и не может быть авторизован. Чтобы восстановить его, нажмите иконку восстановления пользователя в правом нижнем углу.', + ], + 'list' => [ + 'default_title' => 'Список', + 'search_prompt' => 'Поиск...', + 'no_records' => 'По вашему запросу ничего не найдено.', + 'missing_model' => 'Для списка используемого в :class не определена модель.', + 'missing_column' => 'Нет никаких определений столбца для :columns.', + 'missing_columns' => 'Список используемый в :class не имеет никаких столбцов.', + 'missing_definition' => "Поведение списка не содержит столбец для ':field'.", + 'missing_parent_definition' => "Поведение списка не содержит определения для ':definition'.", + 'behavior_not_ready' => 'Поведение списка не было инициализировано, проверьте вызов makeLists() в вашем контроллере.', + 'invalid_column_datetime' => "Значение столбца ':column' не является объектом DateTime. Отсутствует \$dates ссылка в модели?", + 'pagination' => 'Отображено записей: :from-:to из :total', + 'first_page' => 'Первая страница', + 'last_page' => 'Последняя страница', + 'prev_page' => 'Предыдущая страница', + 'next_page' => 'Следующая страница', + 'refresh' => 'Обновить', + 'updating' => 'Обновление...', + 'loading' => 'Загрузка...', + 'setup_title' => 'Настройка списка', + 'setup_help' => 'Используйте флажки для выбора колонок, которые вы хотите видеть в списке. Вы можете изменить положение столбцов, перетаскивая их вверх или вниз.', + 'records_per_page' => 'Записей на странице', + 'records_per_page_help' => 'Выберите количество записей на странице для отображения. Обратите внимание, что большое количество записей на одной странице может привести к снижению производительности.', + 'check' => 'Проверить', + 'delete_selected' => 'Удалить выбранное', + 'delete_selected_empty' => 'Нет выбранных записей для удаления.', + 'delete_selected_confirm' => 'Удалить выбранные записи?', + 'delete_selected_success' => 'Выбранные записи успешно удалены.', + 'column_switch_true' => 'Да', + 'column_switch_false' => 'Нет', + ], + 'fileupload' => [ + 'attachment' => 'Приложение', + 'help' => 'Добавьте заголовок и описание для этого вложения.', + 'title_label' => 'Название', + 'description_label' => 'Описание', + 'default_prompt' => 'Кликните по %s или перетащите файл сюда для загрузки', + 'attachment_url' => 'URL', + 'upload_file' => 'Загрузить файл', + 'upload_error' => 'Ошибка загрузки', + 'remove_confirm' => 'Вы уверены?', + 'remove_file' => 'Удалить файл', + ], + 'repeater' => [ + 'add_new_item' => 'Добавить новый объект', + 'min_items_failed' => ':name требует минимум :min объектов, было передано только :items', + 'max_items_failed' => ':name позволяет передать максимум :max объектов, было передано :items', + ], + 'form' => [ + 'create_title' => 'Создание :name', + 'update_title' => 'Редактирование :name', + 'preview_title' => 'Предпросмотр :name', + 'create_success' => ':name был успешно создан', + 'update_success' => ':name был успешно сохранен', + 'delete_success' => ':name был успешно удален', + 'restore_success' => ':name восстановлен', + 'reset_success' => 'Сброс завершен', + 'missing_id' => 'Идентификатор формы записи не указан.', + 'missing_model' => 'Для формы используемой в :class не определена модель.', + 'missing_definition' => "Поведение формы не содержит поле для':field'.", + 'not_found' => 'Форма записи с идентификатором :ID не найдена.', + 'action_confirm' => 'Вы уверены, что хотите сделать это?', + 'create' => 'Создать', + 'create_and_close' => 'Создать и закрыть', + 'creating' => 'Создание...', + 'creating_name' => 'Создание :name...', + 'save' => 'Сохранить', + 'save_and_close' => 'Сохранить и закрыть', + 'saving' => 'Сохранение...', + 'saving_name' => 'Сохранение :name...', + 'delete' => 'Удалить', + 'deleting' => 'Удаление...', + 'confirm_delete' => 'Вы действительно хотите удалить эту запись?', + 'confirm_delete_multiple' => 'Вы действительно хотите удалить выбранные записи?', + 'deleting_name' => 'Удаление :name...', + 'restore' => 'Восстановить', + 'restoring' => 'Восстановление...', + 'confirm_restore' => 'Вы уверены, что хотите восстановить эту запись?', + 'reset_default' => 'Сбросить настройки', + 'resetting' => 'Сброс', + 'resetting_name' => 'Сброс :name', + 'undefined_tab' => 'Разное', + 'field_off' => 'Выкл', + 'field_on' => 'Вкл', + 'add' => 'Добавить', + 'apply' => 'Применить', + 'cancel' => 'Отмена', + 'close' => 'Закрыть', + 'confirm' => 'Подтвердить', + 'reload' => 'Обновить', + 'complete' => 'Завершить', + 'ok' => 'OK', + 'or' => 'или', + 'confirm_tab_close' => 'Закрыть вкладку? Несохраненные изменения будут потеряны.', + 'behavior_not_ready' => 'Поведение формы не было инициализировано, проверьте вызов initForm() в вашем контроллере.', + 'preview_no_files_message' => 'Нет загруженных файлов.', + 'preview_no_media_message' => 'Нет выбраного медиа.', + 'preview_no_record_message' => 'Нет выбранных записей.', + 'select' => 'Выбрать', + 'select_all' => 'выбрать все', + 'select_none' => 'выберите ни одного', + 'select_placeholder' => 'Пожалуйста, выберите', + 'insert_row' => 'Вставить строку', + 'insert_row_below' => 'Вставить строку ниже', + 'delete_row' => 'Удалить строку', + 'concurrency_file_changed_title' => 'Файл был изменен', + 'concurrency_file_changed_description' => 'Файл,редактируемый вами, был изменен другим пользователем. Вы можете перезагрузить файл и потерять ваши изменения или перезаписать его', + 'return_to_list' => 'Вернуться к списку', + ], + 'recordfinder' => [ + 'find_record' => 'Найти запись', + 'invalid_model_class' => 'Предоставленный класс модели ":modelClass" для поиска записи является недействительным', + 'cancel' => 'Отмена', + ], + 'pagelist' => [ + 'page_link' => 'Ссылка на страницу', + 'select_page' => 'Выберите страницу...', + ], + 'relation' => [ + 'missing_config' => "Поведение отношения не имеет конфигурации для ':config'.", + 'missing_definition' => "Поведение отношения не содержит определения для ':field'.", + 'missing_model' => 'Для поведения отношения, используемого в :class не определена модель.', + 'invalid_action_single' => 'Это действие не может быть выполнено для особого отношения.', + 'invalid_action_multi' => 'Это действие не может быть выполнено для множественных отношений.', + 'help' => 'Нажмите на элемент, который нужно добавить', + 'related_data' => 'Связанные :name данные', + 'add' => 'Добавить', + 'add_selected' => 'Добавить выбранные', + 'add_a_new' => 'Добавить новый :name', + 'link_selected' => 'Связать выбранное', + 'link_a_new' => 'Новая ссылка :name', + 'cancel' => 'Отмена', + 'close' => 'Закрыть', + 'add_name' => 'Добавление :name', + 'create' => 'Создать', + 'create_name' => 'Создание :name', + 'update' => 'Обновить', + 'update_name' => 'Обновление :name', + 'preview' => 'Предпросмотр', + 'preview_name' => 'Предпросмотр :name', + 'remove' => 'Удалить', + 'remove_name' => 'Удаление :name', + 'delete' => 'Удалить', + 'delete_name' => 'Удаление :name', + 'delete_confirm' => 'Вы уверены?', + 'link' => 'Ссылка', + 'link_name' => 'Соединение :name', + 'unlink' => 'Отвязать', + 'unlink_name' => 'Разъединение :name', + 'unlink_confirm' => 'Вы уверены?', + ], + 'reorder' => [ + 'default_title' => 'Сортировать записи', + 'no_records' => 'Нет доступных записей для сортировки.', + ], + 'model' => [ + 'name' => 'Модель', + 'not_found' => "Модель ':class' с идентификатором :id не найдена", + 'missing_id' => 'Нет идентификатора для поиска модели записи.', + 'missing_relation' => "Модель ':class' не содержит определения для ':relation'", + 'missing_method' => "Модель ':class' не содержит метод ':method'.", + 'invalid_class' => 'Модель :model используемая в :class не допустима, она должна наследовать класс \Model.', + 'mass_assignment_failed' => "Массовое заполнение недоступно для атрибута модели ':attribute'.", + ], + 'warnings' => [ + 'tips' => 'Подсказки по конфигурации системы', + 'tips_description' => 'Есть проблемы, на которые стоит обратить внимание, чтобы правильно настроить систему.', + 'permissions' => 'Каталог :name или его подкаталоги недоступны для записи. Укажите соответствующие разрешения для веб-сервера.', + 'extension' => 'Расширение PHP :name не установлено. Установите эту библиотеку и активируйте расширение.', + 'plugin_missing' => 'Плагин :name имеет зависимость. Установите этот плагин.', + 'debug' => 'Режим отладки включен. Это не рекомендуется для рабочих инсталяций.', + 'decompileBackendAssets' => 'Ассеты в бэкенде в настоящее время декомпилированы. Это не рекомендуется для рабочих инсталяций.', + ], + 'editor' => [ + 'menu_label' => 'Настройки редактора', + 'menu_description' => 'Управление настройками редактора кода.', + 'preview' => 'Предпросмотр', + 'font_size' => 'Размер шрифта', + 'tab_size' => 'Размер табуляции', + 'use_hard_tabs' => 'Использовать табуляцию для индентации', + 'code_folding' => 'Свертывание кода', + 'code_folding_begin' => 'Mark begin', + 'code_folding_begin_end' => 'Mark begin and end', + 'autocompletion' => 'Автодополнение', + 'word_wrap' => 'Перенос слов', + 'highlight_active_line' => 'Подсвечивать активную строку', + 'auto_closing' => 'Автоматическое закрытие тегов и специальных символов', + 'show_invisibles' => 'Показывать невидимые символы', + 'show_gutter' => 'Показывать нумерацию строк', + 'basic_autocompletion' => 'Базовое автодополнение (Ctrl + Space)', + 'live_autocompletion' => 'Живое автодополнение', + 'enable_snippets' => 'Включить сниппеты (Tab)', + 'display_indent_guides' => 'Показывать символы перевода строки', + 'show_print_margin' => 'Показывать границу печати', + 'mode_off' => 'Выключено', + 'mode_fluid' => 'Адаптивный', + '40_characters' => '40 символов', + '80_characters' => '80 символов', + 'theme' => 'Цветовая схема', + 'markup_styles' => 'Стили разметки', + 'custom_styles' => 'Дополнительные CSS стили', + 'custom styles_comment' => 'Дополнительные стили для использования в HTML редакторе.', + 'markup_classes' => 'Классы разметки', + 'paragraph' => 'Параграф', + 'link' => 'Ссылка', + 'table' => 'Таблица', + 'table_cell' => 'Ячейка таблицы', + 'image' => 'Изображение', + 'label' => 'Название', + 'class_name' => 'Класс', + 'markup_tags' => 'Теги разметки', + 'markup_tag' => 'Тег разметки', + 'allowed_empty_tags' => 'Разрешенные пустые теги', + 'allowed_empty_tags_comment' => 'Список тегов, которые не будут удаляться, если внутри них нет содержания.', + 'allowed_tags' => 'Разрешенные теги', + 'allowed_tags_comment' => 'Список разрешенных тегов.', + 'no_wrap' => 'Не оборачивать теги', + 'no_wrap_comment' => 'Список тегов, которые не должны быть обернуты в блочные элементы.', + 'remove_tags' => 'Удаляемые теги', + 'remove_tags_comment' => 'Список тегов, которые будут удалены вместе с их содержанием.', + 'line_breaker_tags' => 'Теги с переводом строки', + 'line_breaker_tags_comment' => 'Список тегов, в которых будет использоваться тег перевода строки', + 'toolbar_options' => 'Опции панели инструментов', + 'toolbar_buttons' => 'Кнопки панели инструментов', + 'toolbar_buttons_comment' => 'Кнопки панели инструментов, которые будут отображаться в Rich Editor по умолчанию.', + 'toolbar_buttons_preset' => 'Вставить предустановленный набор кнопок панели инструментов:', + 'toolbar_buttons_presets' => [ + 'default' => 'По умолчанию', + 'minimal' => 'Минимальный', + 'full' => 'Полный', + ], + 'paragraph_formats' => 'Форматы абзацев', + 'paragraph_formats_comment' => 'Опции появляющиеся в выпадающем списке Форматы абзацев.', + ], + 'tooltips' => [ + 'preview_website' => 'Просмотр сайта', + ], + 'mysettings' => [ + 'menu_label' => 'Мои настройки', + 'menu_description' => 'Управление настройками учетной записи администратора.', + ], + 'myaccount' => [ + 'menu_label' => 'Мой аккаунт', + 'menu_description' => 'Управление личной информацией (имя, почта, пароль)', + 'menu_keywords' => 'безопасность логин', + ], + 'branding' => [ + 'menu_label' => 'Персонализация панели управления', + 'menu_description' => 'Управление внешним видом панели управления (название, цвет, логотип)', + 'brand' => 'Бренд', + 'logo' => 'Логотип', + 'logo_description' => 'Загрузите логотип для панели управления', + 'favicon' => 'Фавикон', + 'favicon_description' => 'Загрузите пользовательский фавикон для бекенда', + 'app_name' => 'Название приложения', + 'app_name_description' => 'Это имя отображается в заголовке панели управления', + 'app_tagline' => 'Слоган приложения', + 'app_tagline_description' => 'Слоган будет отображаться на экране входа в панель управления.', + 'colors' => 'Цвета', + 'primary_color' => 'Первичный color', + 'secondary_color' => 'Вторичный color', + 'accent_color' => 'Цвет акцента', + 'styles' => 'Стили', + 'custom_stylesheet' => 'Пользовательские стили', + 'navigation' => 'Навигация', + 'menu_mode' => 'Стиль меню', + 'menu_mode_inline' => 'Строчный', + 'menu_mode_inline_no_icons' => 'Строчный (без иконок)', + 'menu_mode_tile' => 'Плитка', + 'menu_mode_collapsed' => 'Схлопнутый', + ], + 'backend_preferences' => [ + 'menu_label' => 'Настройки панели управления', + 'menu_description' => 'Управление языком и внешним видом панели управления.', + 'region' => 'Регион', + 'code_editor' => 'Редактор кода', + 'timezone' => 'Часовой пояс', + 'timezone_comment' => 'Выводить даты в выбранном часовом поясе.', + 'locale' => 'Язык', + 'locale_comment' => 'Выберите желаемый язык панели управления.', + ], + 'access_log' => [ + 'hint' => 'В этом журнале отображается список успешных попыток авторизаций администраторов. Записи хранятся :days дней.', + 'menu_label' => 'Журнал доступа', + 'menu_description' => 'Просмотр списка успешных авторизаций администраторов.', + 'id' => 'ID', + 'created_at' => 'Дата & Время', + 'type' => 'Тип', + 'login' => 'Логин', + 'ip_address' => 'IP адрес', + 'first_name' => 'Имя', + 'last_name' => 'Фамилия', + 'email' => 'Email', + ], + 'filter' => [ + 'all' => 'все', + 'options_method_not_exists' => "Модель класса :model должна определить метод :method() возвращающего варианты для фильтра ':filter'.", + 'date_all' => 'весь период', + 'number_all' => 'все номера', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Загрузка CSV-файл', + 'import_file' => 'Импорт файла', + 'row' => 'Строка :row', + 'first_row_contains_titles' => 'Первая строка содержит заголовки столбцов', + 'first_row_contains_titles_desc' => 'Выберите эту опцию, если первая строка в CSV-файле используется как заголовки для столбцов.', + 'match_columns' => '2. Применение столбцов файла к полям базы данных', + 'file_columns' => 'Столбцы файла', + 'database_fields' => 'Поля базы данных', + 'set_import_options' => '3. Установка параметров импорта', + 'export_output_format' => '1. Выбор формата экспорта', + 'file_format' => 'Формат файла', + 'standard_format' => 'Стандартный формат', + 'custom_format' => 'Пользовательский формат', + 'delimiter_char' => 'Символ разделения полей', + 'enclosure_char' => 'Символ обрамления полей', + 'escape_char' => 'Экранирующий символ', + 'select_columns' => '2. Выберите колонки для экспорта', + 'column' => 'Столбец', + 'columns' => 'Столбцы', + 'set_export_options' => '3. Установка параметров экспорта', + 'show_ignored_columns' => 'Показать пропущенные столбцы', + 'auto_match_columns' => 'Авто применение столбцов', + 'created' => 'Создано', + 'updated' => 'Обновлено', + 'skipped' => 'Пропущено', + 'warnings' => 'Предупреждения', + 'errors' => 'Ошибки', + 'skipped_rows' => 'Пропущенные строки', + 'import_progress' => 'Прогресс импорта', + 'processing' => 'Обработка', + 'import_error' => 'Ошибка импорта', + 'upload_valid_csv' => 'Пожалуйста, загрузите валидный CSV-файл..', + 'drop_column_here' => 'Отпустите столбец здесь...', + 'ignore_this_column' => 'Игонорировать этот столбец', + 'processing_successful_line1' => 'Процесс экспорта файла завершился успешно!', + 'processing_successful_line2' => 'Теперь браузер автоматически должен начать загрузку файла.', + 'export_progress' => 'Прогресс экспорта', + 'export_error' => 'Ошибка экспорта', + 'column_preview' => 'Предпросмотр столбца', + 'file_not_found_error' => 'Файл не найден', + 'empty_error' => 'Нет данных доступных для экспорта', + 'empty_import_columns_error' => 'Укажите некоторые столбцы для импорта.', + 'match_some_column_error' => 'Сначала сначала сопоставьте некоторые столбцы.', + 'required_match_column_error' => 'Укажите соответствующее поле :label.', + 'empty_export_columns_error' => 'Укажите некоторые столбцы для экспорта.', + 'behavior_missing_uselist_error' => "Вы должны реализовать поведение контроллера ListController с включенной опцией 'useList' экспорта.", + 'missing_model_class_error' => 'Укажите свойство modelClass для :type', + 'missing_column_id_error' => 'Отсутствует идентификатор столбца', + 'unknown_column_error' => 'Неизвестная колонка', + 'encoding_not_supported_error' => 'Кодировка исходного файла не распознается. Пожалуйста, выберите опцию пользовательского формата файла с правильной кодировкой для импорта файла.', + 'encoding_format' => 'Кодирование файлов', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1250' => 'Windows-1250 (CP1250, Central and Eastern European)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Загрузка и управление медиаконтентом - изображениями, видео, звуками, документами', + 'allow_unsafe_markdown' => 'Использовать небезопасный Markdown (может включать Javascript)', + ], + 'mediafinder' => [ + 'label' => 'Поиск медиа', + 'default_prompt' => 'Кликните на кнопку %s, чтобы найти медиафайл', + 'no_image' => 'Не удалось найти изображение', + ], + 'media' => [ + 'menu_label' => 'Медиафайлы', + 'upload' => 'Загрузить', + 'move' => 'Переместить', + 'delete' => 'Удалить', + 'add_folder' => 'Создать папку', + 'search' => 'Поиск', + 'display' => 'Отобразить', + 'filter_everything' => 'Все файлы', + 'filter_images' => 'Изображения', + 'filter_video' => 'Видео', + 'filter_audio' => 'Музыка', + 'filter_documents' => 'Документы', + 'library' => 'Библиотека', + 'size' => 'Размер', + 'title' => 'Имя', + 'last_modified' => 'Последнее изменение', + 'public_url' => 'Публичный адрес', + 'click_here' => 'Нажмите здесь', + 'thumbnail_error' => 'Ошибка создания миниатюры.', + 'return_to_parent' => 'Вернуться в родительскую папку', + 'return_to_parent_label' => 'Подняться на уровень выше ..', + 'nothing_selected' => 'Ничего не выбрано.', + 'multiple_selected' => 'Выбрано несколько объектов.', + 'uploading_file_num' => 'Загрузка файлов: :number ...', + 'uploading_complete' => 'Загрузка файлов завершена!', + 'uploading_error' => 'Ошибка загрузки', + 'type_blocked' => 'Используемый тип файла блокируется по соображениям безопасности.', + 'order_by' => 'Сортировать по', + 'direction' => 'Направление сортировки', + 'direction_asc' => 'По возрастанию', + 'direction_desc' => 'По убыванию', + 'folder' => 'Папка', + 'no_files_found' => 'Ни один из файлов не удовлетворяет вашему запросу.', + 'delete_empty' => 'Пожалуйста, выберите объекты для удаления.', + 'delete_confirm' => 'Вы действительно хотите удалить выбранные объекты?', + 'error_renaming_file' => 'Ошибка изменения имени файла.', + 'new_folder_title' => 'Новая папка', + 'folder_name' => 'Название папки', + 'error_creating_folder' => 'Ошибка создания папки', + 'folder_or_file_exist' => 'Папка или файл с таким именем уже существует.', + 'move_empty' => 'Пожалуйста, выберите объекты для перемещения.', + 'move_popup_title' => 'Перемещение файлов или папок', + 'move_destination' => 'Папка назначения', + 'please_select_move_dest' => 'Пожалуйста, выберите папку назначения для перемещения.', + 'move_dest_src_match' => 'Пожалуйста, выберите другую папку.', + 'empty_library' => 'Библиотека медиафайлов пуста. Для начала загрузите файлы или создайте папки.', + 'insert' => 'Вставить', + 'crop_and_insert' => 'Обрезать и вставить', + 'select_single_image' => 'Пожалуйста, выберите одно изображение.', + 'selection_not_image' => 'Выбранный элемент не является изображением.', + 'restore' => 'Отменить все изменения', + 'resize' => 'Изменение размера...', + 'selection_mode_normal' => 'Нормальный', + 'selection_mode_fixed_ratio' => 'Фиксированное соотношение', + 'selection_mode_fixed_size' => 'Фиксированный размер', + 'height' => 'Высота', + 'width' => 'Ширина', + 'selection_mode' => 'Режим выделения', + 'resize_image' => 'Изменение размера изображения', + 'image_size' => 'Размер изображения:', + 'selected_size' => 'Выбрано:', + ], +]; diff --git a/modules/backend/lang/sk/lang.php b/modules/backend/lang/sk/lang.php new file mode 100644 index 0000000..259d108 --- /dev/null +++ b/modules/backend/lang/sk/lang.php @@ -0,0 +1,592 @@ + [ + 'title' => 'Administrácia', + 'invalid_login' => 'Údaje, ktoré ste zadali sú nesprávne. Prosím skontrolujte údaje a skúste to znova.' + ], + 'field' => [ + 'invalid_type' => 'Bol použitý zlý typ :type.', + 'options_method_invalid_model' => "Vlastnosť ':field' nezodpovedá platnému modelu. Skúste špecifikovať metódu možností pre triedu modelu :model explicitne.", + 'options_method_not_exists' => "Trieda modelu :model musí implementovať metódu :method(), ktorá vracia možností pre formulárové pole ':field'." + ], + 'widget' => [ + 'not_registered' => "Trieda widgetu s menom ':name' nie je zaregistrovaná", + 'not_bound' => "Widget s názvom triedy ':name' nie je naviazaný na controller" + ], + 'page' => [ + 'untitled' => 'Bez názvu', + '404' => [ + 'label' => 'Stránka nenájdená', + 'help' => "Hľadali sme a hľadali, ale požadovanú adresu URL jednoducho nebolo možné nájsť. Možno ste hľadali niečo iné?", + 'back_link' => 'Späť na predchodzú stránku', + ], + 'access_denied' => [ + 'label' => 'Prístup odmietnutý', + 'help' => "Nemáte potrebné oprávnenia na zobrazenie tejto stránky.", + 'cms_link' => 'Späť do administrácie' + ], + 'no_database' => [ + 'label' => 'Chýba databáza', + 'help' => "Pre prístup do administrácie je potrebná databáza. Zkontrolujte, či je databáza nakonfigurovaná a zmigrovaná a skúste to znova.", + 'cms_link' => 'Späť na úvodnú stránku' + ], + ], + 'partial' => [ + 'not_found_name' => "Čiastočná šablona ':name' nebola nájdená." + ], + 'account' => [ + 'signed_in_as' => 'Prihlásený ako :full_name', + 'sign_out' => 'Odhlásiť', + 'login' => 'Prihlásiť sa', + 'reset' => 'Resetovať', + 'restore' => 'Obnoviť', + 'login_placeholder' => 'prihlasovacie meno', + 'password_placeholder' => 'heslo', + 'remember_me' => 'Ostať prihlásený', + 'forgot_password' => 'Zabudli ste heslo?', + 'enter_email' => 'Zadajte váš email', + 'enter_login' => 'Zadajte vaše prihlasovacie meno', + 'email_placeholder' => 'email', + 'enter_new_password' => 'Zadajte nové heslo', + 'password_reset' => 'Obnova hesla', + 'restore_success' => 'E-mail s inštrukciami bol zaslaný na vašu e-mailovú adresu.', + 'restore_error' => "Užívateľ s prihlasovacím menom ':login' nebol nájdený", + 'reset_success' => 'Vaše heslo bolo úspešne obnovené. Teraz sa môžete prihlásiť.', + 'reset_error' => 'Dáta pre obnovu hesla nie sú správne. Prosím skúste to znova!', + 'reset_fail' => 'Obnova hesla zlyhala!', + 'apply' => 'Použiť', + 'cancel' => 'Zrušiť', + 'delete' => 'Zmazať', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Hlavný panel', + 'widget_label' => 'Widget', + 'widget_width' => 'Šírka', + 'full_width' => 'plná šírka', + 'manage_widgets' => 'Správa widgetov', + 'add_widget' => 'Pridať widget', + 'widget_inspector_title' => 'Nastavenie widgetu', + 'widget_inspector_description' => 'Tu si upravte všetky nastavenia widgetu', + 'widget_columns_label' => 'Šírka :columns', + 'widget_columns_description' => 'Šírka widgetu, číslo medzi 1 a 10.', + 'widget_columns_error' => 'Zadajte prosím šírku widgetu ako číslo medzi 1 a 10.', + 'columns' => '{1} stĺpec|[2,4] stĺpce|[5,Inf] stĺpcov', + 'widget_new_row_label' => 'Vždy na novom riadku', + 'widget_new_row_description' => 'Umiestniť widget do nového riadku.', + 'widget_title_label' => 'Názov widgetu', + 'widget_title_error' => 'Musíte zadať názov widgetu.', + 'reset_layout' => 'Obnoviť pôvodné usporiadanie', + 'reset_layout_confirm' => 'Naozaj obnoviť pôvodné usporiadanie?', + 'reset_layout_success' => 'Pôvodné usporiadanie bolo obnovené', + 'make_default' => 'Nastaviť ako predvolené', + 'make_default_confirm' => 'Nastaviť aktuálne usporiadanie ako predvolené?', + 'make_default_success' => 'Aktuálne usporiadanie je teraz nastavené ako predvolené', + 'collapse_all' => 'Zbaliť všetko', + 'expand_all' => 'Rozbaliť všetko', + 'status' => [ + 'widget_title_default' => 'Stav systému', + 'update_available' => '{0} dostupných aktualizácií!|{1} dostupná aktualizácia!|[2,4] dostupné aktualizácie!|[4,Inf] dostupných aktualizácií!', + 'updates_pending' => 'Sú dostupné aktualizácie softwaru', + 'updates_nil' => 'Software je aktuálny', + 'updates_link' => 'Aktualizovať', + 'warnings_pending' => 'Niektoré problémy vyžadujú pozornosť', + 'warnings_nil' => 'Žiadne varovania na zobrazenie', + 'warnings_link' => 'Zobraziť', + 'core_build' => 'Verzia systému', + 'event_log' => 'Záznam udalostí', + 'request_log' => 'Záznam požiadavkov', + 'app_birthday' => 'Online od', + ], + 'welcome' => [ + 'widget_title_default' => 'Vitajte', + 'welcome_back_name' => 'Vitajte späť na :app, :name.', + 'welcome_to_name' => 'Vitajte na :app, :name.', + 'first_sign_in' => 'Toto je vaše prvé prihlásenie.', + 'last_sign_in' => 'Vaše posledné prihlásenie bolo', + 'view_access_logs' => 'Zobraziť záznam prihlásení', + 'nice_message' => 'Pekný deň!', + ] + ], + 'user' => [ + 'name' => 'Administrátor', + 'menu_label' => 'Administrátori', + 'menu_description' => 'Správa administrátorov, skupín a oprávnení.', + 'list_title' => 'Spríva administrátorov', + 'new' => 'Nový administrátor', + 'login' => 'Prihlasovacie meno', + 'first_name' => 'Krstné meno', + 'last_name' => 'Priezvisko', + 'full_name' => 'Celé meno', + 'email' => 'E-mail', + 'role_field' => 'Rola', + 'role_comment' => 'Role definujú užívateľské oprávnenia, ktoré môžu byť prepísané na užívateľskej úrovni, na karte Oprávnení.', + 'groups' => 'Skupiny', + 'groups_comment' => 'Vyberto do akých skupín tento účet patrí.', + 'avatar' => 'Avatar', + 'password' => 'Heslo', + 'password_confirmation' => 'Potvrdiť heslo', + 'permissions' => 'Oprávnenia', + 'account' => 'Účet', + 'superuser' => 'Super užívateľ', + 'superuser_comment' => 'Umožňuje tomuto účtu neomedzený prístup do všetkých častí systému. Super užívatelia môžu pridávať a spravovať ostatných užívateľov.', + 'send_invite' => 'Poslať pozvánku e-mailom.', + 'send_invite_comment' => 'Pošle uvítací e-mail s prihlasovacími údajmi.', + 'delete_confirm' => 'Skutočne zmazať tohto administrátora?', + 'return' => 'Späť na zoznam adminitrátorov', + 'allow' => 'Povoliť', + 'inherit' => 'Zdediť', + 'deny' => 'Zakázať', + 'activated' => 'Aktivovaný', + 'last_login' => 'Posledné prihlásenie', + 'created_at' => 'Vytvorený', + 'updated_at' => 'Aktualizovaný', + 'group' => [ + 'name' => 'Skupina', + 'name_field' => 'Meno', + 'name_comment' => 'Meno je zobrazené v zozname skupín na formulári administrátora.', + 'description_field' => 'Popis', + 'is_new_user_default_field_label' => 'Predvolená skupina', + 'is_new_user_default_field_comment' => 'Automaticky zaradiť nových administrátorov do tejto skupiny', + 'code_field' => 'Kód', + 'code_comment' => 'Zadajte unikátny kód pre prístup cez API k objektu skupiny.', + 'menu_label' => 'Skupiny', + 'list_title' => 'Správa skupín', + 'new' => 'Nová skupina', + 'delete_confirm' => 'Skutočne zmazať túto skupinu administrátorov?', + 'return' => 'Späť na zoznam skupín', + 'users_count' => 'Užívateľov' + ], + 'role' => [ + 'name' => 'Rola', + 'name_field' => 'Meno', + 'name_comment' => 'Meno je zobrazené v zozname rolí na formulári administrátora.', + 'description_field' => 'Popis', + 'code_field' => 'Kód', + 'code_comment' => 'Zadajte unikátny kód pre prístup cez API k objektu role.', + 'menu_label' => 'Role', + 'list_title' => 'Správa rolí', + 'new' => 'Nová rola', + 'delete_confirm' => 'Skutočne znazať túto rolu?', + 'return' => 'Späť na zoznam rolí', + 'users_count' => 'Užívatelia' + ], + 'preferences' => [ + 'not_authenticated' => 'Nebol nájdený žiadny prihlásený užívateľ pre načítanie alebo uloženie nastavení.' + ] + ], + 'list' => [ + 'default_title' => 'Zoznam', + 'search_prompt' => 'Hľadať...', + 'no_records' => 'Žiadne záznamy na zobrazenie.', + 'missing_model' => 'Správanie zoznamu použité v :class nemá definovaný model.', + 'missing_column' => 'Neexistujú žiadne definície stĺpcov pre :columns.', + 'missing_columns' => 'Zoznam použitý v :class nemá definované žiadne stĺpce.', + 'missing_definition' => "Správanie zoznamu neobsahuje stĺpec pre ':field'.", + 'missing_parent_definition' => "Správanie zoznamu neobsahuje definíciu pre ':definition'.", + 'behavior_not_ready' => 'Správanie zoznamu nebolo inicializovanéd, skontrolujte, či ste zavolali metódu makeLists() vo svojom kontroleri.', + 'invalid_column_datetime' => "Hodnotu stĺpca ':column' nie je objekt typu DateTime, nechýba vám referencia \$dates v modeli?", + 'pagination' => 'Zobrazené záznamy: :from-:to z :total', + 'first_page' => 'Prvá stránka', + 'last_page' => 'Posledná stránka', + 'prev_page' => 'Predchádzajúca stránka', + 'next_page' => 'Nasledujúca stránka', + 'refresh' => 'Obnoviť', + 'updating' => 'Aktualizujem...', + 'loading' => 'Načítavam...', + 'setup_title' => 'Nastavenie zoznamu', + 'setup_help' => 'Pomocou checkboxov vyberte , ktoré stĺpce majú byť v zozname viditeľné. Môžete zmeniť pozíciu stĺpcov chytením a posunom hore alebo dole.', + 'records_per_page' => 'Záznamov na stránku', + 'records_per_page_help' => 'Vyberte koľko záznamov chcete vidieť na jednej stránke. Vysoký počet záznamov môže negatívne ovplyvniť rýchlosť stránok.', + 'check' => 'Zaškrtnúť', + 'delete_selected' => 'Zmazať vybrané', + 'delete_selected_empty' => 'Neboli vybrané žiadne záznamy na zmazanie.', + 'delete_selected_confirm' => 'Skutočne chcete zmazať vybrané záznamy?', + 'delete_selected_success' => 'Vybrané záznamy boli zmazané.', + 'column_switch_true' => 'Áno', + 'column_switch_false' => 'Nie' + ], + 'fileupload' => [ + 'attachment' => 'Príloha', + 'help' => 'Pridať názov a popis pre túto prílohu.', + 'title_label' => 'Názov', + 'description_label' => 'Popis', + 'default_prompt' => 'Kliknutím na %s alebo potiahnutím na toto miesto môžete súbor nahrať', + 'attachment_url' => 'URL prílohy', + 'upload_file' => 'Nahrať súbor', + 'upload_error' => 'Chyba nahrávanie', + 'remove_confirm' => 'Ste si istý?', + 'remove_file' => 'Odstrániť súbor' + ], + 'form' => [ + 'create_title' => 'Nový :name', + 'update_title' => 'Upraviť :name', + 'preview_title' => 'Náhľad :name', + 'create_success' => ':name bol vytvorený', + 'update_success' => ':name bol upravený', + 'delete_success' => ':name bol zmazaný', + 'reset_success' => 'Úspešne obnovené', + 'missing_id' => 'Musíte uviesť ID záznamu.', + 'missing_model' => 'Správanie formulára použité v :class nemá definovaný model.', + 'missing_definition' => "Správanie formulára neobsahuje pole pre ':field'.", + 'not_found' => 'Záznam formulíára s ID :id nebol nájdený.', + 'action_confirm' => 'Ste si istý?', + 'create' => 'Vytvoriť', + 'create_and_close' => 'Vytvoriť a zavrieť', + 'creating' => 'Vytváranie...', + 'creating_name' => 'Vytváranie :name...', + 'save' => 'Uložiť', + 'save_and_close' => 'Uložiť a zatvoriť', + 'saving' => 'Ukladanie...', + 'saving_name' => 'Ukladanie :name...', + 'delete' => 'Zmazať', + 'deleting' => 'Mazanie...', + 'confirm_delete' => 'Zmazať záznam?', + 'confirm_delete_multiple' => 'SKutočne zmazať vybrané záznamy?', + 'deleting_name' => 'Mazanie :name...', + 'reset_default' => 'Obnoviť predvolené', + 'resetting' => 'Obnova', + 'resetting_name' => 'Obnova :name', + 'undefined_tab' => 'Ostatné', + 'field_off' => 'Vyp', + 'field_on' => 'Zap', + 'add' => 'Pridať', + 'apply' => 'Použiť', + 'cancel' => 'Zrušiť', + 'close' => 'Zavrieť', + 'confirm' => 'Potvrdiť', + 'reload' => 'Znovu načítať', + 'complete' => 'Kompletné', + 'ok' => 'OK', + 'or' => 'alebo', + 'confirm_tab_close' => 'Skutočne zavrieť kartu? Neuložené zmeny budú stratené.', + 'behavior_not_ready' => 'Správanie formulára nebolo inicializované, skontrolujte či voláte funkciu initForm() vo svojom kontroleri.', + 'preview_no_files_message' => 'Žiadny súbor nebol nahraný.', + 'preview_no_media_message' => 'Žiadne médium nebolo vybrané.', + 'preview_no_record_message' => 'Žiadny záznam nie je vybraný', + 'select' => 'Vybrať', + 'select_all' => 'vybrať všetko', + 'select_none' => 'nevyber nič', + 'select_placeholder' => 'prosím vyberte', + 'insert_row' => 'Vložiť riadok', + 'insert_row_below' => 'Vložiť riadok pod', + 'delete_row' => 'Zmazať riadok', + 'concurrency_file_changed_title' => 'Súbor bol zmenený', + 'concurrency_file_changed_description' => "Súbor, ktorý upravujete bol na disku zmenený iným užívateľom. Môžete buď znovu načítať súbor a stratiť zmeny alebo prepísať súbor na disku.", + 'return_to_list' => 'Spať na zoznam' + ], + 'recordfinder' => [ + 'find_record' => 'Nájsť záznam', + 'cancel' => 'Zrušiť', + ], + 'pagelist' => [ + 'page_link' => 'Odkaz na stránku', + 'select_page' => 'Vyberte stránku...' + ], + 'relation' => [ + 'missing_config' => "Správanie relácie nemá žiadne nastavenie pre ':config'.", + 'missing_definition' => "Správanie ralácie neobsahuje definíciu pre ':field'.", + 'missing_model' => 'Správanie relácie použité v :class nemá definovaný žiadny model.', + 'invalid_action_single' => 'Táto akcia nemôže byť vykonaná na jednoduchej relácií.', + 'invalid_action_multi' => 'Táto akcia nemôže byť vykonaná na viacnásobnej relácií.', + 'help' => 'Pre pridanie kliknite na položku', + 'related_data' => 'Súvisiace dáta pre :name', + 'add' => 'Pridať', + 'add_selected' => 'Pridať vybrané', + 'add_a_new' => 'Pridať nový :name', + 'link_selected' => 'Vytvoriť väzbu na vybrané', + 'link_a_new' => 'Vytvoriť novú väzbu na :name', + 'cancel' => 'Zrušiť', + 'close' => 'Zatvoriť', + 'add_name' => 'Pridať :name', + 'create' => 'Vytvoriť', + 'create_name' => 'Vytvoriť :name', + 'update' => 'Upraviť', + 'update_name' => 'Upraviť :name', + 'preview' => 'Náhľad', + 'preview_name' => 'Náhľad :name', + 'remove' => 'Odstrániť', + 'remove_name' => 'Odstrániť :name', + 'delete' => 'Zmazať', + 'delete_name' => 'Zmazať :name', + 'delete_confirm' => 'Ste si istý?', + 'link' => 'Väzba', + 'link_name' => 'Väzba :name', + 'unlink' => 'Zrušiť väzbu', + 'unlink_name' => 'Zrušiť väzbu :name', + 'unlink_confirm' => 'Ste si istý?' + ], + 'reorder' => [ + 'default_title' => 'Zoradiť záznamy', + 'no_records' => 'Nenašli sa žiadne záznamy na zoradenie.' + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => "Model ':class' s ID :id nebol nájdený", + 'missing_id' => 'Nie je špecifikované ID pre hľadanie záznamov v modeli.', + 'missing_relation' => "Model ':class' neobsahuje definíciu pre ':relation'.", + 'missing_method' => "Model ':class' nemá implementovanú metódu ':method'.", + 'invalid_class' => "Model :model použitý v :class nie je platný, musí dediť triedu \Model.", + 'mass_assignment_failed' => "Hromadné priradenie zlyhalo pre atribút ':attribute'." + ], + 'warnings' => [ + 'tips' => 'Tipy pre konfiguráciu systému', + 'tips_description' => 'Existujú problémy, ktoré vyžadujú vašu pozornosť, aby vol systém správne nastavený.', + 'permissions' => 'Do adresára :name alebo jeho podadresárov sa nedá zapisovať z PHP. Prosím nastavte správne oprávnenia tomuto adresáru.', + 'extension' => 'PHP rozšírenie :name nie je nainštalované. Prosím nainštalujte túto knižnicu a aktivujte rozšírenie.', + 'plugin_missing' => 'Plugin :name je vyžadovaný ale nie je nainštalovaný. Prosím nainštaujte tento plugin.', + ], + 'editor' => [ + 'menu_label' => 'Nastavenia editora kódu', + 'menu_description' => 'Upraviť globálne nastavenia editora, napríklad veľkosť písma a farebnú schému.', + 'font_size' => 'Veľkosť písma', + 'tab_size' => 'Počet znakov odsadenia', + 'use_hard_tabs' => 'Odsadenia tabulatorom', + 'code_folding' => 'Skladanie kódu', + 'code_folding_begin' => 'Označiť začiatok', + 'code_folding_begin_end' => 'Označiť začiatok a koniec', + 'autocompletion' => 'Automatické doplňovanie', + 'word_wrap' => 'Zalamovanie slov', + 'highlight_active_line' => 'Zvýrazniť aktívny riadok', + 'auto_closing' => 'Automaticky uzatvárať značky', + 'show_invisibles' => 'Zobraziť neviditeľné znaky', + 'show_gutter' => 'Zobraziť kurzor', + 'basic_autocompletion'=> 'Základné automatické doplňovanie (Ctrl + Space)', + 'live_autocompletion'=> 'Živé automatické doplňovanie', + 'enable_snippets'=> 'Povoliť úryvky (snippets) kódu (Tab)', + 'display_indent_guides'=> 'Zobraziť vodítka odsadenia', + 'show_print_margin'=> 'Zobraziť okraje tlače', + 'mode_off' => 'Vyp', + 'mode_fluid' => 'Plynulý', + '40_characters' => '40 znakov', + '80_characters' => '80 znakov', + 'theme' => 'Farebná schéma', + 'markup_styles' => 'Štýly', + 'custom_styles' => 'Vlastné štýly', + 'custom styles_comment' => 'Vlastné štýly, ktoré budú zahrnuté do editora HTML.', + 'markup_classes' => 'Triedy štýlov', + 'paragraph' => 'Odstavec', + 'link' => 'Odkaz', + 'table' => 'Tabuľka', + 'table_cell' => 'Bunka tabuľky', + 'image' => 'Obrázok', + 'label' => 'Popis', + 'class_name' => 'Názov triedy', + 'markup_tags' => 'Značky', + 'allowed_empty_tags' => 'Povolené prázdne značky', + 'allowed_empty_tags_comment' => 'Zoznam značiek, ktoré nie sú odstránené v prípade, že nemajú žiadny obsah.', + 'allowed_tags' => 'Povolené značky', + 'allowed_tags_comment' => 'Zoznam povelných značiek.', + 'no_wrap' => 'Nezabaľovať tieto značky', + 'no_wrap_comment' => 'Zoznam značiek, ktoré by nemali byť zabalené vnútri blokových značiek.', + 'remove_tags' => 'Odstrániť značky', + 'remove_tags_comment' => 'Zoznam značiek, ktoré sú odstránené spolu s ich obsahom.', + 'toolbar_buttons' => 'Tlačítka na paneli nástrojov', + 'toolbar_buttons_comment' => 'Predvolené tlačítka, ktoré budú zobrazené na paneli nástrojov textového editoru.', + ], + 'tooltips' => [ + 'preview_website' => 'Náhľad stránok' + ], + 'mysettings' => [ + 'menu_label' => 'Moje nastavenia', + 'menu_description' => 'Nastavenia vášho administrátorského účtu' + ], + 'myaccount' => [ + 'menu_label' => 'Môj účet', + 'menu_description' => 'Nastavte si detaily svojho účtu ako meno, e-mail a heslo.', + 'menu_keywords' => 'bezpečnosť login' + ], + 'branding' => [ + 'menu_label' => 'Nastavenia administrácie', + 'menu_description' => 'Nastavte si mano, použité farby a logo v administrácií.', + 'brand' => 'Značka', + 'logo' => 'Logo', + 'logo_description' => 'Nahrajte vlastné logo, ktoré bude použité v administrácií.', + 'app_name' => 'Meno aplikácie', + 'app_name_description' => 'Toto meno se zobrazí v úvodnej lište stránok.', + 'app_tagline' => 'Motto aplikácie', + 'app_tagline_description' => 'Toto motto se zobrazí na prihlasovacej stránke administrácie.', + 'colors' => 'Farby', + 'primary_color' => 'Primárna farba', + 'secondary_color' => 'Sekundárna farba', + 'accent_color' => 'Farba zvýraznenia', + 'styles' => 'Štýly', + 'custom_stylesheet' => 'Vlastné kaskádové štýly', + 'navigation' => 'Navigácia', + 'menu_mode' => 'Štýl menu', + 'menu_mode_inline' => 'V riadku', + 'menu_mode_tile' => 'Dlaždice', + 'menu_mode_collapsed' => 'Zbalené' + ], + 'backend_preferences' => [ + 'menu_label' => 'Nastavenia administrácie', + 'menu_description' => 'Spravujte nastavenia svojho účtu ako napríklad jazyk.', + 'region' => 'Región', + 'code_editor' => 'Editor kódu', + 'timezone' => 'Časové pásmo', + 'timezone_comment' => 'Upraví zobrazenie času podľa tejto časovej zóny.', + 'locale' => 'Jazyk', + 'locale_comment' => 'Vyberte jazyk administrácie.' + ], + 'access_log' => [ + 'hint' => 'Tento záznam zobrazuje zoznam úspešných administrátorských prihlásení. Záznamy sú uchovávané po dobu :days dní.', + 'menu_label' => 'Záznam prihlásení', + 'menu_description' => 'Zobraziť zoznam úspešných prihlásení do administrácie.', + 'created_at' => 'Čas a dátum', + 'login' => 'Login', + 'ip_address' => 'IP adresa', + 'first_name' => 'Meno', + 'last_name' => 'Priezvisko', + 'email' => 'E-mail' + ], + 'filter' => [ + 'all' => 'všetko', + 'options_method_not_exists' => "Trieda modelu :model musí definovať metódu :method() vracajúcu možnosti pre ':filter' filter.", + 'date_all' => 'všetky obdobia', + 'number_all' => 'všetky čísla', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Nahrať CSV súbor', + 'import_file' => 'Importovať súbor', + 'row' => 'Riadok :row', + 'first_row_contains_titles' => 'Prvý riadok obsahuje názvy stĺpcov', + 'first_row_contains_titles_desc' => 'Nechajte zaškrtnuté ak prvý riadok v CSV je použitý pre názvy stĺpcov.', + 'match_columns' => '2. Vytvoriť väzbu medzi stĺpcami v databáze a v súbore', + 'file_columns' => 'Sĺpce súboru', + 'database_fields' => 'Polia v databáze', + 'set_import_options' => '3. Nastavte možnosti importu', + 'export_output_format' => '1. Formát exportu', + 'file_format' => 'Formát súboru', + 'standard_format' => 'Štandardný formát', + 'custom_format' => 'Vlastný formát', + 'delimiter_char' => 'Oddeľovací znak', + 'enclosure_char' => 'Znak pre ohraničenie (enclosure character)', + 'escape_char' => 'Ukončovací znak (escape character)', + 'select_columns' => '2. Vybrať exportované stĺpce', + 'column' => 'Stĺpec', + 'columns' => 'Stĺpce', + 'set_export_options' => '3. Nastaviť vlastnosti exportu', + 'show_ignored_columns' => 'Zobraziť ignorované stĺpce', + 'auto_match_columns' => 'VytvoriŤ väzby automaticky', + 'created' => 'Vytvorené', + 'updated' => 'Aktualizované', + 'skipped' => 'Preskočené', + 'warnings' => 'Upozornenia', + 'errors' => 'Chyby', + 'skipped_rows' => 'Preskočené riadky', + 'import_progress' => 'Priebeh importu', + 'processing' => 'Spracovávam', + 'import_error' => 'Chyba importu', + 'upload_valid_csv' => 'Prosím nahrajte platný CSV súbor.', + 'drop_column_here' => 'Sem potiahnite stĺpec...', + 'ignore_this_column' => 'Ignorovať tento stĺpec', + 'processing_successful_line1' => 'Export bol dokončený!', + 'processing_successful_line2' => 'Prehliadač vás teraz presmeruje na stránku pre stiahnutie súboru.', + 'export_progress' => 'Priebeh exportu', + 'export_error' => 'Chyba exportu', + 'column_preview' => 'Náhľad stĺpa', + 'file_not_found_error' => 'Súbor nenájdený', + 'empty_error' => 'Neboli nájdené žiadne záznamy pre export', + 'empty_import_columns_error' => 'Prosím vyberte stĺpce pre import.', + 'match_some_column_error' => 'Prosím najprv vytvorte väzbu medzi stĺpcami.', + 'required_match_column_error' => 'Prosím vytvorte väzbu pre vyžadované pole :label.', + 'empty_export_columns_error' => 'Prosím vyberte stĺpce pre export.', + 'behavior_missing_uselist_error' => 'Musíte implementovať správanie kontrolera ListController s povolenou vlastnosťou "useList".', + 'missing_model_class_error' => 'Posím špecifikujtey vlastnosť triedy pre :type', + 'missing_column_id_error' => 'Chýbajúci identifikátor stĺpca', + 'unknown_column_error' => 'Neznámy stĺpec', + 'encoding_not_supported_error' => 'Kódovanie zdrojového súboru nie je rozpoznané. Zvoľte voľbu formátu súboru s vlastným kódovaním pre import súboru.', + 'encoding_format' => 'Kódovanie súboru', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Nahrávanie a správa mediálneho obsahu - obrázkov, videí, zvukov, dokumentov' + ], + 'mediafinder' => [ + 'label' => 'Vyhľadávač médií', + 'default_prompt' => 'Kliknite na tlačítko %s pre hľadanie súboru' + ], + 'media' => [ + 'menu_label' => 'Médiá', + 'upload' => 'Nahrať', + 'move' => 'Presunúť', + 'delete' => 'Zmazať', + 'add_folder' => 'Pridať priečinok', + 'search' => 'Hľadať', + 'display' => 'Zobraziť', + 'filter_everything' => 'Všetko', + 'filter_images' => 'Obrázky', + 'filter_video' => 'Video', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Dokumenty', + 'library' => 'Knižnica', + 'size' => 'Veľkosť', + 'title' => 'Názov', + 'last_modified' => 'Naposledy zmenené', + 'public_url' => 'URL', + 'click_here' => 'Kliknite sem', + 'thumbnail_error' => 'Chyba pri generovaní náhľadu.', + 'return_to_parent' => 'Späť do nadradeného priečinka', + 'return_to_parent_label' => 'Hore ..', + 'nothing_selected' => 'Nič nevybrané.', + 'multiple_selected' => 'Vybraných viac položiek.', + 'uploading_file_num' => 'Nahrávam :number súbor(y)...', + 'uploading_complete' => 'Nahrávanie dokončené', + 'uploading_error' => 'Nahrávanie zlyhalo', + 'type_blocked' => 'Použitý typ súboru je blokovaný z bezpečnostných dôvodov.', + 'order_by' => 'Zoradiť podľa', + 'direction' => 'Smer', + 'direction_asc' => 'Vzostupne', + 'direction_desc' => 'Zostupne', + 'folder' => 'Priečinok', + 'no_files_found' => 'Pre túto požiadavku neboli nájdené žiaadne súbory.', + 'delete_empty' => 'Prosím vyberte položky pre zmazanie.', + 'delete_confirm' => 'Skutočne zmazať vybrané položky?', + 'error_renaming_file' => 'Cyba pri premenovávaní súboru.', + 'new_folder_title' => 'Nový priečinok', + 'folder_name' => 'Názov priečinka', + 'error_creating_folder' => 'Chyba pri vytváraní priečinka', + 'folder_or_file_exist' => 'Priečinok alebo súbor s daným menom už existuje.', + 'move_empty' => 'Prosím vyberte položky na presunutie.', + 'move_popup_title' => 'Presunúť súbory alebo priečinky', + 'move_destination' => 'Cieľový priečinok', + 'please_select_move_dest' => 'Prosím vyberte cieľový priečinok.', + 'move_dest_src_match' => 'Prosím vyberte iný cieľový priečinok.', + 'empty_library' => 'Knižnica médií je prázdna. Nahrajte súbory alebo vytvorte priečinky.', + 'insert' => 'Vložiť', + 'crop_and_insert' => 'Orezať a vložiť', + 'select_single_image' => 'Prosím vyberte iba jeden obrázok.', + 'selection_not_image' => 'Vybraná položka nie je obrázok.', + 'restore' => 'Späť všetky zmeny', + 'resize' => 'Zmeniť veľkosť...', + 'selection_mode_normal' => 'Normálna', + 'selection_mode_fixed_ratio' => 'Pevný pomer strán', + 'selection_mode_fixed_size' => 'Pevná veľkosť', + 'height' => 'Výška', + 'width' => 'Šírka', + 'selection_mode' => 'Spôsob označovania', + 'resize_image' => 'Zmeniť veľkosť obrázku', + 'image_size' => 'Veľkosť obrázku:', + 'selected_size' => 'Vybrané:' + ], +]; diff --git a/modules/backend/lang/sl/lang.php b/modules/backend/lang/sl/lang.php new file mode 100644 index 0000000..4cb459a --- /dev/null +++ b/modules/backend/lang/sl/lang.php @@ -0,0 +1,645 @@ + [ + 'title' => 'Nadzorna plošča', + 'invalid_login' => 'Podatki, ki ste jih vnesli, se ne ujemajo z našimi zapisi. Prosimo, ponovno preverite podatke in poskusite znova.', + ], + 'field' => [ + 'invalid_type' => 'Uporabljen je neveljaven tip polja :type.', + 'options_method_invalid_model' => "Atribut ':field' ne ustreza veljavnemu modelu. Poskusite natančno določiti možnosti metode za model :model.", + 'options_method_not_exists' => "Model :model mora vsebovati metodo :method(), ki vrača možnosti za polje ':field' na obrazcu.", + 'options_static_method_invalid_value' => "Statična metoda ':method()' v razredu :class ni vrnila veljavnih možnosti.", + 'colors_method_not_exists' => "Model :model mora vsebovati metodo :method(), ki vrača HTML barvne kode v HEX formatu za polje ':field' na obrazcu.", + ], + 'widget' => [ + 'not_registered' => "Ime vtičnika ':name' ni bilo registrirano.", + 'not_bound' => "Vtičnik z imenom ':name' ni vezan na kontroler.", + ], + 'page' => [ + 'untitled' => 'Brez naslova', + '404' => [ + 'label' => 'Stran ne obstaja', + 'help' => 'Kljub intenzivnemu iskanju, zahtevanega URL-ja preprosto ni mogoče najti. Ste morda iskali kaj drugega?', + 'back_link' => 'Vrni se na prejšnjo stran', + ], + 'access_denied' => [ + 'label' => 'Dostop zavrnjen', + 'help' => 'Nimate potrebnih dovoljenj za ogled te strani.', + 'cms_link' => 'Vrni se v administracijo', + ], + 'no_database' => [ + 'label' => 'Podatkovna zbirka manjka', + 'help' => 'Za dostop do administracije je potrebna podatkovna zbirka. Preverite, če je podatkovna zbirka pravilno nastavljena in če so bile migracije pognane ter poskusite ponovno.', + 'cms_link' => 'Vrni se na domačo stran', + ], + ], + 'partial' => [ + 'not_found_name' => "Predloge ':name' ni mogoče najti.", + 'invalid_name' => 'Neveljavno ime predloge: :name.', + ], + 'ajax_handler' => [ + 'invalid_name' => "Neveljavno ime AJAX akcije ':name'.", + 'not_found' => "Ni mogoče najti AJAX akcije ':name'.", + ], + 'account' => [ + 'impersonate' => 'Impersonacija uporabnika', + 'impersonate_confirm' => 'Ali ste prepričani, da želite impersonirati tega uporabnika? V prvotno stanje se lahko vrnete tako, da se odjavite.', + 'impersonate_success' => 'Sedaj impersonirate tega uporabnika.', + 'impersonate_working' => 'Impersoniram...', + 'impersonating' => 'Impersonacija uporabnika :full_name', + 'stop_impersonating' => 'Prekliči impersonacijo', + 'unsuspend' => 'Odsuspendiraj', + 'unsuspend_confirm' => 'Ali ste prepričani, da želite odsuspendirati tega uporabnika?', + 'unsuspend_success' => 'Uporabnik je odsuspendiran.', + 'unsuspend_working' => 'Odsuspendiram...', + 'signed_in_as' => 'Prijavljeni ste kot :full_name', + 'sign_out' => 'Odjava', + 'login' => 'Prijava', + 'reset' => 'Ponastavi', + 'restore' => 'Obnovi', + 'login_placeholder' => 'uporabniško ime', + 'password_placeholder' => 'geslo', + 'remember_me' => 'Ostanite prijavljeni', + 'forgot_password' => 'Ste pozabili svoje geslo?', + 'enter_email' => 'Vnesite svoj e-poštni naslov', + 'enter_login' => 'Vnesite svoje uporabniško ime', + 'email_placeholder' => 'e-pošta', + 'enter_new_password' => 'Vnesite novo geslo', + 'password_reset' => 'Ponastavitev gesla', + 'restore_success' => 'Na vaš e-poštni naslov je bilo poslano sporočilo z navodili.', + 'restore_error' => "Uporabnika z uporabniškim imenom ':login' ni mogoče najti.", + 'reset_success' => 'Geslo je bilo ponastavljeno. Sedaj se lahko prijavite.', + 'reset_error' => 'Posredovani so bili neveljavni podatki za ponastavitev gesla. Prosimo, poskusite znova!', + 'reset_fail' => 'Gesla ni bilo mogoče ponastaviti!', + 'apply' => 'Sprejmi', + 'cancel' => 'Prekliči', + 'delete' => 'Izbriši', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => 'Namizje', + 'widget_label' => 'Vtičnik', + 'widget_width' => 'Širina', + 'full_width' => 'Celotna širina', + 'manage_widgets' => 'Upravljanje vtičnikov', + 'add_widget' => 'Dodaj vtičnik', + 'widget_inspector_title' => 'Nastavitve vtičnika', + 'widget_inspector_description' => 'Nastavitve prikaza vtičnika', + 'widget_columns_label' => 'Širina :columns', + 'widget_columns_description' => 'Širina vtičnika, število stolpcev med 1 in 12.', + 'widget_columns_error' => 'Prosimo, vnesite širino vtičnika v obliki števila med 1 in 10.', + 'columns' => '{1} stolpec|{2} stolpca|[3,4] stolpci|[5,Inf] stolpcev', + 'widget_new_row_label' => 'Vsili novo vrstico', + 'widget_new_row_description' => 'Postavi vtičnik v novo vrstico.', + 'widget_title_label' => 'Naslov vtičnika', + 'widget_title_error' => 'Potreben je vnos naslova vtičnika.', + 'reset_layout' => 'Ponastavi postavitev', + 'reset_layout_confirm' => 'Želite postavitev ponastaviti nazaj na privzeto obliko?', + 'reset_layout_success' => 'Postavitev je bila ponastavljena', + 'make_default' => 'Nastavi za privzeto', + 'make_default_confirm' => 'Želite trenutno postavitev nastaviti za privzeto?', + 'make_default_success' => 'Trenutna postavitev je nastavljena kot privzeta.', + 'collapse_all' => 'Strni vse', + 'expand_all' => 'Razširi vse', + 'status' => [ + 'widget_title_default' => 'Status sistema', + 'update_available' => '[0,1] posodobitev na voljo!|{2} posodobitvi na voljo!|[3,4] posodobitve na voljo!|[5,Inf] posodobitev na voljo!', + 'updates_pending' => 'Posodobitev programske opreme je na voljo', + 'updates_nil' => 'Programska oprema je posodobljena', + 'updates_link' => 'Posodobi', + 'warnings_pending' => 'Nekatere zadeve potrebujejo vašo pozornost', + 'warnings_nil' => 'Ni opozoril za prikaz', + 'warnings_link' => 'Prikaži', + 'core_build' => 'Različica sistema', + 'event_log' => 'Dnevnik dogodkov', + 'request_log' => 'Dnevnik zahtev', + 'app_birthday' => 'Na spletu od', + ], + 'welcome' => [ + 'widget_title_default' => 'Dobrodošli', + 'welcome_back_name' => 'Dobrodošli nazaj v :app, :name.', + 'welcome_to_name' => 'Dobrodošli v :app, :name.', + 'first_sign_in' => 'To je vaša prva prijava.', + 'last_sign_in' => 'Vaša zadnja prijava je zabeležena.', + 'view_access_logs' => 'Prikaži dnevnik prijav', + 'nice_message' => 'Imejte lep dan!', + ], + ], + 'user' => [ + 'name' => 'Administrator', + 'menu_label' => 'Administratorji', + 'menu_description' => 'Upravljanje z administratorji, skupinami in dovoljenji.', + 'list_title' => 'Upravljanje administratorjev', + 'new' => 'Nov administrator', + 'login' => 'Uporabniško ime', + 'first_name' => 'Ime', + 'last_name' => 'Priimek', + 'full_name' => 'Polno ime', + 'email' => 'E-poštni naslov', + 'role_field' => 'Vloga', + 'role_comment' => 'Vloge določajo uporabniška dovoljenja, ki jih je možno spremeniti na ravni uporabnika, na zavihku "Dovoljenja".', + 'groups' => 'Skupine', + 'groups_comment' => 'Določite, katerim skupinam pripada ta uporabniški račun.', + 'avatar' => 'Avatar', + 'password' => 'Geslo', + 'password_confirmation' => 'Potrdite geslo', + 'permissions' => 'Dovoljenja', + 'account' => 'Uporabniški račun', + 'superuser' => 'Super administrator', + 'superuser_comment' => 'Temu uporabniškemu računu omogoča neomejen dostop do vseh področij sistema. Super administrator lahko dodaja in upravlja druge uporabnike.', + 'send_invite' => 'Pošlji vabilo po e-pošti', + 'send_invite_comment' => 'Pošlje pozdravno e-poštno sporočilo s podatki o uporabniškem imenu in geslu.', + 'delete_confirm' => 'Želite izbrisati tega administratorja?', + 'return' => 'Vrni se na seznam administratorjev', + 'allow' => 'Dovoli', + 'inherit' => 'Podeduj', + 'deny' => 'Ne dovoli', + 'activated' => 'Aktiviran', + 'last_login' => 'Zadnja prijava', + 'created_at' => 'Ustvarjen', + 'updated_at' => 'Posodobljen', + 'deleted_at' => 'Izbrisan', + 'show_deleted' => 'Prikaži izbrisane', + 'group' => [ + 'name' => 'Skupina', + 'name_field' => 'Ime', + 'name_comment' => 'Ime je prikazano na seznamu skupin na administratorskem obrazcu.', + 'description_field' => 'Opis', + 'is_new_user_default_field_label' => 'Privzeta skupina', + 'is_new_user_default_field_comment' => 'Nove administratorje vedno vključi v to skupino.', + 'code_field' => 'Koda', + 'code_comment' => 'Vnesite unikatno kodo, če želite dostopati do objekta skupine preko API klica.', + 'menu_label' => 'Upravljanje s skupinami', + 'list_title' => 'Upravljanje s skupinami', + 'new' => 'Nova skupina', + 'delete_confirm' => 'Želite odstraniti to administratorsko skupino?', + 'return' => 'Vrni se na seznam skupin', + 'users_count' => 'Uporabniki', + ], + 'role' => [ + 'name' => 'Vloga ', + 'name_field' => 'Ime', + 'name_comment' => 'Ime je prikazano na seznamu vlog na administratorskem obrazcu.', + 'description_field' => 'Opis', + 'code_field' => 'Koda', + 'code_comment' => 'Vnesite unikatno kodo, če želite dostopati do objekta vloge preko API klica.', + 'menu_label' => 'Upravljanje z vlogami', + 'list_title' => 'Upravljanje z vlogami', + 'new' => 'Nova vloga', + 'delete_confirm' => 'Želite odstraniti to administratorsko vlogo?', + 'return' => 'Vrni se na seznam vlog', + 'users_count' => 'Uporabniki', + ], + 'preferences' => [ + 'not_authenticated' => 'Ni overjenega uporabnika, za katerega bi lahko naložili ali shranili nastavitve.', + ], + 'trashed_hint_title' => 'Ta uporabniški račun je bil izbrisan', + 'trashed_hint_desc' => 'Ta uporabniški račun je bil izbrisan in prijava z njim ni več mogoča. Če ga želite obnoviti, kliknite ikono za obnovitev uporabnika v spodnjem desnem kotu.', + ], + 'list' => [ + 'default_title' => 'Seznam', + 'search_prompt' => 'Iskanje...', + 'no_records' => 'Ni najdenih zapisov.', + 'missing_model' => 'Seznam, uporabljen v :class, nima definiranega modela.', + 'missing_column' => 'Manjkajo definicije stolpcev za stolpce :columns.', + 'missing_columns' => 'Seznam, uporabljen v :class, nima definiranih stolpcev seznama.', + 'missing_definition' => "Seznam ne vsebuje stolpca za ':field'.", + 'missing_parent_definition' => "Seznam ne vsebuje definicije za ':definition'.", + 'behavior_not_ready' => 'Seznam se ni inicializiral. Preverite, če ste v kontrolerju poklicali metodo makeLists().', + 'invalid_column_datetime' => "Vrednost stolpca ':column' ni DateTime objekt. Preverite, če imate v vašem modelu definirano referenco \$dates.", + 'pagination' => 'Prikazani zapisi: :from-:to od :total', + 'first_page' => 'Prva stran', + 'last_page' => 'Zadnja stran', + 'prev_page' => 'Prejšnja stran', + 'next_page' => 'Naslednja stran', + 'refresh' => 'Osveži', + 'updating' => 'Posodabljanje...', + 'loading' => 'Nalaganje...', + 'setup_title' => 'Nastavitve seznama', + 'setup_help' => 'Izberite stolpce, ki jih želite prikazati na seznamu. Položaj stolpcev lahko spremenite tako, da jih povlečete gor ali dol.', + 'records_per_page' => 'Število zapisov na strani', + 'records_per_page_help' => 'Izberite koliko zapisov želite prikazati na eni strani. Upoštevajte, da lahko večje število zapisov na eni strani zmanjša hitrost delovanja.', + 'check' => 'Označi', + 'delete_selected' => 'Izbriši izbrano', + 'delete_selected_empty' => 'Ni izbranih zapisov za izbris.', + 'delete_selected_confirm' => 'Želite izbrisati izbrane zapise?', + 'delete_selected_success' => 'Izbrani zapisi so izbrisani.', + 'column_switch_true' => 'Da', + 'column_switch_false' => 'Ne', + ], + 'fileupload' => [ + 'attachment' => 'Priponka', + 'help' => 'Dodajte naslov in opis za to priponko.', + 'title_label' => 'Naslov', + 'description_label' => 'Opis', + 'default_prompt' => 'Če želite naložiti datoteko, kliknite %s ali povlecite datoteko v to polje.', + 'attachment_url' => 'URL priloge', + 'upload_file' => 'Naloži datoteko', + 'upload_error' => 'Napaka pri nalaganju', + 'remove_confirm' => 'Ali ste prepričani?', + 'remove_file' => 'Odstrani datoteko', + ], + 'repeater' => [ + 'add_new_item' => 'Dodaj nov element', + 'min_items_failed' => ':name zahteva najmanj :min elementov, vendar je zagotovljenih le :items elementov.', + 'max_items_failed' => ':name dovoli največ :max elementov, vendar je bilo podanih :items elementov.', + ], + 'form' => [ + 'create_title' => 'Ustvari element ":name"', + 'update_title' => 'Uredi element ":name"', + 'preview_title' => 'Predogled elementa ":name"', + 'create_success' => 'Element ":name" je ustvarjen', + 'update_success' => 'Element ":name" je posodobljen', + 'delete_success' => 'Element ":name" je izbrisan', + 'restore_success' => 'Element ":name" je obnovljen', + 'reset_success' => 'Ponastavitev je zaključena', + 'missing_id' => 'ID obrazca ni bil določen.', + 'missing_model' => 'Obrazec, uporabljen v :class, nima definiranega modela.', + 'missing_definition' => "Obrazec ne vsebuje stolpca za ':field'.", + 'not_found' => 'Obrazca z ID-jem :id ni mogoče najti.', + 'action_confirm' => 'Ali ste prepričani?', + 'create' => 'Ustvari', + 'create_and_close' => 'Ustvari in zapri', + 'creating' => 'Ustvarjanje...', + 'creating_name' => 'Ustvarjanje :name...', + 'save' => 'Shrani', + 'save_and_close' => 'Shrani in zapri', + 'saving' => 'Shranjevanje...', + 'saving_name' => 'Shranjevanje :name...', + 'delete' => 'Izbriši', + 'deleting' => 'Brisanje...', + 'confirm_delete' => 'Želite izbrisati zapis?', + 'confirm_delete_multiple' => 'Želite izbrisati izbrane zapise?', + 'deleting_name' => 'Brisanje :name...', + 'restore' => 'Obnovi', + 'restoring' => 'Obnavljanje', + 'confirm_restore' => 'Ali ste prepričani, da želite obnoviti ta zapis?', + 'reset_default' => 'Ponastavi na privzeto', + 'resetting' => 'Ponastavljanje', + 'resetting_name' => 'Ponastavljanje :name', + 'undefined_tab' => 'Razno', + 'field_off' => 'Ne', + 'field_on' => 'Da', + 'add' => 'Dodaj', + 'apply' => 'Uporabi', + 'cancel' => 'Prekliči', + 'close' => 'Zapri', + 'confirm' => 'Potrdi', + 'reload' => 'Ponovno naloži', + 'complete' => 'Zaključi', + 'ok' => 'OK', + 'or' => 'ali', + 'confirm_tab_close' => 'Zaprem zavihek? Neshranjene spremembe bodo izgubljene.', + 'behavior_not_ready' => 'Obrazec se ni inicializiral. Preverite, če ste v kontrolerju poklicali metodo initForm().', + 'preview_no_files_message' => 'Ni naloženih datotek.', + 'preview_no_media_message' => 'Ni izbranih media datotek.', + 'preview_no_record_message' => 'Ni izbranih zapisov.', + 'select' => 'Izberi', + 'select_all' => 'vse', + 'select_none' => 'nobenega', + 'select_placeholder' => 'izberite', + 'insert_row' => 'Vstavi vrstico', + 'insert_row_below' => 'Vstavi vrstico spodaj', + 'delete_row' => 'Izbriši vrstico', + 'concurrency_file_changed_title' => 'Datoteka je bila spremenjena', + 'concurrency_file_changed_description' => 'Datoteka, ki jo urejate, je bila spremenjena s strani drugega uporabnika. Datoteko lahko znova naložite in izgubite vaše spremembe ali pa jo prepišete s svojimi spremembami.', + 'return_to_list' => 'Vrni se na seznam', + ], + 'recordfinder' => [ + 'find_record' => 'Poišči zapis', + 'invalid_model_class' => 'Model ":modelClass", določen za iskalnik zapisov, je neveljaven.', + 'cancel' => 'Prekliči', + ], + 'pagelist' => [ + 'page_link' => 'Povezava do strani', + 'select_page' => 'Izberite stran...', + ], + 'relation' => [ + 'missing_config' => "Relacija ne vsebuje nastavitev za ':config'.", + 'missing_definition' => "Relacija ne vsebuje definicije za ':field'.", + 'missing_model' => 'Relacija, uporabljena v :class, nima definiranega modela.', + 'invalid_action_single' => 'Tega dejanja ni mogoče izvesti na relaciji ena proti ena.', + 'invalid_action_multi' => 'Tega dejanja ni mogoče izvesti na relaciji mnogo proti mnogo.', + 'help' => 'Kliknite na element, ki ga želite dodati.', + 'related_data' => 'Povezani podatki :name', + 'add' => 'Dodaj', + 'add_selected' => 'Dodaj izbrano', + 'add_a_new' => 'Dodaj novo :name', + 'link_selected' => 'Povezava je izbrana', + 'link_a_new' => 'Poveži novo :name', + 'cancel' => 'Prekliči', + 'close' => 'Zapri', + 'add_name' => 'Dodaj :name', + 'create' => 'Ustvari', + 'create_name' => 'Ustvari :name', + 'update' => 'Posodobi', + 'update_name' => 'Posodobi :name', + 'preview' => 'Predogled', + 'preview_name' => 'Predogled za :name', + 'remove' => 'Odstrani', + 'remove_name' => 'Odstrani :name', + 'delete' => 'Izbriši', + 'delete_name' => 'Izbriši :name', + 'delete_confirm' => 'Ali ste prepričani?', + 'link' => 'Povezava', + 'link_name' => 'Povezava za :name', + 'unlink' => 'Odstrani povezavo', + 'unlink_name' => 'Odstrani povezavo :name', + 'unlink_confirm' => 'Ali ste prepričani?', + ], + 'reorder' => [ + 'default_title' => 'Razvrsti zapise', + 'no_records' => 'Na voljo ni nobenih zapisov za razvrščanje.', + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => "Modela ':class' z ID-jem :id ni mogoče najti", + 'missing_id' => 'Za iskanje modela ni določen noben ID.', + 'missing_relation' => "Model ':class' nima definirane relacije ':relation'.", + 'missing_method' => "Model ':class' ne vsebuje metode ':method'.", + 'invalid_class' => "Model :model, uporabljen v :class ni veljaven. Dedovati mora objekt \Model.", + 'mass_assignment_failed' => "Masovna dodelitev je bila neuspešna za atribut ':attribute' na modelu.", + ], + 'warnings' => [ + 'tips' => 'Nasveti glede nastavitev sistema', + 'tips_description' => 'Za pravilno nastavitev sistema morate biti pozorni na določene podrobnosti.', + 'permissions' => 'PHP ne more pisati v mapo :name in njene podmape. Prosimo, nastavite spletnemu strežniku ustrezna dovoljenja za to mapo.', + 'extension' => 'PHP razširitev (extension) :name ni nameščena. Prosimo, namestite ustrezno knjižnico in aktivirajte razširitev.', + 'plugin_missing' => 'Za delovanje je potreben vtičnik :name, vendar ni nameščen. Prosimo, namestite ta vtičnik.', + 'debug' => 'Način za odpravljanje napak je omogočen. Ta način ni priporočljiv za produkcijsko okolje.', + 'decompileBackendAssets' => 'Oblikovne datoteke (CSS, JavaSrcipt) v administraciji so trenutno ne-stisnjene. To ni priporočljivo za produkcijsko okolje.', + ], + 'editor' => [ + 'menu_label' => 'Nastavitve urejevalnika', + 'menu_description' => 'Splošne nastavitve urejevalnika, kot npr. velikost pisave in barvna shema.', + 'font_size' => 'Velikost pisave', + 'tab_size' => 'Širina tabulatorja', + 'use_hard_tabs' => 'Odmik s tabulatorjem', + 'code_folding' => 'Strnjevanje kode', + 'code_folding_begin' => 'Označi začetek', + 'code_folding_begin_end' => 'Označi začetek in konec', + 'autocompletion' => 'Samodejno dokončanje', + 'word_wrap' => 'Prelom besed', + 'highlight_active_line' => 'Označi aktivno vrstico', + 'auto_closing' => 'Samodejno zapri označbe', + 'show_invisibles' => 'Prikaži nevidne znake', + 'show_gutter' => 'Prikaži odmike', + 'basic_autocompletion' => 'Osnovno samodejno dokončanje (Ctrl + Space)', + 'live_autocompletion' => 'Instantno samodejno dokončanje', + 'enable_snippets' => 'Omogoči odseke kode (Tab)', + 'display_indent_guides' => 'Prikaži vodila za odmike', + 'show_print_margin' => 'Prikaži rob tiskanja', + 'mode_off' => 'Izključi', + 'mode_fluid' => 'Fluidno', + '40_characters' => '40 znakov', + '80_characters' => '80 znakov', + 'theme' => 'Barvna shema', + 'markup_styles' => 'Označevalni slogi', + 'custom_styles' => 'Slog po meri', + 'custom styles_comment' => 'Slogi, ki jih želite vključiti v urejevalnik HTML.', + 'markup_classes' => 'Označevalni razredi', + 'paragraph' => 'Odstavek', + 'link' => 'Povezava', + 'table' => 'Tabela', + 'table_cell' => 'Celica tabele', + 'image' => 'Slika', + 'label' => 'Opis', + 'class_name' => 'Oznaka razreda', + 'markup_tags' => 'Označevalne oznake', + 'markup_tag' => 'Označevalna oznaka', + 'allowed_empty_tags' => 'Dovoljene prazne oznake', + 'allowed_empty_tags_comment' => 'Seznam oznak, ki niso odstranjene, če v njih ni vsebine.', + 'allowed_tags' => 'Dovoljene oznake', + 'allowed_tags_comment' => 'Seznam dovoljenih oznak.', + 'no_wrap' => 'Ne-zavite oznake', + 'no_wrap_comment' => 'Seznam oznak, ki naj ne bodo zavite znotraj blokovskih oznak.', + 'remove_tags' => 'Odstrani oznake', + 'remove_tags_comment' => 'Seznam oznak, ki so odstranjene skupaj z njihovo vsebino.', + 'line_breaker_tags' => 'Oznake prekinitve vrstic', + 'line_breaker_tags_comment' => 'Seznam oznak, ki se uporabljajo za postavitev elementa prekinitve med vrstice.', + 'toolbar_options' => 'Nastavitve orodne vrstice', + 'toolbar_buttons' => 'Gumbi orodne vrstice', + 'toolbar_buttons_comment' => 'Gumbi orodne vrstice, ki se privzeto prikažejo v urejevalniku. [fullscreen, bold, italic, underline, strikeThrough, subscript, superscript, fontFamily, fontSize, |, color, emoticons, inlineStyle, paragraphStyle, |, paragraphFormat, align, formatOL, formatUL, outdent, indent, quote, insertHR, -, insertLink, insertImage, insertVideo, insertAudio, insertFile, insertTable, undo, redo, clearFormatting, selectAll, html]', + 'toolbar_buttons_preset' => 'Vstavite prednastavljeno konfiguracijo gumbov orodne vrstice:', + 'toolbar_buttons_presets' => [ + 'default' => 'Privzeto', + 'minimal' => 'Minimalno', + 'full' => 'Polno', + ], + 'paragraph_formats' => 'Formati odstavkov', + 'paragraph_formats_comment' => 'Možnosti, ki se prikažejo v spustnem seznamu Format odstavka.', + ], + 'tooltips' => [ + 'preview_website' => 'Ogled spletne strani', + ], + 'mysettings' => [ + 'menu_label' => 'Moje nastavitve', + 'menu_description' => 'Nastavitve, povezane z vašim administratorskim računom', + ], + 'myaccount' => [ + 'menu_label' => 'Moj profil', + 'menu_description' => 'Urejanje podatkov vašega profila, kot so ime, e-pošta in geslo.', + 'menu_keywords' => 'varnostna prijava', + ], + 'branding' => [ + 'menu_label' => 'Prilagoditev administracije', + 'menu_description' => 'Prilagoditev okolja administracije, kot so npr. ime, barve in logotip.', + 'brand' => 'Splošno', + 'logo' => 'Logotip', + 'logo_description' => 'Naložite poljuben logotip, ki ga želite prikazati v administraciji.', + 'favicon' => 'Ikona zaznamka (favicon)', + 'favicon_description' => 'Naložite poljubno ikono zaznamka za administracijo.', + 'app_name' => 'Ime aplikacije', + 'app_name_description' => 'Ime je prikazano v naslovni vrstici administracije.', + 'app_tagline' => 'Slogan aplikacije', + 'app_tagline_description' => 'Slogan je prikazan na prijavnem oknu administracije.', + 'colors' => 'Barve', + 'primary_color' => 'Primarna barva', + 'secondary_color' => 'Sekundarna barva', + 'accent_color' => 'Poudarjena barva', + 'styles' => 'CSS slogi', + 'custom_stylesheet' => 'CSS slogi po meri', + 'navigation' => 'Navigacija', + 'menu_mode' => 'Slog menija', + 'menu_mode_inline' => 'Vrstični', + 'menu_mode_inline_no_icons' => 'Vrstični (brez ikon)', + 'menu_mode_tile' => 'Ploščice', + 'menu_mode_collapsed' => 'Strnjen', + ], + 'backend_preferences' => [ + 'menu_label' => 'Nastavitve administracije', + 'menu_description' => 'Upravljajte nastavitve vašega profila, kot je npr. jezik.', + 'region' => 'Regija', + 'code_editor' => 'Urejevalnik kode', + 'timezone' => 'Časovni pas', + 'timezone_comment' => 'Prikazani datumi se prilagodijo glede na izbran časovni pas.', + 'locale' => 'Jezik', + 'locale_comment' => 'Izberite želeni jezik za uporabo v administraciji.', + ], + 'access_log' => [ + 'hint' => 'Ta dnevnik beleži seznam uspešnih prijav administratorjev. Zapisi se hranijo :days dni.', + 'menu_label' => 'Dnevnik dostopov', + 'menu_description' => 'Prikaz seznama uspešnih prijav administratorjev.', + 'id' => 'ID', + 'created_at' => 'Datum in čas', + 'type' => 'Tip', + 'login' => 'Uporabniško ime', + 'ip_address' => 'IP naslov', + 'first_name' => 'Ime', + 'last_name' => 'Priimek', + 'email' => 'E-pošta', + ], + 'filter' => [ + 'all' => 'vsi', + 'options_method_not_exists' => "Model :model mora vsebovati metodo :method(), ki vrača možnosti za filter ':filter'.", + 'date_all' => 'vse periode', + 'number_all' => 'vsa števila', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Naložite CSV datoteko', + 'import_file' => 'Uvozi datoteko', + 'row' => 'Vrstica :row', + 'first_row_contains_titles' => 'Prva vrstica vsebuje naslove stolpcev', + 'first_row_contains_titles_desc' => 'To polje pustite označeno, če prva vrstica v vaši CSV datoteki vsebuje naslove stolpcev.', + 'match_columns' => '2. Povežite stolpce v datoteki s polji v podatkovni zbirki', + 'file_columns' => 'Stolpci v datoteki', + 'database_fields' => 'Polja v podatkovni zbirki', + 'set_import_options' => '3. Nastavite možnosti uvoza', + 'export_output_format' => '1. Izberite format izvozne datoteke', + 'file_format' => 'Format datoteke', + 'standard_format' => 'Standardni format', + 'custom_format' => 'Format po meri', + 'delimiter_char' => 'Znak ločila', + 'enclosure_char' => 'Znak zaključka', + 'escape_char' => 'Izhodni znak', + 'select_columns' => '2. Označite stolpce za izvoz', + 'column' => 'Stolpec', + 'columns' => 'Stolpci', + 'set_export_options' => '3. Nastavitve možnosti izvoza', + 'show_ignored_columns' => 'Prikaži prezrte stolpce', + 'auto_match_columns' => 'Samodejno poveži stolpce', + 'created' => 'Ustvarjeno', + 'updated' => 'Posodobljeno', + 'skipped' => 'Izpuščeno', + 'warnings' => 'Opozorila', + 'errors' => 'Napake', + 'skipped_rows' => 'Izpuščene vrstice', + 'import_progress' => 'Napredek uvoza', + 'processing' => 'Procesiranje', + 'import_error' => 'Napaka pri uvozu', + 'upload_valid_csv' => 'Prosimo, naložite veljavno CSV datoteko.', + 'drop_column_here' => 'Spustite stolpec sem...', + 'ignore_this_column' => 'Prezri ta stolpec', + 'processing_successful_line1' => 'Izvoz datoteke je zaključen!', + 'processing_successful_line2' => 'Brskalnik vas bo sedaj preusmeril na prenos datoteke.', + 'export_progress' => 'Napredek izvoza', + 'export_error' => 'Napaka pri izvozu', + 'column_preview' => 'Predogled stolpca', + 'file_not_found_error' => 'Datoteke ni mogoče najti', + 'empty_error' => 'Ni podanih podatkov za izvoz', + 'empty_import_columns_error' => 'Prosimo, določite nekaj stolpcev za uvoz.', + 'match_some_column_error' => 'Prosimo, najprej povežite nekaj stolpcev.', + 'required_match_column_error' => 'Prosimo, določite povezavo za zahtevano polje :label.', + 'empty_export_columns_error' => 'Prosimo, določite nekaj stolpcev za izvoz.', + 'behavior_missing_uselist_error' => 'Implementirati morate kontroler ListController z omogočeno možnostjo izvoza "useList".', + 'missing_model_class_error' => 'Prosimo, določite modelClass lastnost za :type.', + 'missing_column_id_error' => 'Manjka identifikator stolpca', + 'unknown_column_error' => 'Neznan stolpec', + 'encoding_not_supported_error' => 'Kodiranje izvorne datoteke ni prepoznano. Za uspešen uvoz vaše datoteke izberite ustrezno kodiranje.', + 'encoding_format' => 'Kodiranje datoteke', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1250' => 'Windows-1250 (CP1250, Central and Eastern European)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)', + ], + ], + 'permissions' => [ + 'manage_media' => 'Nalaganje in upravljanje z media vsebinami - slike, video posnetki, zvočni posnetki, dokumenti', + 'allow_unsafe_markdown' => 'Dovoli uporabo nevarnih označb (lahko vključi Javascript)', + ], + 'mediafinder' => [ + 'label' => 'Media brskalnik', + 'default_prompt' => 'Kliknite gumb %s za iskanje media elementa', + 'no_image' => 'Slike ni mogoče najti', + ], + 'media' => [ + 'menu_label' => 'Media', + 'upload' => 'Naloži', + 'move' => 'Premakni', + 'delete' => 'Izbriši', + 'add_folder' => 'Dodaj mapo', + 'search' => 'Iskanje', + 'display' => 'Prikaz', + 'filter_everything' => 'Vse', + 'filter_images' => 'Slike', + 'filter_video' => 'Video', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Dokumenti', + 'library' => 'Knjižnica', + 'size' => 'Velikost', + 'title' => 'Naslov', + 'last_modified' => 'Zadnja sprememba', + 'public_url' => 'URL', + 'click_here' => 'Kliknite tukaj', + 'thumbnail_error' => 'Napaka pri ustvarjanju sličice.', + 'return_to_parent' => 'Vrni se v nadrejeno mapo', + 'return_to_parent_label' => 'Pojdi gor ..', + 'nothing_selected' => 'Nič ni izbrano.', + 'multiple_selected' => 'Izbranih je več elementov.', + 'uploading_file_num' => 'Nalaganje :number datotek(e)...', + 'uploading_complete' => 'Nalaganje zaključeno', + 'uploading_error' => 'Nalaganje ni uspelo', + 'type_blocked' => 'Izbrani tip datoteke je blokiran iz varnostnih razlogov.', + 'order_by' => 'Razvrsti po', + 'direction' => 'Smer', + 'direction_asc' => 'Naraščajoče', + 'direction_desc' => 'Padajoče', + 'folder' => 'Mapa', + 'no_files_found' => 'Vaše iskanje se ne ujema z nobeno datoteko.', + 'delete_empty' => 'Prosimo, izberite elemente, ki jih želite izbrisati.', + 'delete_confirm' => 'Želite izbrisati izbrane elemente?', + 'error_renaming_file' => 'Napaka pri preimenovanju elementa.', + 'new_folder_title' => 'Nova mapa', + 'folder_name' => 'Ime mape', + 'error_creating_folder' => 'Napaka pri ustvarjanju mape', + 'folder_or_file_exist' => 'Datoteka ali mapa z izbranim imenom že obstaja.', + 'move_empty' => 'Prosimo, izberite elemente, ki jih želite premakniti.', + 'move_popup_title' => 'Premakni datoteke ali mape', + 'move_destination' => 'Ciljna mapa', + 'please_select_move_dest' => 'Prosimo, izberite ciljno mapo.', + 'move_dest_src_match' => 'Prosimo, izberite drugo ciljno mapo.', + 'empty_library' => 'Tukaj izgleda malo prazno. Za začetek naložite datoteke ali ustvarite mape.', + 'insert' => 'Vstavi', + 'crop_and_insert' => 'Obreži in vstavi', + 'select_single_image' => 'Prosimo, izberite samo eno sliko.', + 'selection_not_image' => 'Izbrani element ni slika.', + 'restore' => 'Razveljavi vse spremembe', + 'resize' => 'Spremeni velikost...', + 'selection_mode_normal' => 'Normalno', + 'selection_mode_fixed_ratio' => 'Fiksno razmerje', + 'selection_mode_fixed_size' => 'Fiksna velikost', + 'height' => 'Višina', + 'width' => 'Širina', + 'selection_mode' => 'Izbirni način', + 'resize_image' => 'Spremeni velikost slike', + 'image_size' => 'Velikost slike:', + 'selected_size' => 'Izbrano:', + ], +]; diff --git a/modules/backend/lang/sv/lang.php b/modules/backend/lang/sv/lang.php new file mode 100644 index 0000000..2557d7f --- /dev/null +++ b/modules/backend/lang/sv/lang.php @@ -0,0 +1,380 @@ + [ + 'title' => 'Administrationsområde' + ], + 'field' => [ + 'invalid_type' => 'Felaktig fälttyp använd :type.', + 'options_method_not_exists' => 'Modellklassen :model måste definera en metod :method() som returnerar villkor för formfältet ":field"', + ], + 'widget' => [ + 'not_registered' => "En widget med klassnamnet ':name' har inte blivit registrerad", + 'not_bound' => "En widget med klassnamnet ':name' saknas i controllern", + ], + 'page' => [ + 'untitled' => "Ej namngiven", + 'access_denied' => [ + 'label' => "Nekat tillträde", + 'help' => "Du har inte behörighet att visa den här sidan.", + 'cms_link' => "Gå till CMS backend", + ], + ], + 'partial' => [ + 'not_found_name' => "En partial med namn ':name' kunde inte hittas", + ], + 'account' => [ + 'sign_out' => 'Logga ut', + 'login' => 'Logga in', + 'reset' => 'Nollställ', + 'restore' => 'Återställ', + 'login_placeholder' => 'användarnamn', + 'password_placeholder' => 'lösenord', + 'forgot_password' => "Glömt ditt lösenord?", + 'enter_email' => "Ange din e-postadress", + 'enter_login' => "Ange ditt användarnamn", + 'email_placeholder' => "e-post", + 'enter_new_password' => "Välj ett nytt lösenord", + 'password_reset' => "Återställ lösenord", + 'restore_success' => "Ett meddelande har skickats till din e-postadress med instruktioner om hur du återställer ditt lösenord", + 'restore_error' => "En användare med användarnamnet ':login' kunde inte hittas", + 'reset_success' => "Ditt lösenord har blivit återställt. Du kan nu logga in", + 'reset_error' => "Felaktig data för lösenordsåterställning. Var vänlig försök igen", + 'reset_fail' => "Det gick tyvärr inte att nollställa ditt lösenord", + 'apply' => 'Spara', + 'cancel' => 'Avbryt', + 'delete' => 'Radera', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => 'Kontrollpanelen', + 'widget_label' => 'Widget', + 'widget_width' => 'Bredd', + 'full_width' => 'max bredd', + 'add_widget' => 'Lägg till widget', + 'widget_inspector_title' => 'Widget inställningar', + 'widget_inspector_description' => 'Widget informations inställningar', + 'widget_columns_label' => 'Bredd :columns', + 'widget_columns_description' => 'Bredden på widgeten ska vara ett nummer mellan 1 och 10.', + 'widget_columns_error' => 'Vänligen ange widgetens bredden som ett nummer mellan 1 och 10.', + 'columns' => '{1} column|[2,Inf] kolonner', + 'widget_new_row_label' => 'Forcera en ny rad', + 'widget_new_row_description' => 'Lägg widgeten på en ny rad.', + 'widget_title_label' => 'Widget-titel', + 'widget_title_error' => 'En widgets titel är tvingande.', + 'status' => [ + 'widget_title_default' => 'Systemstatus', + 'update_available' => '{0} uppdateringar tillgängliga!|{1} uppdatering tillgänglig!|[2,Inf] uppdateringar tillgängliga!' + ] + ], + 'user' => [ + 'name' => 'Administratör', + 'menu_label' => 'Administratörer', + 'menu_description' => 'Hantera administratörer, grupper och behörigheter.', + 'list_title' => 'Hantera administratörer', + 'new' => 'Ny administratör', + 'login' => "Användarnamn", + 'first_name' => "Förnamn", + 'last_name' => "Efternamn", + 'full_name' => "Fullständigt namn", + 'email' => "E-post", + 'groups' => "Grupper", + 'groups_comment' => "Välj vilken grupp denna person hör till", + 'avatar' => "Avatar", + 'password' => "Lösenord", + 'password_confirmation' => "Bekräfta lösenord", + 'permissions' => 'Rättigheter', + 'account' => 'Konto', + 'superuser' => "Superanvändare", + 'superuser_comment' => "Markera denna checkbox för att ge denna person tillgång till alla områden", + 'send_invite' => 'Inbjudan är sänd via e-post', + 'send_invite_comment' => 'Markera denna checkbox för att skicka en inbjudan till användaren via e-post', + 'delete_confirm' => 'Vill du verkligen radera denna administratör?', + 'return' => 'Återgå till administratörlistan', + 'allow' => 'Tillåt', + 'inherit' => 'Ärv', + 'deny' => 'Förbjud', + 'group' => [ + 'name' => 'Grupp', + 'name_field' => 'Namn', + 'description_field' => 'Beskriving', + 'is_new_user_default_field' => 'Lägg till nya administratörer till gruppen som standard', + 'code_field' => 'Kod', + 'code_comment' => 'Ange en unik kod om du vill komma åt det med API.', + 'menu_label' => 'Grupper', + 'list_title' => 'Hantera grupper', + 'new' => 'Ny administratörsgrupp', + 'delete_confirm' => 'Vill du verkligen radera denna administratörsgrupp?', + 'return' => 'Återgå till grupplistan', + 'users_count' => 'Användare' + ], + 'preferences' => [ + 'not_authenticated' => 'Det finns ingen autentiserad användare att ladda eller spara inställningar för', + ] + ], + 'list' => [ + 'default_title' => 'Lista', + 'search_prompt' => 'Sök...', + 'no_records' => 'Det finns inga träffar för denna vy', + 'missing_model' => 'List-egenskapen i :class har ingen modell definerad', + 'missing_column' => 'Det finns inga kolumndefinitioner för :columns', + 'missing_columns' => 'Listan som används i :class har inga listkolumner definerade', + 'missing_definition' => "Listegenskapen saknar en kolumn för ':field'", + 'behavior_not_ready' => 'Listegenskapen har inte blivit initierad, kontrollera att du har anropat makeLists() i din controller', + 'invalid_column_datetime' => "Kolumns värde ':column' är inte ett DateTime objekt, saknar du en \$dates referens i Model?", + 'pagination' => 'Visade poster: :from-:to av :total', + 'prev_page' => 'Föregående sida', + 'next_page' => 'Nästa sida', + 'loading' => 'Laddar...', + 'setup_title' => 'List inställningar', + 'setup_help' => 'Använd kryssrutorna för att välja kolumner du vill se i listan. Du kan ändra positionen på kolumnerna genom att dra dem upp eller ner.', + 'records_per_page' => 'Poster per sida', + 'records_per_page_help' => 'Välj antalet poster som ska visas per sida. Observera att högt antal poster per sida kan påverka prestandan.', + 'delete_selected' => 'Radera utvald', + 'delete_selected_empty' => 'Det finns inga markerad post att radera.', + 'delete_selected_confirm' => 'Ta bort de markerade posterna?', + 'delete_selected_success' => 'De markerade posterna är raderade.', + ], + 'fileupload' => [ + 'attachment' => 'Bilaga', + 'help' => 'Lägg till en och beskriving för denna bilagan.', + 'title_label' => 'Titel', + 'description_label' => 'Beskriving', + 'default_prompt' => 'Klicka på %s eller dra en fil hit för att ladda upp', + 'attachment_url' => 'Bilage-URL', + 'upload_file' => 'Ladda upp fil', + 'upload_error' => 'Fel vid uppladdning', + 'remove_confirm' => 'Är du säker?', + 'remove_file' => 'Radera fil' + ], + 'form' => [ + 'create_title' => "Skapa :name", + 'update_title' => "Redigera :name", + 'preview_title' => "Förhandsgranska :name", + 'create_success' => ':name har skapats', + 'update_success' => ':name har uppdaterats', + 'delete_success' => ':name kunde inte raderas', + 'missing_id' => "Rad-ID för formuläret har inte blivit specificerat", + 'missing_model' => 'Formuläregenskapen som används i :class har ingen modell definierad', + 'missing_definition' => "Formuläregenskapen saknar ett fält för ':field'", + 'not_found' => 'Rad-ID :id för formuläret kunde inte hittas', + 'action_confirm' => 'Är du säker?', + 'create' => 'Skapa', + 'create_and_close' => 'Skapa och stäng', + 'creating' => 'Skapar...', + 'creating_name' => 'Skapar :name...', + 'save' => 'Spara', + 'save_and_close' => 'Spara och stäng', + 'saving' => 'Sparar...', + 'saving_name' => 'Sparar :name...', + 'delete' => 'Radera', + 'deleting' => 'Raderar...', + 'deleting_name' => 'Raderar :name...', + 'reset_default' => 'Äterställ till utgångsläge', + 'resetting' => 'Återställer', + 'resetting_name' => 'Återställer :name', + 'undefined_tab' => 'Övrigt', + 'field_off' => 'Av', + 'field_on' => 'På', + 'add' => 'Lägg till', + 'apply' => 'Spara', + 'cancel' => 'Avbryt', + 'close' => 'Stäng', + 'confirm' => 'Bekräfta', + 'reload' => 'Ladda om', + 'complete' => 'Slutför', + 'ok' => 'OK', + 'or' => 'eller', + 'confirm_tab_close' => 'Vill du verkligen stänga fliken? Ej sparade ändringar kommer gå förlorade', + 'behavior_not_ready' => 'Formuläregenskap har inte blivit initierad, kontrollera att du anropat initForm() i din controller', + 'preview_no_files_message' => 'Filen är inte uppladdad', + 'preview_no_record_message' => 'Ingen rad är vald.', + 'select' => 'Välj', + 'select_all' => 'Välj alla', + 'select_none' => 'Välj ingen', + 'select_placeholder' => 'Vänligen välj', + 'insert_row' => 'Lägg till rad', + 'delete_row' => 'Radera rad', + 'concurrency_file_changed_title' => 'Filen var ändrad', + 'concurrency_file_changed_description' => "Filen du redigerar har ändrats av en annan användare. Du kan antingen ladda om sidan och förlora dina ändringar eller skriva över filen med dina ändringar." + ], + 'relation' => [ + 'missing_config' => "Relationsbeteendet har ingen konfiguration för ': config '.", + 'missing_definition' => "Relationen saknar en definintion för ':field'", + 'missing_model' => "Relationen som används i :class har ingen modell definierad", + 'invalid_action_single' => "Den här åtgärden kan inte appliceras på en enskild relation", + 'invalid_action_multi' => "Denna åtgärd kan inte appliceras på flera relationer", + 'help' => "Klicka på en post för att lägga till", + 'related_data' => "Relaterad :name data", + 'add' => "Lägg till", + 'add_selected' => "Lägg till vald", + 'add_a_new' => "Lägg till ny :name", + 'link_selected' => "Länka vald", + 'link_a_new' => "Länka till ny :name", + 'cancel' => "Avbryt", + 'close' => "Stäng", + 'add_name' => "Lägg till :name", + 'create' => "Skapa", + 'create_name' => "Skapa :name", + 'update' => "Uppdatera", + 'update_name' => "Uppdatera :name", + 'preview' => "Förhandsgranska", + 'preview_name' => "Förhandsgranska :name", + 'remove' => "Ta bort", + 'remove_name' => "Ta bort :name", + 'delete' => "Radera", + 'delete_name' => "Radera :name", + 'delete_confirm' => "Är du säker?", + 'link' => "Länka", + 'link_name' => "Länka :name", + 'unlink' => "Avlänka", + 'unlink_name' => "Avlänka :name", + 'unlink_confirm' => "Är du säker?", + ], + 'reorder' => [ + 'default_title' => 'Ordna om rader', + 'no_records' => 'Det finns inga rader att sortera.', + ], + 'model' => [ + 'name' => "Modell", + 'not_found' => "Modellen ':class' med ID :id kunde inte hittas", + 'missing_id' => "Det finns inget ID anviget för modellen", + 'missing_relation' => "Modellen ':class' saknar en definition för ':relation'", + 'missing_method' => "Modellen ':class' innehåller inte metoden ':method'.", + 'invalid_class' => "Modellen :model i klass :class är inte giltig. Den måste ärva från \Model-klassen", + 'mass_assignment_failed' => "Massuppdraget misslyckades för Modell-attributet ':attribute'.", + ], + 'warnings' => [ + 'tips' => 'Systemkonfigurationstips', + 'tips_description' => 'Det finns problem som du behöver åtgärda för att konfigurera systemet ordentligt.', + 'permissions' => 'Katalogen :name eller dess underkataloger är inte skrivbara av PHP. Väligen ändra dess motsvarande behörigheter för web-servern i denna katalogen.', + 'extension' => 'PHP-tillägget: Namnet är inte installerat. Vänligen installera och aktivera det biblioteket.' + ], + 'editor' => [ + 'menu_label' => 'Kodnings preferenser', + 'menu_description' => 'Anpassa dina preferenser för kodredigering, så som typsnitt och färgschema.', + 'font_size' => 'Teckenstorlek', + 'tab_size' => 'Tab längd', + 'use_hard_tabs' => 'Indentera med tab', + 'code_folding' => 'Dölj kod', + 'word_wrap' => 'Radbryting', + 'highlight_active_line' => 'Markera aktiv rad', + 'auto_closing' => 'Stäng taggar och specialtecken automatiskt', + 'show_invisibles' => 'Visa dolda tecken', + 'show_gutter' => 'Visa ränna', + 'theme' => 'Färgschema' + ], + 'tooltips' => [ + 'preview_website' => 'Förhandsgranska websidan' + ], + 'mysettings' => [ + 'menu_label' => 'Mina inställningar', + 'menu_description' => 'Inställningar rörande ditt administrationskonto' + ], + 'myaccount' => [ + 'menu_label' => 'Mitt konto', + 'menu_description' => 'Uppdatera dina kontouppgifter såsom namn, e-postadress och lösenord.', + 'menu_keywords' => 'säkerhets inloggning' + ], + 'branding' => [ + 'menu_label' => 'Anpassa back-end', + 'menu_description' => 'Anpassa administrations området såsom namn, färger och logotyp.', + 'brand' => 'Varumärke', + 'logo' => 'Logga', + 'logo_description' => 'Ladda upp en egen logotyp för att använda i back-end.', + 'app_name' => 'Applikationsnamn', + 'app_name_description' => 'Detta namn visas i titelområdet back-end.', + 'app_tagline' => 'Applikationstaggning', + 'app_tagline_description' => 'Detta namn visas på inloggningsskärmen för back-end.', + 'colors' => 'Färger', + 'primary_color' => 'Primär color', + 'secondary_color' => 'Sekundär color', + 'accent_color' => 'Accent color', + 'styles' => 'Formatmallar', + 'custom_stylesheet' => 'Anpassad formatmall' + ], + 'backend_preferences' => [ + 'menu_label' => 'Back-end preferenser', + 'menu_description' => 'Hantera dina kontoinställningar såsom önskat språk.', + 'locale' => 'Språk', + 'locale_comment' => 'Välj önskat språk.' + ], + 'access_log' => [ + 'hint' => 'Denna logg visar en lista över lyckade inloggningsförsök till administratrationen. Registret behålls i :days dagar.', + 'menu_label' => 'Åtkomstlogg', + 'menu_description' => 'Visa en lista över framgångsrika inloggningar av back-end användare.', + 'created_at' => 'Dataum och tid', + 'login' => 'Inloggning', + 'ip_address' => 'IP adress', + 'first_name' => 'Förnamn', + 'last_name' => 'Efternamn', + 'email' => 'E-post' + ], + 'filter' => [ + 'all' => 'alla' + ], + 'permissions' => [ + 'manage_media' => 'Hantera media' + ], + 'mediafinder' => [ + 'default_prompt' => 'Klicka på %s knappen för att hitta ett mediaföremål' + ], + 'media' => [ + 'menu_label' => 'Media', + 'upload' => 'Ladda upp', + 'move' => 'Flytta', + 'delete' => 'Radera', + 'add_folder' => 'Ny mapp', + 'search' => 'Sök', + 'display' => 'Visa', + 'filter_everything' => 'Allt', + 'filter_images' => 'Bilder', + 'filter_video' => 'Videor', + 'filter_audio' => 'Ljud', + 'filter_documents' => 'Dokument', + 'library' => 'Bibliotek', + 'size' => 'Storlek', + 'title' => 'Titel', + 'last_modified' => 'Senast ändrad', + 'public_url' => 'Publik URL', + 'click_here' => 'Klicka här', + 'thumbnail_error' => 'Fel vid generering av thumbnail.', + 'return_to_parent' => 'Återgå till mappens förälder', + 'return_to_parent_label' => 'Upp ..', + 'nothing_selected' => 'Inget är valt.', + 'multiple_selected' => 'Flera föremål valda.', + 'uploading_file_num' => 'Laddar upp :number fil(er)...', + 'uploading_complete' => 'Uppladdning slutförd', + 'order_by' => 'Ordna efter', + 'folder' => 'Mapp', + 'no_files_found' => 'Inga filer kunde hittas baserat på din sökning.', + 'delete_empty' => 'Vänligen välj föremål att radera.', + 'delete_confirm' => 'Är du säker att du vill radera de valda föremålen?', + 'error_renaming_file' => 'Fel vid namnbyte av föremålet.', + 'new_folder_title' => 'Ny mapp', + 'folder_name' => 'Mappnamn', + 'error_creating_folder' => 'Fel vid skapande av mapp', + 'folder_or_file_exist' => 'En mapp eller fil med det angivna namnet existerar redan.', + 'move_empty' => 'Vänligen välj föremål att flytta.', + 'move_popup_title' => 'Flytta filer eller mappar', + 'move_destination' => 'Destinationsmapp', + 'please_select_move_dest' => 'Vänligen välj en destinationsmapp.', + 'move_dest_src_match' => 'Vänligen välj en annan destinationsmapp.', + 'empty_library' => 'Mediabiblioteket är tomt. Ladda upp filer eller skapa mappar för att börja.', + 'insert' => 'Infoga', + 'crop_and_insert' => 'Beskär & infoga', + 'select_single_image' => 'Vänligen välj en enskild bild.', + 'selection_not_image' => 'Det valda föremålet är inte en bild.', + 'restore' => 'Ångra alla ändringar', + 'resize' => 'Anpassa storlek...', + 'selection_mode_normal' => 'Normal', + 'selection_mode_fixed_ratio' => 'Fast proportion', + 'selection_mode_fixed_size' => 'Fast storlek', + 'height' => 'Höjd', + 'width' => 'Bredd', + 'selection_mode' => 'Urvalsläge', + 'resize_image' => 'Anpassa bildstorlek', + 'image_size' => 'Bildstorlek:', + 'selected_size' => 'Vald:' + ] +]; diff --git a/modules/backend/lang/th/lang.php b/modules/backend/lang/th/lang.php new file mode 100644 index 0000000..4fc3fa5 --- /dev/null +++ b/modules/backend/lang/th/lang.php @@ -0,0 +1,513 @@ + [ + 'title' => 'ส่วนการจัดการ', + 'invalid_login' => 'รายละเอียดที่คุณเพิ่มเข้ามาไม่ตรงกับข้อมูลของเรา กรุณาตรวจสอบและลองอีกครั้ง', + ], + 'field' => [ + 'invalid_type' => 'ประเภทของฟิลด์ไม่ถูกต้อง :type.', + ], + 'widget' => [ + 'not_registered' => "วิดเจทชื่อ ':name' ยังไม่ได้ถูกลงทะเบียน", + 'not_bound' => "วิดเจทชื่อ ':name' ยังไม่ได้ถูกผูกกับคอนโทรลเลอร์", + ], + 'page' => [ + 'untitled' => 'ไม่มีชื่อเรื่อง', + '404' => [ + 'label' => 'ไม่พบหน้านี้', + 'help' => "เราพยายามค้นหาแล้ว แต่ไม่พบ URL ที่ร้องขอ บางทีคุณกำลังหาอย่างอื่นอยู่หรือเปล่า?", + 'back_link' => 'กลับไปยังหน้าที่แล้ว', + ], + 'access_denied' => [ + 'label' => 'ไม่อนุญาตให้เข้าถึง', + 'help' => "คุณไม่มีสิทธิ์ที่จำเป็นในการดูหน้านี้", + 'cms_link' => 'กลับสู่หน้าเว็บหลังบ้าน', + ], + 'no_database' => [ + 'label' => 'ไม่พบฐานข้อมูล', + 'help' => "จำเป็นต้องมีฐานข้อมูลในการเข้าถึงหน้าเว็บหลังบ้าน ตรวจสอบว่าฐานข้อมูลได้ถูกตั้งค่าและโอนย้ายก่อนลองอีกครั้ง", + 'cms_link' => 'กลับสู่หน้าเว็บหลัก', + ], + ], + 'partial' => [ + 'not_found_name' => "ไม่พบส่วนย่อย ':name'", + 'invalid_name' => 'ส่วนย่อยชื่อ: :name ไม่ถูกต้อง', + ], + 'ajax_handler' => [ + 'invalid_name' => 'ชื่อผู้จัดการ AJAX: :name ไม่ถูกต้อง', + 'not_found' => "หาผู้จัดการ AJAX ':name' ไม่พบ", + ], + 'account' => [ + 'impersonate' => 'ปลอมตัวเป็นผู้ใช้', + 'impersonate_confirm' => 'คุณแน่ใจว่าต้องการปลอมตัวเป็นผู้ใช้คนนี้? คุณสามารถย้อนกลับโดยการล็อกเอาท์', + 'impersonate_success' => 'คุณกำลังปลอมตัวเป็นผู้ใช้คนนี้', + 'impersonate_working' => 'กำลังปลอมตัว...', + 'impersonating' => 'กำลังปลอมตัว :full_name', + 'stop_impersonating' => 'หยุดการปลอมตัว', + 'signed_in_as' => 'ลงชื่อเข้าโดยใช้ชื่อ :full_name', + 'sign_out' => 'ลงชื่อออก', + 'login' => 'ล็อกอิน', + 'reset' => 'ตั้งใหม่', + 'login_placeholder' => 'ชื่อล็อกอิน', + 'restore' => 'กู้คืน', + 'password_placeholder' => 'รหัสผ่าน', + 'remember_me' => 'ให้ล็อกอินค้างไว้', + 'forgot_password' => 'ลืมรหัสผ่านของคุณ?', + 'enter_email' => 'ใส่ข้อมูลอีเมลของคุณ', + 'enter_login' => 'ใส่ข้อมูลล็อกอินของคุณ', + 'email_placeholder' => 'อีเมล', + 'enter_new_password' => 'ใส่ข้อมูลรหัสผ่านใหม่', + 'password_reset' => 'ตั้งค่ารหัสผ่านใหม่', + 'restore_success' => 'ได้ส่งข้อความไปทางอีเมลของคุณพร้อมด้วยขั้นตอนการทำงาน', + 'restore_error' => "ไม่เจอผู้ใช้ชื่อ ':login'", + 'reset_success' => 'ตั้งรหัสผ่านใหม่แล้ว คุณสามารถลงชื่อเข้าใช้ได้', + 'reset_error' => 'ข้อมูลที่ใช้ตั้งรหัสผ่านไม่ถูกต้อง กรุณาลองใหม่!', + 'reset_fail' => 'ไม่สามารถตั้งค่ารหัสผ่านของคุณใหม่ได้!', + 'apply' => 'นำไปใช้', + 'cancel' => 'ยกเลิก', + 'delete' => 'ลบ', + 'ok' => 'ตกลง', + ], + 'dashboard' => [ + 'menu_label' => 'แผงควบคุม', + 'widget_label' => 'วิดเจ็ท', + 'widget_width' => 'ความกว้าง', + 'full_width' => 'ความกว้างเต็มหน้า', + 'manage_widgets' => 'จัดการวิดเจ็ท', + 'add_widget' => 'เพิ่มวิดเจ็ท', + 'widget_inspector_title' => 'การปรับแต่งค่าวิดเจ็ท', + 'widget_inspector_description' => 'ปรับแต่งค่าวิดเจ็ทแบบรายงาน', + 'widget_columns_label' => 'กว้าง :columns', + 'widget_columns_description' => 'ความกว้างของวิดเจ็ท, ตัวเลขระหว่าง 1 ถึง 10', + 'widget_columns_error' => 'กรุณาใส่ค่าความกว้างของวิดเจ็ทเป็นตัวเลขระหว่าง 1 ถึง 10', + 'columns' => '{1} คอลัมน์|[2,Inf] คอลัมน์', + 'widget_new_row_label' => 'บังคับขึ้นแถวใหม่', + 'widget_new_row_description' => 'วางวิดเจ็ทไว้ในแถวใหม่', + 'widget_title_label' => 'หัวเรื่องวิดเจ็ท', + 'widget_title_error' => 'ต้องมีหัวเรื่องวิดเจ็ท', + 'reset_layout' => 'ตั้งค่าเริ่มต้นการวางโครงร่าง', + 'reset_layout_confirm' => 'ตั้งค่าการวางโครงร่างกลับสู่ค่าเริ่มต้น?', + 'reset_layout_success' => 'ตั้งค่าการวางโครงร่างเป็นค่าเริ่มต้นแล้ว', + 'make_default' => 'ทำให้เป็นค่าเริ่มต้น', + 'make_default_confirm' => 'ตั้งการวางโครงร่างปัจจุบันเป็นค่าเริ่มต้น?', + 'make_default_success' => 'ตั้งการวางโครงร่างปัจจุบันเป็นค่าเริ่มต้นแล้ว', + 'collapse_all' => 'ย่อทั้งหมด', + 'expand_all' => 'ขยายทั้งหมด', + 'status' => [ + 'widget_title_default' => 'สถานะระบบ', + 'updates_pending' => 'รอการอัพเดทซอฟต์แวร์', + 'updates_nil' => 'ซอฟต์แวร์เป็นปัจจุบันแล้ว', + 'updates_link' => 'อัพเดท', + 'warnings_pending' => 'มีปัญหาบางอย่างต้องตรวจสอบ', + 'warnings_nil' => 'ไม่มีคำเตือนให้แสดง', + 'warnings_link' => 'ดู', + 'core_build' => 'ระบบ', + 'event_log' => 'บันทึกเหตุการณ์', + 'request_log' => 'บันทึกการขอเข้าใช้งาน', + 'app_birthday' => 'ออนไลน์ตั้งแต่', + ], + 'welcome' => [ + 'widget_title_default' => 'ยินดีต้อนรับ', + 'welcome_back_name' => 'ยินดีต้อนรับกลับมาสู่ :app, :name.', + 'welcome_to_name' => 'ยินดีต้อนรับสู่ :app, :name.', + 'first_sign_in' => 'นี่เป็นครั้งแรกที่คุณได้ลงชื่อเข้า', + 'last_sign_in' => 'คุณได้ลงชื่อเข้าครั้งสุดท้ายเมื่อ', + 'view_access_logs' => 'ดูบันทึกการเข้าถึง', + 'nice_message' => 'ขอให้มีวันที่ยอดเยี่ยม!', + ], + ], + 'user' => [ + 'name' => 'ผู้ดูแลระบบ', + 'menu_label' => 'ผู้ดูแลระบบ', + 'menu_description' => 'กำหนด ผู้ใช้ กลุ่ม และสิทธิ์การใช้งาน ของหน้าเว็บหลังบ้าน', + 'list_title' => 'จัดการผู้ดูแลระบบ', + 'new' => 'สร้างผู้ดูแลระบบใหม่', + 'login' => 'ชื่อล็อกอิน', + 'first_name' => 'ชื่อ', + 'last_name' => 'นามสกุล', + 'full_name' => 'ชื่อเต็ม', + 'email' => 'อีเมล', + 'role_field' => 'บทบาท', + 'role_comment' => 'บทบาทกำหนดสิทธิ์การใช้งานของผู้ใช้ ซึ่งสามารถกำหนดทับเป็นรายผู้ใช้ได้ ที่แท็บสิทธิ์การใช้งาน', + 'groups' => 'กลุ่ม', + 'groups_comment' => 'กำหนดว่ามีกลุ่มไหนบ้างที่ผู้ใช้เป็นสมาชิก', + 'avatar' => 'อวตาร', + 'password' => 'รหัสผ่าน', + 'password_confirmation' => 'ยืนยันรหัสผ่าน', + 'permissions' => 'สิทธิ์การใช้งาน', + 'account' => 'บัญชีผู้ใช้', + 'superuser' => 'Super User', + 'superuser_comment' => 'อนุญาตให้บัญชีผู้ใช้นี้สามารถเข้าถึงได้ทุกระบบ Super user สามารถเพิ่มหรือจัดการผู้ใช้คนอื่นได้', + 'send_invite' => 'ส่งคำเชิญทางอีเมล', + 'send_invite_comment' => 'ส่งข้อความยินดีต้อนรับ พร้อมข้อมูลล็อกอินและรหัสผ่าน', + 'delete_confirm' => 'ลบผู้ดูแลระบบนี้?', + 'return' => 'กลับสู่รายชื่อผู้ดูแลระบบ', + 'allow' => 'อนุญาต', + 'inherit' => 'สืบต่อ', + 'deny' => 'ปฏิเสธ', + 'activated' => 'เริ่มการทำงานแล้ว', + 'last_login' => 'ล็อกอินครั้งสุดท้าย', + 'created_at' => 'สร้างเมื่อ', + 'updated_at' => 'อัพเดทเมื่อ', + 'deleted_at' => 'ลบเมื่อ', + 'show_deleted' => 'แสดงคนที่ถูกลบ', + 'group' => [ + 'name' => 'กลุ่ม', + 'name_field' => 'ชื่อ', + 'name_comment' => 'เป็นชื่อที่ถูกแสดงผลในรายการกลุ่มในหน้าผู้ดูแลระบบ', + 'description_field' => 'รายละเอียด', + 'is_new_user_default_field_label' => 'เข้ากลุ่มอัตโนมัติ', + 'is_new_user_default_field_comment' => 'เพิ่มผู้ดูแลระบบใหม่เข้ากลุ่มนี้โดยอัตโนมัติ', + 'code_field' => 'รหัส', + 'code_comment' => 'ใส่รหัสที่ไม่ซ้ำ ถ้าคุณต้องการเข้าถึงกลุ่มผ่านทาง API', + 'menu_label' => 'จัดการกลุ่ม', + 'list_title' => 'จัดการกลุ่ม', + 'new' => 'กลุ่มใหม่', + 'delete_confirm' => 'ลบกลุ่มนี้?', + 'return' => 'กลับสู่รายชื่อกลุ่ม', + 'users_count' => 'จำนวนผู้ใช้', + ], + 'role' => [ + 'name' => 'บทบาท', + 'name_field' => 'ชื่อ', + 'name_comment' => 'เป็นชื่อที่ถูกแสดงผลในรายการบทบาทในหน้าผู้ดูแลระบบ', + 'description_field' => 'รายละเอียด', + 'code_field' => 'รหัส', + 'code_comment' => 'ใส่รหัสที่ไม่ซ้ำ ถ้าคุณต้องการเข้าถึงบทบาทผ่านทาง API', + 'menu_label' => 'จัดการบทบาท', + 'list_title' => 'จัดการบทบาท', + 'new' => 'บทบาทใหม่', + 'delete_confirm' => 'ลบบทบาทนี้?', + 'return' => 'กลับสู่รายชื่อบทบาท', + 'users_count' => 'จำนวนผู้ใช้', + ], + 'preferences' => [ + 'not_authenticated' => 'ไม่พบผู้ใช้ที่ได้รับการยืนยันแล้วสำหรับอ่านหรือบันทึกค่าที่เลือก', + ], + 'trashed_hint_title' => 'บัญชีผู้ใช้นี้ถูกลบไปแล้ว', + 'trashed_hint_desc' => 'บัญชีผู้ใช้นี้ถูกลบไปแล้ว และจะไม่สามารถลงชื่อเข้าระบบได้ หากต้องการกู้คืน, คลิกไอคอน restore user ที่มุมล่างขวา', + ], + 'list' => [ + 'default_title' => 'รายการ', + 'search_prompt' => 'ค้นหา...', + 'no_records' => 'ไม่มีข้อมูลในหน้านี้', + 'missing_column' => 'ไม่มีการกำหนดค่าคอลัมน์ :columns.', + 'pagination' => 'แสดงข้อมูล: :from-:to จาก :total', + 'first_page' => 'หน้าแรก', + 'last_page' => 'หน้าสุดท้าย', + 'prev_page' => 'หน้าก่อน', + 'next_page' => 'หน้าถัดไป', + 'refresh' => 'รีเฟรช', + 'updating' => 'กำลังอัพเดท...', + 'loading' => 'กำลังโหลด...', + 'setup_title' => 'กำหนดค่ารายการ', + 'setup_help' => 'เลือก checkbox เพื่อเลือกคอลัมน์ที่คุณต้องการแสดงผลในตาราง คุณสามารถย้ายตำแหน่งของคอลัมน์โดยลากคอลัมน์ขึ้นหรือลง', + 'records_per_page' => 'ข้อมูลต่อหน้า', + 'records_per_page_help' => 'เลือกจำนวนข้อมูลต่อหน้าในการแสดงผล การเลือกจำนวนต่อหน้ามากๆทำให้ประสิทธิภาพลดลงได้', + 'check' => 'ตรวจสอบ', + 'delete_selected' => 'ลบรายการที่เลือกไว้', + 'delete_selected_empty' => 'ไม่มีรายการที่เลือกไว้', + 'delete_selected_confirm' => 'ต้องการลบรายการที่เลือกไว้?', + 'delete_selected_success' => 'ลบรายการที่เลือกไว้แล้ว', + 'column_switch_true' => 'ใช่', + 'column_switch_false' => 'ไม่', + ], + 'fileupload' => [ + 'attachment' => 'สิ่งที่แนบมา', + 'help' => 'เพิ่มหัวเรื่องและรายละเอียดสำหรับไฟล์แนบนี้', + 'title_label' => 'หัวเรื่อง', + 'description_label' => 'รายละเอียด', + 'default_prompt' => 'คลิก %s หรือลากไฟล์มาวางที่นี่เพื่ออัพโหลด', + 'attachment_url' => 'URL ไฟล์แนบ', + 'upload_file' => 'อัพโหลดไฟล์', + 'upload_error' => 'อัพโหลดผิดพลาด', + 'remove_confirm' => 'คุณแน่ใจ?', + 'remove_file' => 'ลบไฟล์', + ], + 'form' => [ + 'create_title' => 'สร้าง :name', + 'update_title' => 'แก้ไข :name', + 'preview_title' => 'ดูตัวอย่าง :name', + 'create_success' => 'สร้าง :name แล้ว', + 'update_success' => 'แก้ไข :name แล้ว', + 'delete_success' => 'ลบ :name แล้ว', + 'restore_success' => 'กู้คืน :name แล้ว', + 'reset_success' => 'ตั้งค่าเริ่มต้นสำเร็จ', + 'action_confirm' => 'คุณแน่ใจหรือไม่?', + 'create' => 'สร้าง', + 'create_and_close' => 'สร้าง และ ปิด', + 'creating' => 'กำลังสร้าง...', + 'creating_name' => 'กำลังสร้าง :name...', + 'save' => 'บันทึก', + 'save_and_close' => 'บันทึก และ ปิด', + 'saving' => 'กำลังบันทึก...', + 'saving_name' => 'กำลังบันทึก :name...', + 'delete' => 'ลบ', + 'deleting' => 'กำลังลบ...', + 'confirm_delete' => 'ลบข้อมูล?', + 'confirm_delete_multiple' => 'ลบข้อมูลที่เลือกไว้?', + 'deleting_name' => 'กำลังลบ :name...', + 'restore' => 'กู้คืน', + 'restoring' => 'กำลังกู้คืน', + 'confirm_restore' => 'คุณแน่ใจว่าต้องการกู้คืนข้อมูลนี้?', + 'reset_default' => 'ตั้งค่าเริ่มต้น', + 'resetting' => 'กำลังตั้งค่าเริ่มต้น', + 'resetting_name' => 'กำลังตั้งค่าเริ่มต้น :name', + 'undefined_tab' => 'อื่นๆ', + 'field_off' => 'ปิด', + 'field_on' => 'เปิด', + 'add' => 'เพิ่ม', + 'apply' => 'นำไปใช้', + 'cancel' => 'ยกเลิก', + 'close' => 'ปิด', + 'confirm' => 'ยืนยัน', + 'reload' => 'Reload', + 'complete' => 'เสร็จสมบูรณ์', + 'ok' => 'ตกลง', + 'or' => 'หรือ', + 'confirm_tab_close' => 'ปิดแท็บนี้? การเปลี่ยนแปลงที่ยังไม่ได้บันทึกจะสูญหาย', + 'preview_no_files_message' => 'ไม่มีไฟล์ถูกอัพโหลด', + 'preview_no_media_message' => 'ไม่มีสื่อบันทึกที่ถูกเลือก', + 'select' => 'เลือก', + 'select_all' => 'เลือกทั้งหมด', + 'select_none' => 'ไม่เลือกเลย', + 'select_placeholder' => 'กรุณาเลือก', + 'insert_row' => 'เพิ่มบรรทัด', + 'insert_row_below' => 'เพิ่มบรรทัดด้านล่าง', + 'delete_row' => 'ลบบรรทัด', + 'concurrency_file_changed_title' => 'ไฟล์ได้ถูกแก้ไข', + 'concurrency_file_changed_description' => "ไฟล์ที่คุณกำลังแก้ไขได้ถูกเปลี่ยนแปลงโดยผู้ใช้ท่านอื่น คุณสามารถโหลดไฟล์ใหม่แต่สิ่งที่แก้ไขไว้จะหายไป หรือบันทึกการแก้ไขทับ", + 'return_to_list' => 'กลับสู่หน้ารายการ', + ], + 'recordfinder' => [ + 'cancel' => 'ยกเลิก', + ], + 'pagelist' => [ + 'page_link' => 'ลิงก์หน้าเว็บ', + 'select_page' => 'เลือกหน้า...', + ], + 'relation' => [ + 'add' => 'เพิ่ม', + 'add_selected' => 'เพิ่มรายการที่เลือก', + 'add_a_new' => 'เพิ่มใหม่ :name', + 'link_selected' => 'ลิงก์รายการที่เลือก', + 'link_a_new' => 'ลิงก์ใหม่ :name', + 'cancel' => 'ยกเลิก', + 'close' => 'ปิด', + 'add_name' => 'เพิ่ม :name', + 'create' => 'สร้าง', + 'create_name' => 'สร้าง :name', + 'update' => 'อัพเดท', + 'update_name' => 'อัพเดท :name', + 'preview' => 'ดูตัวอย่าง', + 'preview_name' => 'ดูตัวอย่าง :name', + 'remove' => 'เอาออก', + 'remove_name' => 'เอาออก :name', + 'delete' => 'ลบ', + 'delete_name' => 'ลบ :name', + 'delete_confirm' => 'คุณแน่ใจหรือไม่?', + 'link' => 'ลิงก์', + 'link_name' => 'ลิงก์ :name', + 'unlink' => 'ยกเลิกลิงก์', + 'unlink_name' => 'ยกเลิกลิงก์ :name', + 'unlink_confirm' => 'คุณแน่ใจหรือไม่?', + ], + 'warnings' => [ + 'tips' => 'เคล็ดลับการตั้งค่าระบบ', + 'tips_description' => 'ประเด็นต่างๆที่ท่านต้องให้ความสนใจเพื่อตั้งค่าระบบได้อย่างเหมาะสม', + 'permissions' => 'โฟลเดอร์ :name หรือโฟลเดอร์ย่อยของมัน ไม่สามารถเขียนได้โดย PHP กรุณาตั้งสิทธิ์ที่สอดคล้องกับเว็บเซิร์ฟเวอร์ที่โฟลเดอร์นี้', + 'extension' => 'ส่วนต่อเติม PHP :name ไม่ถูกติดตั้ง กรุณาติดตั้งส่วนต่อเติมนี้และเปิดการใช้งานส่วนต่อเติม', + 'plugin_missing' => 'ปลั๊กอิน :name เป็น dependency แต่ไม่ถูกติดตั้ง กรุณาติดตั้งปลั๊กอินนี้', + ], + 'editor' => [ + 'menu_label' => 'การตั้งค่าตัวแก้ไข', + 'menu_description' => 'ปรับแก้ตามความชอบตัวแก้ไข เช่น ขนาดฟอนท์ และแผนผังสี', + 'font_size' => 'ขนาดฟอนท์', + 'tab_size' => 'ขนาดแท็บ', + 'use_hard_tabs' => 'ย่อหน้าโดยใช้แท็บ', + 'code_folding' => 'พับย่อโค้ด', + 'code_folding_begin' => 'ทำเครื่องหมายที่บรรทัดเริ่มต้น', + 'code_folding_begin_end' => 'ทำเครื่องหมายที่บรรทัดเริ่มต้นและสุดท้าย', + 'autocompletion' => 'การเติมคำโดยอัตโนมัติ', + 'word_wrap' => 'ขึ้นบรรทัดใหม่', + 'highlight_active_line' => 'ไฮไลท์บรรทัดที่เลือก', + 'auto_closing' => 'ปิดแท็กโดยอัตโนมัติ', + 'show_invisibles' => 'แสดงตัวอักษรที่มองไม่เห็น', + 'show_gutter' => 'แสดงเลขบรรทัด', + 'basic_autocompletion' => 'การเติมคำอัตโนมัติพื้นฐาน (คอนโทรล + สเปซ)', + 'live_autocompletion' => 'การเติมคำอัตโนมัติทันที', + 'enable_snippets' => 'เปิดใช้งาน code snippets (แท็บ)', + 'display_indent_guides' => 'แสดงแนวเส้นย่อหน้า', + 'show_print_margin' => 'แสดงขอบการพิมพ์', + 'mode_off' => 'ปิด', + 'mode_fluid' => 'ลื่นไหล', + '40_characters' => '40 ตัวอักษร', + '80_characters' => '80 ตัวอักษร', + 'theme' => 'แผนผังสี', + 'markup_styles' => 'รูปแบบ', + 'custom_styles' => 'กำหนด stylesheet เอง', + 'custom styles_comment' => 'รูปแบบกำหนดเองที่จะเพิ่มในตัวแก้ไข HTML', + 'markup_classes' => 'คลาส', + 'paragraph' => 'ย่อหน้า', + 'link' => 'ลิงก์', + 'table' => 'ตาราง', + 'table_cell' => 'เซลล์ตาราง', + 'image' => 'รูปภาพ', + 'label' => 'ป้ายชื่อ', + 'class_name' => 'ชื่อคลาส', + 'markup_tags' => 'แท็ก', + 'allowed_empty_tags' => 'แท็กเปล่าที่อนุญาตให้ใช้ได้', + 'allowed_empty_tags_comment' => 'รายการแท็กที่ไม่ถูกเอาออกถ้าไม่มีเนื้อหาภายในแท็ก', + 'allowed_tags' => 'แท็กที่ใช้ได้', + 'allowed_tags_comment' => 'รายการแท็กที่อนุญาตให้ใช้', + 'no_wrap' => 'แท็กที่ไม่ควรห่อ', + 'no_wrap_comment' => 'รายการแท็กที่ไม่ควรถูกห่ออยู่ในบล๊อก', + 'remove_tags' => 'เอาแท็กออก', + 'remove_tags_comment' => 'รายการของแท็กที่ถูกเอาออกรวมถึงเนื้อหาข้างใน', + 'line_breaker_tags' => 'แท็กสำหรับขึ้นบรรทัดใหม่', + 'line_breaker_tags_comment' => 'รายการของแท็กที่ให้ตัวขึ้นบรรทัดใหม่วางคั่นได้', + 'toolbar_buttons' => 'ปุ่มในแถบเครื่องมือ', + 'toolbar_buttons_comment' => 'ปุ่มในแถบเครื่องมือที่จะแสดงในหน้าแก้ไขโดยอัตโนมัติ', + ], + 'tooltips' => [ + 'preview_website' => 'ดูตัวอย่างเว็บไซต์', + ], + 'mysettings' => [ + 'menu_label' => 'การตั้งค่าของฉัน', + 'menu_description' => 'การตั้งค่าที่เกี่ยวกับบัญชีผู้ดูแลระบบของท่าน', + ], + 'myaccount' => [ + 'menu_label' => 'บัญชีของฉัน', + 'menu_description' => 'อัพเดทรายละเอียดบัญชีผู้ใช้ของท่านเช่น ชื่อ อีเมล และรหัสผ่าน', + ], + 'branding' => [ + 'menu_label' => 'ปรับแก้หน้าเว็บหลังบ้าน', + 'menu_description' => 'ปรับแก้ส่วนจัดการระบบ เช่น ชื่อ สี และโลโก้', + 'brand' => 'เครื่องหมายการค้า', + 'logo' => 'โลโก้', + 'logo_description' => 'อัพโหลดโลโก้สำหรับใช้ในหน้าเว็บหลังบ้าน', + 'favicon' => 'ไอคอนสำหรับเว็บไซต์ (Favicon)', + 'favicon_description' => 'อัพโหลดไอคอนสำหรับเว็บไซต์สำหรับใช้ในหน้าเว็บหลังบ้าน', + 'app_name' => 'ชื่อแอป', + 'app_name_description' => 'ชื่อนี้จะถูกแสดงที่หัวเรื่องของหน้าเว็บหลังบ้าน', + 'app_tagline' => 'สโลแกนของแอป', + 'app_tagline_description' => 'สโลแกนนี้จะถูกแสดงในหน้าลงชื่อเข้าระบบของเว็บหลังบ้าน', + 'colors' => 'สี', + 'primary_color' => 'สีหลัก', + 'secondary_color' => 'สีรอง', + 'accent_color' => 'สีเน้น', + 'styles' => 'รูปแบบ', + 'custom_stylesheet' => 'กำหนด stylesheet เอง', + 'navigation' => 'ตัวนำทาง', + 'menu_mode' => 'รูปแบบเมนู', + 'menu_mode_inline' => 'อยู่ในบรรทัดเดียว', + 'menu_mode_inline_no_icons' => 'อยู่ในบรรทัดเดียว (ไม่มีไอคอน)', + 'menu_mode_tile' => 'กระเบื้อง', + 'menu_mode_collapsed' => 'ย่อ', + ], + 'backend_preferences' => [ + 'menu_label' => 'หน้าเว็บหลังบ้านตามใจชอบ', + 'menu_description' => 'จัดการบัญชีผู้ใช้ของคุณตามใจชอบ เช่นเลือกภาษาที่ต้องการ', + 'region' => 'ภูมิภาค', + 'code_editor' => 'ตัวแก้ไขโค้ด', + 'timezone' => 'เขตเวลา (Timezone)', + 'timezone_comment' => 'ปรับแก้การแสดงวันเวลาตามเขตเวลานี้', + 'locale' => 'ภาษาท้องถิ่น (Locale)', + 'locale_comment' => 'เลือกภาษาท้องถิ่นที่ต้องการ', + ], + 'access_log' => [ + 'hint' => 'บันทึกนี้แสดงรายการการล็อกอินที่สำเร็จโดยผู้ดูแลระบบ บันทึกจะถูกเก็บไว้เป็นเวลา :days วัน', + 'menu_label' => 'บันทึกการเข้าถึง', + 'menu_description' => 'แสดงรายการของการลงชื่อที่สำเร็จของผู้ใช้หลังบ้าน', + 'id' => 'ไอดี', + 'created_at' => 'วันเวลา', + 'type' => 'ประเภท', + 'login' => 'ชื่อล็อกอิน', + 'ip_address' => 'ไอพีแอดเดรส', + 'first_name' => 'ชื่อ', + 'last_name' => 'นามสกุล', + 'email' => 'อีเมล', + ], + 'filter' => [ + 'all' => 'ทั้งหมด', + 'date_all' => 'ช่วงเวลาทั้งหมด', + 'number_all' => 'เลขทั้งหมด', + ], + 'import_export' => [ + 'upload_csv_file' => '1. อัพโหลดไฟล์ CSV', + 'created' => 'สร้างแล้ว', + 'updated' => 'อัพเดทแล้ว', + ], + 'permissions' => [ + 'manage_media' => 'อัพโหลดและจัดการเนื้อหาสื่อบันทึก - รูปภาพ, วิดีโอ, เสียง, เอกสาร', + ], + 'mediafinder' => [ + 'label' => 'ตัวค้นหาคลังข้อมูล', + 'default_prompt' => 'คลิกปุ่ม %s เพื่อค้นหา', + 'no_image' => 'หารูปภาพไม่พบ', + ], + 'media' => [ + 'menu_label' => 'สื่อบันทึก', + 'upload' => 'อัพโหลด', + 'move' => 'ย้าย', + 'delete' => 'ลบ', + 'add_folder' => 'เพิ่มโฟลเดอร์', + 'search' => 'ค้นหา', + 'display' => 'แสดงผล', + 'filter_everything' => 'ทุกอย่าง', + 'filter_images' => 'รูปภาพ', + 'filter_video' => 'วิดีโอ', + 'filter_audio' => 'เสียง', + 'filter_documents' => 'เอกสาร', + 'library' => 'คลัง', + 'size' => 'ขนาด', + 'title' => 'หัวเรื่อง', + 'last_modified' => 'แก้ไขครั้งสุดท้าย', + 'public_url' => 'URL', + 'click_here' => 'คลิกที่นี่', + 'thumbnail_error' => 'การสร้างรูปย่อผิดพลาด', + 'return_to_parent' => 'กลับสู่โฟลเดอร์บน', + 'return_to_parent_label' => 'ไปข้างบน ..', + 'nothing_selected' => 'ไม่มีรายการที่ถูกเลือก', + 'multiple_selected' => 'มีหลายรายการถูกเลือก', + 'uploading_file_num' => 'กำลังอัพโหลด :number ไฟล์...', + 'uploading_complete' => 'อัพโหลดสำเร็จ', + 'uploading_error' => 'อัพโหลดไม่สำเร็จ', + 'type_blocked' => 'ประเภทไฟล์นี้ถูกบล๊อกเพื่อความปลอดภัย', + 'order_by' => 'เรียงลำดับโดย', + 'direction' => 'ทิศทาง', + 'direction_asc' => 'จากน้อยไปมาก', + 'direction_desc' => 'จากมากไปน้อย', + 'folder' => 'โฟลเดอร์', + 'no_files_found' => 'ไม่พบไฟล์', + 'delete_empty' => 'กรุณาเลือกไฟล์หรือโฟลเดอร์ที่ต้องการลบ', + 'delete_confirm' => 'ลบไฟล์หรือโฟลเดอร์ที่ถูกเลือก?', + 'error_renaming_file' => 'มีปัญหาการเปลี่ยนชื่อ', + 'new_folder_title' => 'โฟลเดอร์ใหม่', + 'folder_name' => 'ชื่อโฟลเดอร์', + 'error_creating_folder' => 'มีข้อผิดพลาดในการสร้างโฟลเดอร์', + 'folder_or_file_exist' => 'ไฟล์หรือโฟลเดอร์ตามชื่อนี้มีอยู่แล้ว', + 'move_empty' => 'กรุณาเลือกไฟล์หรือโฟลเดอร์ที่ต้องการย้าย', + 'move_popup_title' => 'ย้ายไฟล์หรือโฟลเดอร์', + 'move_destination' => 'โฟลเดอร์ปลายทาง', + 'please_select_move_dest' => 'กรุณาเลือกโฟลเดอร์ปลายทาง', + 'move_dest_src_match' => 'กรุณาเลือกโฟลเดอร์ปลายทางอื่น', + 'empty_library' => 'มันดูว่างๆไปหน่อยนะ เริ่มด้วยการอัพโหลดไฟล์ หรือสร้างโฟลเดอร์เลย', + 'insert' => 'แทรก', + 'crop_and_insert' => 'หั่น & แทรก', + 'select_single_image' => 'กรุณาเลือกไฟล์รูปภาพไฟล์เดียว', + 'selection_not_image' => 'รายการที่ถูกเลือกไม่ใช่รูปภาพ', + 'restore' => 'ยกเลิกการเปลี่ยนแปลง', + 'resize' => 'เปลี่ยนขนาด...', + 'selection_mode_normal' => 'ปกติ', + 'selection_mode_fixed_ratio' => 'อัตราส่วนคงที่', + 'selection_mode_fixed_size' => 'ขนาดคงที่', + 'height' => 'ความสูง', + 'width' => 'ความกว้าง', + 'selection_mode' => 'โหมดการเลือก', + 'resize_image' => 'เปลี่ยนขนาดรูปภาพ', + 'image_size' => 'ขนาดรูปภาพ:', + 'selected_size' => 'พื้นที่เลือก:', + ], +]; diff --git a/modules/backend/lang/tr/lang.php b/modules/backend/lang/tr/lang.php new file mode 100644 index 0000000..4495f3b --- /dev/null +++ b/modules/backend/lang/tr/lang.php @@ -0,0 +1,604 @@ + [ + 'title' => 'Yönetim Paneli', + 'invalid_login' => 'Girdiğiniz bilgiler kayıtlarla eşleşmiyor. Lütfen kontrol edip tekrar deneyin.', + ], + 'field' => [ + 'invalid_type' => 'Geçersiz alan tipi :type.', + 'options_method_invalid_model' => "':field' metodu, geçerli bir model ile eşleşmiyor. :model Model'i için options metodu tanımlamalısınız.", + 'options_method_not_exists' => ":model Model'i içerisinde ':field' formuna geri dönüş için bir :method() metodu tanımlanmalıdır.", + 'colors_method_not_exists' => ":model Model'i içerisinde ':field' form alanı için html renk HEX kodu üreten :method() metodu tanımlanmalıdır.", + ], + 'widget' => [ + 'not_registered' => "':name' isimli widget sınıfı sistemde kayıtlı değil", + 'not_bound' => "':name' isimli widget sınıfı controllerda tanımlanmamış", + ], + 'page' => [ + 'untitled' => "Başlıksız", + 'access_denied' => [ + 'label' => "Giriş engellendi", + 'help' => "Bu sayfayı görüntülemek için gerekli izinlere sahip değilsiniz.", + 'cms_link' => "Ana sayfaya dön", + ], + 'no_database' => [ + 'label' => 'Veritabanı yapılandırılmamış', + 'help' => "Yönetim paneline erişebilmeniz için geçerli bir veritabanı yapılandırması yapmalısınız. Lütfen ayarların kontrol edin.", + 'cms_link' => 'Anasayfaya dön', + ], + ], + 'partial' => [ + 'not_found_name' => "':name' bölümü bulunamadı.", + ], + 'account' => [ + 'signed_in_as' => ':full_name olarak giriş yapıldı', + 'sign_out' => 'Çıkış', + 'login' => 'Giriş', + 'reset' => 'Sıfırla', + 'restore' => 'Geri yükle', + 'login_placeholder' => 'kullanıcı adı', + 'password_placeholder' => 'şifre', + 'remember_me' => 'Beni hatırla', + 'forgot_password' => "Şifrenizi mi unuttunuz?", + 'enter_email' => "Email adresinizi girin", + 'enter_login' => "Kullanıcı adınızı girin", + 'email_placeholder' => "email", + 'enter_new_password' => "Yeni Şifrenizi girin", + 'password_reset' => "Şifre Sıfırla", + 'restore_success' => "Email adresinize şifrenizi nasıl sıfırlayacağınıza dair bilgiler gönderildi.", + 'restore_error' => "':login' kullanıcı adı bulunamadı.", + 'reset_success' => "Şifreniz başarıyla sıfırlandı. Giriş yapabilirsiniz.", + 'reset_error' => "Hatalı giriş yaptınız. Lütfen tekrar deneyin!", + 'reset_fail' => "Şifre sıfırlanamadı!", + 'apply' => 'Onayla', + 'cancel' => 'İptal', + 'delete' => 'Sil', + 'ok' => 'Tamam', + ], + 'dashboard' => [ + 'menu_label' => 'Anasayfa', + 'widget_label' => 'Eklenti', + 'widget_width' => 'Genişlik', + 'full_width' => 'tam genişlik', + 'manage_widgets' => 'Eklentileri yönet', + 'add_widget' => 'Eklenti ekle', + 'widget_inspector_title' => 'Eklenti ayarları', + 'widget_inspector_description' => 'Eklentinin ayarlarını düzenleyin', + 'widget_columns_label' => 'Genişlik :columns', + 'widget_columns_description' => 'Eklenti genişliği, 1 ile 10 arasında bir sayı.', + 'widget_columns_error' => 'Lütfen eklenti genişliğini 1 ile 10 arasında girin.', + 'columns' => '{1} sütun|[2,Inf] sütun', + 'widget_new_row_label' => 'Yeni satıra zorla', + 'widget_new_row_description' => 'Eklentiyi yeni satıra indir.', + 'widget_title_label' => 'Eklenti başlığı', + 'widget_title_error' => 'Eklenti Başlığı gerekli.', + 'reset_layout' => 'Şablonu sıfırla', + 'reset_layout_confirm' => 'Şablonu özgün haline döndermek istediğinize emin misiniz?', + 'reset_layout_success' => 'Şablonu sıfırlandı', + 'make_default' => 'Öntanımlı yap', + 'make_default_confirm' => 'Şuan kullanılan şablonu öntanımlı yapmak istediğinize emin misiniz?', + 'make_default_success' => 'Geçerli şablon öntanımlı olarak ayarlandı', + 'collapse_all' => 'Tümünü daralt', + 'expand_all' => 'Tümünü genişlet', + 'status' => [ + 'widget_title_default' => 'Sistem durumu', + 'update_available' => '{0} güncelleme var!|{1} güncelleme var!|[2,Inf] güncelleme var!', + 'updates_pending' => 'Bekleyen güncelleme var', + 'updates_nil' => 'Sistem güncel', + 'updates_link' => 'Güncelle', + 'warnings_pending' => 'İncelemeniz gereken değişiklikler var', + 'warnings_nil' => 'Gösterilecek uyarı yok', + 'warnings_link' => 'Göster', + 'core_build' => 'Altyapı sürümü', + 'event_log' => 'Olay günlüğü', + 'request_log' => 'Hatalı istek günlüğü', + 'app_birthday' => 'İlk aktiflik tarihi', + ], + 'welcome' => [ + 'widget_title_default' => 'Hoşgeldiniz', + 'welcome_back_name' => ':app yönetim paneline tekrar hoşgeldiniz Sayın :name.', + 'welcome_to_name' => ':app yönetim paneline hoşgeldiniz Sayın :name.', + 'first_sign_in' => 'Bu sizin ilk ziyaretiniz.', + 'last_sign_in' => 'En yakın giriş yaptığınız tarih', + 'view_access_logs' => 'Erişim günlüğüne göz at', + 'nice_message' => 'İyi çalışmalar dileriz!', + ], + ], + 'user' => [ + 'name' => 'Yönetici', + 'menu_label' => 'Yöneticiler', + 'menu_description' => 'Yönetim paneli gruplarını, kullanıcılarını ve izinlerini yönetin.', + 'list_title' => 'Yöneticileri Yönet', + 'new' => 'Yeni Yönetici', + 'login' => "Kullanıcı Adı", + 'first_name' => "İsim", + 'last_name' => "Soyisim", + 'full_name' => "Tam Adı", + 'email' => "Email", + 'role_field' => 'Roller', + 'role_comment' => 'Roller kullanıcı izinlerini tanımlar. Bu roller, izinler sekmesinden kullanıcı düzeyinde değiştirilebilir.', + 'groups' => "Gruplar", + 'groups_comment' => "Kullanıcının hangi gruba bağlı olduğunu belirleyin.", + 'avatar' => "Avatar", + 'password' => "Şifre", + 'password_confirmation' => "Şifre (Tekrar)", + 'permissions' => 'İzinler', + 'account' => 'Hesap', + 'superuser' => "Süper Kullanıcı", + 'superuser_comment' => "Kullanıcıya her alanda yetki vermek için burayı işaretleyin.", + 'send_invite' => 'Email ile davet gönder', + 'send_invite_comment' => 'Kullanıcının email adresine davet göndermek için burayı işaretleyin', + 'delete_confirm' => 'Bu yöneticiyi silmek istiyor musunuz?', + 'return' => 'Yöneticiler listesine dön', + 'allow' => 'Yetki Var', + 'inherit' => 'Grup Yetkisi', + 'deny' => 'Yetki Yok', + 'activated' => 'Aktifleştirildi', + 'last_login' => 'Son giriş', + 'created_at' => 'Oluşturulma', + 'updated_at' => 'Güncellenme', + 'deleted_at' => 'Silinme', + 'show_deleted' => 'Silinenleri göster', + 'group' => [ + 'name' => 'Grup', + 'name_comment' => 'Grup ismi, grup listesinde Yönetici Ekleme/Düzenleme formunda görüntülenecek.', + 'name_field' => 'Adı', + 'description_field' => 'Açıklama', + 'is_new_user_default_field_label' => 'Öntanımlı grup', + 'is_new_user_default_field_comment' => 'Yeni eklenen yöneticileri bu gruba dahil et', + 'code_field' => 'Grup kodu', + 'code_comment' => 'Grup kodunu yazın', + 'menu_label' => 'Gruplar', + 'list_title' => 'Grupları Yönet', + 'new' => 'Yeni Yönetici Grubu', + 'delete_confirm' => 'Bu yönetici grubunu silmek istiyor musunuz?', + 'return' => 'Grup listesine dön', + 'users_count' => 'Kişiler', + ], + 'role' => [ + 'name' => 'Rol', + 'name_field' => 'İsim', + 'name_comment' => 'Rol ismi, Yönetici formundaki rol listesinde görüntülenir.', + 'description_field' => 'Açıklama', + 'code_field' => 'Kod', + 'code_comment' => 'API ile rol nesnesine erişmek istiyorsanız, eşsiz bir kod girin.', + 'menu_label' => 'Rolleri Yönet', + 'list_title' => 'Rolleri Yönet', + 'new' => 'Yeni Rol', + 'delete_confirm' => 'Bu yönetici rolü silinsin mi?', + 'return' => 'Rol listesine dön', + 'users_count' => 'Kişiler', + ], + 'preferences' => [ + 'not_authenticated' => 'Ayarları görüntülemek veya düzenlemek için yetkili bir kullanıcı yok.' + ], + 'trashed_hint_title' => 'Bu hesap silindi', + 'trashed_hint_desc' => 'Bu hesap silindi ve oturum açılamadı. Tekrar aktifleştirmek için sağ alt kısımdaki kullanıcıyı aktifleştir simgesine tıklayın.', + ], + 'list' => [ + 'default_title' => 'Liste', + 'search_prompt' => 'Arama...', + 'no_records' => 'Bu alan için görüntülenecek kayıt yok.', + 'missing_model' => ':class da kullanılan liste için model değeri tanımlanmamış.', + 'missing_column' => ':columns için sütun değeri tanımlanmamış.', + 'missing_columns' => ':class da kullanılan liste için sütun değeri tanımlanmamış.', + 'missing_definition' => "Liste ':field' için bir sütun değeri içermiyor.", + 'missing_parent_definition' => "Liste davranışı ':definition' tanımlaması için tanımlama bilgisi içermiyor.", + 'behavior_not_ready' => 'Liste oluşturulamadı, controller da makeLists() metodunu kontrol edin.', + 'invalid_column_datetime' => "':column' için sütun değeri DateTime nesnesi değil, Model kısmında \$dates referansını unutmuş olabilir misiniz?", + 'pagination' => 'Gösterilen kayıtlar: :from-:to Toplam: :total', + 'first_page' => 'İlk sayfa', + 'last_page' => 'Son sayfa', + 'prev_page' => 'Önceki sayfa', + 'next_page' => 'Sonraki sayfa', + 'refresh' => 'Yenile', + 'updating' => 'Güncelleniyor...', + 'loading' => 'Yükleniyor...', + 'setup_title' => 'Liste Ayarları', + 'setup_help' => 'Listede görmek istediğiniz sütunları seçmek için onay kutularını kullanın. Sütunları yukarı veya aşağı sürükleyerek konumlarını değiştirebilirsiniz.', + 'records_per_page' => 'Sayfa başına kayıt sayısı', + 'records_per_page_help' => 'Sayfa başına görüntülenecek kayıt sayısını seçin. Tek sayfada yüksek miktarda kayıt görüntülemek sistem performansını azaltabilir.', + 'check' => 'Kontrol et', + 'delete_selected' => 'Seçili olanı sil', + 'delete_selected_empty' => 'Silinecek seçili kayıt bulunamadı.', + 'delete_selected_confirm' => 'Seçili kayıtları silmek istediğize emin misiniz?', + 'delete_selected_success' => 'Seçili kayıtlar başarıyla silindi.', + 'column_switch_true' => 'Evet', + 'column_switch_false' => 'Hayır', + ], + 'fileupload' => [ + 'attachment' => 'Dosya Eki', + 'help' => 'Bu ek için bir başlık ve tanım girin.', + 'title_label' => 'Başlık', + 'description_label' => 'Tanım', + 'default_prompt' => '%s e tıkla ya da bir dosya sürükleyin', + 'attachment_url' => 'Ek URLsi', + 'upload_file' => 'Dosya yükle', + 'upload_error' => 'Dosya yükleme hatası', + 'remove_confirm' => 'Emin misiniz?', + 'remove_file' => 'Dosyayı sil', + ], + 'repeater' => [ + 'min_items_failed' => ':name için en az :min nesne gerekli, sadece :items nesne tanımlandı', + 'max_items_failed' => ':name için en fazla :max nesne tanımlanabilir, :items nesne tanımlandı', + ], + 'form' => [ + 'create_title' => ":name Oluştur", + 'update_title' => ":name Düzenle", + 'preview_title' => ":name Görüntüle", + 'create_success' => ':name başarıyla oluşturuldu', + 'update_success' => ':name başarıyla güncellendi', + 'delete_success' => ':name başarıyla silindi', + 'restore_success' => ':name geri yüklendi', + 'reset_success' => 'Sıfırlama başarılı', + 'missing_id' => "Form kayıt ID'si belirtilmedi.", + 'missing_model' => ':class da kullanılan form için model değeri tanımlanmamış.', + 'missing_definition' => "Form ':field' için bir sütun değeri içermiyor.", + 'not_found' => 'ID\'si :id olan Form bulunamadı.', + 'action_confirm' => 'Emin misiniz?', + 'create' => 'Oluştur', + 'create_and_close' => 'Oluştur ve Kapat', + 'creating' => 'Oluşturuluyor...', + 'creating_name' => 'Oluşturuluyor :name...', + 'save' => 'Kaydet', + 'save_and_close' => 'Kaydet ve Kapat', + 'saving' => 'Kaydediliyor...', + 'saving_name' => 'Kaydediliyor :name...', + 'delete' => 'Sil', + 'deleting' => 'Siliniyor...', + 'confirm_delete' => 'Bu kaydı silmek istediğinize emin misiniz?', + 'confirm_delete_multiple' => 'Seçilen kayıtları silmek istediğinize emin misiniz?', + 'deleting_name' => 'Siliniyor :name...', + 'restore' => 'Geri yükle', + 'restoring' => 'Geri yükleniyor', + 'confirm_restore' => 'Bu kaydı geri yüklemek istediğinize emin misiniz?', + 'reset_default' => 'Ön Tanımlı Ayarlara Dön!', + 'resetting' => 'İşleniyor', + 'resetting_name' => ':name İşleniyor', + 'undefined_tab' => 'Çeşitli', + 'field_off' => 'Kapalı', + 'field_on' => 'Açık', + 'add' => 'Ekle', + 'apply' => 'Uygula', + 'cancel' => 'İptal', + 'close' => 'Kapat', + 'confirm' => 'Onayla', + 'reload' => 'Yenile', + 'complete' => 'Tamamla', + 'ok' => 'Tamam', + 'or' => 'veya', + 'confirm_tab_close' => 'Bu sekmeyi kapatmak istediğinize emin misiniz? Kaydedilmemiş değişiklikleri kaybedeceksiniz.', + 'behavior_not_ready' => 'Form oluşturulamadı, controller da initForm() metodunu kontrol edin.', + 'preview_no_files_message' => 'Dosyalar yüklenmedi', + 'preview_no_media_message' => 'Seçilmiş medya yok.', + 'preview_no_record_message' => 'Seçili kayıt yok.', + 'select' => 'Seç', + 'select_all' => 'hepsini seç', + 'select_none' => 'hiçbir şey seçilmedi', + 'select_placeholder' => 'lütfen seçin', + 'insert_row' => 'Kayıt Ekle', + 'insert_row_below' => 'Alt Satıra Kayıt Ekle', + 'delete_row' => 'Kayıt Sil', + 'concurrency_file_changed_title' => 'Dosya değiştirildi', + 'concurrency_file_changed_description' => "Düzenlemeye çalıştığınız dosya disk üzerinde başka bir kullanıcı tarafından değiştirilmiş. Dosyayı yeniden yükleyebilir ve değişiklikleri kaybedersiniz ya da diskteki dosyayı kendi düzenlediğiniz hali ile değiştirebilirsiniz.", + 'return_to_list' => 'Listeye dön', + ], + 'recordfinder' => [ + 'find_record' => 'Kayıt Bul', + 'cancel' => 'İptal', + ], + 'pagelist' => [ + 'page_link' => 'Sayfa bağlantısı', + 'select_page' => 'Sayfa seçin...', + ], + 'relation' => [ + 'missing_config' => "İlişki ':config' için bir yapılandırma ayarı içermiyor.", + 'missing_definition' => "İlişki ':field' için bir sütun değeri içermiyor.", + 'missing_model' => ":class da kullanılan ilişki için model değeri tanımlanmamış.", + 'invalid_action_single' => "Bu işlem tekli ilişkilendirme için kullanılamaz.", + 'invalid_action_multi' => "Bu işlem çoklu ilişkilendirme için kullanılamaz.", + 'help' => 'Eklemek için bir öğeye tıklayın', + 'related_data' => 'İlişkili veri :name', + 'add' => "Ekle", + 'add_selected' => 'Seçilenleri ekle', + 'add_a_new' => 'Yeni bir :name ekle', + 'link_selected' => 'Seçileni bağla', + 'link_a_new' => 'Yeni bir :name bağla', + 'cancel' => 'İptal', + 'close' => "Kapat", + 'add_name' => ":name Ekle", + 'create' => "Oluştur", + 'create_name' => ":name Oluştur", + 'update' => "Güncelle", + 'update_name' => ":name Güncelle", + 'preview' => "Önizle", + 'preview_name' => ":name Önizle", + 'remove' => "Kaldır", + 'remove_name' => ":name Kaldır", + 'delete' => "Sil", + 'delete_name' => ":name Sil", + 'delete_confirm' => 'Emin misiniz?', + 'link' => 'Bağla', + 'link_name' => ':name bağla', + 'unlink' => 'Bağlamayı kaldır', + 'unlink_name' => ':name bağlamasını kaldır', + 'unlink_confirm' => 'Emin misiniz?', + ], + 'reorder' => [ + 'default_title' => 'Kayıtları yeniden sırala', + 'no_records' => 'Sıralamak için bir kayıt bulunamadı.', + ], + 'model' => [ + 'name' => "Model", + 'not_found' => "ID'si :id olan ':class' Model bulunamadı.", + 'missing_id' => "Aranılan model için ID belirtilmedi.", + 'missing_relation' => "':class' Model'i ':relation' ilişkisi için tanımlanmamış.", + 'missing_method' => "':class' Model'i ':method' isimli bir metod içermiyor.", + 'invalid_class' => ":class da tanımlanan :model Model'i geçerli değil, \Model sınıfını extend almalı.", + 'mass_assignment_failed' => "':attribute' Model değeri için toplu atama başarısız.", + ], + 'warnings' => [ + 'tips' => 'Sistem ayar ipuçları', + 'tips_description' => 'Sistemin düzgün çalışabilmesi için dikkat etmeniz gereken sorunlar var.', + 'permissions' => ':name dizini ve alt dizinleri PHP tarafından yazılabilir değil. Lütfen bu dizindeki webserver için gerekli yazma izinlerini verin.', + 'extension' => ':name PHP eklentisi sistemde yüklü değil. Lütfen kütüphaneyi kurun ve eklentiyi aktifleştirin.', + 'plugin_missing' => ':name isimli eklenti gerekli, fakat yüklenmemiş. Lütfen bu eklentiyi yükleyin.', + ], + 'editor' => [ + 'menu_label' => 'Editör ayarları', + 'menu_description' => 'Metin editörü ayarlarını düzenleyebilirsiniz.', + 'font_size' => 'Font büyüklüğü', + 'tab_size' => 'Tab genişliği', + 'use_hard_tabs' => 'Tab girintisi', + 'code_folding' => 'Kod katlama (Alt satıra inme)', + 'code_folding_begin' => 'Başlangıcı işaretle', + 'code_folding_begin_end' => 'Başlangıcı ve sonu işaretle', + 'autocompletion' => 'Otomatik kod tamamlama', + 'word_wrap' => 'Uzun kelimeleri yeni satırda göster', + 'highlight_active_line' => 'Aktif satırı vurgula', + 'auto_closing' => 'Etiketleri ve özel karakterleri otomatik kapat', + 'show_invisibles' => 'Gizli karakterleri göster', + 'show_gutter' => 'Satır numarasını göster', + 'basic_autocompletion'=> 'Otomatik tamamlama (Temel) (Ctrl + Boşluk)', + 'live_autocompletion'=> 'Anlık Otomatik tamamlama', + 'enable_snippets'=> 'Kod snippetlerini aktifleştir (Tab)', + 'display_indent_guides'=> 'İçeri girintileri göster', + 'show_print_margin'=> 'Yazdırma boşluklarını göster', + 'mode_off' => 'Kapalı', + 'mode_fluid' => 'Akışkan', + '40_characters' => '40 Karakter', + '80_characters' => '80 Karakter', + 'theme' => 'Renk şeması', + 'markup_styles' => 'Markup Stilleri', + 'custom_styles' => 'Özel CSS', + 'custom styles_comment' => 'HTML editöre uygulanacak özel stiller.', + 'markup_classes' => 'Markup Classlar', + 'paragraph' => 'Paragraf', + 'link' => 'Link', + 'table' => 'Tablo', + 'table_cell' => 'Tablo Hücresi', + 'image' => 'Resim', + 'label' => 'Etiket', + 'class_name' => 'Class ismi', + 'markup_tags' => 'Markup Tagları', + 'allowed_empty_tags' => 'İzin verilen boş taglar', + 'allowed_empty_tags_comment' => 'İçeriği olmasada kaydederken silinmeyen, bulunmasına izin verilen taglar.', + 'allowed_tags' => 'İzin verilen taglar', + 'allowed_tags_comment' => 'İzin verilen taglar listesi.', + 'no_wrap' => 'Tagları sarmalama', + 'no_wrap_comment' => 'Tag blokları içinde sarmalanmayacak taglar listesi.', + 'remove_tags' => 'Silinecek taglar', + 'remove_tags_comment' => 'İçeriği ile birlikte silinecek taglar listesi.', + 'line_breaker_tags' => 'Satır atlatma etiketleri', + 'line_breaker_tags_comment' => 'Aralarına bir satır atlatma öğesi yerleştirmek için kullanılan etiketlerin listesi.', + 'toolbar_buttons' => 'Araç Çubuğu Düğmeleri', + 'toolbar_buttons_comment' => 'Rich Editor\'de varsayılan olarak görüntülenecek Araç Çubuğu düğmeleri.', + ], + 'tooltips' => [ + 'preview_website' => 'Websiteyi Önizle', + ], + 'mysettings' => [ + 'menu_label' => 'Ayarlarım', + 'menu_description' => 'Yönetim hesabı ile ilgili ayarlar', + ], + 'myaccount' => [ + 'menu_label' => 'Kişisel Bilgilerim', + 'menu_description' => 'Hesabınızın ismi, email adresi ve şifresi gibi bilgilerini düzenleyebilirsiniz.', + 'menu_keywords' => 'güvenli oturum açma', + ], + 'branding' => [ + 'menu_label' => 'Yönetim paneli ayarlarını düzenle', + 'menu_description' => 'Yönetim Panelinin isim, renk şeması ve logo gibi ayarlarını düzenleyin.', + 'brand' => 'Marka', + 'logo' => 'Logo', + 'logo_description' => 'Yönetim Panelinde kullanılacak logoyu yükleyin.', + 'app_name' => 'Site Adı', + 'app_name_description' => 'Bu isim, Yönetim Panelinde başlık olarak kullanılacaktır.', + 'app_tagline' => 'Site Mottosu', + 'app_tagline_description' => 'Bu motto Yönetim Paneli giriş ekranında görüntülenecektir.', + 'colors' => 'Renkler', + 'primary_color' => 'Ana Renk color', + 'secondary_color' => 'İkincil Renk color', + 'accent_color' => 'Accent color', + 'styles' => 'Stiller', + 'custom_stylesheet' => 'Özel stil - CSS', + 'navigation' => 'Navigsyon', + 'menu_mode' => 'Menü stili', + 'menu_mode_inline' => 'Sıralı', + 'menu_mode_tile' => 'Mozaik', + 'menu_mode_collapsed' => 'Katlanmış', + ], + 'backend_preferences' => [ + 'menu_label' => 'Panel Ayarları', + 'menu_description' => 'Hesabınızın tercih edilen dil ayarını değiştirebilirsiniz.', + 'region' => 'Bölge', + 'code_editor' => 'Kod editörü', + 'timezone' => 'Zaman Dilimi', + 'timezone_comment' => 'Tarihleri bu zaman dilimine göre göster.', + 'locale' => 'Dil', + 'locale_comment' => 'Yönetim Paneli dil seçiminizi belirleyin.', + ], + 'access_log' => [ + 'hint' => 'Bu kayıtlar yöneticiler tarafından başarılı şekilde yapılan girişleri gösterir. Kayıtlar :days gün boyunca saklanır.', + 'menu_label' => 'Yönetim paneli erişim kayıtları', + 'menu_description' => 'Yönetim paneline başarılı şekilde yapılan girişleri görüntüler.', + 'id' => 'ID', + 'created_at' => 'Tarih & Saat', + 'type' => 'Tipi', + 'login' => 'Giriş', + 'ip_address' => 'IP adres', + 'first_name' => 'İsim', + 'last_name' => 'Soyisim', + 'email' => 'Email', + ], + 'filter' => [ + 'all' => 'tümü', + 'options_method_not_exists' => ":model modelinde :method() metodu bulunmalı ve ':filter' filtresi için uygun seçenekleri döndermelidir.", + 'date_all' => 'tüm periyotlar', + 'number_all' => 'Tüm numaralar', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Bir CSV dosyası yükleyin', + 'import_file' => 'Dosya İçeri Aktar', + 'row' => 'Satır :row', + 'first_row_contains_titles' => 'İlk satır, sütun isimlerini içermelidir', + 'first_row_contains_titles_desc' => 'Eğer CSV dosyanızda ilk satır, sütun isimlerini içeriyorsa bu seçeneği işaretleyin.', + 'match_columns' => '2. Veritabanı sütunları ile dosyanızdaki verileri eşleştirin', + 'file_columns' => 'Dosyadaki sütunlar', + 'database_fields' => 'Veritabanındaki sütunlar', + 'set_import_options' => '3. İçeri aktarmayı yapılandırın', + 'export_output_format' => '1. Dışarı aktarma formatı', + 'file_format' => 'Dosya formatı', + 'standard_format' => 'Standart format', + 'custom_format' => 'Özel format', + 'delimiter_char' => 'Ayırıcı karakter', + 'enclosure_char' => 'Kapsayıcı karakter', + 'escape_char' => 'Kaçış karakteri', + 'select_columns' => '2. Dışarı aktarılacak sütunları seçin', + 'column' => 'Sütun', + 'columns' => 'Sütunlar', + 'set_export_options' => '3. Dışarı aktarmayı yapılandırın', + 'show_ignored_columns' => 'Göz ardı edilen sütunları göster', + 'auto_match_columns' => 'Sütunları otomatik eşleştir', + 'created' => 'Oluşturulma', + 'updated' => 'Güncellenme', + 'skipped' => 'Atlandı', + 'warnings' => 'Uyarılar', + 'errors' => 'Hatalar', + 'skipped_rows' => 'Atlanan Satırlar', + 'import_progress' => 'İçeri aktarma ilerlemesi', + 'processing' => 'İşleniyor', + 'import_error' => 'İçeri aktarma hatası', + 'upload_valid_csv' => 'Lütfen geçerli bir CSV dosyası seçin.', + 'drop_column_here' => 'Sütunu buraya bırakın...', + 'ignore_this_column' => 'Bu sütunu göz ardı et', + 'processing_successful_line1' => 'Dosya dışarı aktarma işlemi başarıyla tamamlandı!', + 'processing_successful_line2' => 'Tarayıcınız dosyayı otomatik olarak indirecektir', + 'export_progress' => 'Dışarı aktarma ilerlemesi', + 'export_error' => 'Dışarı aktarma hatası', + 'column_preview' => 'Sütun önizlemesi', + 'file_not_found_error' => 'Dosya bulunamadı', + 'empty_error' => 'Dışarı aktarılacak veri bulunamadı', + 'empty_import_columns_error' => 'Lütfen içeri aktarılacak veri sütunlarını seçin.', + 'match_some_column_error' => 'Önce sütunları eşleştirin.', + 'required_match_column_error' => 'Gerekli alan olan :label için bir eşleştirme yapın.', + 'empty_export_columns_error' => 'Lütfen dışarı aktarılacak veri sütunlarını seçin.', + 'behavior_missing_uselist_error' => 'ListController davranışını "useList" seçeneği aktif olacak şekilde sistem altyapısında Controller kısmında aktifleştirmelisiniz.', + 'missing_model_class_error' => ':type tipi için modelClass özelliği tanımlamalısınız', + 'missing_column_id_error' => 'Sütun tnaımlayıcı eksik', + 'unknown_column_error' => 'Tanımlanamayan sütun', + 'encoding_not_supported_error' => 'Kaynak dosyanın karakter kodlaması tanımlanamadı. Lütfen düzgün bir dosyayı özel dosya formatı seçeneğini seçerek içeri aktarmayı deneyin.', + 'encoding_format' => 'Dosya karakter kodlaması', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Batı Avrupa)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Merkez Avrupa)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, Güney Avrupa)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, Kuzey Avrupa)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Kril)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arapça)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Yunanca)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, İbranice)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Türkçe)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Norveççe)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai Dili)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltık Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic Dili)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Euro işareti revizyonlu Batı Avrupa)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)', + ], + ], + 'permissions' => [ + 'manage_media' => 'Medyaları düzenleyebilsin', + ], + 'mediafinder' => [ + 'label' => 'Medya Bulucu', + 'default_prompt' => 'Bir medya öğesi bulmak için %s butonuna tıklayın', + ], + 'media' => [ + 'menu_label' => 'Medya', + 'upload' => 'Yükle', + 'move' => 'Taşı', + 'delete' => 'Sil', + 'add_folder' => 'Yeni Klasör', + 'search' => 'Ara', + 'display' => 'Görüntüle', + 'filter_everything' => 'Her şey', + 'filter_images' => 'Resimler', + 'filter_video' => 'Video', + 'filter_audio' => 'Ses', + 'filter_documents' => 'Belgeler', + 'library' => 'Kütüphane', + 'size' => 'Boyut', + 'title' => 'Başlık', + 'last_modified' => 'Son düzenleme tarihi', + 'public_url' => 'Public URL', + 'click_here' => 'Buraya tıkla', + 'thumbnail_error' => 'Önizleme oluşturulurken hata.', + 'return_to_parent' => 'Ana klasöre geri dön', + 'return_to_parent_label' => 'Yukarı git..', + 'nothing_selected' => 'Hiçbir şey seçilmedi.', + 'multiple_selected' => 'Birden fazla öğe seçildi.', + 'uploading_file_num' => ':number adet dosya yükleniyor...', + 'uploading_complete' => 'Yükleme tamamlandı', + 'uploading_error' => 'Yükleme hatası', + 'type_blocked' => 'Seçilen dosya türünü güvenlik nedenleriyle izin verilmiyor.', + 'order_by' => 'Sırala', + 'direction' => 'Yön', + 'direction_asc' => 'Artan', + 'direction_desc' => 'Azalan', + 'folder' => 'Klasör', + 'no_files_found' => 'İsteğiniz doğrultusunda hiçbir dosya bulunamadı.', + 'delete_empty' => 'Lütfen silinecek öğeleri seçiniz.', + 'delete_confirm' => 'Bu öğe veya öğeleri gerçekten silmek istediğinize emin misiniz?', + 'error_renaming_file' => 'Öğeyi yeniden isimlendirirken hata.', + 'new_folder_title' => 'Yeni Klasör', + 'folder_name' => 'Klasör ismi', + 'error_creating_folder' => 'Klasör oluştururken hata', + 'folder_or_file_exist' => 'Belirtilen isimde bir klasör ya da dosya zaten mevcut.', + 'move_empty' => 'Lütfen taşınacak öğeleri seçiniz.', + 'move_popup_title' => 'Dosyaları veya klasörleri taşı', + 'move_destination' => 'Hedef klasör', + 'please_select_move_dest' => 'Lütfen hedef klasörü seçiniz.', + 'move_dest_src_match' => 'Lütfen başka bir hedef klasör seçiniz.', + 'empty_library' => 'Medya kütüphanesi boş. Başlamak için dosya yükleyin yada klasör oluşturun.', + 'insert' => 'Ekle', + 'crop_and_insert' => 'Kırp ve Ekle', + 'select_single_image' => 'Lütfen sadece bir tane resim seçiniz.', + 'selection_not_image' => 'Seçili öğe bir resim değil.', + 'restore' => 'Tüm değişiklikleri geri al', + 'resize' => 'Yeniden boyutlandırma...', + 'selection_mode_normal' => 'Normal', + 'selection_mode_fixed_ratio' => 'Sabit oran', + 'selection_mode_fixed_size' => 'Sabit boyut', + 'height' => 'Yükseklik', + 'width' => 'Genişlik', + 'selection_mode' => 'Seçim modu', + 'resize_image' => 'Resimi yeniden boyutlandırs', + 'image_size' => 'Resim boyutu:', + 'selected_size' => 'Seçili:', + ], +]; diff --git a/modules/backend/lang/uk/lang.php b/modules/backend/lang/uk/lang.php new file mode 100644 index 0000000..ca0f02e --- /dev/null +++ b/modules/backend/lang/uk/lang.php @@ -0,0 +1,580 @@ + [ + 'title' => 'Зона адміністрування' + ], + 'field' => [ + 'invalid_type' => 'Неправильний тип поля :type.', + 'options_method_invalid_model' => "The attribute ':field' does not resolve to a valid model. Try specifying the options method for model class :model explicitly.", + 'options_method_not_exists' => "Клас моделі :model повинен містити метод :method(), що повертає опції для поля ':field'.", + ], + 'widget' => [ + 'not_registered' => "Назву класу віджету ':name' не зареєстровано", + 'not_bound' => "Клас віджета ':name' не прив'зано до контролера", + ], + 'page' => [ + 'untitled' => 'Без назви', + 'access_denied' => [ + 'label' => 'Доступ заборонено', + 'help' => 'У Вас немає необхідних прав для перегляду цієї сторінки.', + 'cms_link' => 'Повернутися до back-end-у' + ], + 'no_database' => [ + 'label' => 'База данних відсутня', + 'help' => 'Для доступу до back-end - потрібна база данних. Перевірте, налаштування та міграції бази данних, перш ніж спробувати знову.', + 'cms_link' => 'Повернутися на домашню сторінку' + ], + ], + 'partial' => [ + 'not_found_name' => "Частину ':name' не знайдено.", + ], + 'account' => [ + 'sign_out' => 'Вийти', + 'login' => 'Увійти', + 'reset' => 'Скинути', + 'restore' => 'Відновити', + 'login_placeholder' => 'логін', + 'password_placeholder' => 'пароль', + 'remember_me' => 'Залишитись в системі', + 'forgot_password' => 'Забули свій пароль?', + 'enter_email' => 'Введіть свою електронну адресу', + 'enter_login' => 'Введіть своє ім\'я користувача', + 'email_placeholder' => 'електронна адреса', + 'enter_new_password' => 'Введіть новий пароль', + 'password_reset' => 'Скинути пароль', + 'restore_success' => 'На Вашу електронну адресу було надіслано інструкції з відновлення паролю.', + 'restore_error' => "Неможливо знайти користувача з іменем користувача ':login'", + 'reset_success' => 'Ваш пароль було успішно змінено. Тепер Ви можете ввійти.', + 'reset_error' => 'Надано неправильні дані з відновлення паролю. Будь ласка, спробуйте знову!', + 'reset_fail' => 'Не вдалося змінити Ваш пароль!', + 'apply' => 'Застосувати', + 'cancel' => 'Скасувати', + 'delete' => 'Видалити', + 'ok' => 'ОК' + ], + 'dashboard' => [ + 'menu_label' => 'Панель керування', + 'widget_label' => 'Віджет', + 'widget_width' => 'Ширина', + 'full_width' => 'повна ширина', + 'manage_widgets' => 'Керування віджетами', + 'add_widget' => 'Додати віджет', + 'widget_inspector_title' => 'Налаштування віджету', + 'widget_inspector_description' => 'Налаштування віджету', + 'widget_columns_label' => 'Ширина :columns', + 'widget_columns_description' => 'Ширина віджету, число між 1 та 10.', + 'widget_columns_error' => 'Будь ласка, уведіть ширину віджету як число між 1 та 10.', + 'columns' => '{1} колонка|[2,4] колонки|[5,Inf] колонок', + 'widget_new_row_label' => 'Перенести на новий рядок', + 'widget_new_row_description' => 'Помістити віджет у новий рядок.', + 'widget_title_label' => 'Назва віджету', + 'widget_title_error' => 'Назва віджету є обов\'язковою.', + 'reset_layout' => 'Скидання макета', + 'reset_layout_confirm' => 'Ви дійсно хочете встановити за замовчуванням?', + 'reset_layout_success' => 'Макет був скинутий', + 'make_default' => 'Використовувати за замовчуванням', + 'make_default_confirm' => 'Встановіть поточну схему розташування за замовчуванням?', + 'make_default_success' => 'Поточне розташування тепер за замовчуванням', + 'collapse_all' => 'Згорнути', + 'expand_all' => 'Розгорнути', + 'status' => [ + 'widget_title_default' => 'Статус системи', + 'update_available' => 'Доступно {0} оновлень!|Доступно {1} оновлення!|Доступно [2,4] оновленя|Доступно [5,Inf] оновлень!', + 'updates_pending' => 'В очікуванні оновлення програмного забезпечення', + 'updates_nil' => 'Програмне забезпечення в актуальному стані', + 'updates_link' => 'Оновити', + 'warnings_pending' => 'Деякі питання потребують уваги', + 'warnings_nil' => 'Немає попереджень для відображення', + 'warnings_link' => 'Переглянути', + 'core_build' => 'Версія системи', + 'event_log' => 'Журнал подій', + 'request_log' => 'Журнал запитів', + 'app_birthday' => 'Сайт засновано' + ], + 'welcome' => [ + 'widget_title_default' => 'Ласкаво просимо', + 'welcome_back_name' => 'Ласкаво просимо до :app, :name.', + 'welcome_to_name' => 'Ласкаво просимо до :app, :name.', + 'first_sign_in' => 'Це ваша перша авторизація.', + 'last_sign_in' => 'Дата останньої авторизації', + 'view_access_logs' => 'Перегляд журналу доступу', + 'nice_message' => 'Гарного дня!' + ], + ], + 'user' => [ + 'name' => 'Адміністратор', + 'menu_label' => 'Адміністратори', + 'menu_description' => 'Керування адміністративними користувачами, групами та дозволами back-end-у.', + 'list_title' => 'Керування адміністраторами', + 'new' => 'Новий адміністратор', + 'login' => 'Логін', + 'first_name' => 'Ім\'я', + 'last_name' => 'Прізвище', + 'full_name' => 'Повне ім\'я', + 'email' => 'Електронна пошта', + 'role_field' => 'Роль', + 'role_comment' => 'Ролі визначають рівні доступу користувачів, які можна визначити у вкладці "Права".', + 'groups' => 'Групи', + 'groups_comment' => 'Вкажіть до яких груп повинен належати цей обліковий запис.', + 'avatar' => 'Аватар', + 'password' => 'Пароль', + 'password_confirmation' => 'Підтвердження паролю', + 'permissions' => 'Дозволи', + 'account' => 'Обліковий запис', + 'superuser' => 'Супер-адміністратор', + 'superuser_comment' => 'Надає цьому обліковому запису необмежений доступ.', + 'send_invite' => 'Надіслати запрошення за електронною адресою', + 'send_invite_comment' => 'Надсилає вітальне повідомлення, що містить інформацію про ім\'я користувача та пароль.', + 'delete_confirm' => 'Ви дійсно хочете видалити цього адміністратора?', + 'return' => 'Повернутися до списку адміністраторів', + 'allow' => 'Дозволити', + 'inherit' => 'Успадкувати', + 'deny' => 'Заборонити', + 'activated' => 'Активований', + 'last_login' => 'Останній вхід', + 'created_at' => 'Створено', + 'updated_at' => 'Оновлено', + 'group' => [ + 'name' => 'Група', + 'name_comment' => 'Назва відображається на сторінці стоврення/редагування адміністратора.', + 'name_field' => 'Назва', + 'description_field' => 'Опис', + 'is_new_user_default_field_label' => 'Група за замовчуванням', + 'is_new_user_default_field_comment' => 'Додавання нових адміністраторів в цю групу за замовчуванням', + 'code_field' => 'Код', + 'code_comment' => 'Введіть унікальний код якщо Ви хочете отримувати до неї доступ через API.', + 'menu_label' => 'Групи', + 'list_title' => 'Керування групами', + 'new' => 'Нова група', + 'delete_confirm' => 'Видалити цю групу адміністраторів?', + 'return' => 'Повернутись до списку груп', + 'users_count' => 'Користувачі' + ], + 'role' => [ + 'name' => 'Роль', + 'name_field' => 'Назва', + 'name_comment' => 'Назва відображається у списку ролей у формі "Адміністратор".', + 'description_field' => 'Опис', + 'code_field' => 'Код', + 'code_comment' => 'Введіть унікальний код, якщо ви хочете отримати доступ до об\'єкту ролі за допомогою API.', + 'menu_label' => 'Керування ролями', + 'list_title' => 'Керування ролями', + 'new' => 'Нова роль', + 'delete_confirm' => 'Видалити цю роль адміністратора?', + 'return' => 'Повернутися до списку ролей', + 'users_count' => 'Користувачі' + ], + 'preferences' => [ + 'not_authenticated' => 'Немає автентифікованих користувачів, чиї налаштування можна завантажити або зберегти.' + ], + ], + 'list' => [ + 'default_title' => 'Список', + 'search_prompt' => 'Пошук…', + 'no_records' => 'У цьому вигляді немає записів.', + 'missing_model' => 'Поведінка списку, що використовується в :class не містить визначення моделі.', + 'missing_column' => 'Немає визначень колонок для :columns.', + 'missing_columns' => 'Список використаний в :class не містить визначених колонок.', + 'missing_definition' => "Поведінка списку не містить колонки для ':field'.", + 'missing_parent_definition' => "Список поведінки не містить визначення ':definition'.", + 'behavior_not_ready' => 'Поведінку списку не було ініціалізовано, перевірте чи Ви викликали makeLists() у своєму контролері.', + 'invalid_column_datetime' => "Значення колонки ':column' не є DateTime-об'єктом, Ви не пропускаєте посилання на \$dates посилання в моделі?", + 'pagination' => 'Показано записів: :from-:to з :total', + 'first_page' => 'Перша сторінка', + 'last_page' => 'Остання', + 'prev_page' => 'Попередня сторінка', + 'next_page' => 'Наступна сторінка', + 'refresh' => 'Оновити', + 'updating' => 'Оновлення…', + 'loading' => 'Завантаження…', + 'setup_title' => 'Створення списку', + 'setup_help' => 'Використовуйте позначки для вибору колонок, які Ви хочете бачити в списку. Ви моєете змінювати позиції колонок перетягуючи їх вниз-вгору.', + 'records_per_page' => 'Записів на сторінку', + 'records_per_page_help' => 'Оберіть число записів на сторінку для показу. Будь ласка, зауважте, що велике число записів на одну сторінку може зменшити швидкодію.', + 'check' => 'Перевірити', + 'delete_selected' => 'Видалити обрані', + 'delete_selected_empty' => 'Немає обраних записів до видалення.', + 'delete_selected_confirm' => 'Видалити обрані записи?', + 'delete_selected_success' => 'Обрані записи успішно видалено', + 'column_switch_true' => 'Так', + 'column_switch_false' => 'Ні' + ], + 'fileupload' => [ + 'attachment' => 'Прикріплення', + 'help' => 'Додайте назву та опис для цього прикріплення.', + 'title_label' => 'Назва', + 'description_label' => 'Опис', + 'default_prompt' => 'Натисніть %s або перетягніть файл сюди для завантаження', + 'attachment_url' => 'URL прикріплення', + 'upload_file' => 'Завантажити файл', + 'upload_error' => 'Помилка завантаження', + 'remove_confirm' => 'Ви впевнені?', + 'remove_file' => 'Видалити файл' + ], + 'form' => [ + 'create_title' => 'Нова :name', + 'update_title' => 'Редагувати :name', + 'preview_title' => 'Попередній перегляд :name', + 'create_success' => ':name створено', + 'update_success' => ':name оновлено', + 'delete_success' => ':name видалено', + 'reset_success' => 'Успішно скасовано', + 'missing_id' => 'Ідентифікатор запису форми не було вказано.', + 'missing_model' => 'Поведінка форми, що використовується в :class не містить визначення моделі.', + 'missing_definition' => "Поведніка форми не містить поля для ':field'.", + 'not_found' => 'Запис форми з ідентифікатором :id не знайдено.', + 'action_confirm' => 'Ви впевнені?', + 'create' => 'Створити', + 'create_and_close' => 'Створити та закрити', + 'creating' => 'Створення…', + 'creating_name' => 'Створення :name…', + 'save' => 'Зберегти', + 'save_and_close' => 'Зберегти та закрити', + 'saving' => 'Збереження…', + 'saving_name' => 'Збереження :name…', + 'delete' => 'Видалити', + 'deleting' => 'Видалення…', + 'confirm_delete' => 'Ви дійсно хочете видалити цей запис?', + 'confirm_delete_multiple' => 'Ви дійсно хочете видалити обрані записи?', + 'deleting_name' => 'Видалення :name…', + 'reset_default' => 'Скинути за замовчуванням', + 'resetting' => 'Скидання', + 'resetting_name' => 'Скидання :name', + 'undefined_tab' => 'Різне', + 'field_off' => 'Викл', + 'field_on' => 'Вкл', + 'add' => 'Додати', + 'apply' => 'Застосувати', + 'cancel' => 'Скасувати', + 'close' => 'Закрити', + 'confirm' => 'Підтвердити', + 'reload' => 'Перезавантажити', + 'complete' => 'Готово', + 'ok' => 'ОК', + 'or' => 'або', + 'confirm_tab_close' => 'Ви дійсно хочете закрити цю вкладку? Незбережені зміни буде втрачено.', + 'behavior_not_ready' => 'Поведінку форми не було ініціалізовано, перевірте чи Ви викликали initForm() у своєму контролері.', + 'preview_no_files_message' => 'Немає завантажених файлів.', + 'preview_no_media_message' => 'Немає обраного файла.', + 'preview_no_record_message' => 'Немає обраних записів.', + 'select' => 'Обрати', + 'select_all' => 'вибрати все', + 'select_none' => 'вибрати жоден', + 'select_placeholder' => 'будь ласка, оберіть', + 'insert_row' => 'Вставити рядок', + 'insert_row_below' => 'Вставити рядок нижче', + 'delete_row' => 'Видалити рядок', + 'concurrency_file_changed_title' => 'Файл було змінено', + 'concurrency_file_changed_description' => 'Файл, що Ви редагуєте, було змінено на диску іншим користувачем. Ви можете або перезавантажити файл та втратити свої зміни, або перезаписати файл на диску.', + 'return_to_list' => 'Повернутися до списку' + ], + 'recordfinder' => [ + 'find_record' => 'Знайти запис', + 'cancel' => 'Скасувати' + ], + 'pagelist' => [ + 'page_link' => 'Посилання на сторінку', + 'select_page' => 'Обрати сторынку...' + ], + 'relation' => [ + 'missing_config' => "Поведінка відношення не містить жодного налаштування для ':config'.", + 'missing_definition' => "Поведінка відношення не містить визначення для ':field'.", + 'missing_model' => 'Поведінка відношення, що використовується в :class не містить визначення моделі.', + 'invalid_action_single' => 'Ця дія не може бути здійсненою щодо одного відношення.', + 'invalid_action_multi' => 'Ця дія не може бути здійснена щодо кількох відношень.', + 'help' => 'Натисніть по елементу щоб додати', + 'related_data' => 'Відносяться дані :name', + 'add' => 'Додати', + 'add_selected' => 'Додати обрані', + 'add_a_new' => 'Додати нове :name', + 'link_selected' => 'Обрано зв\'язок', + 'link_a_new' => 'Зв\'язати нове :name', + 'cancel' => 'Скасувати', + 'close' => 'Закрити', + 'add_name' => 'Додати :name', + 'create' => 'Створити', + 'create_name' => 'Створити :name', + 'update' => 'Оновити', + 'update_name' => 'Оновити :name', + 'preview' => 'Попередній перегляд', + 'preview_name' => 'Попередній перегляд :name', + 'remove' => 'Видалити', + 'remove_name' => 'Видалити :name', + 'delete' => 'Видалити', + 'delete_name' => 'Видалити :name', + 'delete_confirm' => 'Ви впевнені?', + 'link' => 'Зв\'язати', + 'link_name' => 'Зв\'язати :name', + 'unlink' => 'Відв\'язати', + 'unlink_name' => 'Відв\'язати :name', + 'unlink_confirm' => 'Ви впевнені?' + ], + 'reorder' => [ + 'default_title' => 'Перевпорядкувати записи', + 'no_records' => 'Немає доступних до сортування записів.' + ], + 'model' => [ + 'name' => 'Модель', + 'not_found' => "Модель ':class' з ідентифікатором :id не знайдено", + 'missing_id' => 'Не вказано ідентифікатор для пошуку запису моделі.', + 'missing_relation' => "Модель ':class' не містить визначення для ':relation'.", + 'missing_method' => "Модель ':class' не містить метод ':method'.", + 'invalid_class' => "Модель :model використана в :class не є правильною, вона повинна успадковувати клас \Model .", + 'mass_assignment_failed' => "Масове призначення не вдалось для атрибуту ':attribute' моделі.", + ], + 'warnings' => [ + 'tips' => 'Підказки з налаштування системи', + 'tips_description' => 'Є речі, на які потрібно звернути увагу щоб правильно налаштувати систему.', + 'permissions' => 'Директорія :name та її субдиректорії не мають дозволу для запису для PHP. Будь ласка, встановіть відповідні дозволи для веб-серверу для цієї директорії.', + 'extension' => 'Розширення PHP :name не встановлено. Будь ласка, встановіть цю бібліотеку та активуйте розширення.', + 'plugin_missing' => 'Плагін :name має залежності, які не встановлено. Будь ласка, встановіть ці плагіни.' + ], + 'editor' => [ + 'menu_label' => 'Налаштування редактору коду', + 'menu_description' => 'Персоналізуйте свої налаштування редактору коду, такі як розмір шрифту та колір.', + 'font_size' => 'Розмір шрифту', + 'tab_size' => 'Розмір табуляції', + 'use_hard_tabs' => 'Відступ табуляціями', + 'code_folding' => 'Згортання коду', + 'code_folding_begin' => 'Відмітка на початку блоку', + 'code_folding_begin_end' => 'Відмітка на початку та кінці блоку', + 'autocompletion' => 'Заповнити форму', + 'word_wrap' => 'Перенос слів', + 'highlight_active_line' => 'Підсвічувати активні рядки', + 'auto_closing' => 'Автоматично закривати теги та спецсимволи', + 'show_invisibles' => 'Показувати невидимі символи', + 'show_gutter' => 'Показувати нумерацію рядків', + 'basic_autocompletion' => 'Автозаповнення (Ctrl + Space)', + 'live_autocompletion' => 'Живе автозаповнення', + 'enable_snippets' => 'Увімкнути фрагменти коду (Tab)', + 'display_indent_guides' => 'Показати відступ напрямних', + 'show_print_margin' => 'Показати запас друку', + 'mode_off' => 'Вимкнено', + 'mode_fluid' => 'Адаптивно', + '40_characters' => '40 символів', + '80_characters' => '80 символів', + 'theme' => 'Кольорова схема', + 'markup_styles' => 'Стилі розмітки', + 'custom_styles' => 'Спеціальна таблиця стилів', + 'custom styles_comment' => 'Спеціальні стилі для включення в редактор HTML.', + 'markup_classes' => 'Класи розмітки', + 'paragraph' => 'Абзац', + 'link' => 'Посилання', + 'table' => 'Таблиця', + 'table_cell' => 'Клітинки таблиці', + 'image' => 'Зображення', + 'label' => 'Назва поля', + 'class_name' => 'Назва класу', + 'markup_tags' => 'Теги розмітки', + 'allowed_empty_tags' => 'Дозволені порожні теги', + 'allowed_empty_tags_comment' => 'Контактні дані, які не видаляються, коли вони не мають ніякого змісту всередині.', + 'allowed_tags' => 'Дозволені теги', + 'allowed_tags_comment' => 'Список дозволених тегів.', + 'no_wrap' => 'Не обертати теги', + 'no_wrap_comment' => 'Список тегів, які не повинні бути обгорнуті в блокові елементи.', + 'remove_tags' => 'Видаляємі теги', + 'remove_tags_comment' => 'Теги які видаляються разом з їх вмістом.', + 'toolbar_buttons' => 'Кнопки панелі інструментів', + 'toolbar_buttons_comment' => 'Кнопки панелі інструментів, які за замовчуванням відображаються в Rich Editor.' + ], + 'tooltips' => [ + 'preview_website' => 'Перегляд веб-сайту' + ], + 'mysettings' => [ + 'menu_label' => 'Мої налаштування', + 'menu_description' => 'Налаштування, що стосуються Вашого адміністративного облікового запису' + ], + 'myaccount' => [ + 'menu_label' => 'Мій обліковий запис', + 'menu_description' => 'Оновіть свої деталі облікового запису, такі як ім\'я, електронна адреса та пароль.', + 'menu_keywords' => 'безпека ім\'я користувача' + ], + 'branding' => [ + 'menu_label' => 'Налаштування вигляду back-end-у', + 'menu_description' => 'Налаштуйте адміністративну зону, зокрема ім\'я, кольори та лого.', + 'brand' => 'Бренд', + 'logo' => 'Лого', + 'logo_description' => 'Завантажити власне лого для використання в back-end-і.', + 'app_name' => 'Назва додатку', + 'app_name_description' => 'Ця назва показується в заголовку back-end-у.', + 'app_tagline' => 'Девіз додатку', + 'app_tagline_description' => 'Ця назва показується на екрані входу до back-end-у.', + 'colors' => 'Кольори', + 'primary_color' => 'Основний колір', + 'secondary_color' => 'Вторинний колір', + 'accent_color' => 'Акцентний колір', + 'styles' => 'Стилі', + 'custom_stylesheet' => 'Власна таблиця стилів', + 'navigation' => 'Навігація', + 'menu_mode' => 'Cтиль меню', + 'menu_mode_inline' => 'В лінію', + 'menu_mode_tile' => 'Плитка', + 'menu_mode_collapsed' => 'Схлопнутий' + ], + 'backend_preferences' => [ + 'menu_label' => 'Налаштування back-end-у', + 'menu_description' => 'Керуйте своїми налаштуваннями облікового запису, як то бажана мова.', + 'region' => 'Область', + 'code_editor' => 'Редактор коду', + 'timezone' => 'Часовий пояс', + 'timezone_comment' => 'Виводити дати в обраному часовому поясі.', + 'locale' => 'Мова', + 'locale_comment' => 'Оберіть бажану мову для використання.' + ], + 'access_log' => [ + 'hint' => 'Цей журнал показує список успішних спроб входу адміністраторів. Записи зберігаються :days днів.', + 'menu_label' => 'Журнал доступу', + 'menu_description' => 'Переглянути список успішних входів користувачів back-end-у.', + 'created_at' => 'Дата та час', + 'login' => 'Ім\'я користувача', + 'ip_address' => 'IP-адреса', + 'first_name' => 'Ім\'я', + 'last_name' => 'Прізвище', + 'email' => 'Електронна адреса' + ], + 'filter' => [ + 'all' => 'всі', + 'options_method_not_exists' => "Модель класу :model повинна містити метод :method() який повертає значення для поля ':filter'.", + 'date_all' => 'весь період' + ], + 'import_export' => [ + 'upload_csv_file' => '1. Завантажити CSV-файл', + 'import_file' => 'Імпортувати файл', + 'first_row_contains_titles' => 'Перший рядок містить назви колонок', + 'first_row_contains_titles_desc' => 'Залиште це відміченим якщо перший рядок CSV використовується для назв колонок.', + 'match_columns' => '2. Віднести колонки файлу до полів бази даних', + 'file_columns' => 'Колонки файлу', + 'database_fields' => 'Поля бази даних', + 'set_import_options' => '3. Встановити опції імпорту', + 'export_output_format' => '1. Експортувати формат виводу', + 'file_format' => 'Формат файлу', + 'standard_format' => 'Стандартний формат', + 'custom_format' => 'Власний формат', + 'delimiter_char' => 'Розділювач', + 'enclosure_char' => 'Огортувач', + 'escape_char' => 'Символ екранування', + 'select_columns' => '2. Оберіть колонки до експорту', + 'column' => 'Колонка', + 'columns' => 'Колонки', + 'set_export_options' => '3. Встановіть опції експорту', + 'show_ignored_columns' => 'Показати ігноровані колонки', + 'auto_match_columns' => 'Автовіднесення колонок', + 'created' => 'Створено', + 'updated' => 'Оновлено', + 'skipped' => 'Пропущено', + 'warnings' => 'Попереджень', + 'errors' => 'Помилок', + 'skipped_rows' => 'Пропущені рядки', + 'import_progress' => 'Прогрес імпорту', + 'processing' => 'Обробка', + 'import_error' => 'Помилка імпорту', + 'upload_valid_csv' => 'Будь ласка, завантажте правильний CSV-файл.', + 'drop_column_here' => 'Перетягніть колонку сюди…', + 'ignore_this_column' => 'Ігнорувати цю колонку', + 'processing_successful_line1' => 'Процес експорту файлу було успішно завершено!', + 'processing_successful_line2' => 'Тепер браузер має автоматично перенаправити до завантаження файлу.', + 'export_progress' => 'Прогрес експорту', + 'export_error' => 'Помилка експорту', + 'column_preview' => 'Попередній перегляд колонки', + 'file_not_found_error' => 'Файл не знайдено', + 'empty_error' => 'Не вказано даних для експорту', + 'empty_import_columns_error' => 'Please specify some columns to import.', + 'match_some_column_error' => 'Please match some columns first.', + 'required_match_column_error' => 'Please specify a match for the required field :label.', + 'empty_export_columns_error' => 'Будь ласка, вкажіть деякі стовпці для експорту.', + 'behavior_missing_uselist_error' => 'Необхідно реалізувати поведінку контролера ListController з експортом "useList".', + 'missing_model_class_error' => 'Будь ласка, вкажіть властивість modelClass для типу :type', + 'missing_column_id_error' => 'Відсутній ідентифікатор стовпця', + 'unknown_column_error' => 'Невідомий стовпець', + 'encoding_not_supported_error' => 'Кодування вихідного файлу не розпізнається. Будь ласка, оберіть відповідний формать кодування для імпорту файлу.', + 'encoding_format' => 'Кодування файлу', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Керування медіафайлами' + ], + 'mediafinder' => [ + 'label' => 'Пошук медіа', + 'default_prompt' => 'Натисніть на кнопку %s, щоб знайти медіафайл' + ], + 'media' => [ + 'menu_label' => 'Медіафайли', + 'upload' => 'Завантажити', + 'move' => 'Перемістити', + 'delete' => 'Видалити', + 'add_folder' => 'Створити папку', + 'search' => 'Пошук', + 'display' => 'Показати', + 'filter_everything' => 'Всі файли', + 'filter_images' => 'Зображення', + 'filter_video' => 'Відео', + 'filter_audio' => 'Музика', + 'filter_documents' => 'Документи', + 'library' => 'Бібліотека', + 'size' => 'Розмір', + 'title' => 'Ім\'я', + 'last_modified' => 'Остання зміна', + 'public_url' => 'Публічна адреса', + 'click_here' => 'Натисніть тут', + 'thumbnail_error' => 'Помилка створення мініатюри.', + 'return_to_parent' => 'Повернутися до батьківської папки', + 'return_to_parent_label' => 'Піднятися на рівень вище...', + 'nothing_selected' => 'Нічого не обрано.', + 'multiple_selected' => 'Обрано кілька об\'єктів.', + 'uploading_file_num' => 'Завантаження файлів: :number', + 'uploading_complete' => 'Завантаження файлів завершено!', + 'uploading_error' => 'Помилка завантаження', + 'type_blocked' => 'Тип файлу, який використовується заблокований з міркувань безпеки.', + 'order_by' => 'Сортувати за', + 'folder' => 'Папка', + 'no_files_found' => 'Жоден з файлів не задовольняє вашому запиту.', + 'delete_empty' => 'Будь ласка, оберіть об\'єкти для видалення.', + 'delete_confirm' => 'Ви дійсно хочете видалити вибрані об\'єкти?', + 'error_renaming_file' => 'Помилка зміни імені файлу.', + 'new_folder_title' => 'Нова папка', + 'folder_name' => 'Назва папки', + 'error_creating_folder' => 'Помилка створення папки', + 'folder_or_file_exist' => 'Папка або файл з таким ім\'ям вже існує.', + 'move_empty' => 'Будь ласка, оберіть об\'єкти для переміщення.', + 'move_popup_title' => 'Переміщення файлів або папок', + 'move_destination' => 'Папка призначення', + 'please_select_move_dest' => 'Будь ласка, оберіть папку призначення для переміщення.', + 'move_dest_src_match' => 'Будь ласка, оберіть іншу папку.', + 'empty_library' => 'Бібліотека медіафайлів порожня. Для початку завантажте файли або створіть папки.', + 'insert' => 'Вставити', + 'crop_and_insert' => 'Обрізати і вставити', + 'select_single_image' => 'Будь ласка, оберіть одне зображення.', + 'selection_not_image' => 'Обраний елемент не є зображенням.', + 'restore' => 'Скасувати всі зміни', + 'resize' => 'Зміна розміру...', + 'selection_mode_normal' => 'Нормальний', + 'selection_mode_fixed_ratio' => 'Фіксоване співвідношення', + 'selection_mode_fixed_size' => 'Фіксований розмір', + 'height' => 'Висота', + 'width' => 'Ширина', + 'selection_mode' => 'Режим виділення', + 'resize_image' => 'Зміна розміру зображення', + 'image_size' => 'Розмір зображення:', + 'selected_size' => 'Обрано:' + ], +]; diff --git a/modules/backend/lang/vn/lang.php b/modules/backend/lang/vn/lang.php new file mode 100644 index 0000000..c121812 --- /dev/null +++ b/modules/backend/lang/vn/lang.php @@ -0,0 +1,585 @@ + [ + 'title' => 'Khu vực quản trị' + ], + 'field' => [ + 'invalid_type' => 'Loại Field không hợp lệ :type.', + 'options_method_invalid_model' => "Thuộc tính ':field' không đưa ra được model hợp lệ. Hãy thử chỉ định phương pháp tùy chọn cho model :model một cách rõ ràng.", + 'options_method_not_exists' => "Model class :model phải khai báo :method() trả về tùy chọn cho trường ':field'." + ], + 'widget' => [ + 'not_registered' => "Tên của widget class ':name' chưa được đăng ký", + 'not_bound' => "Widget với tên class ':name' đã không bị ràng buộc với controller" + ], + 'page' => [ + 'untitled' => 'Không có tiêu đề', + 'access_denied' => [ + 'label' => 'Truy cập bị chặn', + 'help' => "Bạn không đủ quyền để xem trang này.", + 'cms_link' => 'Quay lại trang quản trị' + ], + 'no_database' => [ + 'label' => 'Không tìm thấy Database', + 'help' => "Bắt buộc phải có 1 database để truy cập vào trang quản trị. Kiểm tra lại cấu hình database và migrated trước khi thử lại.", + 'cms_link' => 'Quay lại trang chủ' + ], + ], + 'partial' => [ + 'not_found_name' => "Không tìm thấy partial ':name'." + ], + 'account' => [ + 'signed_in_as' => 'Đã đăng nhập với :full_name', + 'sign_out' => 'Đăng xuất', + 'login' => 'Đăng nhập', + 'reset' => 'Reset', + 'restore' => 'Khôi phục', + 'login_placeholder' => 'đăng nhập', + 'password_placeholder' => 'mật khẩu', + 'remember_me' => 'Giữ trạng thái đăng nhập', + 'forgot_password' => 'Quên mật khẩu?', + 'enter_email' => 'Nhập email của bạn', + 'enter_login' => 'Tên đăng nhập', + 'email_placeholder' => 'email', + 'enter_new_password' => 'Nhập mật khẩu mới', + 'password_reset' => 'Lấy lại mật khẩu', + 'restore_success' => 'Một tin nhắn đã được gửi vào email của bạn. Vui lòng làm theo hướng dẫn', + 'restore_error' => "Không tìm thấy người dùng có tên ':login'", + 'reset_success' => 'Đã đặt lại mật khẩu. Bạn có thể đăng nhập ngay bây giờ', + 'reset_error' => 'Dữ liệu khôi phục mật khẩu không hợp lệ. Vui lòng thử lại!', + 'reset_fail' => 'Không thể đặt lại mật khẩu của bạn!', + 'apply' => 'Áp dụng', + 'cancel' => 'Bỏ qua', + 'delete' => 'Xóa', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => 'Bảng điều khiển chính', + 'widget_label' => 'Widget', + 'widget_width' => 'chiều rộng', + 'full_width' => 'rộng toàn màn hình', + 'manage_widgets' => 'Quản lý widgets', + 'add_widget' => 'Thêm mới widget', + 'widget_inspector_title' => 'Cấu hình widget', + 'widget_inspector_description' => 'Cấu hình widget', + 'widget_columns_label' => 'Độ rộng :columns', + 'widget_columns_description' => 'Độ rộng của widget, là một số nguyên trong khoảng 1 đến 10.', + 'widget_columns_error' => 'Vui lòng nhập vào độ rộng của widget là một số nguyên trong khoảng 1 đến 10.', + 'columns' => '{1} cột|[2,Inf] cột', + 'widget_new_row_label' => 'Một hàng mới', + 'widget_new_row_description' => 'Đẩy widget thành 1 hàng mới', + 'widget_title_label' => 'Tên Widget', + 'widget_title_error' => 'Tên của widget là bắt buộc', + 'reset_layout' => 'Reset layout', + 'reset_layout_confirm' => 'Reset layout về mặc định?', + 'reset_layout_success' => 'Layout đã được reset', + 'make_default' => 'Đặt thành mặc định', + 'make_default_confirm' => 'Đặt layout hiện tại thành mặc định?', + 'make_default_success' => 'Layout hiện tại đã trở thành layout mặc định', + 'collapse_all' => 'Thu gọn tất cả', + 'expand_all' => 'Mở rộng tất cả', + 'status' => [ + 'widget_title_default' => 'Tình trạng hệ thống', + 'update_available' => '{0} cập nhật có sãn!|{1} cập nhật có sẵn!|[2,Inf] cập nhật có sẵn!', + 'updates_pending' => 'Đang chờ cập nhật phần mềm', + 'updates_nil' => 'Phần mềm đã được cập nhật', + 'updates_link' => 'Cập nhật', + 'warnings_pending' => 'Một số vấn đề cần chú ý', + 'warnings_nil' => 'Không có cảnh báo nào', + 'warnings_link' => 'Chi tiết', + 'core_build' => 'Phiên bản hệ thống', + 'event_log' => 'Nhật ký các sự kiện', + 'request_log' => 'Nhật ký các request thất bại', + 'app_birthday' => 'Lần đăng nhập gần nhất', + ], + 'welcome' => [ + 'widget_title_default' => 'Xin chào', + 'welcome_back_name' => 'Chào mừng :name quay trở lại :app.', + 'welcome_to_name' => 'Chào mừng :name đến với :app.', + 'first_sign_in' => 'Đây là lần đầu tiên bạn đang nhập vào hệ thống.', + 'last_sign_in' => 'Lần cuối bạn đăng nhập vào lúc', + 'view_access_logs' => 'Xem nhật ký các lần đăng nhập', + 'nice_message' => 'Chúc bạn một ngày vui vẻ!', + ] + ], + 'user' => [ + 'name' => 'Administrator', + 'menu_label' => 'Administrators', + 'menu_description' => 'Quản lý các administrator, nhóm quản trị và quyền truy cập.', + 'list_title' => 'Quản lý Administrators', + 'new' => 'Thêm mới Administrator', + 'login' => 'Tên đăng nhập', + 'first_name' => 'Họ', + 'last_name' => 'Tên', + 'full_name' => 'Tên đầy đủ', + 'email' => 'Email', + 'role_field' => 'Role', + 'role_comment' => 'Các Role định nghĩa sẵn một số quyền của người dùng, nó có thể bị ghi đè bởi cấp độ của người dùng trong tab quyền hạn', + 'groups' => 'Nhóm quản trị', + 'groups_comment' => 'Chỉ định nhóm quản trị cho người dùng', + 'avatar' => 'Avatar', + 'password' => 'Mật khẩu', + 'password_confirmation' => 'Nhập lại mật khẩu', + 'permissions' => 'Các quyền truy cập', + 'account' => 'Tài khoản', + 'superuser' => 'Super User', + 'superuser_comment' => 'Super User có thể truy cập không giới hạn vào tất cả mọi nơi của hệ thống. Super User có thể quản lý, thêm mới các user khác ', + 'send_invite' => 'Gửi email chào mừng đến user', + 'send_invite_comment' => 'Gửi một tin nhắn chào mừng đến user với thông tin đăng nhập và mật khẩu', + 'delete_confirm' => 'Xóa administrator này?', + 'return' => 'Quay lại danh sách admin', + 'allow' => 'Cho phép', + 'inherit' => 'Inherit', + 'deny' => 'Không cho phép', + 'activated' => 'Đã active', + 'last_login' => 'Lần cuối đăng nhập', + 'created_at' => 'Tạo lúc', + 'updated_at' => 'Chỉnh sửa vào lúc', + 'group' => [ + 'name' => 'Nhóm quản trị', + 'name_field' => 'Tên', + 'name_comment' => 'Tên được hiển thị trong danh sách nhóm', + 'description_field' => 'Mô tả', + 'is_new_user_default_field_label' => 'Nhóm mặc định', + 'is_new_user_default_field_comment' => 'Khi thêm mới administrators mặc định sẽ vào nhóm này', + 'code_field' => 'Code', + 'code_comment' => 'Nhập mã code không được trùng lặp nếu bạn muốn truy cập group objectuop bằng API', + 'menu_label' => 'Quản lý các nhóm', + 'list_title' => 'Quản lý các nhóm', + 'new' => 'Nhóm mới', + 'delete_confirm' => 'Xóa nhóm này?', + 'return' => 'Quay lại danh sách nhóm', + 'users_count' => 'Số user' + ], + 'role' => [ + 'name' => 'Role', + 'name_field' => 'Tên Role', + 'name_comment' => 'Tên hiển thị trong danh sách Role.', + 'description_field' => 'Mô tả', + 'code_field' => 'Code', + 'code_comment' => 'Nhập mã code không được trùng lặp nếu bạn muốn truy cập group objectuop bằng API.', + 'menu_label' => 'Quản lý các Role', + 'list_title' => 'Quản lý các Role', + 'new' => 'Thêm mới Role', + 'delete_confirm' => 'Xóa role này?', + 'return' => 'Quay lại trang danh sách role', + 'users_count' => 'Số user' + ], + 'preferences' => [ + 'not_authenticated' => 'Người dùng không xác định.' + ] + ], + 'list' => [ + 'default_title' => 'Trang danh sách các bản ghi', + 'search_prompt' => 'Tìm kiếm...', + 'no_records' => 'Không có bản ghi nào.', + 'missing_model' => 'List behavior sử dụng trong :class không được định nghĩa trong model nào.', + 'missing_column' => 'Column chưa được định nghĩa :columns.', + 'missing_columns' => 'List đã dử dụng trong :class chưa được định nghĩa (list columns).', + 'missing_definition' => "List behavior không chứa cột ':field'.", + 'missing_parent_definition' => "List behavior không có định nghĩa cho ':definition'.", + 'behavior_not_ready' => 'List behavior chưa được khởi tạo,kiểm tra lại xem bạn đã gọi makeLists() trong controller chưa.', + 'invalid_column_datetime' => "Giá trị Column ':column' không phải là DateTime object, bạn đã thiếu \$dates trong model?", + 'pagination' => 'Hiển thị bản ghi: :from-:to của :total', + 'first_page' => 'Trang đầu tiên', + 'last_page' => 'Trang cuối cùng', + 'prev_page' => 'Trang trước', + 'next_page' => 'Trang tiếp theo', + 'refresh' => 'Làm mới', + 'updating' => 'Đang cập nhật...', + 'loading' => 'Đang tải...', + 'setup_title' => 'Cài đặt trang danh sách', + 'setup_help' => 'Chọn các cột bạn muốn hiển thị ở trang danh sách các bản ghi. Bạn có thể thay đổi vị trí của chúng bằng các kéo lên hoặc xuống.', + 'records_per_page' => 'Số bản ghi trên một trang', + 'records_per_page_help' => 'Điền vào số bản ghi bạn muốn hiển thị trên một trang. Chú ý quá nhiều bản ghi trên một trang sẽ khiến trang tải chậm', + 'check' => 'Kiểm tra', + 'delete_selected' => 'Xóa các mục đã chọn', + 'delete_selected_empty' => 'Không có bản ghi nào được chọn', + 'delete_selected_confirm' => 'Xóa các bản ghi đã chọn?', + 'delete_selected_success' => 'Xóa thành công các bản ghi.', + 'column_switch_true' => 'Có', + 'column_switch_false' => 'Không' + ], + 'fileupload' => [ + 'attachment' => 'Tệp đính kèm', + 'help' => 'Tên và mô tả cho tệp.', + 'title_label' => 'Tên', + 'description_label' => 'Mô tả', + 'default_prompt' => 'Bấm vào %s hoặc kéo thả file vào đây để upload', + 'attachment_url' => 'URL file', + 'upload_file' => 'Upload file', + 'upload_error' => 'Lỗi upload', + 'remove_confirm' => 'Bạn có chắc chắn muốn xóa?', + 'remove_file' => 'Xóa file' + ], + 'form' => [ + 'create_title' => 'Thêm mới :name', + 'update_title' => 'Chỉnh sửa :name', + 'preview_title' => 'Xem trước :name', + 'create_success' => ':name đã được tạo', + 'update_success' => 'Cập nhật thành công :name', + 'delete_success' => 'Xóa thành công :name', + 'reset_success' => 'Reset thành công', + 'missing_id' => 'Không xác định được ID của bản ghi.', + 'missing_model' => 'Form behavior sử dụng trong :class không có trong model nào.', + 'missing_definition' => "Form behavior không chứa ':field'.", + 'not_found' => 'Không tìm thấy bản ghi có id: :id.', + 'action_confirm' => 'Bạn chắc chắn không?', + 'create' => 'Thêm mới', + 'create_and_close' => 'Thêm và đóng lại', + 'creating' => 'Đang tạo...', + 'creating_name' => 'Đang tạo :name...', + 'save' => 'Lưu lại', + 'save_and_close' => 'Lưu và đóng', + 'saving' => 'Đang lưu...', + 'saving_name' => 'Đang lưu :name...', + 'delete' => 'Xóa', + 'deleting' => 'Đang xóa...', + 'confirm_delete' => 'Xóa bản ghi này?', + 'confirm_delete_multiple' => 'Xóa bản ghi đã chọn?', + 'deleting_name' => 'Đang xóa :name...', + 'reset_default' => 'Đặt về mặc định', + 'resetting' => 'Đang đặt lại', + 'resetting_name' => 'Đang đặt lại :name', + 'undefined_tab' => 'Misc', + 'field_off' => 'Tắt', + 'field_on' => 'Bật', + 'add' => 'Thêm', + 'apply' => 'Áp dụng', + 'cancel' => 'Bỏ qua', + 'close' => 'Đóng', + 'confirm' => 'Xác nhận', + 'reload' => 'Tại lại', + 'complete' => 'Hoàn thành', + 'ok' => 'OK', + 'or' => 'or', + 'confirm_tab_close' => 'Đóng tab? Các thay đổi của bạn sẽ không được lưu.', + 'behavior_not_ready' => 'Form behavior chưa được khởi tạo, kiểm tra lại đã gọi initForm() trong controller cửa bạn chưa.', + 'preview_no_files_message' => 'Chưa có file nào được upload lên.', + 'preview_no_media_message' => 'Không có file media nào được chọn.', + 'preview_no_record_message' => 'Không có bản ghi nào được chọn.', + 'select' => 'Select', + 'select_all' => 'chọn tất cả', + 'select_none' => 'không chọn', + 'select_placeholder' => 'Vui lòng lựa chọn', + 'insert_row' => 'Thêm mới Row', + 'insert_row_below' => 'Thêm Row dưới đây', + 'delete_row' => 'Xóa Row', + 'concurrency_file_changed_title' => 'File đã được thay đổi', + 'concurrency_file_changed_description' => "File bạn đang chỉnh sửa đã bị thay đổi bởi người khác. Bạn có thể tải lại và các thay đổi của bạn không được lưu hoặc ghi đè lên file đó", + 'return_to_list' => 'Quay lại trang danh sách' + ], + 'recordfinder' => [ + 'find_record' => 'Tìm kiếm bản ghi', + 'cancel' => 'Cancel', + ], + 'pagelist' => [ + 'page_link' => 'Page link', + 'select_page' => 'Lựa chọn một trang...' + ], + 'relation' => [ + 'missing_config' => "Relation behavior không được cấu hình cho ':config'.", + 'missing_definition' => "Relation behavior không có định nghĩa cho ':field'.", + 'missing_model' => 'Relation behavior đã sử dụng trong :class chưa được định nghĩa trong model nào.', + 'invalid_action_single' => 'Hành động này không thể thực hiện trên một singular relationship.', + 'invalid_action_multi' => 'Hành động này không thể thực hiện trên một multiple relationship.', + 'help' => 'Bấm vào 1 item để thêm mới', + 'related_data' => 'Dữ liệu quan đến :name', + 'add' => 'Thêm mới', + 'add_selected' => 'Thêm các mục đã chọn', + 'add_a_new' => 'Thêm mới :name', + 'link_selected' => 'Link đã chọn', + 'link_a_new' => 'Link mới :name', + 'cancel' => 'Cancel', + 'close' => 'Đóng lại', + 'add_name' => 'Thêm :name', + 'create' => 'Thêm mới', + 'create_name' => 'Thêm mới :name', + 'update' => 'Cập nhật', + 'update_name' => 'Cập nhật :name', + 'preview' => 'Xem trước', + 'preview_name' => 'Xem trước :name', + 'remove' => 'Xóa', + 'remove_name' => 'Xóa :name', + 'delete' => 'Xóa', + 'delete_name' => 'Xóa :name', + 'delete_confirm' => 'Bạn có chắc muốn xóa?', + 'link' => 'Link', + 'link_name' => 'Link :name', + 'unlink' => 'Unlink', + 'unlink_name' => 'Unlink :name', + 'unlink_confirm' => 'Bạn có chắc muốn xóa?' + ], + 'reorder' => [ + 'default_title' => 'Xắp xếp các bản ghi', + 'no_records' => 'Không có bản ghi nào để sắp xếp.' + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => "Không tìm thấy Model ':class' với id :id", + 'missing_id' => 'Không xác định được ID tìm kiếm.', + 'missing_relation' => "Model ':class' không được định nghĩa cho ':relation'.", + 'missing_method' => "Model ':class' không có phương thức ':method'.", + 'invalid_class' => "Model :model sử dụng trong :class không hợp lệ, nó phải được kế thừa từ \Model class.", + 'mass_assignment_failed' => "Có lỗi của Model attribute ':attribute'." + ], + 'warnings' => [ + 'tips' => 'Hướng dẫn cấu hình hệ thống', + 'tips_description' => 'Một số điều bạn cần chú ý để cấu hình hệ thống đúng cách.', + 'permissions' => 'PHP không có quyền ghi trong thư mục :name hoặc các thư mục con của nó. Vui lòng kiểm tra lại quyền ghi cho thư mục này.', + 'extension' => 'PHP extension :name chưa được cài đặt. Vui lòng cài đặt extension này từ thư viện và kích hoạt nó.', + 'plugin_missing' => 'Plugin :name cần phải cài đặt. Vui lòng cài đặt plugin này.', + ], + 'editor' => [ + 'menu_label' => 'Cài đặt trình biên tập (Code editor)', + 'menu_description' => 'Tùy chỉnh trình biên tập (Code editor) cho toàn trang, ví dụ kích thước chữ,màu nền cho trình biên tập.', + 'font_size' => 'Kích thước chữ', + 'tab_size' => 'Kích thước Tab', + 'use_hard_tabs' => 'Sử dụng tabs để lùi dòng', + 'code_folding' => 'Thu gọn code', + 'code_folding_begin' => 'Đánh dấu điểm bắt đầu', + 'code_folding_begin_end' => 'Đánh dấu điểm bắt đầu và kết thúc', + 'autocompletion' => 'Autocompletion', + 'word_wrap' => 'Không bị xuống dòng(word wrap)', + 'highlight_active_line' => 'Hiện nổi bật dòng đang trỏ chuột', + 'auto_closing' => 'Tự động đóng thẻ', + 'show_invisibles' => 'Hiển thị các ký tự ẩn', + 'show_gutter' => 'Hiện lề bên trong', + 'basic_autocompletion'=> 'Basic Autocompletion (Ctrl + Space)', + 'live_autocompletion'=> 'Live Autocompletion', + 'enable_snippets'=> 'Kích hoạt snippets (Tab)', + 'display_indent_guides'=> 'Hiển thị hướng dẫn căn lề', + 'show_print_margin'=> 'Hiện lề in', + 'mode_off' => 'Off', + 'mode_fluid' => 'Fluid', + '40_characters' => '40 ký tự', + '80_characters' => '80 ký tự', + 'theme' => 'Color scheme', + 'markup_styles' => 'Markup Styles', + 'custom_styles' => 'Stylesheet tùy chỉnh', + 'custom styles_comment' => 'Styles tùy chỉnh được thêm vào HTML editor.', + 'markup_classes' => 'Markup Classes', + 'paragraph' => 'Paragraph', + 'link' => 'Link', + 'table' => 'Table', + 'table_cell' => 'Table Cell', + 'image' => 'Image', + 'label' => 'Label', + 'class_name' => 'Class name', + 'markup_tags' => 'Markup Tags', + 'allowed_empty_tags' => 'Cho phép tags trống', + 'allowed_empty_tags_comment' => 'Danh sách tag sẽ không bị xóa khi chúng không có nội dung bên trong.', + 'allowed_tags' => 'Các tag được phép sử dụng', + 'allowed_tags_comment' => 'Danh sách tag được phép sử dụng trong Markup.', + 'no_wrap' => 'Không thu gọn tag', + 'no_wrap_comment' => 'Danh sách các tag sẽ không bị thu gọn nội dung bên trong block tags.', + 'remove_tags' => 'Xóa các tag', + 'remove_tags_comment' => 'Danh sách tag bị xóa kể cả nội dung của chúng.', + 'toolbar_buttons' => 'Các nút trên thanh công cụ', + 'toolbar_buttons_comment' => 'Các nút mặc định ở trên thanh công cụ của Rich Editor.', + ], + 'tooltips' => [ + 'preview_website' => 'Xem trước website' + ], + 'mysettings' => [ + 'menu_label' => 'Những cài đặt của tôi', + 'menu_description' => 'Những cài đặt liên quan đến tài khoản quản trị của bạn' + ], + 'myaccount' => [ + 'menu_label' => 'Tài khoản của tôi', + 'menu_description' => 'Cập nhật thông tin tài khoản của bạn ví dụ như tên, email hoặc mật khẩu.', + 'menu_keywords' => 'bảo mật đăng nhập' + ], + 'branding' => [ + 'menu_label' => 'Tùy chỉnh trang quản trị', + 'menu_description' => 'Tùy chỉnh trang quản trị, ví dụ như chỉnh sửa tên,màu sắc, logo.', + 'brand' => 'Nhãn', + 'logo' => 'Logo', + 'logo_description' => 'Tải lên logo sử dụng cho trang quản trị.', + 'app_name' => 'Tên ứng dụng', + 'app_name_description' => 'Tên này sẽ được làm tiêu đề cho trang quản trị.', + 'app_tagline' => 'App Tagline', + 'app_tagline_description' => 'Mục này hiển thị ở màn hình đăng nhập trang quản trị.', + 'colors' => 'Màu sắc', + 'primary_color' => 'Màu chủ đạo', + 'secondary_color' => 'Màu thứ hai', + 'accent_color' => 'Màu tạo các điểm nhấn', + 'styles' => 'Styles', + 'custom_stylesheet' => 'Stylesheet tùy chỉnh', + 'navigation' => 'Thanh menu', + 'menu_mode' => 'Kiểu menu', + 'menu_mode_inline' => 'Icon và tiêu đề cùng một dòng', + 'menu_mode_tile' => 'Icon và tiêu đề khác dòng', + 'menu_mode_collapsed' => 'Thu gọn icon và tiêu đề' + ], + 'backend_preferences' => [ + 'menu_label' => 'Tùy chỉnh cá nhân', + 'menu_description' => 'Cá nhân hóa trang quản trị với tài khoản của bạn, ví dụ chọn ngôn ngữ.', + 'region' => 'Khu vực', + 'code_editor' => 'Code editor', + 'timezone' => 'Múi giờ', + 'timezone_comment' => 'Điều chỉnh thời gian hiển thị cho múi giờ này.', + 'locale' => 'Ngôn ngữ địa phương', + 'locale_comment' => 'Chọn khu vực của bạn để sử dụng đúng ngôn ngữ.' + ], + 'access_log' => [ + 'hint' => 'Nhật ký những lần đăng nhập thành công của administrators. Số bản ghi được lưu trữ trong :days ngày.', + 'menu_label' => 'Nhật ký truy cập', + 'menu_description' => 'Danh sách các lần người quản trị đăng nhập thành công.', + 'created_at' => 'Thời gian', + 'login' => 'Tên đăng nhập', + 'ip_address' => 'Địa chỉ IP', + 'first_name' => 'First name', + 'last_name' => 'Last name', + 'email' => 'Email' + ], + 'filter' => [ + 'all' => 'tất cả', + 'options_method_not_exists' => "Model class :model cần phải khai báo method :method() trả về các tùy chọn lọc ':filter'.", + 'date_all' => 'tất cả', + 'number_all' => 'tất cả', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Tải lên tệp CSV', + 'import_file' => 'Import file', + 'first_row_contains_titles' => 'Dòng đầu tiên là tiêu đề cột', + 'first_row_contains_titles_desc' => 'Bỏ check nếu dòng đầu tiên trong file CSV là tiêu đề của cột.', + 'match_columns' => '2. Các cột dữ liệu trùng với các cột dữ liệu của database', + 'file_columns' => 'Các cột của tệp CSV', + 'database_fields' => 'Các cột của database', + 'set_import_options' => '3. Set import options', + 'export_output_format' => '1. Định dạng dữ liệu xuất ra', + 'file_format' => 'Định dang file', + 'standard_format' => 'Định dạng chuẩn', + 'custom_format' => 'Định dạng khác', + 'delimiter_char' => 'Delimiter character', + 'enclosure_char' => 'Enclosure character', + 'escape_char' => 'Escape character', + 'select_columns' => '2. Chọn cột để xuất ra', + 'column' => 'Column', + 'columns' => 'Columns', + 'set_export_options' => '3. Các tùy chọn xuất file', + 'show_ignored_columns' => 'Hiển thị các cột bị bỏ qua', + 'auto_match_columns' => 'Tự động khớp các cột', + 'created' => 'Đã tạo', + 'updated' => 'Đã cập nhật', + 'skipped' => 'Đã bỏ qua', + 'warnings' => 'Cảnh báo', + 'errors' => 'Lỗi', + 'skipped_rows' => 'Các dòng đã bỏ qua', + 'import_progress' => 'Tiến độ nhập file', + 'processing' => 'Đang xử lý', + 'import_error' => 'Lỗi nhập file', + 'upload_valid_csv' => 'Vui lòng tải lên tệp CSV hợp lệ', + 'drop_column_here' => 'Kéo cột vào đây...', + 'ignore_this_column' => 'Bỏ qua cột này', + 'processing_successful_line1' => 'Xuất file thành công!', + 'processing_successful_line2' => 'Bạn sẽ được chuyển đến nơi tải file về ngay bây giờ.', + 'export_progress' => 'Tiến độ xuất file', + 'export_error' => 'Lỗi xuất file', + 'column_preview' => 'Xem trước cột', + 'file_not_found_error' => 'Không tìm thấy file', + 'empty_error' => 'Không có dữ liệu để xuất ra', + 'empty_import_columns_error' => 'Vui lòng chọn một số cột để nhập vào.', + 'match_some_column_error' => 'Các cột chưa khớp nhau.', + 'required_match_column_error' => 'Trường bắt buộc sau đây chưa khớp :label.', + 'empty_export_columns_error' => 'Vui lòng chọn các cột để xuất ra.', + 'behavior_missing_uselist_error' => 'Bạn cần phải implement cái controller behavior ListCotroller với tùy chọn "useList" được chọn', + 'missing_model_class_error' => 'Ghi rõ thuộc tính modelClass cho :type', + 'missing_column_id_error' => 'Không xác định được cột', + 'unknown_column_error' => 'Cột không xác định', + 'encoding_not_supported_error' => 'Kiểu mã hóa(encoding) của tập tin sai. Vui lòng chọn lại kiểu mã hóa phù hợp để import', + 'encoding_format' => 'Kiểu mã hóa(encoding)', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Tải lên và quản lý các tập tin đa phương tiện - images, videos, sounds, documents' + ], + 'mediafinder' => [ + 'label' => 'Media Finder', + 'default_prompt' => 'Bấm vào nút %s để tìm kiếm medai file' + ], + 'media' => [ + 'menu_label' => 'Media', + 'upload' => 'Tải lên', + 'move' => 'Di chuyển', + 'delete' => 'Xóa', + 'add_folder' => 'Thêm folder', + 'search' => 'Tìm kiếm', + 'display' => 'Hiển thị', + 'filter_everything' => 'Mọi thứ', + 'filter_images' => 'Images', + 'filter_video' => 'Video', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Documents', + 'library' => 'Thư viện', + 'size' => 'Kích thước', + 'title' => 'Tên ảnh', + 'last_modified' => 'Lần cuối chỉnh sửa', + 'public_url' => 'URL', + 'click_here' => 'Bấm vào đây', + 'thumbnail_error' => 'Lỗi tạo thumbnail.', + 'return_to_parent' => 'Trả về thư mục cha', + 'return_to_parent_label' => 'Lên trên ..', + 'nothing_selected' => 'Chưa chọn mục nào.', + 'multiple_selected' => 'Đã chọn nhiều mục.', + 'uploading_file_num' => 'Đang tải lên :number file...', + 'uploading_complete' => 'Tải lên hoàn tất', + 'uploading_error' => 'Lỗi tải lên', + 'type_blocked' => 'Loại file này bị khóa vì lý do bảo mật.', + 'order_by' => 'Xắp xếp theo', + 'direction' => 'Theo hướng', + 'direction_asc' => 'Tăng dần', + 'direction_desc' => 'Giảm dần', + 'folder' => 'Thư mục', + 'no_files_found' => 'Không tìm thấy file bạn yêu cầu.', + 'delete_empty' => 'Vui lòng chọn các mục để xóa.', + 'delete_confirm' => 'Xác nhận xóa các mục đã chọn?', + 'error_renaming_file' => 'Lỗi đổi tên file.', + 'new_folder_title' => 'Thư mục mới', + 'folder_name' => 'Tên thư mục', + 'error_creating_folder' => 'Lỗi khi tạo thư mục mới', + 'folder_or_file_exist' => 'Tên file hoặc thư mục đã tồn tại.', + 'move_empty' => 'Chọn một mục để di chuyển.', + 'move_popup_title' => 'Di chuyển file hoặc thư mục', + 'move_destination' => 'Chọn nơi đến', + 'please_select_move_dest' => 'Chọn nơi mà file hoặc thư mục cần chuyển đến.', + 'move_dest_src_match' => 'Chọn thư mục khác.', + 'empty_library' => 'Thư mục trống.Vui lòng tải tệp tin lên hoặc tạo thư mục mới để bắt đầu.', + 'insert' => 'Chàn vào', + 'crop_and_insert' => 'Cắt & Chèn vào', + 'select_single_image' => 'vui lòng chọn một hình ảnh.', + 'selection_not_image' => 'Mục đã chọn không phải là hình ảnh.', + 'restore' => 'Hoàn lại tất cả các thay đổi', + 'resize' => 'Đổi kích thước...', + 'selection_mode_normal' => 'Bình thường', + 'selection_mode_fixed_ratio' => 'Tỉ lệ cố định', + 'selection_mode_fixed_size' => 'Kích thước cố định', + 'height' => 'Chiều cao', + 'width' => 'Chiều rộng', + 'selection_mode' => 'Lựa chọn chế độ', + 'resize_image' => 'Đổi kích thước ảnh', + 'image_size' => 'Kích thước ảnh:', + 'selected_size' => 'Đã chọn:' + ], +]; diff --git a/modules/backend/lang/zh-cn/lang.php b/modules/backend/lang/zh-cn/lang.php new file mode 100644 index 0000000..511fe29 --- /dev/null +++ b/modules/backend/lang/zh-cn/lang.php @@ -0,0 +1,616 @@ + [ + 'title' => '管理', + 'invalid_login' => '无法匹配到您输入的相关内容,请检查后重试。' + ], + 'field' => [ + 'invalid_type' => '不合法的字段类型 :type.', + 'options_method_invalid_model' => "属性 ':field' 不能解析为有效模型. 请尝试为模型类:model指定一个可选方法.", + 'options_method_not_exists' => "模型 :model 必须定义一个返回 ':field' 表单字段选项的方法 :method()。", + 'colors_method_not_exists' => "模型 :model 必须定义一个返回十六进制格式的颜色值 ':field' 字段的 :method() 方法。 " + ], + 'widget' => [ + 'not_registered' => "未注册部件 ':name' ", + 'not_bound' => "部件 ':name' 未绑定至控制器" + ], + 'page' => [ + 'untitled' => '未命名', + '404' => [ + 'label' => '找不到页面', + 'help' => "无法访问到您请求的URL资源,试试其它的?", + 'back_link' => '返回上个页面' + ], + 'access_denied' => [ + 'label' => '拒绝访问', + 'help' => "您没有访问该页面所需的权限.", + 'cms_link' => '返回后台' + ], + 'no_database' => [ + 'label' => '无法找到数据库', + 'help' => "需要数据库以访问后端。请在再次尝试之前检查数据库的配置和迁移。", + 'cms_link' => '返回首页' + ], + ], + 'partial' => [ + 'not_found_name' => "未找到部件 ':name' ", + 'invalid_name' => '未知的部件名称 :name ' + ], + 'ajax_handler' => [ + 'invalid_name' => '未知的AJAX处理方法 :name.', + 'not_found' => "无法找到AJAX处理方法 ':name' " + ], + 'account' => [ + 'signed_in_as' => '以 :full_name 身份登陆', + 'sign_out' => '登出', + 'login' => '登录', + 'reset' => '重置', + 'restore' => '还原', + 'login_placeholder' => '登录', + 'password_placeholder' => '密码', + 'remember_me' => '保持登录状态', + 'forgot_password' => '忘记密码?', + 'enter_email' => '输入邮件地址', + 'enter_login' => '输入账号', + 'email_placeholder' => '邮件', + 'enter_new_password' => '输入新密码', + 'password_reset' => '密码重置', + 'restore_success' => '密码重置邮件已发至您的邮箱。', + 'restore_error' => "找不到用户 ':login'", + 'reset_success' => '密码已经重置成功。您现在可以登录了。', + 'reset_error' => '密码重置失败. 请重试!', + 'reset_fail' => '无法重置您的密码!', + 'apply' => '应用', + 'cancel' => '取消', + 'delete' => '删除', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => '仪表盘', + 'widget_label' => '小工具', + 'widget_width' => '宽度', + 'full_width' => '全部宽度', + 'manage_widgets' => '管理小部件', + 'add_widget' => '添加小工具', + 'widget_inspector_title' => '小工具配置', + 'widget_inspector_description' => '配置报表小工具', + 'widget_columns_label' => '宽度 :columns', + 'widget_columns_description' => '小工具宽度, 1 到 10.', + 'widget_columns_error' => '请输入小工具宽度,1 到 10.', + 'columns' => '{1} 栏|[2,Inf] 栏', + 'widget_new_row_label' => '强制新列', + 'widget_new_row_description' => '把小工具放到新列.', + 'widget_title_label' => '小工具标题', + 'widget_title_error' => '需要小工具标题.', + 'reset_layout' => '重置布局', + 'reset_layout_confirm' => '是否将布局恢复为默认?', + 'reset_layout_success' => '布局已经复位', + 'make_default' => '设为默认', + 'make_default_confirm' => '是否设置当前布局作为默认?', + 'make_default_success' => '当前布局为默认', + 'collapse_all' => '全部折叠', + 'expand_all' => '全部展开', + 'status' => [ + 'widget_title_default' => '系统状态', + 'update_available' => '{0} 更新可用!|{1} 更新可用!|[2,Inf] 更新可用!', + 'updates_pending' => '待定软件更新', + 'updates_nil' => '软件已为最新版本', + 'updates_link' => '更新', + 'warnings_pending' => '您需要留意一些问题', + 'warnings_nil' => '没有警告显示', + 'warnings_link' => '查看', + 'core_build' => '系统构建', + 'event_log' => '事件日志', + 'request_log' => '请求日志', + 'app_birthday' => '在线日期', + ], + 'welcome' => [ + 'widget_title_default' => '欢迎', + 'welcome_back_name' => '欢迎归来 :app, :name.', + 'welcome_to_name' => '欢迎到 :app, :name.', + 'first_sign_in' => '这是您首次登陆.', + 'last_sign_in' => '您最后登陆是', + 'view_access_logs' => '访问登陆日志', + 'nice_message' => '祝你有美好的一天!', + ] + ], + 'user' => [ + 'name' => '管理员', + 'menu_label' => '管理员', + 'menu_description' => '管理后台管理员用户, 组和权限.', + 'list_title' => '管理', + 'new' => '新管理员', + 'login' => '登录', + 'first_name' => '名', + 'last_name' => '姓', + 'full_name' => '全名', + 'email' => '邮件', + 'role_field' => '角色', + 'role_comment' => '角色指定了用户的权限,您可以在权限栏中进行修改。', + 'groups' => '团队', + 'groups_comment' => '指定成员所归属的组.', + 'avatar' => '头像', + 'password' => '密码', + 'password_confirmation' => '确认密码', + 'permissions' => '权限', + 'account' => '帐号', + 'superuser' => '超级用户', + 'superuser_comment' => '选中并允许此成员访问所有区域.', + 'send_invite' => '发送邀请邮件', + 'send_invite_comment' => '发送一封包含用户名和密码的欢迎邮件', + 'delete_confirm' => '您真的想要删除这个管理员?', + 'return' => '返回管理员列表', + 'allow' => '允许', + 'inherit' => '继承', + 'deny' => '拒绝', + 'activated' => '已激活', + 'last_login' => '最后登陆', + 'created_at' => '创建时间', + 'updated_at' => '更新时间', + 'deleted_at' => '删除时间', + 'show_deleted' => '显示已删除', + 'group' => [ + 'name' => '组', + 'name_comment' => '该名字将在群组列表中展示', + 'name_field' => '名字', + 'description_field' => '描述', + 'is_new_user_default_field_label' => '默认组', + 'is_new_user_default_field_comment' => '默认增加新管理员到此组', + 'code_field' => '代码', + 'code_comment' => '如果若您想访问 API, 请输入唯一代码。', + 'menu_label' => '群组', + 'list_title' => '管理群组', + 'new' => '新管理组', + 'delete_confirm' => '您真的想要删除这个管理组?', + 'return' => '返回组列表', + 'users_count' => '用户' + ], + 'role' => [ + 'name' => '角色', + 'name_field' => '名称', + 'name_comment' => '名称会显示在管理员菜单下的角色列表中', + 'description_field' => '描述', + 'code_field' => '角色代码', + 'code_comment' => '如果你想通过 API 访问角色对象,请输入一个唯一的角色代码', + 'menu_label' => '管理角色', + 'list_title' => '管理角色', + 'new' => '新建角色', + 'delete_confirm' => '确定删除该角色?', + 'return' => '返回角色列表', + 'users_count' => '用户' + ], + 'preferences' => [ + 'not_authenticated' => '无认证用户加载或保存设置.' + ], + 'trashed_hint_title' => '该账户已经被删除', + 'trashed_hint_desc' => '该账户已经被删除而无法登录。你可以点击右下角的恢复按钮进行恢复。' + ], + 'list' => [ + 'default_title' => '列表', + 'search_prompt' => '搜索...', + 'no_records' => '当前视图中没有记录.', + 'missing_model' => ':class 中的列表没有定义好的模型。', + 'missing_column' => '没有 :columns 的栏定义.', + 'missing_columns' => ':class 中使用的列表没有定义好的栏.', + 'missing_definition' => "列表不包含 ':field' 栏.", + 'missing_parent_definition' => "列表行为未包含 ':definition'.", + 'behavior_not_ready' => '列表未初始化,请确认您的控制器中调用了makeLists().', + 'invalid_column_datetime' => "栏值 ':column' 非时间对象,是否缺少 \$dates 在模型中的引用?", + 'pagination' => '显示记录: :from-:to :total', + 'first_page' => '首页', + 'last_page' => '末页', + 'prev_page' => '上一页', + 'next_page' => '下一页', + 'refresh' => '刷新', + 'updating' => '更新中...', + 'loading' => '加载中...', + 'setup_title' => '建立列表', + 'setup_help' => '您可以通过拖拽调整栏的位置并使用多选框选择您想在列表中看到的栏目。', + 'records_per_page' => '每页的记录', + 'records_per_page_help' => '选择每页显示的记录数。请注意单页中若存在太多记录可能会降低性能。', + 'check' => 'Check', + 'delete_selected' => '删除选择项', + 'delete_selected_empty' => '无需要删除的项.', + 'delete_selected_confirm' => '删除选中的项?', + 'delete_selected_success' => '成功删除选择项', + 'column_switch_true' => '是', + 'column_switch_false' => '否' + ], + 'fileupload' => [ + 'attachment' => '附件', + 'help' => '添加标题和描述到附件', + 'title_label' => '标题', + 'description_label' => '描述', + 'default_prompt' => '点击 %s 或者拖动文件到此处以上传', + 'attachment_url' => '附件地址', + 'upload_file' => '上传文件', + 'upload_error' => '上传错误', + 'remove_confirm' => '你确定吗?', + 'remove_file' => '删除文件' + ], + 'repeater' => [ + 'min_items_failed' => ':name 需要大于 :min ', + 'max_items_failed' => ':name 需要小于 :max ' + ], + 'form' => [ + 'create_title' => '新 :name', + 'update_title' => '编辑 :name', + 'preview_title' => '预览 :name', + 'create_success' => '成功创建 :name', + 'update_success' => '成功更新 :name', + 'delete_success' => '成功删除 :name', + 'restore_success' => '成功恢复 :name', + 'reset_success' => '重置成功', + 'missing_id' => '未指定表单记录ID.', + 'missing_model' => ':class 中使用的表单无定义模型.', + 'missing_definition' => "表单无字段 ':field'.", + 'not_found' => '无法找到表单 ID :id.', + 'action_confirm' => '您确定?', + 'create' => '创建', + 'create_and_close' => '创建和关闭', + 'creating' => '创建中...', + 'creating_name' => '创建 :name...', + 'save' => '保存', + 'save_and_close' => '保存和关闭', + 'saving' => '保存...', + 'saving_name' => '保存 :name...', + 'delete' => '删除', + 'deleting' => '删除中...', + 'confirm_delete' => '您确定删除记录?', + 'confirm_delete_multiple' => '确认删除选中的的记录?', + 'deleting_name' => '删除 :name...', + 'restore' => '恢复', + 'restoring' => '恢复中', + 'confirm_restore' => '你确定恢复这条记录?', + 'reset_default' => '重置为默认', + 'resetting' => '重置', + 'resetting_name' => '重置 :name', + 'undefined_tab' => '杂项', + 'field_off' => '关', + 'field_on' => '开', + 'add' => '增加', + 'apply' => '应用', + 'cancel' => '取消', + 'close' => '关闭', + 'confirm' => '确认', + 'reload' => '重载', + 'complete' => '完成', + 'ok' => '好', + 'or' => '或', + 'confirm_tab_close' => '您真的想要关闭这个标签页吗?未保存的更改将会丢失。', + 'behavior_not_ready' => '表单未初始化,请确认您已调用控制器 initForm().', + 'preview_no_files_message' => '无上传文件。', + 'preview_no_media_message' => '无选中媒体.', + 'preview_no_record_message' => '无选择记录。', + 'select' => '选择', + 'select_all' => '全选', + 'select_none' => '选择无', + 'select_placeholder' => '请选择', + 'insert_row' => '插入行', + 'insert_row_below' => '在下面插入行', + 'delete_row' => '删除行', + 'concurrency_file_changed_title' => '文件改动', + 'concurrency_file_changed_description' => "您正在编辑的文件正在被其他用户修改,您可以重载或覆盖磁盘上的文件。", + 'return_to_list' => '返回列表' + ], + 'recordfinder' => [ + 'find_record' => '查找记录', + 'invalid_model_class' => '提供的 ":modelClass" 不可用', + 'cancel' => '取消', + ], + 'pagelist' => [ + 'page_link' => '页面链接', + 'select_page' => '选择一个页面...' + ], + 'relation' => [ + 'missing_config' => "关系无配置文件 ':config'", + 'missing_definition' => "关系无定义 ':field' ", + 'missing_model' => ":class 关系中无已定义模型", + 'invalid_action_single' => "此操作无法在单一关系上执行.", + 'invalid_action_multi' => "此操作无法在多重关系上执行.", + 'help' => "点击增加", + 'related_data' => "相关的 :name", + 'add' => "增加", + 'add_selected' => "增加选中", + 'add_a_new' => "增加新的 :name", + 'link_selected' => "关联选中", + 'link_a_new' => "关联新的 :name", + 'cancel' => "取消", + 'close' => "关闭", + 'add_name' => "增加 :name", + 'create' => "创建", + 'create_name' => "创建 :name", + 'update' => "更新", + 'update_name' => "更新 :name", + 'preview' => "预览", + 'preview_name' => "预览 :name", + 'remove' => "移除", + 'remove_name' => "移除 :name", + 'delete' => "删除", + 'delete_name' => "删除 :name", + 'delete_confirm' => "您确定?", + 'link' => "关联", + 'link_name' => "关联 :name", + 'unlink' => "取消关联", + 'unlink_name' => "取消关联 :name", + 'unlink_confirm' => "您确定?", + ], + 'reorder' => [ + 'default_title' => '重新排序记录', + 'no_records' => '没有可供排序的记录.' + ], + 'model' => [ + 'name' => '模型', + 'not_found' => "无法找到ID为 :id 的模型 ':class'", + 'missing_id' => '无法找到指定ID的模型记录.', + 'missing_relation' => "模型 ':class' 不包含 ':relation'.", + 'missing_method' => "模型 ':class' 不包含 ':method'.", + 'invalid_class' => "模型 :model 在 :class 中是不合法的,它必须继承 \\Model 类.", + 'mass_assignment_failed' => "为模型属性':attribute'赋值失败." + ], + 'warnings' => [ + 'tips' => '系统配置小技巧', + 'tips_description' => '您需要注意以下问题以使系统更好工作。', + 'permissions' => '目录 :name 或子目录对PHP不可写. 请在服务器中对此目录设置正确权限。', + 'extension' => 'PHP扩展 :name 未安装,请安装此库并激活扩展.', + 'plugin_missing' => '依赖于未安装的插件 :name,请安装该插件.' + ], + 'editor' => [ + 'menu_label' => '代码编辑器选项', + 'menu_description' => '自定义代码编辑器选项,比如字体大小和颜色主题.', + 'font_size' => '字体大小', + 'tab_size' => '标签大小', + 'use_hard_tabs' => '使用标签页缩进', + 'code_folding' => '代码折叠', + 'code_folding_begin' => '标记开始', + 'code_folding_begin_end' => '标记开始与结束', + 'autocompletion' => '自动完成', + 'word_wrap' => '自动换行', + 'highlight_active_line' => '高亮活动行', + 'auto_closing' => '自动关闭标签', + 'show_invisibles' => '显示隐藏字符', + 'show_gutter' => '显示侧边栏', + 'basic_autocompletion'=> '基本自动完成 (Ctrl + Space)', + 'live_autocompletion'=> '实时自动完成', + 'enable_snippets'=> '开启代码片段 (Tab)', + 'display_indent_guides'=> '显示缩进指南', + 'show_print_margin'=> '显示打印边距', + 'mode_off' => '关闭', + 'mode_fluid' => '流体', + '40_characters' => '40字符', + '80_characters' => '80字符', + 'theme' => '色彩主题', + 'markup_styles' => '标记样式', + 'custom_styles' => '定制样式表', + 'custom styles_comment' => '在HTML编辑器中包含自定义样式', + 'markup_classes' => '标记类', + 'paragraph' => '段落', + 'link' => '链接', + 'table' => '表格', + 'table_cell' => '单元格', + 'image' => '图像', + 'label' => '标签', + 'class_name' => '类名', + 'markup_tags' => '标记标签', + 'allowed_empty_tags' => '允许空标签', + 'allowed_empty_tags_comment' => '当标签内无内容时,其不会被移除.', + 'allowed_tags' => '允许标签', + 'allowed_tags_comment' => '允许标签列表.', + 'no_wrap' => '无法包裹标签', + 'no_wrap_comment' => '所列标签无法包裹于快级标签中.', + 'remove_tags' => '移除标签', + 'remove_tags_comment' => '所列标签将与其包裹的内容一起删除.', + 'toolbar_buttons' => '工具栏按钮', + 'toolbar_buttons_comment' => '默认在富文本编辑器中显示的工具栏按钮。例如:' + ], + 'tooltips' => [ + 'preview_website' => '预览网站' + ], + 'mysettings' => [ + 'menu_label' => '我的设置', + 'menu_description' => '涉及您管理帐号的设置' + ], + 'myaccount' => [ + 'menu_label' => '我的账户', + 'menu_description' => '更新你的账户细节, 如姓名、邮件地址和密码.', + 'menu_keywords' => '安全登录' + ], + 'branding' => [ + 'menu_label' => '自定义后台', + 'menu_description' => '自定义管理区域, 比如名字, 颜色和图标.', + 'brand' => '品牌', + 'logo' => '图标', + 'logo_description' => '上传自定义图标到后台.', + 'favicon' => '浏览器favicon', + 'favicon_description' => '上传自定义后台浏览器的favicon', + 'app_name' => '站点名称', + 'app_name_description' => '这个名称显示在后台的标题区域.', + 'app_tagline' => '站点标语', + 'app_tagline_description' => '标语将显示在后台登录界面.', + 'colors' => '颜色', + 'primary_color' => '主颜色', + 'secondary_color' => '次颜色', + 'accent_color' => '强调色', + 'styles' => '样式', + 'custom_stylesheet' => '自定样式', + 'navigation' => '导航', + 'menu_mode' => '菜单样式', + 'menu_mode_inline' => '行内', + 'menu_mode_inline_no_icons' => '行内(无图标)', + 'menu_mode_tile' => '标题', + 'menu_mode_collapsed' => '已折叠' + ], + 'backend_preferences' => [ + 'menu_label' => '后台设置', + 'menu_description' => '管理你的后台设置,如使用语言。', + 'region' => '地区', + 'code_editor' => '代码编辑器', + 'timezone' => '时区', + 'timezone_comment' => '选择您希望使用的本地语言。', + 'locale' => '语言', + 'locale_comment' => '选择您想要的语言环境.' + ], + 'access_log' => [ + 'hint' => '此日志显示管理员成功登录信息。记录将保存 :days 天。', + 'menu_label' => '访问日志', + 'menu_description' => '查看已登陆的后台用户日志。', + 'id' => 'ID', + 'created_at' => '日期 & 时间', + 'login' => '登录', + 'type' => '类型', + 'ip_address' => 'IP地址', + 'first_name' => '名', + 'last_name' => '姓', + 'email' => '电子邮箱' + ], + 'filter' => [ + 'all' => '全部', + 'options_method_not_exists' => "模型 :model 必须定义方法 :method() 并为过滤器 ':filter'返回可选项.", + 'date_all' => '所有日期', + 'number_all' => '任意数值' + ], + 'import_export' => [ + 'upload_csv_file' => '1. 上传一个 CSV 文件', + 'import_file' => '导入文件', + 'row' => ':row 行', + 'first_row_contains_titles' => '第一行包含列标题', + 'first_row_contains_titles_desc' => '若 CSV 首行作为栏标题使用,请点选此项。', + 'match_columns' => '2. 将文件列与数据库字段匹配', + 'file_columns' => '文件列', + 'database_fields' => '数据库字段', + 'set_import_options' => '3. 设置导入选项', + 'export_output_format' => '1. 导出输出格式', + 'file_format' => '文件格式', + 'standard_format' => '标准格式', + 'custom_format' => '自定义格式', + 'delimiter_char' => '定界符', + 'enclosure_char' => '包围字符', + 'escape_char' => '转义字符', + 'select_columns' => '2. 选择导出的列', + 'column' => '列', + 'columns' => '列', + 'set_export_options' => '3. 设置导出选项', + 'show_ignored_columns' => '显示忽略的列', + 'auto_match_columns' => '自动匹配列', + 'created' => '已创建', + 'updated' => '已更新', + 'skipped' => '已跳过', + 'warnings' => '警告', + 'errors' => '错误', + 'skipped_rows' => '跳过行数', + 'import_progress' => '导入进度', + 'processing' => '处理中...', + 'import_error' => '导入错误', + 'upload_valid_csv' => '请上传正确的CSV 文件.', + 'drop_column_here' => '在这里删除列……', + 'ignore_this_column' => '忽略此列', + 'processing_successful_line1' => '文件导出完成!', + 'processing_successful_line2' => '浏览器正在重定向至文件下载.', + 'export_progress' => '导出进度', + 'export_error' => '导出错误', + 'column_preview' => '预览列', + 'file_not_found_error' => '文件未找到', + 'empty_error' => '没有提供导出的数据', + 'empty_import_columns_error' => '请指定要导入的列.', + 'match_some_column_error' => '请先与一些列匹配.', + 'required_match_column_error' => '请特指所需字段 :label 的匹配项', + 'empty_export_columns_error' => '请指定要导出的列.', + 'behavior_missing_uselist_error' => '您必须在开启导出 "useList" 选项的情况下实现控制器行为 ListController 。', + 'missing_model_class_error' => '请特指 modelClass 的属性 :type', + 'missing_column_id_error' => '缺少栏标识符', + 'unknown_column_error' => '未知列', + 'encoding_not_supported_error' => '无法识别源文件编码。请点击自定义文件格式选项并选择正确编码来导入您的文件。', + 'encoding_format' => '文件编码', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => '管理媒体' + ], + 'mediafinder' => [ + 'label' => '媒体查找器', + 'default_prompt' => '点击 %s 按钮查找媒体项' + ], + 'media' => [ + 'menu_label' => '媒体', + 'upload' => '上传', + 'move' => '移动', + 'delete' => '删除', + 'add_folder' => '增加文件夹', + 'search' => '搜索', + 'display' => '显示', + 'filter_everything' => '所有', + 'filter_images' => '图片', + 'filter_video' => '视频', + 'filter_audio' => '音频', + 'filter_documents' => '文档', + 'library' => '库', + 'size' => '大小', + 'title' => '标题', + 'last_modified' => '最近修改', + 'public_url' => '公开URL', + 'click_here' => '点击这里', + 'thumbnail_error' => '生成缩略图错误.', + 'return_to_parent' => '返回上层文件夹', + 'return_to_parent_label' => '返回 ..', + 'nothing_selected' => '没有选中.', + 'multiple_selected' => '多选.', + 'uploading_file_num' => '上传 :number 文件...', + 'uploading_complete' => '上传完毕', + 'uploading_error' => '上传失败', + 'type_blocked' => '该文件类型因安全问题被禁止使用。', + 'order_by' => '排序', + 'direction' => '升降序', + 'direction_asc' => '升序', + 'direction_desc' => '降序', + 'folder' => '文件夹', + 'no_files_found' => '未找到您所请求的文件.', + 'delete_empty' => '请选择删除项.', + 'delete_confirm' => '您是否想要删除选中项?', + 'error_renaming_file' => '重命名错误.', + 'new_folder_title' => '新文件', + 'folder_name' => '文件夹名', + 'error_creating_folder' => '新建文件夹错误', + 'folder_or_file_exist' => '文件夹或文件已经存在.', + 'move_empty' => '请选择移动项.', + 'move_popup_title' => '移动文件或文件夹', + 'move_destination' => '目标文件夹', + 'please_select_move_dest' => '请选择目标文件夹.', + 'move_dest_src_match' => '请选择另一个目标文件夹.', + 'empty_library' => '媒体库为空。请上传文件或新建文件夹。', + 'insert' => '插入', + 'crop_and_insert' => '裁剪并插入', + 'select_single_image' => '请选择图片.', + 'selection_not_image' => '所选项不为图片.', + 'restore' => '取消所有更改', + 'resize' => '调整大小...', + 'selection_mode_normal' => '正常', + 'selection_mode_fixed_ratio' => '固定比例', + 'selection_mode_fixed_size' => '固定大小', + 'height' => '高度', + 'width' => '宽度', + 'selection_mode' => '选择模式', + 'resize_image' => '调整图片', + 'image_size' => '图片大小:', + 'selected_size' => '选中:' + ] +]; diff --git a/modules/backend/lang/zh-tw/lang.php b/modules/backend/lang/zh-tw/lang.php new file mode 100644 index 0000000..9655ef6 --- /dev/null +++ b/modules/backend/lang/zh-tw/lang.php @@ -0,0 +1,379 @@ + [ + 'title' => '管理介面' + ], + 'field' => [ + 'invalid_type' => '錯誤的字串類型 :type', + 'options_method_not_exists' => "模型 :model 必須定義一個返回 ':field' 表單字串選項的方法 :method()。" + ], + 'widget' => [ + 'not_registered' => "元件 ':name' 還沒註冊", + 'not_bound' => "元件 ':name' 沒綁到控制器" + ], + 'page' => [ + 'untitled' => '未命名', + 'access_denied' => [ + 'label' => '拒絕訪問', + 'help' => "您沒有訪問這個頁面需要的權限.", + 'cms_link' => '返回管理介面' + ] + ], + 'partial' => [ + 'not_found_name' => "元件 ':name' 找不到." + ], + 'account' => [ + 'sign_out' => '登出', + 'login' => '登入', + 'reset' => '重置', + 'restore' => '還原', + 'login_placeholder' => '登入', + 'password_placeholder' => '密碼', + 'forgot_password' => '忘記您的密碼?', + 'enter_email' => '輸入您的email', + 'enter_login' => '輸入帳號', + 'email_placeholder' => 'email', + 'enter_new_password' => '輸入新密碼', + 'password_reset' => '密碼重置', + 'restore_success' => '密碼重置的郵件已發送到您的電子信箱', + 'restore_error' => "找不到使用者 ':login'", + 'reset_success' => '您的密碼已經重置成功. 您現在可以登入了', + 'reset_error' => '密碼重置失敗. 請重試!', + 'reset_fail' => '不能重置您的密碼!', + 'apply' => '套用', + 'cancel' => '取消', + 'delete' => '刪除', + 'ok' => 'OK' + ], + 'dashboard' => [ + 'menu_label' => '儀表板', + 'widget_label' => '元件', + 'widget_width' => '寬度', + 'full_width' => '全部寬度', + 'add_widget' => '新增元件', + 'manage_widgets' => '管理元件', + 'widget_inspector_title' => '元件設定', + 'widget_inspector_description' => '設定報表元件', + 'widget_columns_label' => '寬度 :columns', + 'widget_columns_description' => '元件寬度, 1 到 10', + 'widget_columns_error' => '請輸入元件寬度, 1 到 10', + 'columns' => '{1} 欄|[2,Inf] 欄', + 'widget_new_row_label' => '強制新列', + 'widget_new_row_description' => '把元件放到新列', + 'widget_title_label' => '元件標題', + 'widget_title_error' => '需要元件標題', + 'reset_layout' => '重置版面', + 'reset_layout_confirm' => '確定重置為預設版面?', + 'reset_layout_success' => '版面已重置。', + 'make_default' => '設定為預設', + 'make_default_confirm' => '確定將此版面設定為預設?', + 'make_default_success' => '已設定此版面為預設。', + 'status' => [ + 'widget_title_default' => '系統狀態', + 'update_available' => '{0} 更新可用!|{1} 更新可用!|[2,Inf] 更新可用!' + ] + ], + 'user' => [ + 'name' => '管理員', + 'menu_label' => '管理員', + 'menu_description' => '管理管理介面管理員使用者, 群組和權限', + 'list_title' => '管理', + 'new' => '新管理員', + 'login' => '登入', + 'first_name' => '名', + 'last_name' => '姓', + 'full_name' => '全名', + 'email' => '郵件', + 'groups' => '團隊', + 'groups_comment' => '指定這個人屬於哪個群組', + 'avatar' => '頭像', + 'password' => '密碼', + 'password_confirmation' => '確認密碼', + 'permissions' => '權限', + 'account' => '帳號', + 'superuser' => '超級使用者', + 'superuser_comment' => '選取並允許這個人訪問全部區域', + 'send_invite' => '發送邀請郵件', + 'send_invite_comment' => '發送一封包含使用者名和密碼的歡迎郵件', + 'delete_confirm' => '您真的想要刪除這個管理員?', + 'return' => '返回管理員列表', + 'allow' => '允許', + 'inherit' => '繼承', + 'deny' => '拒絕', + 'group' => [ + 'name' => '群組', + 'name_field' => '名字', + 'description_field' => '描述', + 'is_new_user_default_field' => '預設增加新管理員到這個群組', + 'code_field' => '代碼', + 'code_comment' => '如果您想訪問 API, 請輸入唯一碼', + 'menu_label' => '群組', + 'list_title' => '管理群組', + 'new' => '新管理群組', + 'delete_confirm' => '您真的想要刪除這個管理群組?', + 'return' => '返回群組列表', + ], + 'preferences' => [ + 'not_authenticated' => '沒有認證使用者載入或儲存設定' + ] + ], + 'list' => [ + 'default_title' => '列表', + 'search_prompt' => '搜尋...', + 'no_records' => '目前頁面中沒有記錄', + 'missing_model' => ':class 中的列表沒有定義好的模型。', + 'missing_column' => '沒有 :columns 的欄定義', + 'missing_columns' => ':class 中使用的列表沒有定義好的欄', + 'missing_definition' => "列表不包含 ':field' 欄.", + 'behavior_not_ready' => '列表沒有初始化, 確認您的控制器中調用了makeLists()', + 'invalid_column_datetime' => "欄值 ':column' 不是時間對象, 缺少了 \$dates 在模型中的引用嗎?", + 'pagination' => '顯示記錄: :from-:to :total', + 'prev_page' => '之前頁', + 'next_page' => '下一頁', + 'loading' => '載入中...', + 'setup_title' => '建立列表', + 'setup_help' => '使用多選框選擇您想在列表中看到的欄. 您可以通過拖拽調整欄的位置', + 'records_per_page' => '每頁的記錄', + 'records_per_page_help' => '選擇每頁想顯示的記錄數量. 請注意一頁中太多記錄可能會降低性能', + 'delete_selected' => '刪除選擇的', + 'delete_selected_empty' => '沒有需要刪除的記錄', + 'delete_selected_confirm' => '刪除選取的記錄?', + 'delete_selected_success' => '成功刪除選擇的記錄', + ], + 'fileupload' => [ + 'attachment' => '附件', + 'help' => '給附件新增標題和描述', + 'title_label' => '標題', + 'description_label' => '描述' + ], + 'form' => [ + 'create_title' => '新 :name', + 'update_title' => '編輯 :name', + 'preview_title' => '預覽 :name', + 'create_success' => ':name 建立成功', + 'update_success' => ':name 更新成功', + 'delete_success' => ':name 刪除成功', + 'missing_id' => '表單記錄ID沒有指定', + 'missing_model' => ':class 中使用的表單沒有定義的model', + 'missing_definition' => "表單不包含字串 ':field'.", + 'not_found' => '表單 ID :id 找不到', + 'action_confirm' => '您確定?', + 'create' => '建立', + 'create_and_close' => '建立和關閉', + 'creating' => '建立中...', + 'creating_name' => '建立 :name...', + 'save' => '儲存', + 'save_and_close' => '儲存和關閉', + 'saving' => '儲存...', + 'saving_name' => '儲存 :name...', + 'delete' => '刪除', + 'deleting' => '刪除中...', + 'deleting_name' => '刪除 :name...', + 'reset_default' => '重置到預設', + 'resetting' => '重置', + 'resetting_name' => '重置 :name', + 'undefined_tab' => '雜項', + 'field_off' => '關', + 'field_on' => '開', + 'add' => '增加', + 'apply' => '確定', + 'cancel' => '取消', + 'close' => '關閉', + 'confirm' => '確認', + 'reload' => '重新載入', + 'ok' => 'OK', + 'or' => '或', + 'confirm_tab_close' => '您真的想要關閉這個標籤嗎? 未儲存的改變會丟失', + 'behavior_not_ready' => '表單還沒初始化, 確保您調用了控制器中的 initForm()', + 'preview_no_files_message' => '檔案沒有上傳', + 'select' => '選擇', + 'select_all' => '全選', + 'select_none' => '選擇無', + 'select_placeholder' => '請選擇', + 'insert_row' => '插入行', + 'delete_row' => '刪除行', + 'concurrency_file_changed_title' => '檔案異動', + 'concurrency_file_changed_description' => "您正在編輯的檔案正在被其他使用者修改. 您可以重新載入或覆蓋硬碟上的檔案." + ], + 'relation' => [ + 'missing_config' => "關聯沒有':config'的設定檔案.", + 'missing_definition' => "關聯不包含 ':field' 的定義.", + 'missing_model' => "用於 :class 的關聯沒有定義好的model.", + 'invalid_action_single' => "這個操作不能在單一關聯上執行.", + 'invalid_action_multi' => "這個操作不能在多重關聯上執行.", + 'help' => "點選增加", + 'related_data' => "相關的 :name", + 'add' => "增加", + 'add_selected' => "增加選取的", + 'add_a_new' => "增加一個新的 :name", + 'link_selected' => "關聯選取", + 'link_a_new' => "關聯一個新的 :name", + 'cancel' => "取消", + 'close' => "關閉", + 'add_name' => "增加 :name", + 'create' => "建立", + 'create_name' => "建立 :name", + 'update' => "更新", + 'update_name' => "更新 :name", + 'preview' => "預覽", + 'preview_name' => "預覽 :name", + 'remove' => "移除", + 'remove_name' => "移除 :name", + 'delete' => "刪除", + 'delete_name' => "刪除 :name", + 'delete_confirm' => "您確定?", + 'link' => "關聯", + 'link_name' => "關聯 :name", + 'unlink' => "取消關聯", + 'unlink_name' => "取消關聯 :name", + 'unlink_confirm' => "您確定?", + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => "Model ':class' ID :id 找不到", + 'missing_id' => '沒有指定的ID搜尋model記錄', + 'missing_relation' => "Model ':class' 不包含 ':relation'.", + 'missing_method' => "Model ':class' 不包含 ':method'.", + 'invalid_class' => "Model :model 在 :class 中是錯誤的, 必須繼承 \\Model class.", + 'mass_assignment_failed' => "針對Model屬性':attribute'的大量賦值失敗." + ], + 'warnings' => [ + 'tips' => '系統設定技巧', + 'tips_description' => '您需要注意那些issue, 以使系統設定正確', + 'permissions' => '目錄 :name 或子目錄對PHP不可寫. 請對這個目錄上的webserver設定正確的權限', + 'extension' => 'PHP外掛 :name 沒安裝. 請安裝這個庫並且啟用外掛' + ], + 'editor' => [ + 'menu_label' => '代碼編輯器選項', + 'menu_description' => '自訂代碼編輯器選項, 例如字體大小和顏色主題', + 'font_size' => '字體大小', + 'tab_size' => '標籤大小', + 'use_hard_tabs' => '使用tabs縮進', + 'code_folding' => '代碼摺疊', + 'word_wrap' => '自動換行', + 'highlight_active_line' => '醒目顯示操作中的行', + 'show_invisibles' => '顯示隱藏字元', + 'show_gutter' => '顯示gutter', + 'theme' => '色彩主題' + ], + 'tooltips' => [ + 'preview_website' => '預覽網站' + ], + 'mysettings' => [ + 'menu_label' => '我的設定', + 'menu_description' => '設定涉及到您的管理帳號' + ], + 'myaccount' => [ + 'menu_label' => '我的帳號', + 'menu_description' => '更新您的帳號細節, 例如名字, 郵件地址和密碼', + 'menu_keywords' => '安全登入' + ], + 'branding' => [ + 'menu_label' => '自訂管理介面', + 'menu_description' => '自訂管理區域, 例如名字, 顏色和logo', + 'brand' => '品牌', + 'logo' => 'Logo', + 'logo_description' => '上傳自訂logo到管理介面', + 'app_name' => '網站名稱', + 'app_name_description' => '這個名稱顯示在管理介面的標題區域', + 'app_tagline' => '網站標語', + 'app_tagline_description' => '標語顯示在管理介面的登入介面', + 'colors' => '顏色', + 'primary_color' => '主要 color', + 'secondary_color' => '次要 color', + 'accent_color' => 'Accent color', + 'styles' => '樣式', + 'custom_stylesheet' => '自訂樣式' + ], + 'backend_preferences' => [ + 'menu_label' => '管理介面設定', + 'menu_description' => '管理您的管理介面設定, 例如希望使用的語言。', + 'locale' => '語言', + 'locale_comment' => '選擇您希望使用的本地語言。' + ], + 'access_log' => [ + 'hint' => '這個log顯示了管理員成功登入的訊息. 記錄保持:days天。', + 'menu_label' => '訪問日誌', + 'menu_description' => '查看成功登入管理介面使用者日誌。', + 'created_at' => '日期 & 時間', + 'login' => '登入', + 'ip_address' => 'IP地址', + 'first_name' => '名', + 'last_name' => '姓', + 'email' => 'Email' + ], + 'filter' => [ + 'all' => '全部', + 'date_all' => '全部區間', + 'number_all' => '全部數目', + ], + 'permissions' => [ + 'manage_media' => 'Upload and manage media contents - images, videos, sounds, documents' + ], + 'mediafinder' => [ + 'label' => 'Media Finder', + 'default_prompt' => 'Click the %s button to find a media item' + ], + 'media' => [ + 'menu_label' => '媒體', + 'upload' => '上傳', + 'move' => '移動', + 'delete' => '刪除', + 'add_folder' => '增加檔案夾', + 'search' => '搜尋', + 'display' => '顯示', + 'filter_everything' => '所有', + 'filter_images' => '圖片', + 'filter_video' => '影片', + 'filter_audio' => '音訊', + 'filter_documents' => '文檔', + 'library' => '媒體庫', + 'size' => '大小', + 'title' => '標題', + 'last_modified' => '最近修改', + 'public_url' => '公開URL', + 'click_here' => '點選這裡', + 'thumbnail_error' => '生產縮略圖錯誤.', + 'return_to_parent' => '返回上層檔案夾', + 'return_to_parent_label' => '返回 ..', + 'nothing_selected' => '沒有選中.', + 'multiple_selected' => '多選.', + 'uploading_file_num' => '上傳 :number 檔案...', + 'uploading_complete' => '上傳完畢', + 'order_by' => '排列方式', + 'folder' => '檔案夾', + 'no_files_found' => '沒找到您請求的檔案.', + 'delete_empty' => '請選擇刪除項.', + 'delete_confirm' => '您是否想要刪除選中項?', + 'error_renaming_file' => '重命名錯誤.', + 'new_folder_title' => '新檔案', + 'folder_name' => '檔案夾名', + 'error_creating_folder' => '新建檔案夾錯誤', + 'folder_or_file_exist' => '檔案夾或檔案已經存在.', + 'move_empty' => '請選擇移動項.', + 'move_popup_title' => '移動檔案或檔案夾', + 'move_destination' => '目標檔案夾', + 'please_select_move_dest' => '請選擇目標檔案夾.', + 'move_dest_src_match' => '請選擇另一個目標檔案夾.', + 'empty_library' => '媒體庫是空的. 從上傳檔案或建立檔案夾開始.', + 'insert' => '插入', + 'crop_and_insert' => '裁剪並插入', + 'select_single_image' => '請選擇一張圖片.', + 'selection_not_image' => '選擇的不是一張圖片.', + 'restore' => '取消所有更改', + 'resize' => '調整大小...', + 'selection_mode_normal' => '正常', + 'selection_mode_fixed_ratio' => '固定比例', + 'selection_mode_fixed_size' => '固定大小', + 'height' => '高度', + 'width' => '寬度', + 'selection_mode' => '選擇模式', + 'resize_image' => '調整圖片', + 'image_size' => '圖片大小:', + 'selected_size' => '選中:', + 'direction' => '順序', + 'direction_asc' => '升冪', + 'direction_desc' => '降冪', + ] +]; diff --git a/modules/backend/layouts/_browser_detector.htm b/modules/backend/layouts/_browser_detector.htm new file mode 100644 index 0000000..8739da6 --- /dev/null +++ b/modules/backend/layouts/_browser_detector.htm @@ -0,0 +1,73 @@ + + + + + + + diff --git a/modules/backend/layouts/_flash_messages.htm b/modules/backend/layouts/_flash_messages.htm new file mode 100644 index 0000000..8d58eda --- /dev/null +++ b/modules/backend/layouts/_flash_messages.htm @@ -0,0 +1,3 @@ + $message): ?> +

    + \ No newline at end of file diff --git a/modules/backend/layouts/_footer.htm b/modules/backend/layouts/_footer.htm new file mode 100644 index 0000000..870fac3 --- /dev/null +++ b/modules/backend/layouts/_footer.htm @@ -0,0 +1,9 @@ +
    +
    + + +
    +
    +

    +
    +
    \ No newline at end of file diff --git a/modules/backend/layouts/_head.htm b/modules/backend/layouts/_head.htm new file mode 100644 index 0000000..6b0bb19 --- /dev/null +++ b/modules/backend/layouts/_head.htm @@ -0,0 +1,74 @@ + + + + + + + + + + + + <?= e(trans($this->pageTitle)) ?> | <?= e(Backend\Models\BrandSetting::get('app_name')) ?> + + + + + + + + + + + + + + + + + +makeAssets() ?> + +makeLayoutPartial('custom_styles') ?> diff --git a/modules/backend/layouts/_hint.htm b/modules/backend/layouts/_hint.htm new file mode 100644 index 0000000..d558b9e --- /dev/null +++ b/modules/backend/layouts/_hint.htm @@ -0,0 +1,35 @@ +isBackendHintHidden($hintName)): ?> + +
    + + + + +
    + +

    +

    +
    + +
    + + + + makePartial($hintPartial, $hintParams) ?> + +
    +
    + \ No newline at end of file diff --git a/modules/backend/layouts/_mainmenu.htm b/modules/backend/layouts/_mainmenu.htm new file mode 100644 index 0000000..3327218 --- /dev/null +++ b/modules/backend/layouts/_mainmenu.htm @@ -0,0 +1,105 @@ +listItems('mysettings'); + $navbarMode = Backend\Models\BrandSetting::get('menu_mode', 'inline'); +?> + diff --git a/modules/backend/layouts/_sidenav.htm b/modules/backend/layouts/_sidenav.htm new file mode 100644 index 0000000..3b3a537 --- /dev/null +++ b/modules/backend/layouts/_sidenav.htm @@ -0,0 +1,51 @@ +owner, $context->mainMenuCode); +?> + + + +
    +
    + +
    +
    + + + makePartial($contextSidenav) ?> + diff --git a/modules/backend/layouts/auth.htm b/modules/backend/layouts/auth.htm new file mode 100644 index 0000000..344e11e --- /dev/null +++ b/modules/backend/layouts/auth.htm @@ -0,0 +1,88 @@ + + + + + + + + + + + <?= e(trans('backend::lang.auth.title')) ?> + + + + + + + + + + + + + + + + + + makeAssets() ?> + + makeLayoutPartial('custom_styles') ?> + fireViewEvent('backend.layout.extendHead', ['layout' => 'auth.htm']) ?> + + +
    +
    + +
    +
    +

    +
    +
    +
    +
    +
    + +
    +
    +
    + +
    +
    + + +
    makeLayoutPartial('flash_messages') ?>
    + + + diff --git a/modules/backend/layouts/default.htm b/modules/backend/layouts/default.htm new file mode 100644 index 0000000..022fc20 --- /dev/null +++ b/modules/backend/layouts/default.htm @@ -0,0 +1,71 @@ + + + + makeLayoutPartial('head') ?> + fireViewEvent('backend.layout.extendHead', ['layout' => 'default.htm']) ?> + + +
    +
    + + +
    + makeLayoutPartial('mainmenu') ?> +
    + + + +
    +
    + data-control="flyout" + data-flyout-width="400" + data-flyout-toggle="#layout-sidenav" + + > + +
    + + + + makeLayoutPartial('sidenav') ?> + + + +
    + +
    + + + +
    +
    + +
    + + +
    + +
    + + + +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + + +
    makeLayoutPartial('flash_messages') ?>
    + + + \ No newline at end of file diff --git a/modules/backend/layouts/form-with-sidebar.htm b/modules/backend/layouts/form-with-sidebar.htm new file mode 100644 index 0000000..6fdd2d5 --- /dev/null +++ b/modules/backend/layouts/form-with-sidebar.htm @@ -0,0 +1,32 @@ +
    +
    + +
    + + + + + + +
    +
    + +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    diff --git a/modules/backend/models/AccessLog.php b/modules/backend/models/AccessLog.php new file mode 100644 index 0000000..9ca8be6 --- /dev/null +++ b/modules/backend/models/AccessLog.php @@ -0,0 +1,61 @@ + User::class + ]; + + /** + * Creates a log record + * @param Backend\Models\User $user Admin user + * @return self + */ + public static function add($user) + { + $record = new static; + $record->user = $user; + $record->ip_address = Request::getClientIp(); + $record->save(); + + return $record; + } + + /** + * Returns a recent entry, latest entry is not considered recent + * if the creation day is the same as today. + * @return self + */ + public static function getRecent($user) + { + $records = static::where('user_id', $user->id) + ->orderBy('created_at', 'desc') + ->limit(2) + ->get(); + + if (!count($records)) { + return null; + } + + $first = $records->first(); + + return !$first->created_at->isToday() ? $first : $records->pop(); + } +} diff --git a/modules/backend/models/BrandSetting.php b/modules/backend/models/BrandSetting.php new file mode 100644 index 0000000..bdd20bd --- /dev/null +++ b/modules/backend/models/BrandSetting.php @@ -0,0 +1,190 @@ + \System\Models\File::class, + 'logo' => \System\Models\File::class + ]; + + /** + * @var string The key to store rendered CSS in the cache under + */ + public $cacheKey = 'backend::brand.custom_css'; + + const PRIMARY_COLOR = '#34495e'; // Wet Asphalt + const SECONDARY_COLOR = '#e67e22'; // Pumpkin + const ACCENT_COLOR = '#3498db'; // Peter River + + const INLINE_MENU = 'inline'; + const TILE_MENU = 'tile'; + const COLLAPSE_MENU = 'collapse'; + + /** + * Validation rules + */ + public $rules = [ + 'app_name' => 'required', + 'app_tagline' => 'required', + ]; + + /** + * Initialize the seed data for this model. This only executes when the + * model is first created or reset to default. + * @return void + */ + public function initSettingsData() + { + $config = App::make('config'); + + $this->app_name = $config->get('brand.appName', Lang::get('system::lang.app.name')); + $this->app_tagline = $config->get('brand.tagline', Lang::get('system::lang.app.tagline')); + $this->primary_color = $config->get('brand.primaryColor', self::PRIMARY_COLOR); + $this->secondary_color = $config->get('brand.secondaryColor', self::SECONDARY_COLOR); + $this->accent_color = $config->get('brand.accentColor', self::ACCENT_COLOR); + $this->menu_mode = $config->get('brand.menuMode', self::INLINE_MENU); + + // Attempt to load custom CSS + $brandCssPath = File::symbolizePath(Config::get('brand.customLessPath')); + if ($brandCssPath && File::exists($brandCssPath)) { + $this->custom_css = File::get($brandCssPath); + } + } + + public function afterSave() + { + Cache::forget(self::instance()->cacheKey); + } + + public static function getFavicon() + { + $settings = self::instance(); + + if ($settings->favicon) { + return $settings->favicon->getPath(); + } + + return self::getDefaultFavicon() ?: null; + } + + public static function getLogo() + { + $settings = self::instance(); + + if ($settings->logo) { + return $settings->logo->getPath(); + } + + return self::getDefaultLogo() ?: null; + } + + public static function renderCss() + { + $cacheKey = self::instance()->cacheKey; + if (Cache::has($cacheKey)) { + return Cache::get($cacheKey); + } + + try { + $customCss = self::compileCss(); + Cache::forever($cacheKey, $customCss); + } + catch (Exception $ex) { + $customCss = '/* ' . $ex->getMessage() . ' */'; + } + + return $customCss; + } + + public static function compileCss() + { + $parser = new Less_Parser(['compress' => true]); + $basePath = base_path('modules/backend/models/brandsetting'); + + $primaryColor = self::get('primary_color', self::PRIMARY_COLOR); + $secondaryColor = self::get('secondary_color', self::PRIMARY_COLOR); + $accentColor = self::get('accent_color', self::ACCENT_COLOR); + + $parser->ModifyVars([ + 'logo-image' => "'".self::getLogo()."'", + 'brand-primary' => $primaryColor, + 'brand-secondary' => $secondaryColor, + 'brand-accent' => $accentColor, + ]); + + $parser->parse( + File::get($basePath . '/custom.less') . + self::get('custom_css') + ); + + return $parser->getCss(); + } + + // + // Base line configuration + // + + public static function isBaseConfigured() + { + return !!Config::get('brand'); + } + + public static function getDefaultFavicon() + { + $faviconPath = File::symbolizePath(Config::get('brand.faviconPath')); + + if ($faviconPath && File::exists($faviconPath)) { + return Url::asset(File::localToPublic($faviconPath)); + } + + return Backend::skinAsset('assets/images/favicon.png'); + } + + public static function getDefaultLogo() + { + $logoPath = File::symbolizePath(Config::get('brand.logoPath')); + + if ($logoPath && File::exists($logoPath)) { + return Url::asset(File::localToPublic($logoPath)); + } + + return null; + } +} diff --git a/modules/backend/models/EditorSetting.php b/modules/backend/models/EditorSetting.php new file mode 100644 index 0000000..b44081b --- /dev/null +++ b/modules/backend/models/EditorSetting.php @@ -0,0 +1,269 @@ + 'Rounded', + 'oc-img-bordered' => 'Bordered', + ]; + + protected $defaultHtmlStyleLink = [ + 'oc-link-green' => 'Green', + 'oc-link-strong' => 'Strong', + ]; + + protected $defaultHtmlStyleParagraph = [ + 'oc-text-bordered' => 'Bordered', + 'oc-text-gray' => 'Gray', + 'oc-text-spaced' => 'Spaced', + 'oc-text-uppercase' => 'Uppercase', + ]; + + protected $defaultHtmlStyleTable = [ + 'oc-dashed-borders' => 'Dashed Borders', + 'oc-alternate-rows' => 'Alternate Rows', + ]; + + protected $defaultHtmlStyleTableCell = [ + 'oc-cell-highlighted' => 'Highlighted', + 'oc-cell-thick-border' => 'Thick Border', + ]; + + protected $defaultHtmlParagraphFormats = [ + 'N' => 'Normal', + 'H1' => 'Heading 1', + 'H2' => 'Heading 2', + 'H3' => 'Heading 3', + 'H4' => 'Heading 4', + 'PRE' => 'Code', + ]; + + /** + * Editor toolbar presets for Froala. + */ + protected $editorToolbarPresets = [ + 'default' => 'paragraphFormat, paragraphStyle, quote, bold, italic, align, formatOL, formatUL, insertTable, + insertLink, insertImage, insertVideo, insertAudio, insertFile, insertHR, html', + 'minimal' => 'paragraphFormat, bold, italic, underline, |, insertLink, insertImage, |, html', + 'full' => 'undo, redo, |, bold, italic, underline, |, paragraphFormat, paragraphStyle, inlineStyle, |, + strikeThrough, subscript, superscript, clearFormatting, |, fontFamily, fontSize, |, color, + emoticons, -, selectAll, |, align, formatOL, formatUL, outdent, indent, quote, |, insertHR, + insertLink, insertImage, insertVideo, insertAudio, insertFile, insertTable, |, selectAll, + html, fullscreen', + ]; + + /** + * Validation rules + */ + public $rules = []; + + /** + * Initialize the seed data for this model. This only executes when the + * model is first created or reset to default. + * @return void + */ + public function initSettingsData() + { + $this->html_allow_empty_tags = $this->defaultHtmlAllowEmptyTags; + $this->html_allow_tags = $this->defaultHtmlAllowTags; + $this->html_no_wrap_tags = $this->defaultHtmlNoWrapTags; + $this->html_remove_tags = $this->defaultHtmlRemoveTags; + $this->html_line_breaker_tags = $this->defaultHtmlLineBreakerTags; + $this->html_custom_styles = File::get(base_path().'/modules/backend/models/editorsetting/default_styles.less'); + $this->html_style_image = $this->makeStylesForTable($this->defaultHtmlStyleImage); + $this->html_style_link = $this->makeStylesForTable($this->defaultHtmlStyleLink); + $this->html_style_paragraph = $this->makeStylesForTable($this->defaultHtmlStyleParagraph); + $this->html_style_table = $this->makeStylesForTable($this->defaultHtmlStyleTable); + $this->html_style_table_cell = $this->makeStylesForTable($this->defaultHtmlStyleTableCell); + $this->html_paragraph_formats = $this->makeFormatsForTable($this->defaultHtmlParagraphFormats); + } + + public function afterFetch() + { + if (!isset($this->value['html_paragraph_formats'])) { + $this->html_paragraph_formats = $this->makeFormatsForTable($this->defaultHtmlParagraphFormats); + $this->save(); + } + } + + public function afterSave() + { + Cache::forget(self::instance()->cacheKey); + } + + protected function makeStylesForTable($arr) + { + $count = 0; + + return array_build($arr, function ($key, $value) use (&$count) { + return [$count++, ['class_label' => $value, 'class_name' => $key]]; + }); + } + + protected function makeFormatsForTable($arr) + { + $count = 0; + + return array_build($arr, function ($key, $value) use (&$count) { + return [$count++, ['format_label' => $value, 'format_tag' => $key]]; + }); + } + + /** + * Same as getConfigured but uses a special structure for styles. + * @return mixed + */ + public static function getConfiguredStyles($key, $default = null) + { + return static::getConfiguredArray($key, $default, function ($key, $value) { + if (array_has($value, ['class_name', 'class_label'])) { + return [ + array_get($value, 'class_name'), + array_get($value, 'class_label') + ]; + } + }); + } + + /** + * Same as getConfigured but uses a special structure for paragraph formats. + * @return mixed + */ + public static function getConfiguredFormats($key, $default = null) + { + return static::getConfiguredArray($key, $default, function ($key, $value) { + if (array_has($value, ['format_tag', 'format_label'])) { + return [ + array_get($value, 'format_tag'), + array_get($value, 'format_label') + ]; + } + }); + } + + protected static function getConfiguredArray($key, $default = null, $callback = null) + { + $instance = static::instance(); + + $value = $instance->get($key); + + $defaultValue = $instance->getDefaultValue($key); + + if (is_array($value) && is_callable($callback)) { + $value = array_filter(array_build($value, $callback)); + } + + return $value != $defaultValue ? $value : $default; + } + + /** + * Returns the value only if it differs from the default value. + * @return mixed + */ + public static function getConfigured($key, $default = null) + { + $instance = static::instance(); + + $value = $instance->get($key); + + $defaultValue = $instance->getDefaultValue($key); + + return $value != $defaultValue ? $value : $default; + } + + public function getDefaultValue($attribute) + { + $property = 'default'.studly_case($attribute); + + return $this->$property; + } + + /** + * Return the editor toolbar presets without line breaks. + * @return array + */ + public function getEditorToolbarPresets() + { + return array_map(function ($value) { + return preg_replace('/\s+/', ' ', $value); + }, $this->editorToolbarPresets); + } + + public static function renderCss() + { + $cacheKey = self::instance()->cacheKey; + if (Cache::has($cacheKey)) { + return Cache::get($cacheKey); + } + + try { + $customCss = self::compileCss(); + Cache::forever($cacheKey, $customCss); + } + catch (Exception $ex) { + $customCss = '/* ' . $ex->getMessage() . ' */'; + } + + return $customCss; + } + + public static function compileCss() + { + $parser = new Less_Parser(['compress' => true]); + + $customStyles = '.fr-view {'; + $customStyles .= self::get('html_custom_styles'); + $customStyles .= '}'; + + $parser->parse($customStyles); + + return $parser->getCss(); + } +} diff --git a/modules/backend/models/ExportModel.php b/modules/backend/models/ExportModel.php new file mode 100644 index 0000000..e6a767e --- /dev/null +++ b/modules/backend/models/ExportModel.php @@ -0,0 +1,206 @@ + 'Some attribute value', + * 'db_name2' => 'Another attribute value' + * ], + * [...] + * + */ + abstract public function exportData($columns, $sessionKey = null); + + /** + * Export data based on column names and labels. + * The $columns array should be in the format of: + * + * [ + * 'db_name1' => 'Column label', + * 'db_name2' => 'Another label', + * ... + * ] + * + */ + public function export($columns, $options) + { + $sessionKey = array_get($options, 'sessionKey'); + $data = $this->exportData(array_keys($columns), $sessionKey); + return $this->processExportData($columns, $data, $options); + } + + /** + * Download a previously compiled export file. + * @return void + */ + public function download($name, $outputName = null) + { + if (!preg_match('/^oc[0-9a-z]*$/i', $name)) { + throw new ApplicationException(Lang::get('backend::lang.import_export.file_not_found_error')); + } + + $csvPath = temp_path() . '/' . $name; + if (!file_exists($csvPath)) { + throw new ApplicationException(Lang::get('backend::lang.import_export.file_not_found_error')); + } + + return Response::download($csvPath, $outputName)->deleteFileAfterSend(true); + } + + /** + * Converts a data collection to a CSV file. + */ + protected function processExportData($columns, $results, $options) + { + /* + * Validate + */ + if (!$results) { + throw new ApplicationException(Lang::get('backend::lang.import_export.empty_error')); + } + + /* + * Parse options + */ + $defaultOptions = [ + 'firstRowTitles' => true, + 'useOutput' => false, + 'fileName' => 'export.csv', + 'delimiter' => null, + 'enclosure' => null, + 'escape' => null + ]; + + $options = array_merge($defaultOptions, $options); + $columns = $this->exportExtendColumns($columns); + + /* + * Prepare CSV + */ + $csv = CsvWriter::createFromFileObject(new SplTempFileObject); + + $csv->setOutputBOM(CsvWriter::BOM_UTF8); + + if ($options['delimiter'] !== null) { + $csv->setDelimiter($options['delimiter']); + } + + if ($options['enclosure'] !== null) { + $csv->setEnclosure($options['enclosure']); + } + + if ($options['escape'] !== null) { + $csv->setEscape($options['escape']); + } + + $csv->addFormatter(new CsvEscapeFormula()); + + /* + * Add headers + */ + if ($options['firstRowTitles']) { + $headers = $this->getColumnHeaders($columns); + $csv->insertOne($headers); + } + + /* + * Add records + */ + foreach ($results as $result) { + $data = $this->matchDataToColumns($result, $columns); + $csv->insertOne($data); + } + + /* + * Output + */ + if ($options['useOutput']) { + $csv->output($options['fileName']); + } + + /* + * Save for download + */ + $csvName = uniqid('oc'); + $csvPath = temp_path().'/'.$csvName; + $output = $csv->__toString(); + + File::put($csvPath, $output); + + return $csvName; + } + + /** + * Used to override column definitions at export time. + */ + protected function exportExtendColumns($columns) + { + return $columns; + } + + /** + * Extracts the headers from the column definitions. + */ + protected function getColumnHeaders($columns) + { + $headers = []; + + foreach ($columns as $column => $label) { + $headers[] = Lang::get($label); + } + + return $headers; + } + + /** + * Ensures the correct order of the column data. + */ + protected function matchDataToColumns($data, $columns) + { + $results = []; + + foreach ($columns as $column => $label) { + $results[] = array_get($data, $column); + } + + return $results; + } + + /** + * Implodes a single dimension array using pipes (|) + * Multi dimensional arrays are not allowed. + * @return string + */ + protected function encodeArrayValue($data, $delimeter = '|') + { + $newData = []; + foreach ($data as $value) { + if (is_array($value)) { + $newData[] = 'Array'; + } else { + $newData[] = str_replace($delimeter, '\\'.$delimeter, $value); + } + } + + return implode($delimeter, $newData); + } +} diff --git a/modules/backend/models/ImportModel.php b/modules/backend/models/ImportModel.php new file mode 100644 index 0000000..09c1bf4 --- /dev/null +++ b/modules/backend/models/ImportModel.php @@ -0,0 +1,292 @@ + [\System\Models\File::class, 'public' => false], + ]; + + /** + * @var array Import statistics store. + */ + protected $resultStats = [ + 'updated' => 0, + 'created' => 0, + 'errors' => [], + 'warnings' => [], + 'skipped' => [] + ]; + + /** + * Called when data is being imported. + * The $results array should be in the format of: + * + * [ + * 'db_name1' => 'Some value', + * 'db_name2' => 'Another value' + * ], + * [...] + * + */ + abstract public function importData($results, $sessionKey = null); + + /** + * Import data based on column names matching header indexes in the CSV. + * The $matches array should be in the format of: + * + * [ + * 0 => [db_name1, db_name2], + * 1 => [db_name3], + * ... + * ] + * + * The key (0, 1) is the column index in the CSV and the value + * is another array of target database column names. + */ + public function import($matches, $options = []) + { + $sessionKey = array_get($options, 'sessionKey'); + $path = $this->getImportFilePath($sessionKey); + $data = $this->processImportData($path, $matches, $options); + return $this->importData($data, $sessionKey); + } + + /** + * Converts column index to database column map to an array containing + * database column names and values pulled from the CSV file. Eg: + * + * [0 => [first_name], 1 => [last_name]] + * + * Will return: + * + * [first_name => Joe, last_name => Blogs], + * [first_name => Harry, last_name => Potter], + * [...] + * + * @return array + */ + protected function processImportData($filePath, $matches, $options) + { + /* + * Parse options + */ + $defaultOptions = [ + 'firstRowTitles' => true, + 'delimiter' => null, + 'enclosure' => null, + 'escape' => null, + 'encoding' => null + ]; + + $options = array_merge($defaultOptions, $options); + + /* + * Read CSV + */ + $reader = CsvReader::createFromPath($filePath, 'r'); + + if ($options['delimiter'] !== null) { + $reader->setDelimiter($options['delimiter']); + } + + if ($options['enclosure'] !== null) { + $reader->setEnclosure($options['enclosure']); + } + + if ($options['escape'] !== null) { + $reader->setEscape($options['escape']); + } + + if ( + $options['encoding'] !== null && + $reader->supportsStreamFilter() + ) { + $reader->addStreamFilter(sprintf( + '%s%s:%s', + TranscodeFilter::FILTER_NAME, + strtolower($options['encoding']), + 'utf-8' + )); + } + + // Create reader statement + $stmt = (new CsvStatement) + ->where(function (array $row) { + // Filter out empty rows + return count($row) > 1 || reset($row) !== null; + }); + + if ($options['firstRowTitles']) { + $stmt = $stmt->offset(1); + } + + $result = []; + $contents = $stmt->process($reader); + foreach ($contents as $row) { + $result[] = $this->processImportRow($row, $matches); + } + + return $result; + } + + /** + * Converts a single row of CSV data to the column map. + * @return array + */ + protected function processImportRow($rowData, $matches) + { + $newRow = []; + + foreach ($matches as $columnIndex => $dbNames) { + $value = array_get($rowData, $columnIndex); + foreach ((array) $dbNames as $dbName) { + $newRow[$dbName] = $value; + } + } + + return $newRow; + } + + /** + * Explodes a string using pipes (|) to a single dimension array + * @return array + */ + protected function decodeArrayValue($value, $delimeter = '|') + { + if (strpos($value, $delimeter) === false) { + return [$value]; + } + + $data = preg_split('~(?import_file() + ->withDeferred($sessionKey) + ->orderBy('id', 'desc') + ->first() + ; + + if (!$file) { + return null; + } + + return $file->getLocalPath(); + } + + /** + * Returns all available encodings values from the localization config + * @return array + */ + public function getFormatEncodingOptions() + { + $options = [ + 'utf-8', + 'us-ascii', + 'iso-8859-1', + 'iso-8859-2', + 'iso-8859-3', + 'iso-8859-4', + 'iso-8859-5', + 'iso-8859-6', + 'iso-8859-7', + 'iso-8859-8', + 'iso-8859-0', + 'iso-8859-10', + 'iso-8859-11', + 'iso-8859-13', + 'iso-8859-14', + 'iso-8859-15', + 'Windows-1250', + 'Windows-1251', + 'Windows-1252' + ]; + + $translated = array_map(function ($option) { + return Lang::get('backend::lang.import_export.encodings.'.Str::slug($option, '_')); + }, $options); + + return array_combine($options, $translated); + } + + // + // Result logging + // + + public function getResultStats() + { + $this->resultStats['errorCount'] = count($this->resultStats['errors']); + $this->resultStats['warningCount'] = count($this->resultStats['warnings']); + $this->resultStats['skippedCount'] = count($this->resultStats['skipped']); + + $this->resultStats['hasMessages'] = ( + $this->resultStats['errorCount'] > 0 || + $this->resultStats['warningCount'] > 0 || + $this->resultStats['skippedCount'] > 0 + ); + + return (object) $this->resultStats; + } + + protected function logUpdated() + { + $this->resultStats['updated']++; + } + + protected function logCreated() + { + $this->resultStats['created']++; + } + + protected function logError($rowIndex, $message) + { + $this->resultStats['errors'][$rowIndex] = $message; + } + + protected function logWarning($rowIndex, $message) + { + $this->resultStats['warnings'][$rowIndex] = $message; + } + + protected function logSkipped($rowIndex, $message) + { + $this->resultStats['skipped'][$rowIndex] = $message; + } +} diff --git a/modules/backend/models/Preference.php b/modules/backend/models/Preference.php new file mode 100644 index 0000000..9eb5d6b --- /dev/null +++ b/modules/backend/models/Preference.php @@ -0,0 +1,298 @@ +locale = $config->get('app.locale', 'en'); + $this->fallback_locale = $this->getFallbackLocale($this->locale); + $this->timezone = $config->get('cms.backendTimezone', $config->get('app.timezone')); + + $this->editor_font_size = $config->get('editor.font_size', 12); + $this->editor_word_wrap = $config->get('editor.word_wrap', 'fluid'); + $this->editor_code_folding = $config->get('editor.code_folding', 'manual'); + $this->editor_tab_size = $config->get('editor.tab_size', 4); + $this->editor_theme = $config->get('editor.theme', static::DEFAULT_THEME); + $this->editor_show_invisibles = $config->get('editor.show_invisibles', false); + $this->editor_highlight_active_line = $config->get('editor.highlight_active_line', true); + $this->editor_use_hard_tabs = $config->get('editor.use_hard_tabs', false); + $this->editor_show_gutter = $config->get('editor.show_gutter', true); + $this->editor_auto_closing = $config->get('editor.auto_closing', false); + $this->editor_autocompletion = $config->get('editor.editor_autocompletion', 'manual'); + $this->editor_enable_snippets = $config->get('editor.enable_snippets', false); + $this->editor_display_indent_guides = $config->get('editor.display_indent_guides', false); + $this->editor_show_print_margin = $config->get('editor.show_print_margin', false); + } + + /** + * Set the application's locale based on the user preference. + * @return void + */ + public static function setAppLocale() + { + if (Session::has('locale')) { + App::setLocale(Session::get('locale')); + } + elseif ( + ($user = BackendAuth::getUser()) && + ($locale = static::get('locale')) + ) { + Session::put('locale', $locale); + App::setLocale($locale); + } + } + + /** + * Same as setAppLocale except for the fallback definition. + * @return void + */ + public static function setAppFallbackLocale() + { + if (Session::has('fallback_locale')) { + Lang::setFallback(Session::get('fallback_locale')); + } + elseif ( + ($user = BackendAuth::getUser()) && + ($locale = static::get('fallback_locale')) + ) { + Session::put('fallback_locale', $locale); + Lang::setFallback($locale); + } + } + + // + // Events + // + + public function beforeValidate() + { + $this->fallback_locale = $this->getFallbackLocale($this->locale); + } + + public function afterSave() + { + Session::put('locale', $this->locale); + Session::put('fallback_locale', $this->fallback_locale); + } + + // + // Utils + // + + /** + * Called when this model is reset to default by the user. + * @return void + */ + public function resetDefault() + { + parent::resetDefault(); + Session::forget('locale'); + Session::forget('fallback_locale'); + } + + /** + * Overrides the config with the user's preference. + * @return void + */ + public static function applyConfigValues() + { + $settings = self::instance(); + Config::set('app.locale', $settings->locale); + Config::set('app.fallback_locale', $settings->fallback_locale); + } + + // + // Getters + // + + /** + * Attempt to extract the language from the locale, + * otherwise use the configuration. + * @return string + */ + protected function getFallbackLocale($locale) + { + if ($position = strpos($locale, '-')) { + $target = substr($locale, 0, $position); + $available = $this->getLocaleOptions(); + if (isset($available[$target])) { + return $target; + } + } + + return Config::get('app.fallback_locale'); + } + + /** + * Returns available options for the "locale" attribute. + * @return array + */ + public function getLocaleOptions() + { + $localeOptions = [ + 'ar' => [Lang::get('system::lang.locale.ar'), 'flag-sa'], + 'be' => [Lang::get('system::lang.locale.be'), 'flag-by'], + 'bg' => [Lang::get('system::lang.locale.bg'), 'flag-bg'], + 'ca' => [Lang::get('system::lang.locale.ca'), 'flag-es-ct'], + 'cs' => [Lang::get('system::lang.locale.cs'), 'flag-cz'], + 'da' => [Lang::get('system::lang.locale.da'), 'flag-dk'], + 'de' => [Lang::get('system::lang.locale.de'), 'flag-de'], + 'el' => [Lang::get('system::lang.locale.el'), 'flag-gr'], + 'en' => [Lang::get('system::lang.locale.en'), 'flag-us'], + 'en-au' => [Lang::get('system::lang.locale.en-au'), 'flag-au'], + 'en-ca' => [Lang::get('system::lang.locale.en-ca'), 'flag-ca'], + 'en-gb' => [Lang::get('system::lang.locale.en-gb'), 'flag-gb'], + 'es' => [Lang::get('system::lang.locale.es'), 'flag-es'], + 'es-ar' => [Lang::get('system::lang.locale.es-ar'), 'flag-ar'], + 'et' => [Lang::get('system::lang.locale.et'), 'flag-ee'], + 'fa' => [Lang::get('system::lang.locale.fa'), 'flag-ir'], + 'fi' => [Lang::get('system::lang.locale.fi'), 'flag-fi'], + 'fr' => [Lang::get('system::lang.locale.fr'), 'flag-fr'], + 'fr-ca' => [Lang::get('system::lang.locale.fr-ca'), 'flag-ca'], + 'hu' => [Lang::get('system::lang.locale.hu'), 'flag-hu'], + 'id' => [Lang::get('system::lang.locale.id'), 'flag-id'], + 'it' => [Lang::get('system::lang.locale.it'), 'flag-it'], + 'ja' => [Lang::get('system::lang.locale.ja'), 'flag-jp'], + 'kr' => [Lang::get('system::lang.locale.kr'), 'flag-kr'], + 'lt' => [Lang::get('system::lang.locale.lt'), 'flag-lt'], + 'lv' => [Lang::get('system::lang.locale.lv'), 'flag-lv'], + 'nb-no' => [Lang::get('system::lang.locale.nb-no'), 'flag-no'], + 'nl' => [Lang::get('system::lang.locale.nl'), 'flag-nl'], + 'pl' => [Lang::get('system::lang.locale.pl'), 'flag-pl'], + 'pt-br' => [Lang::get('system::lang.locale.pt-br'), 'flag-br'], + 'pt-pt' => [Lang::get('system::lang.locale.pt-pt'), 'flag-pt'], + 'ro' => [Lang::get('system::lang.locale.ro'), 'flag-ro'], + 'rs' => [Lang::get('system::lang.locale.rs'), 'flag-rs'], + 'ru' => [Lang::get('system::lang.locale.ru'), 'flag-ru'], + 'sk' => [Lang::get('system::lang.locale.sk'), 'flag-sk'], + 'sl' => [Lang::get('system::lang.locale.sl'), 'flag-si'], + 'sv' => [Lang::get('system::lang.locale.sv'), 'flag-se'], + 'th' => [Lang::get('system::lang.locale.th'), 'flag-th'], + 'tr' => [Lang::get('system::lang.locale.tr'), 'flag-tr'], + 'uk' => [Lang::get('system::lang.locale.uk'), 'flag-ua'], + 'vn' => [Lang::get('system::lang.locale.vn'), 'flag-vn'], + 'zh-cn' => [Lang::get('system::lang.locale.zh-cn'), 'flag-cn'], + 'zh-tw' => [Lang::get('system::lang.locale.zh-tw'), 'flag-tw'], + ]; + + $locales = Config::get('app.localeOptions', $localeOptions); + + // Sort locales alphabetically + asort($locales); + + return $locales; + } + + /** + * Returns all available timezone options. + * @return array + */ + public function getTimezoneOptions() + { + $timezoneIdentifiers = DateTimeZone::listIdentifiers(); + $utcTime = new DateTime('now', new DateTimeZone('UTC')); + + $tempTimezones = []; + foreach ($timezoneIdentifiers as $timezoneIdentifier) { + $currentTimezone = new DateTimeZone($timezoneIdentifier); + + $tempTimezones[] = [ + 'offset' => (int) $currentTimezone->getOffset($utcTime), + 'identifier' => $timezoneIdentifier + ]; + } + + // Sort the array by offset, identifier ascending + usort($tempTimezones, function ($a, $b) { + return $a['offset'] === $b['offset'] + ? strcmp($a['identifier'], $b['identifier']) + : $a['offset'] - $b['offset']; + }); + + $timezoneList = []; + foreach ($tempTimezones as $tz) { + $sign = $tz['offset'] > 0 ? '+' : '-'; + $offset = gmdate('H:i', abs($tz['offset'])); + $timezoneList[$tz['identifier']] = '(UTC ' . $sign . $offset . ') ' . $tz['identifier']; + } + + return $timezoneList; + } + + /** + * Returns the theme options for the backend editor. + * @return array + */ + public function getEditorThemeOptions() + { + $themeDir = new DirectoryIterator("modules/backend/formwidgets/codeeditor/assets/vendor/ace/"); + $themes = []; + + // Iterate through the themes + foreach ($themeDir as $node) { + // If this file is a theme (starting by "theme-") + if (!$node->isDir() && substr($node->getFileName(), 0, 6) == 'theme-') { + // Remove the theme- prefix and the .js suffix, create an user friendly and capitalized name + $themeId = substr($node->getFileName(), 6, -3); + $themeName = ucwords(str_replace("_", " ", $themeId)); + + // Add the values to the themes array + if ($themeId != static::DEFAULT_THEME) { + $themes[$themeId] = $themeName; + } + } + } + + // Sort the theme alphabetically, and push the default theme + asort($themes); + return [static::DEFAULT_THEME => ucwords(static::DEFAULT_THEME)] + $themes; + } +} diff --git a/modules/backend/models/User.php b/modules/backend/models/User.php new file mode 100644 index 0000000..4625979 --- /dev/null +++ b/modules/backend/models/User.php @@ -0,0 +1,212 @@ + 'required|between:6,255|email|unique:backend_users', + 'login' => 'required|between:2,255|unique:backend_users', + 'password' => 'required:create|min:4|confirmed', + 'password_confirmation' => 'required_with:password|min:4' + ]; + + /** + * @var array Attributes that should be cast to dates + */ + protected $dates = [ + 'activated_at', + 'last_login', + 'created_at', + 'updated_at', + 'deleted_at', + ]; + + /** + * Relations + */ + public $belongsToMany = [ + 'groups' => [UserGroup::class, 'table' => 'backend_users_groups'] + ]; + + public $belongsTo = [ + 'role' => UserRole::class + ]; + + public $attachOne = [ + 'avatar' => \System\Models\File::class + ]; + + /** + * Purge attributes from data set. + */ + protected $purgeable = ['password_confirmation', 'send_invite']; + + /** + * @var string Login attribute + */ + public static $loginAttribute = 'login'; + + /** + * @return string Returns the user's full name. + */ + public function getFullNameAttribute() + { + return trim($this->first_name . ' ' . $this->last_name); + } + + /** + * Gets a code for when the user is persisted to a cookie or session which identifies the user. + * @return string + */ + public function getPersistCode() + { + // Option A: @todo config + // return parent::getPersistCode(); + + // Option B: + if (!$this->persist_code) { + return parent::getPersistCode(); + } + + return $this->persist_code; + } + + /** + * Returns the public image file path to this user's avatar. + */ + public function getAvatarThumb($size = 25, $options = null) + { + if (is_string($options)) { + $options = ['default' => $options]; + } + elseif (!is_array($options)) { + $options = []; + } + + // Default is "mm" (Mystery man) + $default = array_get($options, 'default', 'mm'); + + if ($this->avatar) { + return $this->avatar->getThumb($size, $size, $options); + } + + return '//www.gravatar.com/avatar/' . + md5(strtolower(trim($this->email))) . + '?s='. $size . + '&d='. urlencode($default); + } + + /** + * After create event + * @return void + */ + public function afterCreate() + { + $this->restorePurgedValues(); + + if ($this->send_invite) { + $this->sendInvitation(); + } + } + + /** + * After login event + * @return void + */ + public function afterLogin() + { + parent::afterLogin(); + + /** + * @event backend.user.login + * Provides an opportunity to interact with the Backend User model after the user has logged in + * + * Example usage: + * + * Event::listen('backend.user.login', function ((\Backend\Models\User) $user) { + * Flash::success(sprintf('Welcome %s!', $user->getFullNameAttribute())); + * }); + * + */ + Event::fire('backend.user.login', [$this]); + } + + /** + * Sends an invitation to the user using template "backend::mail.invite". + * @return void + */ + public function sendInvitation() + { + $data = [ + 'name' => $this->full_name, + 'login' => $this->login, + 'password' => $this->getOriginalHashValue('password'), + 'link' => Backend::url('backend'), + ]; + + Mail::send('backend::mail.invite', $data, function ($message) { + $message->to($this->email, $this->full_name); + }); + } + + public function getGroupsOptions() + { + $result = []; + + foreach (UserGroup::all() as $group) { + $result[$group->id] = [$group->name, $group->description]; + } + + return $result; + } + + public function getRoleOptions() + { + $result = []; + + foreach (UserRole::all() as $role) { + $result[$role->id] = [$role->name, $role->description]; + } + + return $result; + } + + /** + * Check if the user is suspended. + * @return bool + */ + public function isSuspended() + { + return BackendAuth::findThrottleByUserId($this->id)->checkSuspended(); + } + + /** + * Remove the suspension on this user. + * @return void + */ + public function unsuspend() + { + BackendAuth::findThrottleByUserId($this->id)->unsuspend(); + } +} diff --git a/modules/backend/models/UserGroup.php b/modules/backend/models/UserGroup.php new file mode 100644 index 0000000..e9be812 --- /dev/null +++ b/modules/backend/models/UserGroup.php @@ -0,0 +1,46 @@ + 'required|between:2,128|unique:backend_user_groups', + ]; + + /** + * @var array Relations + */ + public $belongsToMany = [ + 'users' => [User::class, 'table' => 'backend_users_groups'], + 'users_count' => [User::class, 'table' => 'backend_users_groups', 'count' => true] + ]; + + public function afterCreate() + { + if ($this->is_new_user_default) { + $this->addAllUsersToGroup(); + } + } + + public function addAllUsersToGroup() + { + $this->users()->sync(User::lists('id')); + } +} diff --git a/modules/backend/models/UserPreference.php b/modules/backend/models/UserPreference.php new file mode 100644 index 0000000..cb7ee58 --- /dev/null +++ b/modules/backend/models/UserPreference.php @@ -0,0 +1,38 @@ + 'required|between:2,128|unique:backend_user_roles', + 'code' => 'unique:backend_user_roles', + ]; + + /** + * @var array Relations + */ + public $hasMany = [ + 'users' => [User::class, 'key' => 'role_id'], + 'users_count' => [User::class, 'key' => 'role_id', 'count' => true] + ]; + + public function filterFields($fields) + { + if ($this->is_system) { + $fields->code->disabled = true; + $fields->permissions->disabled = true; + } + } + + public function afterFetch() + { + if ($this->is_system) { + $this->permissions = $this->getDefaultPermissions(); + } + } + + public function beforeSave() + { + if ($this->isSystemRole()) { + $this->is_system = true; + $this->permissions = []; + } + } + + public function isSystemRole() + { + if (!$this->code || !strlen(trim($this->code))) { + return false; + } + + if ($this->is_system || in_array($this->code, [ + self::CODE_DEVELOPER, + self::CODE_PUBLISHER + ])) { + return true; + } + + return AuthManager::instance()->hasPermissionsForRole($this->code); + } + + public function getDefaultPermissions() + { + return AuthManager::instance()->listPermissionsForRole($this->code); + } +} diff --git a/modules/backend/models/UserThrottle.php b/modules/backend/models/UserThrottle.php new file mode 100644 index 0000000..11d2131 --- /dev/null +++ b/modules/backend/models/UserThrottle.php @@ -0,0 +1,33 @@ + User::class + ]; + + public function __construct() + { + parent::__construct(); + + static::$attemptLimit = Config::get('auth.throttle.attemptLimit', 5); + static::$suspensionTime = Config::get('auth.throttle.suspensionTime', 15); + } +} diff --git a/modules/backend/models/accesslog/columns.yaml b/modules/backend/models/accesslog/columns.yaml new file mode 100644 index 0000000..25d6f20 --- /dev/null +++ b/modules/backend/models/accesslog/columns.yaml @@ -0,0 +1,53 @@ +# =================================== +# Column Definitions +# =================================== + +columns: + + id: + label: backend::lang.access_log.id + searchable: yes + invisible: true + width: 75px + + created_at: + label: backend::lang.access_log.created_at + searchable: yes + type: timetense + width: 160px + + type: + label: backend::lang.access_log.type + invisible: true + + ip_address: + label: backend::lang.access_log.ip_address + searchable: yes + + login: + label: backend::lang.access_log.login + relation: user + select: login + searchable: yes + sortable: false + + first_name: + label: backend::lang.access_log.first_name + relation: user + select: first_name + searchable: yes + sortable: false + + last_name: + label: backend::lang.access_log.last_name + relation: user + select: last_name + searchable: yes + sortable: false + + email: + label: backend::lang.access_log.email + relation: user + select: email + searchable: yes + sortable: false diff --git a/modules/backend/models/brandsetting/custom.less b/modules/backend/models/brandsetting/custom.less new file mode 100644 index 0000000..729f586 --- /dev/null +++ b/modules/backend/models/brandsetting/custom.less @@ -0,0 +1,223 @@ +// +// Coded variables +// +// @logo-image +// @brand-primary +// @brand-secondary +// @brand-accent +// + +.br-p { color: @brand-primary; } +.br-s { color: @brand-secondary; } +.br-a { color: @brand-accent; } +.br-p-s10 { color: saturate(@brand-primary, 10%); } +.br-s-s10 { color: saturate(@brand-secondary, 10%); } +.br-a-s10 { color: saturate(@brand-accent, 10%); } +.br-p-s20 { color: saturate(@brand-primary, 20%); } +.br-s-s20 { color: saturate(@brand-secondary, 20%); } +.br-a-s20 { color: saturate(@brand-accent, 20%); } + +.bg-p { background-color: @brand-primary; } +.bg-s { background-color: @brand-secondary; } +.bg-a { background-color: @brand-accent; } +.bg-p-s10 { background-color: saturate(@brand-primary, 10%); } +.bg-s-s10 { background-color: saturate(@brand-secondary, 10%); } +.bg-a-s10 { background-color: saturate(@brand-accent, 10%); } +.bg-p-s20 { background-color: saturate(@brand-primary, 20%); } +.bg-s-s20 { background-color: saturate(@brand-secondary, 20%); } +.bg-a-s20 { background-color: saturate(@brand-accent, 20%); } + +@custom-dark-accent: mix(black, desaturate(@brand-accent, 35%), 20%); +@custom-dark-secondary: mix(black, saturate(@brand-secondary, 20%), 25%); +@custom-dark-primary: mix(black, saturate(@brand-primary, 5%), 15%); + +// +// Sidenav Tree +// + +.sidenav-tree ul.top-level > li { + > div.group:before { + border-top-color: @brand-primary; + } + > ul li.active { + border-color: @brand-secondary; + } +} + +// +// Side panel +// + +#layout-side-panel { + .sidepanel-content-header { + background: @custom-dark-secondary; + } +} + +// +// Asset List +// + +.control-assetlist ul li.active a:after, +.control-assetlist ul li.active a.link:after { + background: @brand-secondary; +} + +// +// Pages List +// + +.control-treeview ol > li.active > div::after { + background: @brand-secondary; +} + +// +// Outside Layout +// + +body.outer { + background: @custom-dark-primary; +} + +// +// Logos +// + +.oc-logo-transparent when not (@logo-image = '') { + background-image: url('@{logo-image}') !important; +} + +.oc-logo when not (@logo-image = '') { + background-image: url('@{logo-image}'); +} + +// +// List +// + +table.table.data { + tbody { + tr.active td { + &:first-child { + border-left: 3px solid @brand-secondary; + } + } + } +} + +// +// Fancy Layout +// + +.fancy-layout .form-tabless-fields { + background: @brand-secondary; + + .loading-indicator-container .loading-indicator { + background: @brand-secondary; + } +} + +.fancy-layout .control-tabs.master-tabs, +.fancy-layout.control-tabs.master-tabs { + > div > div.tabs-container > ul.nav-tabs > li.active a > span.title { + &, &:before, &:after { + background: @brand-secondary; + } + } + + > div > div.tabs-container > ul.nav-tabs > li a > span.title { + &, &:before, &:after { + background-color: mix(black, saturate(@brand-secondary, 20%), 31%); + } + } + + > div > div.tabs-container { + background: @custom-dark-secondary; + } +} + +.fancy-layout .control-tabs.primary-tabs, +.fancy-layout.control-tabs.primary-tabs { + &.master-area > div > ul.nav-tabs { + background: @brand-secondary; + } +} + +.fancy-layout .control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed, +.fancy-layout.control-tabs.secondary-tabs.secondary-content-tabs.primary-collapsed { + > div > ul.nav-tabs { + background: @brand-secondary; + } +} + +.control-filelist ul li.active > a:after { + background: @brand-secondary; +} + +// +// Component List +// + +div.control-componentlist { + &.droppable { + background-color: lighten(@brand-secondary, 20%); + } +} + +// +// Stripe Indicator +// + +.stripe-loading-indicator { + .stripe, .stripe-loaded { + background: @brand-accent; + } +} + +// +// Balloon Selector +// + +.control-balloon-selector { + ul { + li.active { + background: @brand-secondary !important; + } + } +} + +// +// Media +// + +.nav.selector-group li.active { + border-left-color: @brand-secondary; +} + +// +// Fancy breadcrumb +// +body.breadcrumb-fancy .control-breadcrumb, +.control-breadcrumb.breadcrumb-fancy { + background-color: mix(black, saturate(@brand-secondary, 20%), 16%); + + li { + background-color: mix(black, saturate(@brand-secondary, 20%), 31%); + + &:last-child { + background-color: mix(black, saturate(@brand-secondary, 20%), 16%); + + &::before { + border-left-color: mix(black, saturate(@brand-secondary, 20%), 16%); + } + } + + &::after { + border-left-color: mix(black, saturate(@brand-secondary, 20%), 31%); + } + + &:not(:last-child)::before { + border-left-color: @brand-secondary; + } + } +} diff --git a/modules/backend/models/brandsetting/fields.yaml b/modules/backend/models/brandsetting/fields.yaml new file mode 100644 index 0000000..49d8e75 --- /dev/null +++ b/modules/backend/models/brandsetting/fields.yaml @@ -0,0 +1,75 @@ +# =================================== +# Field Definitions +# =================================== +# Light palette: [#1abc9c, #2ecc71, #3498db, #9b59b6, #34495e, #f1c40f, #e67e22, #e74c3c, #ecf0f1, #95a5a6] +# Dark palette: [#16a085, #27ae60, #2980b9, #8e44ad, #2b3e50, #f39c12, #d35400, #c0392b, #bdc3c7, #7f8c8d] + +tabs: + fields: + + logo: + label: backend::lang.branding.logo + type: fileupload + commentAbove: backend::lang.branding.logo_description + mode: image + imageHeight: 170 + tab: backend::lang.branding.brand + span: right + fileTypes: jpg,jpeg,bmp,png,webp,gif,svg + + app_name: + label: backend::lang.branding.app_name + commentAbove: backend::lang.branding.app_name_description + tab: backend::lang.branding.brand + span: left + + app_tagline: + label: backend::lang.branding.app_tagline + commentAbove: backend::lang.branding.app_tagline_description + tab: backend::lang.branding.brand + span: left + + favicon: + label: backend::lang.branding.favicon + type: fileupload + commentAbove: backend::lang.branding.favicon_description + mode: image + imageHeight: 32 + tab: backend::lang.branding.brand + span: right + fileTypes: jpg,jpeg,bmp,png,webp,gif,svg,ico + + primary_color: + label: backend::lang.branding.primary_color + type: colorpicker + tab: backend::lang.branding.colors + availableColors: [#16a085, #27ae60, #2980b9, #8e44ad, #34495e, #f39c12, #d35400, #c0392b, #7f8c8d, #4f5458] + + secondary_color: + label: backend::lang.branding.secondary_color + type: colorpicker + tab: backend::lang.branding.colors + availableColors: [#16a085, #27ae60, #3498db, #9b59b6, #34495e, #f39c12, #e67e22, #e74c3c, #708598, #4f5458] + + accent_color: + label: backend::lang.branding.accent_color + type: colorpicker + tab: backend::lang.branding.colors + availableColors: [#16a085, #27ae60, #3498db, #9b59b6, #34495e, #f1c40f, #e67e22, #e74c3c, #ecf0f1, #95a5a6] + + menu_mode: + label: backend::lang.branding.menu_mode + tab: backend::lang.branding.navigation + type: radio + options: + inline: backend::lang.branding.menu_mode_inline + inline_no_icons: backend::lang.branding.menu_mode_inline_no_icons + tile: backend::lang.branding.menu_mode_tile + collapse: backend::lang.branding.menu_mode_collapsed + + custom_css: + label: backend::lang.branding.custom_stylesheet + type: codeeditor + tab: backend::lang.branding.styles + size: giant + language: css diff --git a/modules/backend/models/editorsetting/_toolbar_presets.htm b/modules/backend/models/editorsetting/_toolbar_presets.htm new file mode 100644 index 0000000..4136704 --- /dev/null +++ b/modules/backend/models/editorsetting/_toolbar_presets.htm @@ -0,0 +1,10 @@ +
    + formWidget->model->getEditorToolbarPresets() as $name => $preset): ?> + + +
    diff --git a/modules/backend/models/editorsetting/default_styles.less b/modules/backend/models/editorsetting/default_styles.less new file mode 100644 index 0000000..11a4b2b --- /dev/null +++ b/modules/backend/models/editorsetting/default_styles.less @@ -0,0 +1,62 @@ +/* + * Text + */ +.oc-text-gray { + color: #AAA !important; +} +.oc-text-bordered { + border-top: solid 1px #222; + border-bottom: solid 1px #222; + padding: 10px 0; +} +.oc-text-spaced { + letter-spacing: 1px; +} +.oc-text-uppercase { + text-transform: uppercase; +} + +/* + * Links + */ +a.oc-link-strong { + font-weight: 700; +} +a.oc-link-green { + color: green; +} + +/* + * Table + */ +table.oc-dashed-borders td, +table.oc-dashed-borders th { + border-style: dashed; +} +table.oc-alternate-rows tbody tr:nth-child(2n) { + background: #f5f5f5; +} + +/* + * Table cell + */ +table td.oc-cell-highlighted, +table th.oc-cell-highlighted { + border: 1px double red; +} +table td.oc-cell-thick-border, +table th.oc-cell-thick-border { + border-width: 2px; +} + +/* + * Images + */ +img.oc-img-rounded { + border-radius: 100%; + background-clip: padding-box; +} +img.oc-img-bordered { + border: solid 10px #CCC; + box-sizing: content-box; +} diff --git a/modules/backend/models/editorsetting/fields.yaml b/modules/backend/models/editorsetting/fields.yaml new file mode 100644 index 0000000..6276519 --- /dev/null +++ b/modules/backend/models/editorsetting/fields.yaml @@ -0,0 +1,133 @@ +# =================================== +# Field Definitions +# =================================== + +tabs: + fields: + + html_custom_styles: + label: backend::lang.editor.custom_styles + commentAbove: backend::lang.editor.custom styles_comment + tab: backend::lang.editor.markup_styles + type: codeeditor + size: giant + language: css + + html_style_paragraph: + label: backend::lang.editor.paragraph + tab: backend::lang.editor.markup_classes + span: auto + type: datatable + columns: + class_label: + title: backend::lang.editor.label + class_name: + title: backend::lang.editor.class_name + + html_style_link: + label: backend::lang.editor.link + tab: backend::lang.editor.markup_classes + span: auto + type: datatable + columns: + class_label: + title: backend::lang.editor.label + class_name: + title: backend::lang.editor.class_name + + html_style_table: + label: backend::lang.editor.table + tab: backend::lang.editor.markup_classes + span: auto + type: datatable + columns: + class_label: + title: backend::lang.editor.label + class_name: + title: backend::lang.editor.class_name + + html_style_table_cell: + label: backend::lang.editor.table_cell + tab: backend::lang.editor.markup_classes + span: auto + type: datatable + columns: + class_label: + title: backend::lang.editor.label + class_name: + title: backend::lang.editor.class_name + + html_style_image: + label: backend::lang.editor.image + tab: backend::lang.editor.markup_classes + span: auto + type: datatable + columns: + class_label: + title: backend::lang.editor.label + class_name: + title: backend::lang.editor.class_name + + html_allow_tags: + label: backend::lang.editor.allowed_tags + comment: backend::lang.editor.allowed_tags_comment + tab: backend::lang.editor.markup_tags + type: textarea + + html_allow_empty_tags: + label: backend::lang.editor.allowed_empty_tags + comment: backend::lang.editor.allowed_empty_tags_comment + tab: backend::lang.editor.markup_tags + type: textarea + size: small + span: auto + + html_no_wrap_tags: + label: backend::lang.editor.no_wrap + comment: backend::lang.editor.no_wrap_comment + tab: backend::lang.editor.markup_tags + type: textarea + size: small + span: auto + + html_remove_tags: + label: backend::lang.editor.remove_tags + comment: backend::lang.editor.remove_tags_comment + tab: backend::lang.editor.markup_tags + type: textarea + size: small + span: auto + + html_line_breaker_tags: + label: backend::lang.editor.line_breaker_tags + comment: backend::lang.editor.line_breaker_tags_comment + tab: backend::lang.editor.markup_tags + type: textarea + size: small + span: auto + + html_paragraph_formats: + label: backend::lang.editor.paragraph_formats + comment: backend::lang.editor.paragraph_formats_comment + tab: backend::lang.editor.toolbar_options + type: datatable + span: right + columns: + format_tag: + title: backend::lang.editor.markup_tag + format_label: + title: backend::lang.editor.label + + html_toolbar_buttons: + label: backend::lang.editor.toolbar_buttons + comment: backend::lang.editor.toolbar_buttons_comment + tab: backend::lang.editor.toolbar_options + type: textarea + span: left + + _html_toolbar_buttons_presets: + label: backend::lang.editor.toolbar_buttons_preset + tab: backend::lang.editor.toolbar_options + type: partial + path: ~/modules/backend/models/editorsetting/_toolbar_presets.htm + span: left diff --git a/modules/backend/models/preference/fields.yaml b/modules/backend/models/preference/fields.yaml new file mode 100644 index 0000000..f8e0aad --- /dev/null +++ b/modules/backend/models/preference/fields.yaml @@ -0,0 +1,138 @@ +# =================================== +# Field Definitions +# =================================== + +tabs: + fields: + + locale: + tab: backend::lang.backend_preferences.region + label: backend::lang.backend_preferences.locale + comment: backend::lang.backend_preferences.locale_comment + type: dropdown + span: left + + timezone: + tab: backend::lang.backend_preferences.region + label: backend::lang.backend_preferences.timezone + comment: backend::lang.backend_preferences.timezone_comment + type: dropdown + span: left + + editor_preview: + type: partial + label: backend::lang.editor.preview + tab: backend::lang.backend_preferences.code_editor + path: field_editor_preview + + editor_theme: + label: backend::lang.editor.theme + tab: backend::lang.backend_preferences.code_editor + span: auto + type: dropdown + + editor_word_wrap: + label: backend::lang.editor.word_wrap + tab: backend::lang.backend_preferences.code_editor + type: dropdown + span: auto + options: + off: backend::lang.editor.mode_off + 40: backend::lang.editor.40_characters + 80: backend::lang.editor.80_characters + fluid: backend::lang.editor.mode_fluid + + editor_font_size: + label: backend::lang.editor.font_size + tab: backend::lang.backend_preferences.code_editor + span: auto + type: dropdown + options: + 11: 11px + 12: 12px + 13: 13px + 14: 14px + 15: 15px + 16: 16px + + editor_tab_size: + label: backend::lang.editor.tab_size + tab: backend::lang.backend_preferences.code_editor + span: auto + type: dropdown + options: + 2: 2 + 3: 3 + 4: 4 + 5: 5 + 6: 6 + 7: 7 + 8: 8 + + editor_code_folding: + label: backend::lang.editor.code_folding + tab: backend::lang.backend_preferences.code_editor + type: dropdown + span: auto + options: + manual: backend::lang.editor.mode_off + markbegin: backend::lang.editor.code_folding_begin + markbeginend: backend::lang.editor.code_folding_begin_end + + editor_autocompletion: + label: backend::lang.editor.autocompletion + tab: backend::lang.backend_preferences.code_editor + type: dropdown + span: auto + options: + manual: backend::lang.editor.mode_off + basic: backend::lang.editor.basic_autocompletion + live: backend::lang.editor.live_autocompletion + + editor_show_gutter: + label: backend::lang.editor.show_gutter + tab: backend::lang.backend_preferences.code_editor + type: checkbox + span: auto + + editor_highlight_active_line: + label: backend::lang.editor.highlight_active_line + tab: backend::lang.backend_preferences.code_editor + type: checkbox + span: auto + + editor_use_hard_tabs: + label: backend::lang.editor.use_hard_tabs + tab: backend::lang.backend_preferences.code_editor + type: checkbox + span: auto + + editor_display_indent_guides: + label: backend::lang.editor.display_indent_guides + tab: backend::lang.backend_preferences.code_editor + type: checkbox + span: auto + + editor_show_invisibles: + label: backend::lang.editor.show_invisibles + tab: backend::lang.backend_preferences.code_editor + type: checkbox + span: auto + + editor_show_print_margin: + label: backend::lang.editor.show_print_margin + tab: backend::lang.backend_preferences.code_editor + type: checkbox + span: auto + + editor_auto_closing: + label: backend::lang.editor.auto_closing + tab: backend::lang.backend_preferences.code_editor + type: checkbox + span: auto + + editor_enable_snippets: + label: backend::lang.editor.enable_snippets + tab: backend::lang.backend_preferences.code_editor + type: checkbox + span: auto diff --git a/modules/backend/models/user/columns.yaml b/modules/backend/models/user/columns.yaml new file mode 100644 index 0000000..6ce6f0d --- /dev/null +++ b/modules/backend/models/user/columns.yaml @@ -0,0 +1,76 @@ +# =================================== +# Column Definitions +# =================================== + +columns: + + first_name: + label: backend::lang.user.first_name + searchable: true + invisible: true + + last_name: + label: backend::lang.user.last_name + searchable: true + invisible: true + + full_name: + label: backend::lang.user.full_name + select: concat(first_name, ' ', last_name) + searchable: true + invisible: true + + login: + label: backend::lang.user.login + searchable: true + width: 15% + + email: + label: backend::lang.user.email + searchable: true + + groups: + label: backend::lang.user.groups + relation: groups + select: name + sortable: false + + role: + label: backend::lang.user.role.name + relation: role + select: name + sortable: true + searchable: true + + last_login: + label: backend::lang.user.last_login + searchable: true + type: datetime + + created_at: + label: backend::lang.user.created_at + searchable: true + invisible: true + type: datetime + + updated_at: + label: backend::lang.user.updated_at + searchable: true + invisible: true + type: datetime + + deleted_at: + label: backend::lang.user.deleted_at + searchable: true + invisible: true + type: datetime + + is_activated: + label: backend::lang.user.activated + invisible: true + type: switch + + is_superuser: + label: backend::lang.user.superuser + invisible: true + type: switch diff --git a/modules/backend/models/user/fields.yaml b/modules/backend/models/user/fields.yaml new file mode 100644 index 0000000..bbfbae2 --- /dev/null +++ b/modules/backend/models/user/fields.yaml @@ -0,0 +1,83 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + is_superuser: + context: [create, update] + tab: backend::lang.user.permissions + label: backend::lang.user.superuser + type: switch + comment: backend::lang.user.superuser_comment + +tabs: + defaultTab: backend::lang.user.account + icons: + backend::lang.user.account: icon-user + backend::lang.user.groups: icon-users + backend::lang.user.permissions: icon-key + + fields: + login: + span: left + label: backend::lang.user.login + + email: + span: right + type: email + label: backend::lang.user.email + + send_invite: + context: create + type: checkbox + label: backend::lang.user.send_invite + comment: backend::lang.user.send_invite_comment + default: true + + first_name: + span: left + label: backend::lang.user.first_name + + last_name: + span: right + label: backend::lang.user.last_name + + password: + type: password + span: left + label: backend::lang.user.password + + password_confirmation: + type: password + span: right + label: backend::lang.user.password_confirmation + + role: + context: [create, update] + label: backend::lang.user.role_field + commentAbove: backend::lang.user.role_comment + type: radio + + groups: + context: [create, update] + label: backend::lang.user.groups + commentAbove: backend::lang.user.groups_comment + type: checkboxlist + tab: backend::lang.user.groups + +secondaryTabs: + fields: + btn_impersonate: + label: '' + context: [update] + type: partial + btn_unsuspend: + label: '' + context: [update] + type: partial + avatar: + label: backend::lang.user.avatar + type: fileupload + mode: image + imageHeight: 250 + imageWidth: 250 diff --git a/modules/backend/models/usergroup/columns.yaml b/modules/backend/models/usergroup/columns.yaml new file mode 100644 index 0000000..0086d15 --- /dev/null +++ b/modules/backend/models/usergroup/columns.yaml @@ -0,0 +1,24 @@ +# =================================== +# Column Definitions +# =================================== + +columns: + name: + label: backend::lang.user.group.name_field + searchable: true + + code: + label: backend::lang.user.group.code_field + searchable: true + invisible: true + + description: + label: backend::lang.user.group.description_field + searchable: true + + users_count: + label: backend::lang.user.group.users_count + relation: users_count + valueFrom: count + default: 0 + sortable: false diff --git a/modules/backend/models/usergroup/fields.yaml b/modules/backend/models/usergroup/fields.yaml new file mode 100644 index 0000000..9a4ab86 --- /dev/null +++ b/modules/backend/models/usergroup/fields.yaml @@ -0,0 +1,24 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + is_new_user_default: + label: backend::lang.user.group.is_new_user_default_field_label + comment: backend::lang.user.group.is_new_user_default_field_comment + type: switch + + name: + label: backend::lang.user.group.name_field + commentAbove: backend::lang.user.group.name_comment + span: auto + + code: + label: backend::lang.user.group.code_field + commentAbove: backend::lang.user.group.code_comment + span: auto + + description: + label: backend::lang.user.group.description_field + type: textarea + size: tiny diff --git a/modules/backend/models/userrole/columns.yaml b/modules/backend/models/userrole/columns.yaml new file mode 100644 index 0000000..20f27aa --- /dev/null +++ b/modules/backend/models/userrole/columns.yaml @@ -0,0 +1,24 @@ +# =================================== +# Column Definitions +# =================================== + +columns: + name: + label: backend::lang.user.role.name_field + searchable: true + + code: + label: backend::lang.user.role.code_field + searchable: true + invisible: true + + description: + label: backend::lang.user.role.description_field + searchable: yes + + users_count: + label: backend::lang.user.role.users_count + relation: users_count + valueFrom: count + default: 0 + sortable: false diff --git a/modules/backend/models/userrole/fields.yaml b/modules/backend/models/userrole/fields.yaml new file mode 100644 index 0000000..f0d7ccf --- /dev/null +++ b/modules/backend/models/userrole/fields.yaml @@ -0,0 +1,22 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + name: + label: backend::lang.user.role.name_field + commentAbove: backend::lang.user.role.name_comment + span: auto + + code: + label: backend::lang.user.role.code_field + commentAbove: backend::lang.user.role.code_comment + span: auto + + description: + label: backend::lang.user.role.description_field + type: textarea + size: tiny + +tabs: + stretch: true diff --git a/modules/backend/reportwidgets/Welcome.php b/modules/backend/reportwidgets/Welcome.php new file mode 100644 index 0000000..827cac0 --- /dev/null +++ b/modules/backend/reportwidgets/Welcome.php @@ -0,0 +1,64 @@ +loadData(); + } + catch (Exception $ex) { + $this->vars['error'] = $ex->getMessage(); + } + + return $this->makePartial('widget'); + } + + public function defineProperties() + { + return [ + 'title' => [ + 'title' => 'backend::lang.dashboard.widget_title_label', + 'default' => 'backend::lang.dashboard.welcome.widget_title_default', + 'type' => 'string', + 'validationPattern' => '^.+$', + 'validationMessage' => 'backend::lang.dashboard.widget_title_error', + ] + ]; + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addCss('css/welcome.css', 'core'); + } + + protected function loadData() + { + $this->vars['user'] = $user = BackendAuth::getUser(); + $this->vars['appName'] = BrandSetting::get('app_name'); + $this->vars['lastSeen'] = AccessLog::getRecent($user); + } +} diff --git a/modules/backend/reportwidgets/welcome/assets/css/welcome.css b/modules/backend/reportwidgets/welcome/assets/css/welcome.css new file mode 100644 index 0000000..fde7854 --- /dev/null +++ b/modules/backend/reportwidgets/welcome/assets/css/welcome.css @@ -0,0 +1,33 @@ +.widget-welcome .welcome-container { + margin-top: -15px; + overflow: hidden; /* clearfix */ +} + +.widget-welcome .welcome-message { + margin-left: 220px; + color: #7e8c8d; + margin-top: 15px; +} +.widget-welcome .welcome-message strong { + color: #666; +} + +.widget-welcome .welcome-logo { + background: #f9f9f9; + width: 200px; + padding: 15px; + float: left; +} + +.widget-welcome .welcome-logo .oc-logo { + height: 80px; +} + +@media (max-width: 468px) { + .widget-welcome .welcome-logo { + float: none; + } + .widget-welcome .welcome-message { + margin-left: 0; + } +} diff --git a/modules/backend/reportwidgets/welcome/partials/_widget.htm b/modules/backend/reportwidgets/welcome/partials/_widget.htm new file mode 100644 index 0000000..743a2c2 --- /dev/null +++ b/modules/backend/reportwidgets/welcome/partials/_widget.htm @@ -0,0 +1,41 @@ +
    +

    property('title'))) ?>

    + + +
    + +
    + +

    + $appName, 'name'=>$user->first_name])) ?> + +

    +

    + created_at, ['formatAlias' => 'dateTimeLongMin']) ?> +

    + hasAccess('system.access_logs')): ?> +

    + +

    + + +

    + $appName, 'name'=>$user->first_name])) ?> +

    +

    + +

    +

    + +

    + +
    +
    + +
    +
    +
    + +
    diff --git a/modules/backend/routes.php b/modules/backend/routes.php new file mode 100644 index 0000000..0268f7e --- /dev/null +++ b/modules/backend/routes.php @@ -0,0 +1,49 @@ + ['web'], + 'prefix' => Config::get('cms.backendUri', 'backend') + ], function () { + Route::any('{slug?}', 'Backend\Classes\BackendController@run')->where('slug', '(.*)?'); + }) + ; + + /* + * Entry point + */ + Route::any(Config::get('cms.backendUri', 'backend'), 'Backend\Classes\BackendController@run')->middleware('web'); + + /** + * @event backend.route + * Fires after backend routes have been added + * + * Example usage: + * + * Event::listen('backend.route', function () { + * // your code here + * }); + * + */ + Event::fire('backend.route'); +}); diff --git a/modules/backend/skins/Standard.php b/modules/backend/skins/Standard.php new file mode 100644 index 0000000..c77cda3 --- /dev/null +++ b/modules/backend/skins/Standard.php @@ -0,0 +1,57 @@ +skinPath = $this->defaultSkinPath = base_path() . '/modules/backend'; + $this->publicSkinPath = $this->defaultPublicSkinPath = File::localToPublic($this->skinPath); + } + + /** + * @inheritDoc + */ + public function skinDetails() + { + return [ + 'name' => 'Default Skin' + ]; + } + + /** + * @inheritDoc + */ + public function getPath($path = null, $isPublic = false) + { + $path = RouterHelper::normalizeUrl($path); + + return $isPublic + ? $this->defaultPublicSkinPath . $path + : $this->defaultSkinPath . $path; + } + + /** + * @inheritDoc + */ + public function getLayoutPaths() + { + return [$this->skinPath.'/layouts']; + } +} diff --git a/modules/backend/traits/CollapsableWidget.php b/modules/backend/traits/CollapsableWidget.php new file mode 100644 index 0000000..3fd9078 --- /dev/null +++ b/modules/backend/traits/CollapsableWidget.php @@ -0,0 +1,129 @@ +setCollapseStatus(post('group'), post('status')); + } + + /** + * Returns the array of all collapsed states belonging to this widget. + * + * @return array + */ + protected function getCollapseStatuses() + { + if ($this->collapseGroupStatusCache !== false) { + return $this->collapseGroupStatusCache; + } + + $groups = $this->getSession($this->collapseSessionKey, []); + + if (!is_array($groups)) { + return $this->collapseGroupStatusCache = []; + } + + return $this->collapseGroupStatusCache = $groups; + } + + /** + * Sets a collapsed state. + * + * @param string $group + * @param string $status + */ + protected function setCollapseStatus($group, $status) + { + $statuses = $this->getCollapseStatuses(); + + $statuses[$group] = $status; + + $this->collapseGroupStatusCache = $statuses; + + $this->putSession($this->collapseSessionKey, $statuses); + } + + /** + * Gets a collapsed state. + * + * @param string $group + * @param bool $default + * @return bool|string + */ + protected function getCollapseStatus($group, $default = true) + { + $statuses = $this->getCollapseStatuses(); + + if (array_key_exists($group, $statuses)) { + return $statuses[$group]; + } + + return $default; + } + + // + // Deprecations, remove if year >= 2019 + // + + /** + * @deprecated onGroupStatusUpdate is deprecated. Please update onSetCollapseStatus instead. + */ + public function onGroupStatusUpdate() + { + traceLog('onGroupStatusUpdate is deprecated. Please update onSetCollapseStatus instead. Class: '.get_class($this)); + $this->onSetCollapseStatus(); + } + + /** + * @deprecated - getGroupStatuses is deprecated. Please update getCollapseStatuses instead. + */ + protected function getGroupStatuses() + { + traceLog('getGroupStatuses is deprecated. Please update getCollapseStatuses instead. Class: '.get_class($this)); + return $this->getCollapseStatuses(); + } + + /** + * @deprecated - setGroupStatus is deprecated. Please update setCollapseStatus instead. + */ + protected function setGroupStatus($group, $status) + { + traceLog('setGroupStatus is deprecated. Please update setCollapseStatus instead. Class: '.get_class($this)); + return $this->setCollapseStatus($group, $status); + } + + /** + * @deprecated - getGroupStatus is deprecated. Please update getCollapseStatus instead. + */ + protected function getGroupStatus($group, $default = true) + { + traceLog('getGroupStatus is deprecated. Please update getCollapseStatus instead. Class: '.get_class($this)); + return $this->getCollapseStatus($group, $default); + } +} diff --git a/modules/backend/traits/ErrorMaker.php b/modules/backend/traits/ErrorMaker.php new file mode 100644 index 0000000..3d807c7 --- /dev/null +++ b/modules/backend/traits/ErrorMaker.php @@ -0,0 +1,44 @@ +fatalError); + } + + /** + * @return string The fatal error message + */ + public function getFatalError() + { + return $this->fatalError; + } + + /** + * Sets standard page variables in the case of a controller error. + */ + public function handleError($exception) + { + $errorMessage = ErrorHandler::getDetailedMessage($exception); + $this->fatalError = $errorMessage; + $this->vars['fatalError'] = $errorMessage; + } +} diff --git a/modules/backend/traits/FormModelSaver.php b/modules/backend/traits/FormModelSaver.php new file mode 100644 index 0000000..221d900 --- /dev/null +++ b/modules/backend/traits/FormModelSaver.php @@ -0,0 +1,120 @@ +push()`. + * + * @package october\backend + * @author Alexey Bobkov, Samuel Georges + */ +trait FormModelSaver +{ + /** + * @var array List of prepared models that require saving. + */ + protected $modelsToSave = []; + + /** + * Takes a model and fills it with data from a multidimensional array. + * If an attribute is found to be a relationship, that relationship + * is also filled. + * + * $modelsToSave = $this->prepareModelsToSave($model, [...]); + * + * foreach ($modelsToSave as $modelToSave) { + * $modelToSave->save(); + * } + * + * @param \October\Rain\Database\Model $model Model to fill. + * @param array $saveData Attribute values to fill model. + * @return array The collection of models to save. + */ + protected function prepareModelsToSave($model, $saveData) + { + $this->modelsToSave = []; + $this->setModelAttributes($model, $saveData); + $this->modelsToSave = array_reverse($this->modelsToSave); + return $this->modelsToSave; + } + + /** + * Sets a data collection to a model attributes, relations are also set. + * + * @param \October\Rain\Database\Model $model Model to fill. + * @param array $saveData Attribute values to fill model. + * @return void + */ + protected function setModelAttributes($model, $saveData) + { + $this->modelsToSave[] = $model; + + if (!is_array($saveData)) { + return; + } + + if ($model instanceof HalcyonModel) { + $model->fill($saveData); + return; + } + + $attributesToPurge = []; + $singularTypes = ['belongsTo', 'hasOne', 'morphTo', 'morphOne']; + + foreach ($saveData as $attribute => $value) { + $isNested = $attribute == 'pivot' || ( + $model->hasRelation($attribute) && + in_array($model->getRelationType($attribute), $singularTypes) + ); + + if ($isNested && is_array($value)) { + $this->setModelAttributes($model->{$attribute}, $value); + } + elseif ($value !== FormField::NO_SAVE_DATA) { + if (Str::startsWith($attribute, '_')) { + $attributesToPurge[] = $attribute; + } + $model->{$attribute} = $value; + } + } + + if ($attributesToPurge) { + $this->deferPurgedSaveAttributes($model, $attributesToPurge); + } + } + + /** + * Removes an array of attributes from the model. If the model implements + * the Purgeable trait, this is preferred over the internal logic. + * + * @param \October\Rain\Database\Model $model Model to adjust. + * @param array $attributesToPurge Attribute values to remove from the model. + * @return void + */ + protected function deferPurgedSaveAttributes($model, $attributesToPurge) + { + if (!is_array($attributesToPurge)) { + return; + } + + /* + * Compatibility with Purgeable trait: + * This will give the ability to restore purged attributes + * and make them available again if necessary. + */ + if (method_exists($model, 'getPurgeableAttributes')) { + $model->addPurgeable($attributesToPurge); + } + else { + $model->bindEventOnce('model.saveInternal', function () use ($model, $attributesToPurge) { + foreach ($attributesToPurge as $attribute) { + unset($model->attributes[$attribute]); + } + }); + } + } +} diff --git a/modules/backend/traits/FormModelWidget.php b/modules/backend/traits/FormModelWidget.php new file mode 100644 index 0000000..0186301 --- /dev/null +++ b/modules/backend/traits/FormModelWidget.php @@ -0,0 +1,101 @@ +resolveModelAttribute($this->valueFrom); + * @param string $attribute. + * @return array + */ + public function resolveModelAttribute($attribute) + { + try { + return $this->formField->resolveModelAttribute($this->model, $attribute); + } + catch (Exception $ex) { + throw new ApplicationException(Lang::get('backend::lang.model.missing_relation', [ + 'class' => get_class($this->model), + 'relation' => $attribute + ])); + } + } + + /** + * Returns the model of a relation type, + * supports nesting via HTML array. + * @return Relation + */ + protected function getRelationModel() + { + list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom); + + if (!$model) { + throw new ApplicationException(Lang::get('backend::lang.model.missing_relation', [ + 'class' => get_class($this->model), + 'relation' => $this->valueFrom + ])); + } + + if (!$model->hasRelation($attribute)) { + throw new ApplicationException(Lang::get('backend::lang.model.missing_relation', [ + 'class' => get_class($model), + 'relation' => $attribute + ])); + } + + return $model->makeRelation($attribute); + } + + /** + * Returns the value as a relation object from the model, + * supports nesting via HTML array. + * @return Relation + */ + protected function getRelationObject() + { + list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom); + + if (!$model) { + throw new ApplicationException(Lang::get('backend::lang.model.missing_relation', [ + 'class' => get_class($this->model), + 'relation' => $this->valueFrom + ])); + } + + if (!$model->hasRelation($attribute)) { + throw new ApplicationException(Lang::get('backend::lang.model.missing_relation', [ + 'class' => get_class($model), + 'relation' => $attribute + ])); + } + + return $model->{$attribute}(); + } + + /** + * Returns the value as a relation type from the model, + * supports nesting via HTML array. + * @return Relation + */ + protected function getRelationType() + { + list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom); + return $model->getRelationType($attribute); + } +} diff --git a/modules/backend/traits/InspectableContainer.php b/modules/backend/traits/InspectableContainer.php new file mode 100644 index 0000000..39bf65b --- /dev/null +++ b/modules/backend/traits/InspectableContainer.php @@ -0,0 +1,73 @@ +flushAssets(); + + $property = trim(Request::input('inspectorProperty')); + if (!$property) { + throw new ApplicationException('The property name is not specified.'); + } + + $className = trim(Request::input('inspectorClassName')); + if (!$className) { + throw new ApplicationException('The inspectable class name is not specified.'); + } + + $traitFound = in_array('System\Traits\PropertyContainer', class_uses_recursive($className)); + if (!$traitFound) { + throw new ApplicationException('The options cannot be loaded for the specified class.'); + } + + $obj = new $className(null); + + // Nested properties have names like object.property. + // Convert them to Object.Property. + $propertyNameParts = explode('.', $property); + $propertyMethodName = ''; + foreach ($propertyNameParts as $part) { + $part = trim($part); + + if (!strlen($part)) { + continue; + } + + $propertyMethodName .= ucfirst($part); + } + + $methodName = 'get'.$propertyMethodName.'Options'; + if (method_exists($obj, $methodName)) { + $options = $obj->$methodName(); + } + else { + $options = $obj->getPropertyOptions($property); + } + + /* + * Convert to array to retain the sort order in JavaScript + */ + $optionsArray = []; + foreach ((array) $options as $value => $title) { + $optionsArray[] = ['value' => $value, 'title' => Lang::get($title)]; + } + + return [ + 'options' => $optionsArray + ]; + } +} diff --git a/modules/backend/traits/PreferenceMaker.php b/modules/backend/traits/PreferenceMaker.php new file mode 100644 index 0000000..7283290 --- /dev/null +++ b/modules/backend/traits/PreferenceMaker.php @@ -0,0 +1,139 @@ +getUserPreferences(); + $preferences[$key] = $value; + + $this->getPreferenceStorage()->set($this->getPreferenceKey(), $preferences); + + // Re-cache user preferences + self::$preferenceCache[$this->getPreferenceKey()] = $preferences; + } + + /** + * Retrieves a widget related key/value pair from the user preferences + * + * @param string $key Unique key for the data store. + * @param mixed $default A default value to use when value is not found. + * @return mixed + */ + public function getUserPreference(string $key = null, $default = null) + { + $preferences = $this->getUserPreferences(); + + return (isset($preferences[$key])) ? $preferences[$key] : $default; + } + + /** + * Retrieves and caches all user preferences for this particular controller/widget. + * + * @return array + */ + public function getUserPreferences() + { + if (isset(self::$preferenceCache[$this->getPreferenceKey()])) { + return self::$preferenceCache[$this->getPreferenceKey()]; + } + + $preferences = $this->getPreferenceStorage()->get($this->getPreferenceKey(), []); + + // Cache user preferences + self::$preferenceCache[$this->getPreferenceKey()] = $preferences; + + return $preferences; + } + + /** + * Clears a single preference key from the user preferences for this controller/widget. + * + * @param string $key Unique key for the data store. + * @return void + */ + public function clearUserPreference(string $key) + { + $preferences = $this->getUserPreferences(); + + if (!isset($preferences[$key])) { + return; + } + + unset($preferences[$key]); + + if (count($preferences)) { + $this->getPreferenceStorage()->set($this->getPreferenceKey(), $preferences); + + // Re-cache user preferences + self::$preferenceCache[$this->getPreferenceKey()] = $preferences; + } else { + // Remove record from user preferences + $this->clearUserPreferences(); + } + } + + /** + * Clears all user preferences for this controller/widget. + * + * @return void + */ + public function clearUserPreferences() + { + $this->getPreferenceStorage()->reset($this->getPreferenceKey()); + + self::$preferenceCache[$this->getPreferenceKey()] = []; + } + + /** + * Returns a unique identifier for this widget and controller action for preference storage. + * + * @return string + */ + protected function getPreferenceKey() + { + $controller = (property_exists($this, 'controller') && $this->controller) + ? $this->controller + : $this; + + $uniqueId = (method_exists($this, 'getId')) ? $this->getId() : $controller->getId(); + + // Removes Class name and "Controllers" directory + $rootNamespace = Str::getClassId(Str::getClassNamespace(Str::getClassNamespace($controller))); + + // The controller action is intentionally omitted, preferences should be shared for all actions + return $rootNamespace . '::' . strtolower(class_basename($controller)) . '.' . strtolower($uniqueId); + } + + /** + * Specifies the model used for storing the user preferences. + * + * @return October\Rain\Database\Model + */ + protected function getPreferenceStorage() + { + return UserPreference::forUser(); + } +} diff --git a/modules/backend/traits/SearchableWidget.php b/modules/backend/traits/SearchableWidget.php new file mode 100644 index 0000000..5c1866e --- /dev/null +++ b/modules/backend/traits/SearchableWidget.php @@ -0,0 +1,43 @@ +searchTerm !== false ? $this->searchTerm : $this->getSession('search'); + } + + protected function setSearchTerm($term) + { + $this->searchTerm = trim($term); + $this->putSession('search', $this->searchTerm); + } + + protected function textMatchesSearch(&$words, $text) + { + foreach ($words as $word) { + $word = trim($word); + if (!strlen($word)) { + continue; + } + + if (Str::contains(Str::lower($text), $word)) { + return true; + } + } + + return false; + } +} diff --git a/modules/backend/traits/SelectableWidget.php b/modules/backend/traits/SelectableWidget.php new file mode 100644 index 0000000..78e76af --- /dev/null +++ b/modules/backend/traits/SelectableWidget.php @@ -0,0 +1,69 @@ +extendSelection(); + } + + protected function getSelectedItems() + { + if ($this->selectedItemsCache !== false) { + return $this->selectedItemsCache; + } + + $items = $this->getSession('selected', []); + if (!is_array($items)) { + return $this->selectedItemsCache = []; + } + + return $this->selectedItemsCache = $items; + } + + protected function extendSelection() + { + $items = (array) Input::get($this->selectionInputName, []); + $currentSelection = $this->getSelectedItems(); + + $this->putSession('selected', $currentSelection + $items); + } + + protected function resetSelection() + { + $this->putSession('selected', []); + } + + protected function removeSelection($itemId) + { + $currentSelection = $this->getSelectedItems(); + + unset($currentSelection[$itemId]); + $this->putSession('selected', $currentSelection); + $this->selectedItemsCache = $currentSelection; + } + + protected function isItemSelected($itemId) + { + $selectedItems = $this->getSelectedItems(); + if (!is_array($selectedItems) || !isset($selectedItems[$itemId])) { + return false; + } + + return $selectedItems[$itemId]; + } +} diff --git a/modules/backend/traits/SessionMaker.php b/modules/backend/traits/SessionMaker.php new file mode 100644 index 0000000..9483c2e --- /dev/null +++ b/modules/backend/traits/SessionMaker.php @@ -0,0 +1,89 @@ +makeSessionId(); + + $currentStore = $this->getSession(); + + $currentStore[$key] = $value; + + Session::put($sessionId, base64_encode(serialize($currentStore))); + } + + /** + * Retrieves a widget related key/value pair from session data. + * @param string $key Unique key for the data store. + * @param string $default A default value to use when value is not found. + * @return string + */ + protected function getSession($key = null, $default = null) + { + $sessionId = $this->makeSessionId(); + + $currentStore = []; + + if ( + Session::has($sessionId) && + ($cached = @unserialize(@base64_decode(Session::get($sessionId)))) !== false + ) { + $currentStore = $cached; + } + + if ($key === null) { + return $currentStore; + } + + return $currentStore[$key] ?? $default; + } + + /** + * Returns a unique session identifier for this widget and controller action. + * @return string + */ + protected function makeSessionId() + { + $controller = property_exists($this, 'controller') && $this->controller + ? $this->controller + : $this; + + $uniqueId = method_exists($this, 'getId') ? $this->getId() : $controller->getId(); + + // Removes Class name and "Controllers" directory + $rootNamespace = Str::getClassId(Str::getClassNamespace(Str::getClassNamespace($controller))); + + // The controller action is intentionally omitted, session should be shared for all actions + return 'widget.' . $rootNamespace . '-' . class_basename($controller) . '-' . $uniqueId; + } + + /** + * Resets all session data related to this widget. + * @return void + */ + public function resetSession() + { + $sessionId = $this->makeSessionId(); + + Session::forget($sessionId); + } +} diff --git a/modules/backend/traits/UploadableWidget.php b/modules/backend/traits/UploadableWidget.php new file mode 100644 index 0000000..d1895d8 --- /dev/null +++ b/modules/backend/traits/UploadableWidget.php @@ -0,0 +1,188 @@ +readOnly) { + return; + } + + try { + if (!Request::hasFile('file_data')) { + throw new ApplicationException('File missing from request'); + } + + $uploadedFile = Request::file('file_data'); + + $fileName = $uploadedFile->getClientOriginalName(); + + /* + * Convert uppcare case file extensions to lower case + */ + $extension = strtolower($uploadedFile->getClientOriginalExtension()); + $fileName = File::name($fileName).'.'.$extension; + + /* + * File name contains non-latin characters, attempt to slug the value + */ + if (!$this->validateFileName($fileName)) { + $fileNameClean = $this->cleanFileName(File::name($fileName)); + $fileName = $fileNameClean . '.' . $extension; + } + + /* + * Check for unsafe file extensions + */ + if (!$this->validateFileType($fileName)) { + throw new ApplicationException(Lang::get('backend::lang.media.type_blocked')); + } + + /* + * See mime type handling in the asset manager + */ + if (!$uploadedFile->isValid()) { + if ($uploadedFile->getError() === UPLOAD_ERR_OK) { + $message = "The file \"{$uploadedFile->getClientOriginalName()}\" uploaded successfully but wasn't available at {$uploadedFile->getPathName()}. Check to make sure that nothing moved it away."; + } else { + $message = $uploadedFile->getErrorMessage(); + } + throw new ApplicationException($message); + } + + // Use the configured upload path unless it's null, in which case use the user-provided path + $path = !empty($this->uploadPath) ? $this->uploadPath : Request::input('path'); + $path = MediaLibrary::validatePath($path); + $filePath = $path . '/' . $fileName; + + /* + * getRealPath() can be empty for some environments (IIS) + */ + $realPath = empty(trim($uploadedFile->getRealPath())) + ? $uploadedFile->getPath() . DIRECTORY_SEPARATOR . $uploadedFile->getFileName() + : $uploadedFile->getRealPath(); + + MediaLibrary::instance()->put( + $filePath, + File::get($realPath) + ); + + /** + * @event media.file.upload + * Called after a file is uploaded + * + * Example usage: + * + * Event::listen('media.file.upload', function ((\Backend\Widgets\MediaManager) $mediaWidget, (string) &$path, (\Symfony\Component\HttpFoundation\File\UploadedFile) $uploadedFile) { + * \Log::info($path . " was upoaded."); + * }); + * + * Or + * + * $mediaWidget->bindEvent('file.upload', function ((string) &$path, (\Symfony\Component\HttpFoundation\File\UploadedFile) $uploadedFile) { + * \Log::info($path . " was uploaded"); + * }); + * + */ + $this->fireSystemEvent('media.file.upload', [&$filePath, $uploadedFile]); + + $response = Response::make([ + 'link' => MediaLibrary::url($filePath), + 'result' => 'success' + ]); + } catch (\Exception $ex) { + throw new ApplicationException($ex->getMessage()); + } + + return $response; + } + + /** + * Validate a proposed media item file name. + * + * @param string + * @return bool + */ + protected function validateFileName($name) + { + if (!preg_match('/^[\w@\.\s_\-]+$/iu', $name)) { + return false; + } + + if (strpos($name, '..') !== false) { + return false; + } + + return true; + } + + /** + * Check for blocked / unsafe file extensions + * + * @param string + * @return bool + */ + protected function validateFileType($name) + { + $extension = strtolower(File::extension($name)); + + $allowedFileTypes = FileDefinitions::get('defaultExtensions'); + + if (!in_array($extension, $allowedFileTypes)) { + return false; + } + + return true; + } + + /** + * Creates a slug form the string. A modified version of Str::slug + * with the main difference that it accepts @-signs + * + * @param string $name + * @return string + */ + protected function cleanFileName($name) + { + $title = Str::ascii($name); + + // Convert all dashes/underscores into separator + $flip = $separator = '-'; + $title = preg_replace('!['.preg_quote($flip).']+!u', $separator, $title); + + // Remove all characters that are not the separator, letters, numbers, whitespace or @. + $title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s@]+!u', '', mb_strtolower($title)); + + // Replace all separator characters and whitespace by a single separator + $title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title); + + return trim($title, $separator); + } +} diff --git a/modules/backend/traits/WidgetMaker.php b/modules/backend/traits/WidgetMaker.php new file mode 100644 index 0000000..a26a8ab --- /dev/null +++ b/modules/backend/traits/WidgetMaker.php @@ -0,0 +1,75 @@ +controller + ? $this->controller + : $this; + + if (!class_exists($class)) { + throw new SystemException(Lang::get('backend::lang.widget.not_registered', [ + 'name' => $class + ])); + } + + return new $class($controller, $widgetConfig); + } + + /** + * Makes a form widget object with the supplied form field and widget configuration. + * @param string $class Widget class name + * @param mixed $fieldConfig A field name, an array of config or a FormField object. + * @param array $widgetConfig An array of config. + * @return \Backend\Classes\FormWidgetBase The widget object + */ + public function makeFormWidget($class, $fieldConfig = [], $widgetConfig = []) + { + $controller = property_exists($this, 'controller') && $this->controller + ? $this->controller + : $this; + + if (!class_exists($class)) { + throw new SystemException(Lang::get('backend::lang.widget.not_registered', [ + 'name' => $class + ])); + } + + if (is_string($fieldConfig)) { + $fieldConfig = ['name' => $fieldConfig]; + } + + if (is_array($fieldConfig)) { + $formField = new FormField( + array_get($fieldConfig, 'name'), + array_get($fieldConfig, 'label') + ); + $formField->displayAs('widget', $fieldConfig); + } + else { + $formField = $fieldConfig; + } + + return new $class($controller, $formField, $widgetConfig); + } +} diff --git a/modules/backend/views/404.php b/modules/backend/views/404.php new file mode 100644 index 0000000..73951c5 --- /dev/null +++ b/modules/backend/views/404.php @@ -0,0 +1,19 @@ + + + + + <?= Lang::get('backend::lang.page.404.label') ?> + + + +
    +

    +
    +

    +

    current()); ?>

    + +

    + +
    + + diff --git a/modules/backend/views/access_denied.php b/modules/backend/views/access_denied.php new file mode 100644 index 0000000..988424c --- /dev/null +++ b/modules/backend/views/access_denied.php @@ -0,0 +1,17 @@ + + + + + <?= Lang::get('backend::lang.page.access_denied.label') ?> + + + +
    +

    +

    + +

    + +
    + + diff --git a/modules/backend/views/mail/invite.htm b/modules/backend/views/mail/invite.htm new file mode 100644 index 0000000..da43549 --- /dev/null +++ b/modules/backend/views/mail/invite.htm @@ -0,0 +1,20 @@ +subject = "Welcome to {{ appName | raw }}" +layout = "system" +description = "Invite new admin to the site" +== +Hi {{ name }} + +A user account has been created for you on **{{ appName }}**. + +{% partial 'panel' body %} +- Login: `{{ login ?: 'sample' }}` +- Password: `{{ (password ?: '********') | raw }}` +{% endpartial %} + +You can use the following link to sign in: + +{% partial 'button' url=link body %} + Sign in to admin area +{% endpartial %} + +After signing in you should change your password by clicking your name on the top right corner of the administration area. diff --git a/modules/backend/views/mail/restore.htm b/modules/backend/views/mail/restore.htm new file mode 100644 index 0000000..1aa3be1 --- /dev/null +++ b/modules/backend/views/mail/restore.htm @@ -0,0 +1,13 @@ +subject = "Password Reset" +layout = "system" +description = "Reset an admin password" +== +Hello {{ name }} + +Somebody has requested a password reset for your account, if this was not you, please ignore this email. + +You can use the following link to restore your password: + +{% partial 'button' url=link type='positive' body %} +Restore password +{% endpartial %} diff --git a/modules/backend/views/no_database.php b/modules/backend/views/no_database.php new file mode 100644 index 0000000..3100d1b --- /dev/null +++ b/modules/backend/views/no_database.php @@ -0,0 +1,15 @@ + + + + + <?= Lang::get('backend::lang.page.no_database.label') ?> + + + +
    +

    +

    + +
    + + diff --git a/modules/backend/widgets/Filter.php b/modules/backend/widgets/Filter.php new file mode 100644 index 0000000..078afca --- /dev/null +++ b/modules/backend/widgets/Filter.php @@ -0,0 +1,1090 @@ +fillFromConfig([ + 'scopes', + 'context', + ]); + } + + /** + * Renders the widget. + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('filter'); + } + + /** + * Prepares the view data + */ + public function prepareVars() + { + $this->defineFilterScopes(); + $this->vars['cssClasses'] = implode(' ', $this->cssClasses); + $this->vars['scopes'] = $this->allScopes; + } + + /** + * Renders the HTML element for a scope + */ + public function renderScopeElement($scope) + { + $params = ['scope' => $scope]; + + switch ($scope->type) { + case 'date': + if ($scope->value && $scope->value instanceof Carbon) { + $params['dateStr'] = Backend::dateTime($scope->value, ['formatAlias' => 'dateMin']); + $params['date'] = $scope->value->format('Y-m-d H:i:s'); + } + + break; + case 'daterange': + if ($scope->value && is_array($scope->value) && count($scope->value) === 2 && + $scope->value[0] && $scope->value[0] instanceof Carbon && + $scope->value[1] && $scope->value[1] instanceof Carbon + ) { + $after = $scope->value[0]->format('Y-m-d H:i:s'); + $before = $scope->value[1]->format('Y-m-d H:i:s'); + + if (strcasecmp($after, self::DEFAULT_AFTER_DATE) > 0) { + $params['afterStr'] = Backend::dateTime($scope->value[0], ['formatAlias' => 'dateMin']); + $params['after'] = $after; + } + else { + $params['afterStr'] = '∞'; + $params['after'] = null; + } + + if (strcasecmp($before, self::DEFAULT_BEFORE_DATE) < 0) { + $params['beforeStr'] = Backend::dateTime($scope->value[1], ['formatAlias' => 'dateMin']); + $params['before'] = $before; + } + else { + $params['beforeStr'] = '∞'; + $params['before'] = null; + } + } + + break; + case 'number': + if (is_numeric($scope->value)) { + $params['number'] = $scope->value; + } + + break; + + case 'numberrange': + if ( + $scope->value + && (is_array($scope->value) && count($scope->value) === 2) + && (isset($scope->value[0]) || isset($scope->value[1])) + ) { + $min = $scope->value[0]; + $max = $scope->value[1]; + + $params['minStr'] = $min ?? '-∞'; + $params['min'] = $min ?? null; + + $params['maxStr'] = $max ?? '∞'; + $params['max'] = $max ?? null; + } + + break; + + case 'text': + $params['value'] = $scope->value; + $params['size'] = array_get($scope->config, 'size', 10); + + break; + } + + return $this->makePartial('scope_'.$scope->type, $params); + } + + /** + * Returns a HTML encoded value containing the other scopes this scope depends on + * @param \Backend\Classes\FilterScope $scope + * @return string + */ + protected function getScopeDepends($scope) + { + if (!$scope->dependsOn) { + return ''; + } + + $dependsOn = is_array($scope->dependsOn) ? $scope->dependsOn : [$scope->dependsOn]; + $dependsOn = htmlspecialchars(json_encode($dependsOn), ENT_QUOTES, 'UTF-8'); + return $dependsOn; + } + + // + // AJAX + // + + /** + * Update a filter scope value. + * @return array + */ + public function onFilterUpdate() + { + $this->defineFilterScopes(); + + if (!$scope = post('scopeName')) { + return; + } + + $scope = $this->getScope($scope); + + switch ($scope->type) { + case 'group': + $data = json_decode(post('options'), true); + $active = $this->optionsFromAjax($data ?: null); + $this->setScopeValue($scope, $active); + break; + + case 'checkbox': + $checked = post('value') == 'true'; + $this->setScopeValue($scope, $checked); + break; + + case 'switch': + $value = post('value'); + $this->setScopeValue($scope, $value); + break; + + case 'date': + $data = json_decode(post('options'), true); + $dates = $this->datesFromAjax($data['dates'] ?? null); + + if (!empty($dates)) { + list($date) = $dates; + } + else { + $date = null; + } + + $this->setScopeValue($scope, $date); + break; + + case 'daterange': + $data = json_decode(post('options'), true); + $dates = $this->datesFromAjax($data['dates'] ?? null); + + if (!empty($dates)) { + list($after, $before) = $dates; + + $dates = [$after, $before]; + } + else { + $dates = null; + } + + $this->setScopeValue($scope, $dates); + break; + + case 'number': + $data = json_decode(post('options'), true); + $numbers = $this->numbersFromAjax($data['numbers'] ?? null); + + if (!empty($numbers)) { + list($number) = $numbers; + } + else { + $number = null; + } + + $this->setScopeValue($scope, $number); + break; + + case 'numberrange': + $data = json_decode(post('options'), true); + $numbers = $this->numbersFromAjax($data['numbers'] ?? null); + + if (!empty($numbers)) { + list($min, $max) = $numbers; + + $numbers = [$min, $max]; + } + else { + $numbers = null; + } + + $this->setScopeValue($scope, $numbers); + break; + + case 'text': + $value = post('options.value.' . $scope->scopeName) ?: null; + $this->setScopeValue($scope, $value); + break; + } + + /* + * Trigger class event, merge results as viewable array + */ + $params = func_get_args(); + + $result = $this->fireEvent('filter.update', [$params]); + + if ($result && is_array($result)) { + return call_user_func_array('array_merge', $result); + } + } + + /** + * Returns available options for group scope type. + * @return array + */ + public function onFilterGetOptions() + { + $this->defineFilterScopes(); + + $searchQuery = post('search'); + if (!$scopeName = post('scopeName')) { + return; + } + + $scope = $this->getScope($scopeName); + $activeKeys = $scope->value ? array_keys($scope->value) : []; + $available = $this->getAvailableOptions($scope, $searchQuery); + $active = $searchQuery ? [] : $this->filterActiveOptions($activeKeys, $available); + + return [ + 'scopeName' => $scopeName, + 'options' => [ + 'available' => $this->optionsToAjax($available), + 'active' => $this->optionsToAjax($active), + ] + ]; + } + + // + // Internals + // + + /** + * Returns the available options a scope can use, either from the + * model relation or from a supplied array. Optionally apply a search + * constraint to the options. + * @param string $scope + * @param string $searchQuery + * @return array + */ + protected function getAvailableOptions($scope, $searchQuery = null) + { + if ($scope->options) { + return $this->getOptionsFromArray($scope, $searchQuery); + } + + $available = []; + $nameColumn = $this->getScopeNameFrom($scope); + $options = $this->getOptionsFromModel($scope, $searchQuery); + foreach ($options as $option) { + $available[$option->getKey()] = $option->{$nameColumn}; + } + + return $available; + } + + /** + * Removes any already selected options from the available options, returns + * a newly built array. + * @param array $activeKeys + * @param array $availableOptions + * @return array + */ + protected function filterActiveOptions(array $activeKeys, array &$availableOptions) + { + $active = []; + foreach ($availableOptions as $id => $option) { + if (!in_array($id, $activeKeys)) { + continue; + } + + $active[$id] = $option; + unset($availableOptions[$id]); + } + + return $active; + } + + /** + * Looks at the model for defined scope items. + * @return Collection + */ + protected function getOptionsFromModel($scope, $searchQuery = null) + { + $model = $this->scopeModels[$scope->scopeName]; + + $query = $model->newQuery(); + + $query->limit(200); + + /** + * @event backend.filter.extendQuery + * Provides an opportunity to extend the query of the list of options + * + * Example usage: + * + * Event::listen('backend.filter.extendQuery', function ((\Backend\Widgets\Filter) $filterWidget, $query, (\Backend\Classes\FilterScope) $scope) { + * if ($scope->scopeName == 'status') { + * $query->where('status', '<>', 'all'); + * } + * }); + * + * Or + * + * $listWidget->bindEvent('filter.extendQuery', function ($query, (\Backend\Classes\FilterScope) $scope) { + * if ($scope->scopeName == 'status') { + * $query->where('status', '<>', 'all'); + * } + * }); + * + */ + $this->fireSystemEvent('backend.filter.extendQuery', [$query, $scope]); + + if (!$searchQuery) { + // If scope has active filter(s) run additional query and merge it with base query + if ($scope->value) { + $modelIds = array_keys($scope->value); + $activeOptions = $model::findMany($modelIds); + } + + $modelOptions = isset($activeOptions) + ? $query->get()->merge($activeOptions) + : $query->get(); + + return $modelOptions; + } + + $searchFields = [$model->getKeyName(), $this->getScopeNameFrom($scope)]; + return $query->searchWhere($searchQuery, $searchFields)->get(); + } + + /** + * Look at the defined set of options for scope items, or the model method. + * @return array + */ + protected function getOptionsFromArray($scope, $searchQuery = null) + { + /* + * Load the data + */ + $options = $scope->options; + + if (is_scalar($options)) { + $model = $this->scopeModels[$scope->scopeName]; + $methodName = $options; + + if (!$model->methodExists($methodName)) { + throw new ApplicationException(Lang::get('backend::lang.filter.options_method_not_exists', [ + 'model' => get_class($model), + 'method' => $methodName, + 'filter' => $scope->scopeName + ])); + } + + if (!empty($scope->dependsOn)) { + $options = $model->$methodName($this->getScopes()); + } else { + $options = $model->$methodName(); + } + } + elseif (!is_array($options)) { + $options = []; + } + + /* + * Apply the search + */ + $searchQuery = Str::lower($searchQuery); + if (strlen($searchQuery)) { + $options = $this->filterOptionsBySearch($options, $searchQuery); + } + + return $options; + } + + /** + * Filters an array of options by a search term. + * @param array $options + * @param string $query + * @return array + */ + protected function filterOptionsBySearch($options, $query) + { + $filteredOptions = []; + + $optionMatchesSearch = function ($words, $option) { + foreach ($words as $word) { + $word = trim($word); + if (!strlen($word)) { + continue; + } + + if (!Str::contains(Str::lower($option), $word)) { + return false; + } + } + + return true; + }; + + /* + * Exact + */ + foreach ($options as $index => $option) { + if (Str::is(Str::lower($option), $query)) { + $filteredOptions[$index] = $option; + unset($options[$index]); + } + } + + /* + * Fuzzy + */ + $words = explode(' ', $query); + foreach ($options as $index => $option) { + if ($optionMatchesSearch($words, $option)) { + $filteredOptions[$index] = $option; + } + } + + return $filteredOptions; + } + + /** + * Creates a flat array of filter scopes from the configuration. + */ + protected function defineFilterScopes() + { + if ($this->scopesDefined) { + return; + } + + /** + * @event backend.filter.extendScopesBefore + * Provides an opportunity to interact with the Filter widget before defining the filter scopes + * + * Example usage: + * + * Event::listen('backend.filter.extendScopesBefore', function ((\Backend\Widgets\Filter) $filterWidget) { + * // Just in case you really had to do something before scopes are defined + * }); + * + * Or + * + * $listWidget->bindEvent('filter.extendScopesBefore', function () use ((\Backend\Widgets\Filter) $filterWidget) { + * // Just in case you really had to do something before scopes are defined + * }); + * + */ + $this->fireSystemEvent('backend.filter.extendScopesBefore'); + + /* + * All scopes + */ + if (!isset($this->scopes) || !is_array($this->scopes)) { + $this->scopes = []; + } + + $this->addScopes($this->scopes); + + /** + * @event backend.filter.extendScopes + * Provides an opportunity to interact with the Filter widget & its scopes after the filter scopes have been initialized + * + * Example usage: + * + * Event::listen('backend.filter.extendScopes', function ((\Backend\Widgets\Filter) $filterWidget) { + * $filterWidget->addScopes([ + * 'my_scope' => [ + * 'label' => 'My Filter Scope' + * ] + * ]); + * }); + * + * Or + * + * $listWidget->bindEvent('filter.extendScopes', function () use ((\Backend\Widgets\Filter) $filterWidget) { + * $filterWidget->removeScope('my_scope'); + * }); + * + */ + $this->fireSystemEvent('backend.filter.extendScopes'); + + $this->scopesDefined = true; + } + + /** + * Programatically add scopes, used internally and for extensibility. + */ + public function addScopes(array $scopes) + { + foreach ($scopes as $name => $config) { + /* + * Check if user has permissions to show this filter + */ + $permissions = array_get($config, 'permissions'); + if (!empty($permissions) && !BackendAuth::getUser()->hasAccess($permissions, false)) { + continue; + } + + $scopeObj = $this->makeFilterScope($name, $config); + + /* + * Check that the filter scope matches the active context + */ + if ($scopeObj->context !== null) { + $context = is_array($scopeObj->context) ? $scopeObj->context : [$scopeObj->context]; + if (!in_array($this->getContext(), $context)) { + continue; + } + } + + /* + * Validate scope model + */ + if (isset($config['modelClass'])) { + $class = $config['modelClass']; + $model = new $class; + $this->scopeModels[$name] = $model; + } + + /* + * Ensure scope type options are set + */ + $scopeProperties = []; + switch ($scopeObj->type) { + case 'date': + case 'daterange': + $scopeProperties = [ + 'minDate' => '2000-01-01', + 'maxDate' => '2099-12-31', + 'firstDay' => 0, + 'yearRange' => 10, + 'ignoreTimezone' => false, + ]; + + break; + } + + foreach ($scopeProperties as $property => $value) { + if (isset($config[$property])) { + $value = $config[$property]; + } + + $scopeObj->{$property} = $value; + } + + $this->allScopes[$name] = $scopeObj; + } + } + + /** + * Programatically remove a scope, used for extensibility. + * @param string $scopeName Scope name + */ + public function removeScope($scopeName) + { + if (isset($this->allScopes[$scopeName])) { + unset($this->allScopes[$scopeName]); + } + } + + /** + * Creates a filter scope object from name and configuration. + */ + protected function makeFilterScope($name, $config) + { + $label = $config['label'] ?? null; + $scopeType = $config['type'] ?? null; + + $scope = new FilterScope($name, $label); + $scope->displayAs($scopeType, $config); + $scope->idPrefix = $this->alias; + + /* + * Set scope value + */ + $scope->value = $this->getScopeValue($scope, @$config['default']); + + return $scope; + } + + // + // Filter query logic + // + + /** + * Applies all scopes to a DB query. + * @param Builder $query + * @return Builder + */ + public function applyAllScopesToQuery($query) + { + $this->defineFilterScopes(); + + foreach ($this->allScopes as $scope) { + // Ensure that only valid values are set scopes of type: group + if ($scope->type === 'group') { + $activeKeys = $scope->value ? array_keys($scope->value) : []; + $available = $this->getAvailableOptions($scope); + $active = $this->filterActiveOptions($activeKeys, $available); + $value = !empty($active) ? $active : null; + $this->setScopeValue($scope, $value); + } + + $this->applyScopeToQuery($scope, $query); + } + + return $query; + } + + /** + * Applies a filter scope constraints to a DB query. + * @param string $scope + * @param Builder $query + * @return Builder + */ + public function applyScopeToQuery($scope, $query) + { + if (is_string($scope)) { + $scope = $this->getScope($scope); + } + + if (!$scope->value) { + return; + } + + switch ($scope->type) { + case 'date': + if ($scope->value instanceof Carbon) { + $value = $scope->value; + + /* + * Condition + */ + if ($scopeConditions = $scope->conditions) { + $query->whereRaw(DbDongle::parse(strtr($scopeConditions, [ + ':filtered' => $value->format('Y-m-d'), + ':after' => $value->format('Y-m-d H:i:s'), + ':before' => $value->copy()->addDay()->addMinutes(-1)->format('Y-m-d H:i:s') + ]))); + } + /* + * Scope + */ + elseif ($scopeMethod = $scope->scope) { + $query->$scopeMethod($value); + } + } + + break; + + case 'daterange': + if (is_array($scope->value) && count($scope->value) > 1) { + list($after, $before) = array_values($scope->value); + + if ($after && $after instanceof Carbon && $before && $before instanceof Carbon) { + /* + * Condition + */ + if ($scopeConditions = $scope->conditions) { + $query->whereRaw(DbDongle::parse(strtr($scopeConditions, [ + ':afterDate' => $after->format('Y-m-d'), + ':after' => $after->format('Y-m-d H:i:s'), + ':beforeDate' => $before->format('Y-m-d'), + ':before' => $before->format('Y-m-d H:i:s') + ]))); + } + /* + * Scope + */ + elseif ($scopeMethod = $scope->scope) { + $query->$scopeMethod($after, $before); + } + } + } + + break; + + case 'number': + if (is_numeric($scope->value)) { + /* + * Condition + */ + if ($scopeConditions = $scope->conditions) { + $query->whereRaw(DbDongle::parse(strtr($scopeConditions, [ + ':filtered' => $scope->value, + ]))); + } + /* + * Scope + */ + elseif ($scopeMethod = $scope->scope) { + $query->$scopeMethod($scope->value); + } + } + + break; + + case 'numberrange': + if (is_array($scope->value) && count($scope->value) > 1) { + list($min, $max) = array_values($scope->value); + + if (isset($min) || isset($max)) { + /* + * Condition + */ + if ($scopeConditions = $scope->conditions) { + $query->whereRaw(DbDongle::parse(strtr($scopeConditions, [ + ':min' => $min === null ? -2147483647 : $min, + ':max' => $max === null ? 2147483647 : $max + ]))); + } + /* + * Scope + */ + elseif ($scopeMethod = $scope->scope) { + $query->$scopeMethod($min, $max); + } + } + } + + break; + + case 'text': + /* + * Condition + */ + if ($scopeConditions = $scope->conditions) { + $query->whereRaw(DbDongle::parse(strtr($scopeConditions, [ + ':value' => Db::getPdo()->quote($scope->value), + ]))); + } + + /* + * Scope + */ + elseif ($scopeMethod = $scope->scope) { + $query->$scopeMethod($scope->value); + } + + break; + + default: + $value = is_array($scope->value) ? array_keys($scope->value) : $scope->value; + + if (empty($value)) { + break; + } + + /* + * Condition + */ + if ($scopeConditions = $scope->conditions) { + /* + * Switch scope: multiple conditions, value either 1 or 2 + */ + if (is_array($scopeConditions)) { + $conditionNum = is_array($value) ? 0 : $value - 1; + list($scopeConditions) = array_slice($scopeConditions, $conditionNum); + } + + if (is_array($value)) { + $filtered = implode(',', array_build($value, function ($key, $_value) { + return [$key, Db::getPdo()->quote($_value)]; + })); + } + else { + $filtered = Db::getPdo()->quote($value); + } + + $query->whereRaw(DbDongle::parse(strtr($scopeConditions, [':filtered' => $filtered]))); + } + /* + * Scope + */ + elseif ($scopeMethod = $scope->scope) { + $query->$scopeMethod($value); + } + + break; + } + + return $query; + } + + // + // Access layer + // + + /** + * Returns a scope value for this widget instance. + */ + public function getScopeValue($scope, $default = null) + { + if (is_string($scope)) { + $scope = $this->getScope($scope); + } + + $cacheKey = 'scope-'.$scope->scopeName; + return $this->getSession($cacheKey, $default); + } + + /** + * Sets an scope value for this widget instance. + */ + public function setScopeValue($scope, $value) + { + if (is_string($scope)) { + $scope = $this->getScope($scope); + } + + $cacheKey = 'scope-'.$scope->scopeName; + $this->putSession($cacheKey, $value); + + $scope->value = $value; + } + + /** + * Get all the registered scopes for the instance. + * @return array + */ + public function getScopes() + { + return $this->allScopes; + } + + /** + * Get a specified scope object + * @param string $scope + * @return mixed + */ + public function getScope($scope) + { + if (!isset($this->allScopes[$scope])) { + throw new ApplicationException('No definition for scope ' . $scope); + } + + return $this->allScopes[$scope]; + } + + /** + * Returns the display name column for a scope. + * @param string $scope + * @return string + */ + public function getScopeNameFrom($scope) + { + if (is_string($scope)) { + $scope = $this->getScope($scope); + } + + return $scope->nameFrom; + } + + /** + * Returns the active context for displaying the filter. + * @return string + */ + public function getContext() + { + return $this->context; + } + + // + // Helpers + // + + /** + * Convert a key/pair array to a named array {id: 1, name: 'Foobar'} + * @param array $options + * @return array + */ + protected function optionsToAjax($options) + { + $processed = []; + foreach ($options as $id => $result) { + $processed[] = ['id' => $id, 'name' => trans($result)]; + } + return $processed; + } + + /** + * Convert a named array to a key/pair array + * @param array $options + * @return array + */ + protected function optionsFromAjax($options) + { + $processed = []; + if (!is_array($options)) { + return $processed; + } + + foreach ($options as $option) { + $id = array_get($option, 'id'); + if ($id === null) { + continue; + } + $processed[$id] = array_get($option, 'name'); + } + return $processed; + } + + /** + * Convert an array from the posted dates + * + * @param array $dates + * + * @return array + */ + protected function datesFromAjax($ajaxDates) + { + $dates = []; + $dateRegex = '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/'; + + if (null !== $ajaxDates) { + if (!is_array($ajaxDates)) { + if (preg_match($dateRegex, $ajaxDates)) { + $dates = [$ajaxDates]; + } + } else { + foreach ($ajaxDates as $i => $date) { + if (preg_match($dateRegex, $date)) { + $dates[] = Carbon::createFromFormat('Y-m-d H:i:s', $date); + } elseif (empty($date)) { + if ($i == 0) { + $dates[] = Carbon::createFromFormat('Y-m-d H:i:s', self::DEFAULT_AFTER_DATE); + } else { + $dates[] = Carbon::createFromFormat('Y-m-d H:i:s', self::DEFAULT_BEFORE_DATE); + } + } else { + $dates = []; + break; + } + } + } + } + return $dates; + } + + /** + * Convert an array from the posted numbers + * + * @param array $dates + * + * @return array + */ + protected function numbersFromAjax($ajaxNumbers) + { + $numbers = []; + $numberRegex = '/\d/'; + + if (!empty($ajaxNumbers)) { + if (!is_array($ajaxNumbers) && preg_match($numberRegex, $ajaxNumbers)) { + $numbers = [$ajaxNumbers]; + } else { + foreach ($ajaxNumbers as $i => $number) { + if (preg_match($numberRegex, $number)) { + $numbers[] = $number; + } else { + $numbers[] = null; + } + } + } + } + + return $numbers; + } + + /** + * @param mixed $scope + * + * @return string + */ + protected function getFilterDateFormat($scope) + { + if (isset($scope->date_format)) { + return $scope->date_format; + } + + return trans('backend::lang.filter.date.format'); + } +} diff --git a/modules/backend/widgets/Form.php b/modules/backend/widgets/Form.php new file mode 100644 index 0000000..07898e5 --- /dev/null +++ b/modules/backend/widgets/Form.php @@ -0,0 +1,1468 @@ + + */ + public $arrayName; + + /** + * @var bool Used to flag that this form is being rendered as part of another form, + * a good indicator to expect that the form model and dataset values will differ. + */ + public $isNested = false; + + // + // Object properties + // + + /** + * @inheritDoc + */ + protected $defaultAlias = 'form'; + + /** + * @var boolean Determines if field definitions have been created. + */ + protected $fieldsDefined = false; + + /** + * @var array Collection of all fields used in this form. + * @see Backend\Classes\FormField + */ + protected $allFields = []; + + /** + * @var object Collection of tab sections used in this form. + * @see Backend\Classes\FormTabs + */ + protected $allTabs = [ + 'outside' => null, + 'primary' => null, + 'secondary' => null, + ]; + + /** + * @var array Collection of all form widgets used in this form. + */ + protected $formWidgets = []; + + /** + * @var string Active session key, used for editing forms and deferred bindings. + */ + public $sessionKey; + + /** + * @var bool Render this form with uneditable preview data. + */ + public $previewMode = false; + + /** + * @var \Backend\Classes\WidgetManager + */ + protected $widgetManager; + + /** + * @inheritDoc + */ + public function init() + { + $this->fillFromConfig([ + 'fields', + 'tabs', + 'secondaryTabs', + 'model', + 'data', + 'context', + 'arrayName', + 'isNested', + ]); + + $this->widgetManager = WidgetManager::instance(); + $this->allTabs = (object) $this->allTabs; + $this->validateModel(); + } + + /** + * Ensure fields are defined and form widgets are registered so they can + * also be bound to the controller this allows their AJAX features to + * operate. + * + * @return void + */ + public function bindToController() + { + $this->defineFormFields(); + parent::bindToController(); + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addJs('js/october.form.js', 'core'); + } + + /** + * Renders the widget. + * + * Options: + * - preview: Render this form as an uneditable preview. Default: false + * - useContainer: Wrap the result in a container, used by AJAX. Default: true + * - section: Which form section to render. Default: null + * - outside: Renders the Outside Fields section. + * - primary: Renders the Primary Tabs section. + * - secondary: Renders the Secondary Tabs section. + * - null: Renders all sections + * + * @param array $options + * @return string|bool The rendered partial contents, or false if suppressing an exception + */ + public function render($options = []) + { + if (isset($options['preview'])) { + $this->previewMode = $options['preview']; + } + if (!isset($options['useContainer'])) { + $options['useContainer'] = true; + } + if (!isset($options['section'])) { + $options['section'] = null; + } + + $extraVars = []; + $targetPartial = 'form'; + + /* + * Determine the partial to use based on the supplied section option + */ + if ($section = $options['section']) { + $section = strtolower($section); + + if (isset($this->allTabs->{$section})) { + $extraVars['tabs'] = $this->allTabs->{$section}; + } + + $targetPartial = 'section'; + $extraVars['renderSection'] = $section; + } + + /* + * Apply a container to the element + */ + if ($useContainer = $options['useContainer']) { + $targetPartial = $section ? 'section-container' : 'form-container'; + } + + $this->prepareVars(); + + /* + * Force preview mode on all widgets + */ + if ($this->previewMode) { + foreach ($this->formWidgets as $widget) { + $widget->previewMode = $this->previewMode; + } + } + + return $this->makePartial($targetPartial, $extraVars); + } + + /** + * Renders a single form field + * + * Options: + * - useContainer: Wrap the result in a container, used by AJAX. Default: true + * + * @param string|array $field The field name or definition + * @param array $options + * @return string|bool The rendered partial contents, or false if suppressing an exception + */ + public function renderField($field, $options = []) + { + $this->prepareVars(); + + if (is_string($field)) { + if (!isset($this->allFields[$field])) { + throw new ApplicationException(Lang::get( + 'backend::lang.form.missing_definition', + compact('field') + )); + } + + $field = $this->allFields[$field]; + } + + if (!isset($options['useContainer'])) { + $options['useContainer'] = true; + } + $targetPartial = $options['useContainer'] ? 'field-container' : 'field'; + + return $this->makePartial($targetPartial, ['field' => $field]); + } + + /** + * Renders the HTML element for a field + * @param FormWidgetBase $field + * @return string|bool The rendered partial contents, or false if suppressing an exception + */ + public function renderFieldElement($field) + { + return $this->makePartial( + 'field_' . $field->type, + [ + 'field' => $field, + 'formModel' => $this->model + ] + ); + } + + /** + * Validate the supplied form model. + * + * @return mixed + */ + protected function validateModel() + { + if (!$this->model) { + throw new ApplicationException(Lang::get( + 'backend::lang.form.missing_model', + ['class'=>get_class($this->controller)] + )); + } + + $this->data = isset($this->data) + ? (object) $this->data + : $this->model; + + return $this->model; + } + + /** + * Prepares the form data + * + * @return void + */ + protected function prepareVars() + { + $this->defineFormFields(); + $this->applyFiltersFromModel(); + $this->vars['sessionKey'] = $this->getSessionKey(); + $this->vars['outsideTabs'] = $this->allTabs->outside; + $this->vars['primaryTabs'] = $this->allTabs->primary; + $this->vars['secondaryTabs'] = $this->allTabs->secondary; + } + + /** + * Sets or resets form field values. + * @param array $data + * @return array + */ + public function setFormValues($data = null) + { + if ($data === null) { + $data = $this->getSaveData(); + } + + /* + * Fill the model as if it were to be saved + */ + $this->prepareModelsToSave($this->model, $data); + + /* + * Data set differs from model + */ + if ($this->data !== $this->model) { + $this->data = (object) array_merge((array) $this->data, (array) $data); + } + + /* + * Set field values from data source + */ + foreach ($this->allFields as $field) { + $field->value = $this->getFieldValue($field); + } + + return $data; + } + + /** + * Event handler for refreshing the form. + * + * @return array + */ + public function onRefresh() + { + $result = []; + $saveData = $this->getSaveData(); + + /** + * @event backend.form.beforeRefresh + * Called before the form is refreshed, modify the $dataHolder->data property in place + * + * Example usage: + * + * Event::listen('backend.form.beforeRefresh', function ((\Backend\Widgets\Form) $formWidget, (stdClass) $dataHolder) { + * $dataHolder->data = $arrayOfSaveDataToReplaceExistingDataWith; + * }); + * + * Or + * + * $formWidget->bindEvent('form.beforeRefresh', function ((stdClass) $dataHolder) { + * $dataHolder->data = $arrayOfSaveDataToReplaceExistingDataWith; + * }); + * + */ + $dataHolder = (object) ['data' => $saveData]; + $this->fireSystemEvent('backend.form.beforeRefresh', [$dataHolder]); + $saveData = $dataHolder->data; + + /* + * Set the form variables and prepare the widget + */ + $this->setFormValues($saveData); + $this->prepareVars(); + + /** + * @event backend.form.refreshFields + * Called when the form is refreshed, giving the opportunity to modify the form fields + * + * Example usage: + * + * Event::listen('backend.form.refreshFields', function ((\Backend\Widgets\Form) $formWidget, (array) $allFields) { + * $allFields['name']->required = false; + * }); + * + * Or + * + * $formWidget->bindEvent('form.refreshFields', function ((array) $allFields) { + * $allFields['name']->required = false; + * }); + * + */ + $this->fireSystemEvent('backend.form.refreshFields', [$this->allFields]); + + /* + * If an array of fields is supplied, update specified fields individually. + */ + if (($updateFields = post('fields')) && is_array($updateFields)) { + foreach ($updateFields as $field) { + if (!isset($this->allFields[$field])) { + continue; + } + + /** @var FormWidgetBase $fieldObject */ + $fieldObject = $this->allFields[$field]; + $result['#' . $fieldObject->getId('group')] = $this->makePartial('field', ['field' => $fieldObject]); + } + } + + /* + * Update the whole form + */ + if (empty($result)) { + $result = ['#'.$this->getId() => $this->makePartial('form')]; + } + + /** + * @event backend.form.refresh + * Called after the form is refreshed, should return an array of additional result parameters. + * + * Example usage: + * + * Event::listen('backend.form.refresh', function ((\Backend\Widgets\Form) $formWidget, (array) $result) { + * $result['#my-partial-id' => $formWidget->makePartial('$/path/to/custom/backend/partial.htm')]; + * return $result; + * }); + * + * Or + * + * $formWidget->bindEvent('form.refresh', function ((array) $result) use ((\Backend\Widgets\Form $formWidget)) { + * $result['#my-partial-id' => $formWidget->makePartial('$/path/to/custom/backend/partial.htm')]; + * return $result; + * }); + * + */ + $eventResults = $this->fireSystemEvent('backend.form.refresh', [$result], false); + + foreach ($eventResults as $eventResult) { + if (!is_array($eventResult)) { + continue; + } + + $result = $eventResult + $result; + } + + return $result; + } + + /** + * Renders all fields of a tab in the target tab-pane. + * + * @return array + */ + public function onLazyLoadTab() + { + $target = post('target'); + $tabName = post('name'); + $tabSection = post('section'); + + $fields = array_get(optional($this->getTab($tabSection))->fields, $tabName); + + return [ + $target => $this->makePartial('form_fields', ['fields' => $fields]), + ]; + } + + /** + * Helper method to convert a field name to a valid ID attribute. + * + * @param $input + * + * @return string + */ + public function nameToId($input) + { + return HtmlHelper::nameToId($input); + } + + /** + * Creates a flat array of form fields from the configuration. + * Also slots fields in to their respective tabs. + * + * @return void + */ + protected function defineFormFields() + { + if ($this->fieldsDefined) { + return; + } + + /** + * @event backend.form.extendFieldsBefore + * Called before the form fields are defined + * + * Example usage: + * + * Event::listen('backend.form.extendFieldsBefore', function ((\Backend\Widgets\Form) $formWidget) { + * // You should always check to see if you're extending correct model/controller + * if (!$formWidget->model instanceof \Foo\Example\Models\Bar) { + * return; + * } + * + * // Here you can't use addFields() because it will throw you an exception because form is not yet created + * // and it does not have tabs and fields + * // For this example we will pretend that we want to add a new field named example_field + * $formWidget->fields['example_field'] = [ + * 'label' => 'Example field', + * 'comment' => 'Your example field', + * 'type' => 'text', + * ]; + * }); + * + * Or + * + * $formWidget->bindEvent('form.extendFieldsBefore', function () use ((\Backend\Widgets\Form $formWidget)) { + * // You should always check to see if you're extending correct model/controller + * if (!$formWidget->model instanceof \Foo\Example\Models\Bar) { + * return; + * } + * + * // Here you can't use addFields() because it will throw you an exception because form is not yet created + * // and it does not have tabs and fields + * // For this example we will pretend that we want to add a new field named example_field + * $formWidget->fields['example_field'] = [ + * 'label' => 'Example field', + * 'comment' => 'Your example field', + * 'type' => 'text', + * ]; + * }); + * + */ + $this->fireSystemEvent('backend.form.extendFieldsBefore'); + + /* + * Outside fields + */ + if (!isset($this->fields) || !is_array($this->fields)) { + $this->fields = []; + } + + $this->allTabs->outside = new FormTabs(FormTabs::SECTION_OUTSIDE, (array) $this->config); + $this->addFields($this->fields); + + /* + * Primary Tabs + Fields + */ + if (!isset($this->tabs['fields']) || !is_array($this->tabs['fields'])) { + $this->tabs['fields'] = []; + } + + $this->allTabs->primary = new FormTabs(FormTabs::SECTION_PRIMARY, $this->tabs); + $this->addFields($this->tabs['fields'], FormTabs::SECTION_PRIMARY); + + /* + * Secondary Tabs + Fields + */ + if (!isset($this->secondaryTabs['fields']) || !is_array($this->secondaryTabs['fields'])) { + $this->secondaryTabs['fields'] = []; + } + + $this->allTabs->secondary = new FormTabs(FormTabs::SECTION_SECONDARY, $this->secondaryTabs); + $this->addFields($this->secondaryTabs['fields'], FormTabs::SECTION_SECONDARY); + + /** + * @event backend.form.extendFields + * Called after the form fields are defined + * + * Example usage: + * + * Event::listen('backend.form.extendFields', function ((\Backend\Widgets\Form) $formWidget) { + * // Only for the User controller + * if (!$formWidget->getController() instanceof \RainLab\User\Controllers\Users) { + * return; + * } + * + * // Only for the User model + * if (!$formWidget->model instanceof \RainLab\User\Models\User) { + * return; + * } + * + * // Add an extra birthday field + * $formWidget->addFields([ + * 'birthday' => [ + * 'label' => 'Birthday', + * 'comment' => 'Select the users birthday', + * 'type' => 'datepicker' + * ] + * ]); + * + * // Remove a Surname field + * $formWidget->removeField('surname'); + * }); + * + * Or + * + * $formWidget->bindEvent('form.extendFields', function () use ((\Backend\Widgets\Form $formWidget)) { + * // Only for the User controller + * if (!$formWidget->getController() instanceof \RainLab\User\Controllers\Users) { + * return; + * } + * + * // Only for the User model + * if (!$formWidget->model instanceof \RainLab\User\Models\User) { + * return; + * } + * + * // Add an extra birthday field + * $formWidget->addFields([ + * 'birthday' => [ + * 'label' => 'Birthday', + * 'comment' => 'Select the users birthday', + * 'type' => 'datepicker' + * ] + * ]); + * + * // Remove a Surname field + * $formWidget->removeField('surname'); + * }); + * + */ + $this->fireSystemEvent('backend.form.extendFields', [$this->allFields]); + + /* + * Convert automatic spanned fields + */ + foreach ($this->allTabs->outside->getFields() as $fields) { + $this->processAutoSpan($fields); + } + + foreach ($this->allTabs->primary->getFields() as $fields) { + $this->processAutoSpan($fields); + } + + foreach ($this->allTabs->secondary->getFields() as $fields) { + $this->processAutoSpan($fields); + } + + /* + * At least one tab section should stretch + */ + if ( + $this->allTabs->secondary->stretch === null + && $this->allTabs->primary->stretch === null + && $this->allTabs->outside->stretch === null + ) { + if ($this->allTabs->secondary->hasFields()) { + $this->allTabs->secondary->stretch = true; + } + elseif ($this->allTabs->primary->hasFields()) { + $this->allTabs->primary->stretch = true; + } + else { + $this->allTabs->outside->stretch = true; + } + } + + /* + * Bind all form widgets to controller + */ + foreach ($this->allFields as $field) { + if ($field->type !== 'widget') { + continue; + } + + $widget = $this->makeFormFieldWidget($field); + $widget->bindToController(); + } + + $this->fieldsDefined = true; + } + + /** + * Converts fields with a span set to 'auto' as either + * 'left' or 'right' depending on the previous field. + * + * @return void + */ + protected function processAutoSpan($fields) + { + $prevSpan = null; + + foreach ($fields as $field) { + if (strtolower($field->span) === 'auto') { + if ($prevSpan === 'left') { + $field->span = 'right'; + } + else { + $field->span = 'left'; + } + } + + $prevSpan = $field->span; + } + } + + /** + * Programatically add fields, used internally and for extensibility. + * + * @param array $fields + * @param string $addToArea + * @return void + */ + public function addFields(array $fields, $addToArea = null) + { + foreach ($fields as $name => $config) { + // Check if user has permissions to show this field + $permissions = array_get($config, 'permissions'); + if (!empty($permissions) && !BackendAuth::getUser()->hasAccess($permissions, false)) { + continue; + } + + $fieldObj = $this->makeFormField($name, $config); + $fieldTab = is_array($config) ? array_get($config, 'tab') : null; + + // Check that the form field matches the active context + if ($fieldObj->context !== null) { + $context = is_array($fieldObj->context) ? $fieldObj->context : [$fieldObj->context]; + if (!in_array($this->getContext(), $context)) { + continue; + } + } + + // Apply the field name to the validation engine + $attrName = implode('.', HtmlHelper::nameToArray($fieldObj->fieldName)); + + if ($this->model && method_exists($this->model, 'setValidationAttributeName')) { + $this->model->setValidationAttributeName($attrName, $fieldObj->label); + } + + $this->allFields[$fieldObj->fieldName] = $fieldObj; + + switch (strtolower($addToArea)) { + case FormTabs::SECTION_PRIMARY: + $this->allTabs->primary->addField($name, $fieldObj, $fieldTab); + break; + case FormTabs::SECTION_SECONDARY: + $this->allTabs->secondary->addField($name, $fieldObj, $fieldTab); + break; + default: + $this->allTabs->outside->addField($name, $fieldObj); + break; + } + } + } + + /** + * Add tab fields. + * + * @param array $fields + * @return void + */ + public function addTabFields(array $fields) + { + $this->addFields($fields, 'primary'); + } + + /** + * @param array $fields + * @return void + */ + public function addSecondaryTabFields(array $fields) + { + $this->addFields($fields, 'secondary'); + } + + /** + * Programatically remove a field. + * + * @param string $name + * @return bool + */ + public function removeField($name) + { + if (!isset($this->allFields[$name])) { + return false; + } + + /* + * Remove from tabs + */ + $this->allTabs->primary->removeField($name); + $this->allTabs->secondary->removeField($name); + $this->allTabs->outside->removeField($name); + + /* + * Remove from main collection + */ + unset($this->allFields[$name]); + + return true; + } + + /** + * Programatically remove all fields belonging to a tab. + * + * @param string $name + * @return bool + */ + public function removeTab($name) + { + foreach ($this->allFields as $fieldName => $field) { + if ($field->tab == $name) { + $this->removeField($fieldName); + } + } + } + + /** + * Creates a form field object from name and configuration. + * + * @param string $name + * @param array $config + * @return FormField + */ + protected function makeFormField($name, $config = []) + { + $label = $config['label'] ?? null; + list($fieldName, $fieldContext) = $this->getFieldName($name); + + $field = new FormField($fieldName, $label); + + if ($fieldContext) { + $field->context = $fieldContext; + } + + $attrName = implode('.', HtmlHelper::nameToArray($field->fieldName)); + $field->arrayName = $this->arrayName; + $field->idPrefix = $this->getId(); + + /* + * Simple field type + */ + if (is_string($config)) { + if ($this->isFormWidget($config) !== false) { + $field->displayAs('widget', ['widget' => $config]); + } + else { + $field->displayAs($config); + } + } + /* + * Defined field type + */ + else { + $fieldType = $config['type'] ?? null; + if (!is_string($fieldType) && $fieldType !== null) { + throw new ApplicationException(Lang::get( + 'backend::lang.field.invalid_type', + ['type' => gettype($fieldType)] + )); + } + + /* + * Widget with configuration + */ + if ($this->isFormWidget($fieldType) !== false) { + $config['widget'] = $fieldType; + $fieldType = 'widget'; + } + + $field->displayAs($fieldType, $config); + } + + /* + * Set field value + */ + $field->value = $this->getFieldValue($field); + + /* + * Check model if field is required + */ + if ($field->required === null && $this->model && method_exists($this->model, 'isAttributeRequired')) { + // Check nested fields + if ($this->isNested) { + // Get the current attribute level + $nameArray = HtmlHelper::nameToArray($this->arrayName); + unset($nameArray[0]); + + // Convert any numeric indexes to wildcards + foreach ($nameArray as $i => $value) { + if (preg_match('/^[0-9]*$/', $value)) { + $nameArray[$i] = '*'; + } + } + + // Recombine names for full attribute name in rules array + $attrName = implode('.', $nameArray) . ".{$attrName}"; + } + + $field->required = $this->model->isAttributeRequired($attrName); + } + + /* + * Get field options from model + */ + $optionModelTypes = ['dropdown', 'radio', 'checkboxlist', 'balloon-selector']; + + if (in_array($field->type, $optionModelTypes, false)) { + /* + * Defer the execution of option data collection + */ + $field->options(function () use ($field, $config) { + $fieldOptions = $config['options'] ?? null; + $fieldOptions = $this->getOptionsFromModel($field, $fieldOptions); + return $fieldOptions; + }); + } + + return $field; + } + + /** + * Check if a field type is a widget or not + * + * @param string $fieldType + * @return boolean + */ + protected function isFormWidget($fieldType) + { + if ($fieldType === null) { + return false; + } + + if (strpos($fieldType, '\\')) { + return true; + } + + $widgetClass = $this->widgetManager->resolveFormWidget($fieldType); + + if (!class_exists($widgetClass)) { + return false; + } + + if (is_subclass_of($widgetClass, 'Backend\Classes\FormWidgetBase')) { + return true; + } + + return false; + } + + /** + * Makes a widget object from a form field object. + * + * @param $field + * @return \Backend\Traits\FormWidgetBase|null + */ + protected function makeFormFieldWidget($field) + { + if ($field->type !== 'widget') { + return null; + } + + if (isset($this->formWidgets[$field->fieldName])) { + return $this->formWidgets[$field->fieldName]; + } + + $widgetConfig = $this->makeConfig($field->config); + $widgetConfig->alias = $this->alias . studly_case($this->nameToId($field->fieldName)); + $widgetConfig->sessionKey = $this->getSessionKey(); + $widgetConfig->previewMode = $this->previewMode; + $widgetConfig->model = $this->model; + $widgetConfig->data = $this->data; + $widgetConfig->parentForm = $this; + + $widgetName = $widgetConfig->widget; + $widgetClass = $this->widgetManager->resolveFormWidget($widgetName); + + if (!class_exists($widgetClass)) { + throw new ApplicationException(Lang::get( + 'backend::lang.widget.not_registered', + ['name' => $widgetClass] + )); + } + + $widget = $this->makeFormWidget($widgetClass, $field, $widgetConfig); + + /* + * If options config is defined, request options from the model. + */ + if (isset($field->config['options'])) { + $field->options(function () use ($field) { + $fieldOptions = $field->config['options']; + if ($fieldOptions === true) { + $fieldOptions = null; + } + $fieldOptions = $this->getOptionsFromModel($field, $fieldOptions); + return $fieldOptions; + }); + } + + return $this->formWidgets[$field->fieldName] = $widget; + } + + /** + * Get all the loaded form widgets for the instance. + * + * @return array + */ + public function getFormWidgets() + { + return $this->formWidgets; + } + + /** + * Get a specified form widget + * + * @param string $field + * @return mixed + */ + public function getFormWidget($field) + { + if (isset($this->formWidgets[$field])) { + return $this->formWidgets[$field]; + } + + return null; + } + + /** + * Get all the registered fields for the instance. + * + * @return array + */ + public function getFields() + { + return $this->allFields; + } + + /** + * Get a specified field object + * + * @param string $field + * @return mixed + */ + public function getField($field) + { + if (isset($this->allFields[$field])) { + return $this->allFields[$field]; + } + + return null; + } + + /** + * Get all tab objects for the instance. + * + * @return object[FormTabs] + */ + public function getTabs() + { + return $this->allTabs; + } + + /** + * Get a specified tab object. + * Options: outside, primary, secondary. + * + * @param string $field + * @return mixed + */ + public function getTab($tab) + { + if (isset($this->allTabs->$tab)) { + return $this->allTabs->$tab; + } + + return null; + } + + /** + * Parses a field's name + * @param string $field Field name + * @return array [columnName, context] + */ + protected function getFieldName($field) + { + if (strpos($field, '@') === false) { + return [$field, null]; + } + + return explode('@', $field); + } + + /** + * Looks up the field value. + * @param mixed $field + * @return string + */ + protected function getFieldValue($field) + { + if (is_string($field)) { + if (!isset($this->allFields[$field])) { + throw new ApplicationException(Lang::get( + 'backend::lang.form.missing_definition', + compact('field') + )); + } + + $field = $this->allFields[$field]; + } + + $defaultValue = $this->shouldFetchDefaultValues() + ? $field->getDefaultFromData($this->data) + : null; + + return $field->getValueFromData( + $this->data, + is_string($defaultValue) ? trans($defaultValue) : $defaultValue + ); + } + + /** + * Checks if default values should be taken from data. + * This should be done when model exists or when explicitly configured + */ + protected function shouldFetchDefaultValues() + { + $enableDefaults = object_get($this->config, 'enableDefaults'); + if ($enableDefaults === false) { + return false; + } + return !$this->model->exists || $enableDefaults; + } + + /** + * Returns a HTML encoded value containing the other fields this + * field depends on + * @param \Backend\Classes\FormField $field + * @return string + */ + protected function getFieldDepends($field) + { + if (!$field->dependsOn) { + return ''; + } + + $dependsOn = is_array($field->dependsOn) ? $field->dependsOn : [$field->dependsOn]; + $dependsOn = htmlspecialchars(json_encode($dependsOn), ENT_QUOTES, 'UTF-8'); + return $dependsOn; + } + + /** + * Helper method to determine if field should be rendered + * with label and comments. + * @param \Backend\Classes\FormField $field + * @return boolean + */ + protected function showFieldLabels($field) + { + if (in_array($field->type, ['checkbox', 'switch', 'section'])) { + return false; + } + + if ($field->type === 'widget') { + return $this->makeFormFieldWidget($field)->showLabels; + } + + return true; + } + + /** + * Returns post data from a submitted form. + * + * @return array + */ + public function getSaveData() + { + $this->defineFormFields(); + + $result = []; + + /* + * Source data + */ + $data = $this->arrayName ? post($this->arrayName) : post(); + if (!$data) { + $data = []; + } + + /* + * Spin over each field and extract the postback value + */ + foreach ($this->allFields as $field) { + /* + * Disabled and hidden should be omitted from data set + */ + if ($field->disabled || $field->hidden) { + continue; + } + + /* + * Handle HTML array, eg: item[key][another] + */ + $parts = HtmlHelper::nameToArray($field->fieldName); + if (($value = $this->dataArrayGet($data, $parts)) !== null) { + /* + * Number fields should be converted to integers + */ + if ($field->type === 'number') { + $value = !strlen(trim($value)) ? null : (float) $value; + } + + $this->dataArraySet($result, $parts, $value); + } + } + + /* + * Give widgets an opportunity to process the data. + */ + foreach ($this->formWidgets as $field => $widget) { + $parts = HtmlHelper::nameToArray($field); + + if ((isset($widget->config->disabled) && $widget->config->disabled) + || (isset($widget->config->hidden) && $widget->config->hidden)) { + continue; + } + + $widgetValue = $widget->getSaveValue($this->dataArrayGet($result, $parts)); + $this->dataArraySet($result, $parts, $widgetValue); + } + + return $result; + } + + /* + * Allow the model to filter fields. + */ + protected function applyFiltersFromModel() + { + /* + * Standard usage + */ + if (method_exists($this->model, 'filterFields')) { + $this->model->filterFields((object) $this->allFields, $this->getContext()); + } + + /* + * Advanced usage + */ + if (method_exists($this->model, 'fireEvent')) { + /** + * @event model.form.filterFields + * Called after the form is initialized + * + * Example usage: + * + * $model->bindEvent('model.form.filterFields', function ((\Backend\Widgets\Form) $formWidget, (stdClass) $fields, (string) $context) use (\October\Rain\Database\Model $model) { + * if ($model->source_type == 'http') { + * $fields->source_url->hidden = false; + * $fields->git_branch->hidden = true; + * } elseif ($model->source_type == 'git') { + * $fields->source_url->hidden = false; + * $fields->git_branch->hidden = false; + * } else { + * $fields->source_url->hidden = true; + * $fields->git_branch->hidden = true; + * } + * }); + * + */ + $this->model->fireEvent('model.form.filterFields', [$this, (object) $this->allFields, $this->getContext()]); + } + } + + /** + * Looks at the model for defined options. + * + * @param $field + * @param $fieldOptions + * @return mixed + */ + protected function getOptionsFromModel($field, $fieldOptions) + { + /* + * Advanced usage, supplied options are callable + * [\Path\To\Class, methodName] + */ + if (is_array($fieldOptions) && is_callable($fieldOptions)) { + $fieldOptions = call_user_func($fieldOptions, $this, $field); + } + + /* + * Refer to the model method or any of its behaviors + */ + if (!is_array($fieldOptions) && !$fieldOptions) { + try { + list($model, $attribute) = $field->resolveModelAttribute($this->model, $field->fieldName); + if (!$model) { + throw new Exception(); + } + } + catch (Exception $ex) { + throw new ApplicationException(Lang::get('backend::lang.field.options_method_invalid_model', [ + 'model' => get_class($this->model), + 'field' => $field->fieldName + ])); + } + + $methodName = 'get'.studly_case($attribute).'Options'; + if ( + !$this->objectMethodExists($model, $methodName) && + !$this->objectMethodExists($model, 'getDropdownOptions') + ) { + throw new ApplicationException(Lang::get('backend::lang.field.options_method_not_exists', [ + 'model' => get_class($model), + 'method' => $methodName, + 'field' => $field->fieldName + ])); + } + + if ($this->objectMethodExists($model, $methodName)) { + $fieldOptions = $model->$methodName($field->value, $this->data); + } + else { + $fieldOptions = $model->getDropdownOptions($attribute, $field->value, $this->data); + } + } + /* + * Field options are an explicit method reference + */ + elseif (is_string($fieldOptions)) { + // \Path\To\Class::staticMethodOptions + if (str_contains($fieldOptions, '::')) { + $options = explode('::', $fieldOptions); + if (count($options) === 2 && class_exists($options[0]) && method_exists($options[0], $options[1])) { + $result = $options[0]::{$options[1]}($this, $field); + if (!is_array($result)) { + throw new ApplicationException(Lang::get('backend::lang.field.options_static_method_invalid_value', [ + 'class' => $options[0], + 'method' => $options[1] + ])); + } + return $result; + } + } + + // $model->{$fieldOptions}() + if (!$this->objectMethodExists($this->model, $fieldOptions)) { + throw new ApplicationException(Lang::get('backend::lang.field.options_method_not_exists', [ + 'model' => get_class($this->model), + 'method' => $fieldOptions, + 'field' => $field->fieldName + ])); + } + + $fieldOptions = $this->model->$fieldOptions($field->value, $field->fieldName, $this->data); + } + + return $fieldOptions; + } + + /** + * Returns the active session key. + * + * @return \Illuminate\Routing\Route|mixed|string + */ + public function getSessionKey() + { + if ($this->sessionKey) { + return $this->sessionKey; + } + + if (post('_session_key')) { + return $this->sessionKey = post('_session_key'); + } + + return $this->sessionKey = FormHelper::getSessionKey(); + } + + /** + * Returns the active context for displaying the form. + * + * @return string + */ + public function getContext() + { + return $this->context; + } + + /** + * Internal helper for method existence checks. + * + * @param object $object + * @param string $method + * @return boolean + */ + protected function objectMethodExists($object, $method) + { + if (method_exists($object, 'methodExists')) { + return $object->methodExists($method); + } + + return method_exists($object, $method); + } + + /** + * Variant to array_get() but preserves dots in key names. + * + * @param array $array + * @param array $parts + * @param null $default + * @return array|null + */ + protected function dataArrayGet(array $array, array $parts, $default = null) + { + if ($parts === null) { + return $array; + } + + if (count($parts) === 1) { + $key = array_shift($parts); + if (isset($array[$key])) { + return $array[$key]; + } + + return $default; + } + + foreach ($parts as $segment) { + if (!is_array($array) || !array_key_exists($segment, $array)) { + return $default; + } + + $array = $array[$segment]; + } + + return $array; + } + + /** + * Variant to array_set() but preserves dots in key names. + * + * @param array $array + * @param array $parts + * @param string $value + * @return array + */ + protected function dataArraySet(array &$array, array $parts, $value) + { + if ($parts === null) { + return $value; + } + + while (count($parts) > 1) { + $key = array_shift($parts); + + if (!isset($array[$key]) || !is_array($array[$key])) { + $array[$key] = []; + } + + $array =& $array[$key]; + } + + $array[array_shift($parts)] = $value; + + return $array; + } +} diff --git a/modules/backend/widgets/Lists.php b/modules/backend/widgets/Lists.php new file mode 100644 index 0000000..8c88002 --- /dev/null +++ b/modules/backend/widgets/Lists.php @@ -0,0 +1,1828 @@ +fillFromConfig([ + 'columns', + 'model', + 'recordUrl', + 'recordOnClick', + 'noRecordsMessage', + 'showPageNumbers', + 'recordsPerPage', + 'perPageOptions', + 'showSorting', + 'defaultSort', + 'showCheckboxes', + 'showSetup', + 'showTree', + 'treeExpanded', + 'showPagination', + 'customViewPath', + ]); + + /* + * Configure the list widget + */ + if ($this->showSetup) { + $this->recordsPerPage = $this->getUserPreference('per_page', $this->recordsPerPage); + } + + if ($this->showPagination == 'auto') { + $this->showPagination = $this->recordsPerPage && $this->recordsPerPage > 0; + } + + if ($this->customViewPath) { + $this->addViewPath($this->customViewPath); + } + + $this->validateModel(); + $this->validateTree(); + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addJs('js/october.list.js', 'core'); + } + + /** + * Renders the widget. + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('list-container'); + } + + /** + * Prepares the list data + */ + public function prepareVars() + { + $this->vars['cssClasses'] = implode(' ', $this->cssClasses); + $this->vars['columns'] = $this->getVisibleColumns(); + $this->vars['columnTotal'] = $this->getTotalColumns(); + $this->vars['records'] = $this->getRecords(); + $this->vars['noRecordsMessage'] = trans($this->noRecordsMessage); + $this->vars['showCheckboxes'] = $this->showCheckboxes; + $this->vars['showSetup'] = $this->showSetup; + $this->vars['showPagination'] = $this->showPagination; + $this->vars['showPageNumbers'] = $this->showPageNumbers; + $this->vars['showSorting'] = $this->showSorting; + $this->vars['sortColumn'] = $this->getSortColumn(); + $this->vars['sortDirection'] = $this->sortDirection; + $this->vars['showTree'] = $this->showTree; + $this->vars['treeLevel'] = 0; + + if ($this->showPagination) { + $this->vars['pageCurrent'] = $this->records->currentPage(); + // Store the currently visited page number in the session so the same + // data can be displayed when the user returns to this list. + $this->putSession('lastVisitedPage', $this->vars['pageCurrent']); + if ($this->showPageNumbers) { + $this->vars['recordTotal'] = $this->records->total(); + $this->vars['pageLast'] = $this->records->lastPage(); + $this->vars['pageFrom'] = $this->records->firstItem(); + $this->vars['pageTo'] = $this->records->lastItem(); + } + else { + $this->vars['hasMorePages'] = $this->records->hasMorePages(); + } + } + else { + $this->vars['recordTotal'] = $this->records->count(); + $this->vars['pageCurrent'] = 1; + } + } + + /** + * Event handler for refreshing the list. + */ + public function onRefresh() + { + $this->prepareVars(); + return ['#'.$this->getId() => $this->makePartial('list')]; + } + + /** + * Event handler for switching the page number. + */ + public function onPaginate() + { + $this->currentPageNumber = post('page'); + return $this->onRefresh(); + } + + /** + * Event handler for changing the filter + */ + public function onFilter() + { + $this->currentPageNumber = 1; + return $this->onRefresh(); + } + + /** + * Validate the supplied form model. + * @return void + */ + protected function validateModel() + { + if (!$this->model) { + throw new ApplicationException(Lang::get( + 'backend::lang.list.missing_model', + ['class'=>get_class($this->controller)] + )); + } + + if (!$this->model instanceof Model) { + throw new ApplicationException(Lang::get( + 'backend::lang.model.invalid_class', + ['model'=>get_class($this->model), 'class'=>get_class($this->controller)] + )); + } + + return $this->model; + } + + /** + * Replaces the @ symbol with a table name in a model + * @param string $sql + * @param string $table + * @return string + */ + protected function parseTableName($sql, $table) + { + return str_replace('@', $table.'.', $sql); + } + + /** + * Applies any filters to the model. + */ + public function prepareQuery() + { + $query = $this->model->newQuery(); + $primaryTable = $this->model->getTable(); + $selects = [$primaryTable.'.*']; + $joins = []; + $withs = []; + $bindings = []; + + /** + * @event backend.list.extendQueryBefore + * Provides an opportunity to modify the `$query` object before the List widget applies its scopes to it. + * + * Example usage: + * + * Event::listen('backend.list.extendQueryBefore', function ($listWidget, $query) { + * $query->whereNull('deleted_at'); + * }); + * + * Or + * + * $listWidget->bindEvent('list.extendQueryBefore', function ($query) { + * $query->whereNull('deleted_at'); + * }); + * + */ + $this->fireSystemEvent('backend.list.extendQueryBefore', [$query]); + + /* + * Prepare searchable column names + */ + $primarySearchable = []; + $relationSearchable = []; + + $columnsToSearch = []; + if (!empty($this->searchTerm) && ($searchableColumns = $this->getSearchableColumns())) { + foreach ($searchableColumns as $column) { + /* + * Related + */ + if ($this->isColumnRelated($column)) { + $table = $this->model->makeRelation($column->relation)->getTable(); + $columnName = isset($column->sqlSelect) + ? DbDongle::raw($this->parseTableName($column->sqlSelect, $table)) + : $table . '.' . $column->valueFrom; + + $relationSearchable[$column->relation][] = $columnName; + } + /* + * Primary + */ + else { + $columnName = isset($column->sqlSelect) + ? DbDongle::raw($this->parseTableName($column->sqlSelect, $primaryTable)) + : DbDongle::cast(Db::getTablePrefix() . $primaryTable . '.' . $column->columnName, 'TEXT'); + + $primarySearchable[] = $columnName; + } + } + } + + /* + * Prepare related eager loads (withs) and custom selects (joins) + */ + foreach ($this->getVisibleColumns() as $column) { + // If useRelationCount is enabled, eager load the count of the relation into $relation_count + if ($column->relation && @$column->config['useRelationCount']) { + $query->withCount($column->relation); + } + + if (!$this->isColumnRelated($column) || (!isset($column->sqlSelect) && !isset($column->valueFrom))) { + continue; + } + + if (isset($column->valueFrom)) { + $withs[] = $column->relation; + } + + $joins[] = $column->relation; + } + + /* + * Add eager loads to the query + */ + if ($withs) { + $query->with(array_unique($withs)); + } + + /* + * Apply search term + */ + $query->where(function ($innerQuery) use ($primarySearchable, $relationSearchable, $joins) { + + /* + * Search primary columns + */ + if (count($primarySearchable) > 0) { + $this->applySearchToQuery($innerQuery, $primarySearchable, 'or'); + } + + /* + * Search relation columns + */ + if ($joins) { + foreach (array_unique($joins) as $join) { + /* + * Apply a supplied search term for relation columns and + * constrain the query only if there is something to search for + */ + $columnsToSearch = array_get($relationSearchable, $join, []); + + if (count($columnsToSearch) > 0) { + $innerQuery->orWhereHas($join, function ($_query) use ($columnsToSearch) { + $this->applySearchToQuery($_query, $columnsToSearch); + }); + } + } + } + }); + + /* + * Custom select queries + */ + foreach ($this->getVisibleColumns() as $column) { + if (!isset($column->sqlSelect)) { + continue; + } + + $alias = $query->getQuery()->getGrammar()->wrap($column->columnName); + + /* + * Relation column + */ + if (isset($column->relation)) { + // @todo Find a way... + $relationType = $this->model->getRelationType($column->relation); + if ($relationType == 'morphTo') { + throw new ApplicationException('The relationship morphTo is not supported for list columns.'); + } + + $table = $this->model->makeRelation($column->relation)->getTable(); + $sqlSelect = $this->parseTableName($column->sqlSelect, $table); + + /* + * Manipulate a count query for the sub query + */ + $relationObj = $this->model->{$column->relation}(); + $countQuery = $relationObj->getRelationExistenceQuery($relationObj->getRelated()->newQueryWithoutScopes(), $query); + + $joinSql = $this->isColumnRelated($column, true) + ? DbDongle::raw("group_concat(" . $sqlSelect . " separator ', ')") + : DbDongle::raw($sqlSelect); + + $joinSql = $countQuery->select($joinSql)->toSql(); + + $selects[] = Db::raw("(".$joinSql.") as ".$alias); + + /* + * If this is a polymorphic relation there will be bindings that need to be added to the query + */ + $bindings = array_merge($bindings, $countQuery->getBindings()); + } + /* + * Primary column + */ + else { + $sqlSelect = $this->parseTableName($column->sqlSelect, $primaryTable); + $selects[] = DbDongle::raw($sqlSelect . ' as '. $alias); + } + } + + /* + * Apply sorting + */ + if (($sortColumn = $this->getSortColumn()) && !$this->showTree && in_array($sortColumn, array_keys($this->getVisibleColumns()))) { + if (($column = array_get($this->allColumns, $sortColumn)) && $column->valueFrom) { + $sortColumn = $this->isColumnPivot($column) + ? 'pivot_' . $column->valueFrom + : $column->valueFrom; + } + + // Set the sorting column to $relation_count if useRelationCount enabled + if (isset($column->relation) && @$column->config['useRelationCount']) { + $sortColumn = $column->relation . '_count'; + } + + $query->orderBy($sortColumn, $this->sortDirection); + } + + /* + * Apply filters + */ + foreach ($this->filterCallbacks as $callback) { + $callback($query); + } + + /* + * Add custom selects + */ + $query->addSelect($selects); + + /* + * Add bindings for polymorphic relations + */ + $query->addBinding($bindings, 'select'); + + /** + * @event backend.list.extendQuery + * Provides an opportunity to modify and / or return the `$query` object after the List widget has applied its scopes to it and before it's used to get the records. + * + * Example usage: + * + * Event::listen('backend.list.extendQuery', function ($listWidget, $query) { + * $newQuery = MyModel::newQuery(); + * return $newQuery; + * }); + * + * Or + * + * $listWidget->bindEvent('list.extendQuery', function ($query) { + * $query->whereNull('deleted_at'); + * }); + * + */ + if ($event = $this->fireSystemEvent('backend.list.extendQuery', [$query])) { + return $event; + } + + return $query; + } + + public function prepareModel() + { + traceLog('Method ' . __METHOD__ . '() has been deprecated, please use the ' . __CLASS__ . '::prepareQuery() method instead.'); + return $this->prepareQuery(); + } + + /** + * Returns all the records from the supplied model, after filtering. + * @return Collection + */ + protected function getRecords() + { + $query = $this->prepareQuery(); + + if ($this->showTree) { + $records = $query->getNested(); + } + elseif ($this->showPagination) { + $method = $this->showPageNumbers ? 'paginate' : 'simplePaginate'; + $currentPageNumber = $this->getCurrentPageNumber($query); + $records = $query->{$method}($this->recordsPerPage, $currentPageNumber); + } + else { + $records = $query->get(); + } + + /** + * @event backend.list.extendRecords + * Provides an opportunity to modify and / or return the `$records` Collection object before the widget uses it. + * + * Example usage: + * + * Event::listen('backend.list.extendRecords', function ($listWidget, $records) { + * $model = MyModel::where('always_include', true)->first(); + * $records->prepend($model); + * }); + * + * Or + * + * $listWidget->bindEvent('list.extendRecords', function ($records) { + * $model = MyModel::where('always_include', true)->first(); + * $records->prepend($model); + * }); + * + */ + if ($event = $this->fireSystemEvent('backend.list.extendRecords', [&$records])) { + $records = $event; + } + + return $this->records = $records; + } + + /** + * Returns the current page number for the list. + * + * This will override the current page number provided by the user if it is past the last page of available records. + * + * @param object $query + * @return int + */ + protected function getCurrentPageNumber($query) + { + $currentPageNumber = $this->currentPageNumber; + if (empty($currentPageNumber)) { + $currentPageNumber = $this->getSession('lastVisitedPage'); + } + + $currentPageNumber = intval($currentPageNumber); + + if ($currentPageNumber > 1) { + $count = $query->count(); + + // If the current page number is higher than the amount of available pages, go to the last available page + if ($count <= (($currentPageNumber - 1) * $this->recordsPerPage)) { + $currentPageNumber = ceil($count / $this->recordsPerPage); + } + } + + return $currentPageNumber; + } + + /** + * Returns the record URL address for a list row. + * @param Model $record + * @return string + */ + public function getRecordUrl($record) + { + if (isset($this->recordOnClick)) { + return 'javascript:;'; + } + + if (!isset($this->recordUrl)) { + return null; + } + + $url = RouterHelper::replaceParameters($record, $this->recordUrl); + return Backend::url($url); + } + + /** + * Returns the onclick event for a list row. + * @param Model $record + * @return string + */ + public function getRecordOnClick($record) + { + if (!isset($this->recordOnClick)) { + return null; + } + + $recordOnClick = RouterHelper::replaceParameters($record, $this->recordOnClick); + return Html::attributes(['onclick' => $recordOnClick]); + } + + /** + * Get all the registered columns for the instance. + * @return array + */ + public function getColumns() + { + return $this->allColumns ?: $this->defineListColumns(); + } + + /** + * Get a specified column object + * @param string $column + * @return mixed + */ + public function getColumn($column) + { + if (!isset($this->allColumns[$column])) { + throw new ApplicationException('No definition for column ' . $column); + } + + return $this->allColumns[$column]; + } + + /** + * Returns the list columns that are visible by list settings or default + */ + public function getVisibleColumns() + { + $definitions = $this->defineListColumns(); + $columns = []; + + /* + * Supplied column list + */ + if ($this->showSetup && $this->columnOverride === null) { + $this->columnOverride = $this->getUserPreference('visible', null); + } + + if ($this->columnOverride && is_array($this->columnOverride)) { + $invalidColumns = array_diff($this->columnOverride, array_keys($definitions)); + if (!count($definitions)) { + throw new ApplicationException(Lang::get( + 'backend::lang.list.missing_column', + ['columns'=>implode(',', $invalidColumns)] + )); + } + + $availableColumns = array_intersect($this->columnOverride, array_keys($definitions)); + foreach ($availableColumns as $columnName) { + $definitions[$columnName]->invisible = false; + $columns[$columnName] = $definitions[$columnName]; + } + } + /* + * Use default column list + */ + else { + foreach ($definitions as $columnName => $column) { + if ($column->invisible) { + continue; + } + + $columns[$columnName] = $definitions[$columnName]; + } + } + + return $this->visibleColumns = $columns; + } + + /** + * Builds an array of list columns with keys as the column name and values as a ListColumn object. + */ + protected function defineListColumns() + { + if (!isset($this->columns) || !is_array($this->columns) || !count($this->columns)) { + $class = get_class($this->model instanceof Model ? $this->model : $this->controller); + throw new ApplicationException(Lang::get('backend::lang.list.missing_columns', compact('class'))); + } + + $this->addColumns($this->columns); + + /** + * @event backend.list.extendColumns + * Provides an opportunity to modify the columns of a List widget + * + * Example usage: + * + * Event::listen('backend.list.extendColumns', function ($listWidget) { + * // Only for the User controller + * if (!$listWidget->getController() instanceof \Backend\Controllers\Users) { + * return; + * } + * + * // Only for the User model + * if (!$listWidget->model instanceof \Backend\Models\User) { + * return; + * } + * + * // Add an extra birthday column + * $listWidget->addColumns([ + * 'birthday' => [ + * 'label' => 'Birthday' + * ] + * ]); + * + * // Remove a Surname column + * $listWidget->removeColumn('surname'); + * }); + * + * Or + * + * $listWidget->bindEvent('list.extendColumns', function () use ($listWidget) { + * // Only for the User controller + * if (!$listWidget->getController() instanceof \Backend\Controllers\Users) { + * return; + * } + * + * // Only for the User model + * if (!$listWidget->model instanceof \Backend\Models\User) { + * return; + * } + * + * // Add an extra birthday column + * $listWidget->addColumns([ + * 'birthday' => [ + * 'label' => 'Birthday' + * ] + * ]); + * + * // Remove a Surname column + * $listWidget->removeColumn('surname'); + * }); + * + */ + $this->fireSystemEvent('backend.list.extendColumns'); + + /* + * Use a supplied column order + */ + if ($columnOrder = $this->getSession('order', null)) { + $orderedDefinitions = []; + foreach ($columnOrder as $column) { + if (isset($this->allColumns[$column])) { + $orderedDefinitions[$column] = $this->allColumns[$column]; + } + } + + $this->allColumns = array_merge($orderedDefinitions, $this->allColumns); + } + + return $this->allColumns; + } + + /** + * Programatically add columns, used internally and for extensibility. + * @param array $columns Column definitions + */ + public function addColumns(array $columns) + { + /* + * Build a final collection of list column objects + */ + foreach ($columns as $columnName => $config) { + // Check if user has permissions to show this column + $permissions = array_get($config, 'permissions'); + if (!empty($permissions) && !BackendAuth::getUser()->hasAccess($permissions, false)) { + continue; + } + + $this->allColumns[$columnName] = $this->makeListColumn($columnName, $config); + } + } + + /** + * Programatically remove a column, used for extensibility. + * @param string $column Column name + */ + public function removeColumn($columnName) + { + if (isset($this->allColumns[$columnName])) { + unset($this->allColumns[$columnName]); + } + } + + /** + * Creates a list column object from it's name and configuration. + */ + protected function makeListColumn($name, $config) + { + if (is_string($config)) { + $label = $config; + } + elseif (isset($config['label'])) { + $label = $config['label']; + } + else { + $label = studly_case($name); + } + + /* + * Auto configure pivot relation + */ + if (starts_with($name, 'pivot[') && strpos($name, ']') !== false) { + $_name = HtmlHelper::nameToArray($name); + $relationName = array_shift($_name); + $valueFrom = array_shift($_name); + + if (count($_name) > 0) { + $valueFrom .= '['.implode('][', $_name).']'; + } + + $config['relation'] = $relationName; + $config['valueFrom'] = $valueFrom; + $config['searchable'] = false; + } + /* + * Auto configure standard relation + */ + elseif (strpos($name, '[') !== false && strpos($name, ']') !== false) { + $config['valueFrom'] = $name; + $config['sortable'] = false; + $config['searchable'] = false; + } + + $columnType = $config['type'] ?? null; + + $column = new ListColumn($name, $label); + $column->displayAs($columnType, $config); + + return $column; + } + + /** + * Calculates the total columns used in the list, including checkboxes + * and other additions. + */ + protected function getTotalColumns() + { + $columns = $this->visibleColumns ?: $this->getVisibleColumns(); + $total = count($columns); + + if ($this->showCheckboxes) { + $total++; + } + + if ($this->showSetup) { + $total++; + } + + if ($this->showTree) { + $total++; + } + + return $total; + } + + /** + * Looks up the column header + */ + public function getHeaderValue($column) + { + $value = Lang::get($column->label); + + /** + * @event backend.list.overrideHeaderValue + * Overrides the column header value in a list widget. + * + * If a value is returned from this event, it will be used as the value for the provided column. + * `$value` is passed by reference so modifying the variable in place is also supported. Example usage: + * + * Event::listen('backend.list.overrideHeaderValue', function ($listWidget, $column, &$value) { + * $value .= '-modified'; + * }); + * + * Or + * + * $listWidget->bindEvent('list.overrideHeaderValue', function ($column, $value) { + * return 'Custom header value'; + * }); + * + */ + if ($response = $this->fireSystemEvent('backend.list.overrideHeaderValue', [$column, &$value])) { + $value = $response; + } + + return $value; + } + + /** + * Returns a raw column value + * @return string + */ + public function getColumnValueRaw($record, $column) + { + $columnName = $column->columnName; + + /* + * Handle taking value from model relation. + */ + if ($column->valueFrom && $column->relation) { + $columnName = $column->relation; + + if (!array_key_exists($columnName, $record->getRelations())) { + $value = null; + } + elseif ($this->isColumnRelated($column, true)) { + $value = $record->{$columnName}->lists($column->valueFrom); + } + elseif ($this->isColumnRelated($column) || $this->isColumnPivot($column)) { + $value = $record->{$columnName} + ? $column->getValueFromData($record->{$columnName}) + : null; + } + else { + $value = null; + } + } + /* + * Handle taking value from model attribute. + */ + elseif ($column->valueFrom) { + $value = $column->getValueFromData($record); + } + /* + * Otherwise, if the column is a relation, it will be a custom select, + * so prevent the Model from attempting to load the relation + * if the value is NULL. + */ + else { + if ($record->hasRelation($columnName) && array_key_exists($columnName, $record->attributes)) { + $value = $record->attributes[$columnName]; + // Load the value from the relationship counter if useRelationCount is specified + } elseif ($column->relation && @$column->config['useRelationCount']) { + $countAttributeName = \Str::snake($column->relation); + $value = $record->{"{$countAttributeName}_count"}; + } else { + $value = $record->{$columnName}; + } + } + + /** + * @event backend.list.overrideColumnValueRaw + * Overrides the raw column value in a list widget. + * + * If a value is returned from this event, it will be used as the raw value for the provided column. + * `$value` is passed by reference so modifying the variable in place is also supported. Example usage: + * + * Event::listen('backend.list.overrideColumnValueRaw', function ($listWidget, $record, $column, &$value) { + * $value .= '-modified'; + * }); + * + * Or + * + * $listWidget->bindEvent('list.overrideColumnValueRaw', function ($record, $column, $value) { + * return 'No values for you!'; + * }); + * + */ + if ($response = $this->fireSystemEvent('backend.list.overrideColumnValueRaw', [$record, $column, &$value])) { + $value = $response; + } + + return $value; + } + + /** + * Returns a column value, with filters applied + * @return string + */ + public function getColumnValue($record, $column) + { + $value = $this->getColumnValueRaw($record, $column); + + if (method_exists($this, 'eval'. studly_case($column->type) .'TypeValue')) { + $value = $this->{'eval'. studly_case($column->type) .'TypeValue'}($record, $column, $value); + } + else { + $value = $this->evalCustomListType($column->type, $record, $column, $value); + } + + /* + * Apply default value. + */ + if (($value === '' || is_null($value)) && !empty($column->defaults)) { + $value = Lang::get($column->defaults); + } + + /** + * @event backend.list.overrideColumnValue + * Overrides the column value in a list widget. + * + * If a value is returned from this event, it will be used as the value for the provided column. + * `$value` is passed by reference so modifying the variable in place is also supported. Example usage: + * + * Event::listen('backend.list.overrideColumnValue', function ($listWidget, $record, $column, &$value) { + * $value .= '-modified'; + * }); + * + * Or + * + * $listWidget->bindEvent('list.overrideColumnValue', function ($record, $column, $value) { + * return 'No values for you!'; + * }); + * + */ + if ($response = $this->fireSystemEvent('backend.list.overrideColumnValue', [$record, $column, &$value])) { + $value = $response; + } + + return $value; + } + + /** + * Adds a custom CSS class string to a record row + * @param Model $record Populated model + * @return string + */ + public function getRowClass($record) + { + $value = ''; + + /** + * @event backend.list.injectRowClass + * Provides opportunity to inject a custom CSS row class + * + * If a value is returned from this event, it will be used as the value for the row class. + * `$value` is passed by reference so modifying the variable in place is also supported. Example usage: + * + * Event::listen('backend.list.injectRowClass', function ($listWidget, $record, &$value) { + * $value .= '-modified'; + * }); + * + * Or + * + * $listWidget->bindEvent('list.injectRowClass', function ($record, $value) { + * return 'strike'; + * }); + * + */ + if ($response = $this->fireSystemEvent('backend.list.injectRowClass', [$record, &$value])) { + $value = $response; + } + + return $value; + } + + // + // Value processing + // + + /** + * Process a custom list types registered by plugins. + */ + protected function evalCustomListType($type, $record, $column, $value) + { + $plugins = PluginManager::instance()->getRegistrationMethodValues('registerListColumnTypes'); + + foreach ($plugins as $availableTypes) { + if (!isset($availableTypes[$type])) { + continue; + } + + $callback = $availableTypes[$type]; + + if (is_callable($callback)) { + return call_user_func_array($callback, [$value, $column, $record]); + } + } + + $customMessage = ''; + if ($type === 'relation') { + $customMessage = 'Type: relation is not supported, instead use the relation property to specify a relationship to pull the value from and set the type to the type of the value expected.'; + } + + throw new ApplicationException(sprintf('List column type "%s" could not be found. %s', $type, $customMessage)); + } + + /** + * Process as text, escape the value + * @return string + */ + protected function evalTextTypeValue($record, $column, $value) + { + if (is_array($value) && count($value) == count($value, COUNT_RECURSIVE)) { + $value = implode(', ', $value); + } + + if (is_string($column->format) && !empty($column->format)) { + $value = sprintf($column->format, $value); + } + + return htmlentities($value, ENT_QUOTES, 'UTF-8', false); + } + + /** + * Process an image value + * @return string + */ + protected function evalImageTypeValue($record, $column, $value) + { + $config = $column->config; + + // Get config options with defaults + $width = isset($config['width']) ? $config['width'] : 50; + $height = isset($config['height']) ? $config['height'] : 50; + $options = isset($config['options']) ? $config['options'] : []; + + // Handle attachMany relationships + if (isset($record->attachMany[$column->columnName])) { + $image = $value->first(); + + // Handle attachOne relationships + } elseif (isset($record->attachOne[$column->columnName])) { + $image = $value; + + // Handle absolute URLs + } elseif (str_contains($value, '://')) { + $image = $value; + + // Assume all other values to be from the media library + } else { + $image = MediaLibrary::url($value); + } + + if (!is_null($image)) { + $imageUrl = ImageResizer::filterGetUrl($image, $width, $height, $options); + return ""; + } + } + + /** + * Process as number, proxy to text + * @return string + */ + protected function evalNumberTypeValue($record, $column, $value) + { + return $this->evalTextTypeValue($record, $column, $value); + } + + /** + * Process as partial reference + */ + protected function evalPartialTypeValue($record, $column, $value) + { + return $this->controller->makePartial($column->path ?: $column->columnName, [ + 'listColumn' => $column, + 'listRecord' => $record, + 'listValue' => $value, + 'column' => $column, + 'record' => $record, + 'value' => $value + ]); + } + + /** + * Process as boolean switch + */ + protected function evalSwitchTypeValue($record, $column, $value) + { + $contents = ''; + + if ($value) { + $contents = Lang::get('backend::lang.list.column_switch_true'); + } + else { + $contents = Lang::get('backend::lang.list.column_switch_false'); + } + + return $contents; + } + + /** + * Process as a datetime value + */ + protected function evalDatetimeTypeValue($record, $column, $value) + { + if ($value === null) { + return null; + } + + $dateTime = $this->validateDateTimeValue($value, $column); + + if ($column->format !== null) { + $value = $dateTime->format($column->format); + } + else { + $value = $dateTime->toDayDateTimeString(); + } + + $options = [ + 'defaultValue' => $value, + 'format' => $column->format, + 'formatAlias' => 'dateTimeLongMin' + ]; + + if (!empty($column->config['ignoreTimezone'])) { + $options['ignoreTimezone'] = true; + } + + return Backend::dateTime($dateTime, $options); + } + + /** + * Process as a time value + */ + protected function evalTimeTypeValue($record, $column, $value) + { + if ($value === null) { + return null; + } + + $dateTime = $this->validateDateTimeValue($value, $column); + + $format = $column->format ?? 'g:i A'; + + $value = $dateTime->format($format); + + $options = [ + 'defaultValue' => $value, + 'format' => $column->format, + 'formatAlias' => 'time' + ]; + + if (!empty($column->config['ignoreTimezone'])) { + $options['ignoreTimezone'] = true; + } + + return Backend::dateTime($dateTime, $options); + } + + /** + * Process as a date value + */ + protected function evalDateTypeValue($record, $column, $value) + { + if ($value === null) { + return null; + } + + $dateTime = $this->validateDateTimeValue($value, $column); + + if ($column->format !== null) { + $value = $dateTime->format($column->format); + } + else { + $value = $dateTime->toFormattedDateString(); + } + + $options = [ + 'defaultValue' => $value, + 'format' => $column->format, + 'formatAlias' => 'dateLongMin' + ]; + + if (!empty($column->config['ignoreTimezone'])) { + $options['ignoreTimezone'] = true; + } + + return Backend::dateTime($dateTime, $options); + } + + /** + * Process as diff for humans (1 min ago) + */ + protected function evalTimesinceTypeValue($record, $column, $value) + { + if ($value === null) { + return null; + } + + $dateTime = $this->validateDateTimeValue($value, $column); + + $value = DateTimeHelper::timeSince($dateTime); + + $options = [ + 'defaultValue' => $value, + 'timeSince' => true + ]; + + if (!empty($column->config['ignoreTimezone'])) { + $options['ignoreTimezone'] = true; + } + + return Backend::dateTime($dateTime, $options); + } + + /** + * Process as time as current tense (Today at 0:00) + */ + protected function evalTimetenseTypeValue($record, $column, $value) + { + if ($value === null) { + return null; + } + + $dateTime = $this->validateDateTimeValue($value, $column); + + $value = DateTimeHelper::timeTense($dateTime); + + $options = [ + 'defaultValue' => $value, + 'timeTense' => true + ]; + + if (!empty($column->config['ignoreTimezone'])) { + $options['ignoreTimezone'] = true; + } + + return Backend::dateTime($dateTime, $options); + } + /** + * Process as background color, to be seen at list + */ + protected function evalColorPickerTypeValue($record, $column, $value) + { + return ''; + } + /** + * Validates a column type as a date + */ + protected function validateDateTimeValue($value, $column) + { + $value = DateTimeHelper::makeCarbon($value, false); + + if (!$value instanceof Carbon) { + throw new ApplicationException(Lang::get( + 'backend::lang.list.invalid_column_datetime', + ['column' => $column->columnName] + )); + } + + return $value; + } + + // + // Filtering + // + + public function addFilter(callable $filter) + { + $this->filterCallbacks[] = $filter; + } + + // + // Searching + // + + /** + * Applies a search term to the list results, searching will disable tree + * view if a value is supplied. + * @param string $term + * @param boolean $resetPagination + */ + public function setSearchTerm($term, $resetPagination = false) + { + if (!empty($term)) { + $this->showTree = false; + } + + if ($resetPagination) { + $this->currentPageNumber = 1; + } + + $this->searchTerm = $term; + } + + /** + * Applies a search options to the list search. + * @param array $options + */ + public function setSearchOptions($options = []) + { + extract(array_merge([ + 'mode' => null, + 'scope' => null + ], $options)); + + $this->searchMode = $mode; + $this->searchScope = $scope; + } + + /** + * Returns a collection of columns which can be searched. + * @return array + */ + protected function getSearchableColumns() + { + $columns = $this->getColumns(); + $searchable = []; + + foreach ($columns as $column) { + if (!$column->searchable) { + continue; + } + + $searchable[] = $column; + } + + return $searchable; + } + + /** + * Applies the search constraint to a query. + */ + protected function applySearchToQuery($query, $columns, $boolean = 'and') + { + $term = $this->searchTerm; + + if ($scopeMethod = $this->searchScope) { + $searchMethod = $boolean == 'and' ? 'where' : 'orWhere'; + $query->$searchMethod(function ($q) use ($term, $columns, $scopeMethod) { + $q->$scopeMethod($term, $columns); + }); + } + else { + $searchMethod = $boolean == 'and' ? 'searchWhere' : 'orSearchWhere'; + $query->$searchMethod($term, $columns, $this->searchMode); + } + } + + // + // Sorting + // + + /** + * Event handler for sorting the list. + */ + public function onSort() + { + if ($column = post('sortColumn')) { + /* + * Toggle the sort direction and set the sorting column + */ + $sortOptions = ['column' => $this->getSortColumn(), 'direction' => $this->sortDirection]; + + if ($column != $sortOptions['column'] || $sortOptions['direction'] == 'asc') { + $this->sortDirection = $sortOptions['direction'] = 'desc'; + } + else { + $this->sortDirection = $sortOptions['direction'] = 'asc'; + } + + $this->sortColumn = $sortOptions['column'] = $column; + + /* + * Persist the page number + */ + $this->currentPageNumber = post('page'); + + /* + * Try to refresh the list with the new sortOptions. Put the + * new sortOptions in to the session if the query succeeded. + */ + $result = $this->onRefresh(); + + $this->putSession('sort', $sortOptions); + + return $result; + } + } + + /** + * Returns the current sorting column, saved in a session or cached. + */ + public function getSortColumn() + { + if (!$this->isSortable()) { + return false; + } + + if ($this->sortColumn !== null) { + return $this->sortColumn; + } + + /* + * User preference + */ + if ($this->showSorting && ($sortOptions = $this->getSession('sort'))) { + $this->sortColumn = $sortOptions['column']; + $this->sortDirection = $sortOptions['direction']; + } + + /* + * Supplied default + */ + else { + if (is_string($this->defaultSort)) { + $this->sortColumn = $this->defaultSort; + $this->sortDirection = 'desc'; + } + elseif (is_array($this->defaultSort) && isset($this->defaultSort['column'])) { + $this->sortColumn = $this->defaultSort['column']; + $this->sortDirection = $this->defaultSort['direction'] ?? 'desc'; + } + } + + /* + * First available column + */ + if ($this->sortColumn === null || !$this->isSortable($this->sortColumn)) { + $columns = $this->visibleColumns ?: $this->getVisibleColumns(); + $columns = array_filter($columns, function ($column) { + return $column->sortable; + }); + $this->sortColumn = key($columns); + $this->sortDirection = 'desc'; + } + + return $this->sortColumn; + } + + /* + * Returns the current sort direction or default of 'asc' + */ + public function getSortDirection() + { + return $this->sortDirection ?? 'asc'; + } + + /** + * Returns true if the column can be sorted. + */ + protected function isSortable($column = null) + { + if ($column === null) { + return (count($this->getSortableColumns()) > 0); + } + + return array_key_exists($column, $this->getSortableColumns()); + } + + /** + * Returns a collection of columns which are sortable. + */ + protected function getSortableColumns() + { + if ($this->sortableColumns !== null) { + return $this->sortableColumns; + } + + $columns = $this->getColumns(); + $sortable = array_filter($columns, function ($column) { + return $column->sortable; + }); + + return $this->sortableColumns = $sortable; + } + + // + // List Setup + // + + /** + * Event handler to display the list set up. + */ + public function onLoadSetup() + { + $this->vars['columns'] = $this->getSetupListColumns(); + $this->vars['perPageOptions'] = $this->getSetupPerPageOptions(); + $this->vars['recordsPerPage'] = $this->recordsPerPage; + return $this->makePartial('setup_form'); + } + + /** + * Event handler to apply the list set up. + */ + public function onApplySetup() + { + if (($visibleColumns = post('visible_columns')) && is_array($visibleColumns)) { + $this->columnOverride = $visibleColumns; + $this->putUserPreference('visible', $this->columnOverride); + } + + $this->recordsPerPage = post('records_per_page', $this->recordsPerPage); + $this->putSession('order', post('column_order')); + $this->putUserPreference('per_page', $this->recordsPerPage); + return $this->onRefresh(); + } + + /** + * Event handler to apply the list set up. + */ + public function onResetSetup() + { + $this->clearUserPreference('visible'); + $this->clearUserPreference('per_page'); + return $this->onRefresh(); + } + + /** + * Returns an array of allowable records per page. + */ + protected function getSetupPerPageOptions() + { + $perPageOptions = is_array($this->perPageOptions) ? $this->perPageOptions : [20, 40, 80, 100, 120]; + if (!in_array($this->recordsPerPage, $perPageOptions)) { + $perPageOptions[] = $this->recordsPerPage; + } + + sort($perPageOptions); + return $perPageOptions; + } + + /** + * Returns all the list columns used for list set up. + */ + protected function getSetupListColumns() + { + /* + * Force all columns invisible + */ + $columns = $this->defineListColumns(); + foreach ($columns as $column) { + $column->invisible = true; + } + + return array_merge($columns, $this->getVisibleColumns()); + } + + // + // Tree + // + + /** + * Validates the model and settings if showTree is used + * @return void + */ + public function validateTree() + { + if (!$this->showTree) { + return; + } + + $this->showSorting = $this->showPagination = false; + + if (!$this->model->methodExists('getChildren')) { + throw new ApplicationException( + 'To display list as a tree, the specified model must have a method "getChildren"' + ); + } + + if (!$this->model->methodExists('getChildCount')) { + throw new ApplicationException( + 'To display list as a tree, the specified model must have a method "getChildCount"' + ); + } + } + + /** + * Checks if a node (model) is expanded in the session. + * @param Model $node + * @return boolean + */ + public function isTreeNodeExpanded($node) + { + return $this->getSession('tree_node_status_' . $node->getKey(), $this->treeExpanded); + } + + /** + * Sets a node (model) to an expanded or collapsed state, stored in the + * session, then renders the list again. + * @return string List HTML contents. + */ + public function onToggleTreeNode() + { + $this->putSession('tree_node_status_' . post('node_id'), post('status') ? 0 : 1); + return $this->onRefresh(); + } + + // + // Helpers + // + + /** + * Check if column refers to a relation of the model + * @param ListColumn $column List column object + * @param boolean $multi If set, returns true only if the relation is a "multiple relation type" + * @return boolean + */ + protected function isColumnRelated($column, $multi = false) + { + if (!isset($column->relation) || $this->isColumnPivot($column)) { + return false; + } + + if (!$this->model->hasRelation($column->relation)) { + throw new ApplicationException(Lang::get( + 'backend::lang.model.missing_relation', + ['class'=>get_class($this->model), 'relation'=>$column->relation] + )); + } + + if (!$multi) { + return true; + } + + $relationType = $this->model->getRelationType($column->relation); + + return in_array($relationType, [ + 'hasMany', + 'belongsToMany', + 'morphToMany', + 'morphedByMany', + 'morphMany', + 'attachMany', + 'hasManyThrough' + ]); + } + + /** + * Checks if a column refers to a pivot model specifically. + * @param ListColumn $column List column object + * @return boolean + */ + protected function isColumnPivot($column) + { + if (!isset($column->relation) || $column->relation != 'pivot') { + return false; + } + + return true; + } +} diff --git a/modules/backend/widgets/MediaManager.php b/modules/backend/widgets/MediaManager.php new file mode 100644 index 0000000..a4e06b7 --- /dev/null +++ b/modules/backend/widgets/MediaManager.php @@ -0,0 +1,1736 @@ +alias = $alias; + $this->readOnly = $readOnly; + + parent::__construct($controller, []); + } + + /** + * Adds widget specific asset files. Use $this->addJs() and $this->addCss() + * to register new assets to include on the page. + * @return void + */ + protected function loadAssets() + { + $this->addCss('css/mediamanager.css', 'core'); + + if (Config::get('develop.decompileBackendAssets', false)) { + $scripts = Backend::decompileAsset($this->getAssetPath('js/mediamanager-browser.js')); + foreach ($scripts as $script) { + $this->addJs($script, 'core'); + } + } else { + $this->addJs('js/mediamanager-browser-min.js', 'core'); + } + } + + /** + * Abort the request with an access-denied code if readOnly mode is active + * @return void + */ + protected function abortIfReadOnly() + { + if ($this->readOnly) { + abort(403); + } + } + + /** + * Renders the widget. + * @return string + */ + public function render() + { + $this->prepareVars(); + + return $this->makePartial('body'); + } + + // + // AJAX handlers + // + + /** + * Perform search AJAX handler + * @return array + */ + public function onSearch() + { + $this->setSearchTerm(Input::get('search')); + + $this->prepareVars(); + + return [ + '#'.$this->getId('item-list') => $this->makePartial('item-list'), + '#'.$this->getId('folder-path') => $this->makePartial('folder-path') + ]; + } + + /** + * Change view AJAX handler + * @return array + */ + public function onGoToFolder() + { + $path = Input::get('path'); + + if (Input::get('clearCache')) { + MediaLibrary::instance()->resetCache(); + } + + if (Input::get('resetSearch')) { + $this->setSearchTerm(null); + } + + $this->setCurrentFolder($path); + $this->prepareVars(); + + return [ + '#'.$this->getId('item-list') => $this->makePartial('item-list'), + '#'.$this->getId('folder-path') => $this->makePartial('folder-path') + ]; + } + + /** + * Generate thumbnail AJAX handler + * @return array + */ + public function onGenerateThumbnails() + { + $batch = Input::get('batch'); + if (!is_array($batch)) { + return; + } + + $result = []; + foreach ($batch as $thumbnailInfo) { + $result[] = $this->generateThumbnail($thumbnailInfo); + } + + return [ + 'generatedThumbnails'=>$result + ]; + } + + /** + * Get thumbnail AJAX handler + * @return array + */ + public function onGetSidebarThumbnail() + { + $path = Input::get('path'); + $lastModified = Input::get('lastModified'); + + $thumbnailParams = $this->getThumbnailParams(); + $thumbnailParams['width'] = 300; + $thumbnailParams['height'] = 255; + $thumbnailParams['mode'] = 'auto'; + + $path = MediaLibrary::validatePath($path); + + if (!is_numeric($lastModified)) { + throw new ApplicationException('Invalid input data'); + } + + /* + * If the thumbnail file exists, just return the thumbnail markup, + * otherwise generate a new thumbnail. + */ + $thumbnailPath = $this->thumbnailExists($thumbnailParams, $path, $lastModified); + if ($thumbnailPath) { + return [ + 'markup' => $this->makePartial('thumbnail-image', [ + 'isError' => $this->thumbnailIsError($thumbnailPath), + 'imageUrl' => $this->getThumbnailImageUrl($thumbnailPath) + ]) + ]; + } + + $thumbnailInfo = $thumbnailParams; + $thumbnailInfo['path'] = $path; + $thumbnailInfo['lastModified'] = $lastModified; + $thumbnailInfo['id'] = 'sidebar-thumbnail'; + + return $this->generateThumbnail($thumbnailInfo, $thumbnailParams); + } + + /** + * Set view preference AJAX handler + * @return array + */ + public function onChangeView() + { + $viewMode = Input::get('view'); + $path = Input::get('path'); + + $this->setViewMode($viewMode); + $this->setCurrentFolder($path); + + $this->prepareVars(); + + return [ + '#'.$this->getId('item-list') => $this->makePartial('item-list'), + '#'.$this->getId('folder-path') => $this->makePartial('folder-path'), + '#'.$this->getId('view-mode-buttons') => $this->makePartial('view-mode-buttons') + ]; + } + + /** + * Set filter preference AJAX handler + * @return array + */ + public function onSetFilter() + { + $filter = Input::get('filter'); + $path = Input::get('path'); + + $this->setFilter($filter); + $this->setCurrentFolder($path); + + $this->prepareVars(); + + return [ + '#'.$this->getId('item-list') => $this->makePartial('item-list'), + '#'.$this->getId('folder-path') => $this->makePartial('folder-path'), + '#'.$this->getId('filters') => $this->makePartial('filters') + ]; + } + + /** + * Set sorting preference AJAX handler + * @return array + */ + public function onSetSorting() + { + $sortBy = Input::get('sortBy', $this->getSortBy()); + $sortDirection = Input::get('sortDirection', $this->getSortDirection()); + $path = Input::get('path'); + + $this->setSortBy($sortBy); + $this->setSortDirection($sortDirection); + $this->setCurrentFolder($path); + + $this->prepareVars(); + + return [ + '#'.$this->getId('item-list') => $this->makePartial('item-list'), + '#'.$this->getId('folder-path') => $this->makePartial('folder-path') + ]; + } + + /** + * Delete library item AJAX handler + * @return array + */ + public function onDeleteItem() + { + $this->abortIfReadOnly(); + + $paths = Input::get('paths'); + + if (!is_array($paths)) { + throw new ApplicationException('Invalid input data'); + } + + $library = MediaLibrary::instance(); + + $filesToDelete = []; + foreach ($paths as $pathInfo) { + $path = array_get($pathInfo, 'path'); + $type = array_get($pathInfo, 'type'); + + if (!$path || !$type) { + throw new ApplicationException('Invalid input data'); + } + + if ($type === MediaLibraryItem::TYPE_FILE) { + /* + * Add to bulk collection + */ + $filesToDelete[] = $path; + } + elseif ($type === MediaLibraryItem::TYPE_FOLDER) { + /* + * Delete single folder + */ + $library->deleteFolder($path); + + /** + * @event media.folder.delete + * Called after a folder is deleted + * + * Example usage: + * + * Event::listen('media.folder.delete', function ((\Backend\Widgets\MediaManager) $mediaWidget, (string) $path) { + * \Log::info($path . " was deleted"); + * }); + * + * Or + * + * $mediaWidget->bindEvent('folder.delete', function ((string) $path) { + * \Log::info($path . " was deleted"); + * }); + * + */ + $this->fireSystemEvent('media.folder.delete', [$path]); + } + } + + if (count($filesToDelete) > 0) { + /* + * Delete collection of files + */ + $library->deleteFiles($filesToDelete); + + /* + * Extensibility + */ + foreach ($filesToDelete as $path) { + /** + * @event media.file.delete + * Called after a file is deleted + * + * Example usage: + * + * Event::listen('media.file.delete', function ((\Backend\Widgets\MediaManager) $mediaWidget, (string) $path) { + * \Log::info($path . " was deleted"); + * }); + * + * Or + * + * $mediaWidget->bindEvent('file.delete', function ((string) $path) { + * \Log::info($path . " was deleted"); + * }); + * + */ + $this->fireSystemEvent('media.file.delete', [$path]); + } + } + + $library->resetCache(); + $this->prepareVars(); + + return [ + '#'.$this->getId('item-list') => $this->makePartial('item-list') + ]; + } + + /** + * Show rename item popup AJAX handler + * @return array + */ + public function onLoadRenamePopup() + { + $this->abortIfReadOnly(); + + $path = Input::get('path'); + $path = MediaLibrary::validatePath($path); + + $this->vars['originalPath'] = $path; + $this->vars['name'] = basename($path); + $this->vars['listId'] = Input::get('listId'); + $this->vars['type'] = Input::get('type'); + + return $this->makePartial('rename-form'); + } + + /** + * Reanem library item AJAX handler + * @return array + */ + public function onApplyName() + { + $this->abortIfReadOnly(); + + $newName = trim(Input::get('name')); + if (!strlen($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.name_cant_be_empty')); + } + + if (!$this->validateFileName($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_name')); + } + + $originalPath = Input::get('originalPath'); + $originalPath = MediaLibrary::validatePath($originalPath); + $newPath = dirname($originalPath).'/'.$newName; + $type = Input::get('type'); + + if ($type == MediaLibraryItem::TYPE_FILE) { + /* + * Validate extension + */ + if (!$this->validateFileType($newName)) { + throw new ApplicationException(Lang::get('backend::lang.media.type_blocked')); + } + + /* + * Move single file + */ + MediaLibrary::instance()->moveFile($originalPath, $newPath); + + /** + * @event media.file.rename + * Called after a file is renamed / moved + * + * Example usage: + * + * Event::listen('media.file.rename', function ((\Backend\Widgets\MediaManager) $mediaWidget, (string) $originalPath, (string) $newPath) { + * \Log::info($originalPath . " was moved to " . $path); + * }); + * + * Or + * + * $mediaWidget->bindEvent('file.rename', function ((string) $originalPath, (string) $newPath) { + * \Log::info($originalPath . " was moved to " . $path); + * }); + * + */ + $this->fireSystemEvent('media.file.rename', [$originalPath, $newPath]); + } + else { + /* + * Move single folder + */ + MediaLibrary::instance()->moveFolder($originalPath, $newPath); + + /** + * @event media.folder.rename + * Called after a folder is renamed / moved + * + * Example usage: + * + * Event::listen('media.folder.rename', function ((\Backend\Widgets\MediaManager) $mediaWidget, (string) $originalPath, (string) $newPath) { + * \Log::info($originalPath . " was moved to " . $path); + * }); + * + * Or + * + * $mediaWidget->bindEvent('folder.rename', function ((string) $originalPath, (string) $newPath) { + * \Log::info($originalPath . " was moved to " . $path); + * }); + * + */ + $this->fireSystemEvent('media.folder.rename', [$originalPath, $newPath]); + } + + MediaLibrary::instance()->resetCache(); + } + + /** + * Create library folder AJAX handler + * @return array + */ + public function onCreateFolder() + { + $this->abortIfReadOnly(); + + $name = trim(Input::get('name')); + if (!strlen($name)) { + throw new ApplicationException(Lang::get('cms::lang.asset.name_cant_be_empty')); + } + + if (!$this->validateFileName($name)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_name')); + } + + $path = Input::get('path'); + $path = MediaLibrary::validatePath($path); + + $newFolderPath = $path.'/'.$name; + + $library = MediaLibrary::instance(); + + if ($library->folderExists($newFolderPath)) { + throw new ApplicationException(Lang::get('backend::lang.media.folder_or_file_exist')); + } + + /* + * Create the new folder + */ + if (!$library->makeFolder($newFolderPath)) { + throw new ApplicationException(Lang::get('backend::lang.media.error_creating_folder')); + } + + /** + * @event media.folder.create + * Called after a folder is created + * + * Example usage: + * + * Event::listen('media.folder.create', function ((\Backend\Widgets\MediaManager) $mediaWidget, (string) $newFolderPath) { + * \Log::info($newFolderPath . " was created"); + * }); + * + * Or + * + * $mediaWidget->bindEvent('folder.create', function ((string) $newFolderPath) { + * \Log::info($newFolderPath . " was created"); + * }); + * + */ + $this->fireSystemEvent('media.folder.create', [$newFolderPath]); + + $library->resetCache(); + + $this->prepareVars(); + + return [ + '#'.$this->getId('item-list') => $this->makePartial('item-list') + ]; + } + + /** + * Show move item popup AJAX handler + * @return array + */ + public function onLoadMovePopup() + { + $this->abortIfReadOnly(); + + $exclude = Input::get('exclude', []); + if (!is_array($exclude)) { + throw new ApplicationException('Invalid input data'); + } + + $folders = MediaLibrary::instance()->listAllDirectories($exclude); + + $folderList = []; + foreach ($folders as $folder) { + $path = $folder; + + if ($folder == '/') { + $name = Lang::get('backend::lang.media.library'); + } + else { + $segments = explode('/', $folder); + $name = str_repeat(' ', (count($segments)-1)*4).basename($folder); + } + + $folderList[$path] = $name; + } + + $this->vars['folders'] = $folderList; + $this->vars['originalPath'] = Input::get('path'); + + return $this->makePartial('move-form'); + } + + /** + * Move library item AJAX handler + * @return array + */ + public function onMoveItems() + { + $this->abortIfReadOnly(); + + $dest = trim(Input::get('dest')); + if (!strlen($dest)) { + throw new ApplicationException(Lang::get('backend::lang.media.please_select_move_dest')); + } + + $dest = MediaLibrary::validatePath($dest); + if ($dest == Input::get('originalPath')) { + throw new ApplicationException(Lang::get('backend::lang.media.move_dest_src_match')); + } + + $files = Input::get('files', []); + if (!is_array($files)) { + throw new ApplicationException('Invalid input data'); + } + + $folders = Input::get('folders', []); + if (!is_array($folders)) { + throw new ApplicationException('Invalid input data'); + } + + $library = MediaLibrary::instance(); + + foreach ($files as $path) { + /* + * Move a single file + */ + $library->moveFile($path, $dest.'/'.basename($path)); + + /** + * @event media.file.move + * Called after a file is moved + * + * Example usage: + * + * Event::listen('media.file.move', function ((\Backend\Widgets\MediaManager) $mediaWidget, (string) $path, (string) $dest) { + * \Log::info($path . " was moved to " . $dest); + * }); + * + * Or + * + * $mediaWidget->bindEvent('file.rename', function ((string) $path, (string) $dest) { + * \Log::info($path . " was moved to " . $dest); + * }); + * + */ + $this->fireSystemEvent('media.file.move', [$path, $dest]); + } + + foreach ($folders as $path) { + /* + * Move a single folder + */ + $library->moveFolder($path, $dest.'/'.basename($path)); + + /** + * @event media.folder.move + * Called after a folder is moved + * + * Example usage: + * + * Event::listen('media.folder.move', function ((\Backend\Widgets\MediaManager) $mediaWidget, (string) $path, (string) $dest) { + * \Log::info($path . " was moved to " . $dest); + * }); + * + * Or + * + * $mediaWidget->bindEvent('folder.rename', function ((string) $path, (string) $dest) { + * \Log::info($path . " was moved to " . $dest); + * }); + * + */ + $this->fireSystemEvent('media.folder.move', [$path, $dest]); + } + + $library->resetCache(); + + $this->prepareVars(); + + return [ + '#'.$this->getId('item-list') => $this->makePartial('item-list') + ]; + } + + /** + * Sidebar visibility AJAX handler + * @return array + */ + public function onSetSidebarVisible() + { + $visible = Input::get('visible'); + + $this->setSidebarVisible($visible); + } + + /** + * Start image cropping session AJAX handler + * @return array + */ + public function onLoadPopup() + { + $this->bottomToolbar = Input::get('bottomToolbar', $this->bottomToolbar); + + $this->cropAndInsertButton = Input::get('cropAndInsertButton', $this->cropAndInsertButton); + + return $this->makePartial('popup-body'); + } + + /** + * Load image for cropping AJAX handler + * @return array + */ + public function onLoadImageCropPopup() + { + $this->abortIfReadOnly(); + + $path = Input::get('path'); + $path = MediaLibrary::validatePath($path); + $cropSessionKey = md5(FormHelper::getSessionKey()); + $selectionParams = $this->getSelectionParams(); + + $urlAndSize = $this->getCropEditImageUrlAndSize($path, $cropSessionKey); + $width = $urlAndSize['dimensions'][0]; + $height = $urlAndSize['dimensions'][1] ?: 1; + + $this->vars['currentSelectionMode'] = $selectionParams['mode']; + $this->vars['currentSelectionWidth'] = $selectionParams['width']; + $this->vars['currentSelectionHeight'] = $selectionParams['height']; + $this->vars['cropSessionKey'] = $cropSessionKey; + $this->vars['imageUrl'] = $urlAndSize['url']; + $this->vars['dimensions'] = $urlAndSize['dimensions']; + $this->vars['originalRatio'] = round($width / $height, 5); + $this->vars['path'] = $path; + + return $this->makePartial('image-crop-popup-body'); + } + + /** + * End crop session AJAX handler + * @return array + */ + public function onEndCroppingSession() + { + $this->abortIfReadOnly(); + + $cropSessionKey = Input::get('cropSessionKey'); + if (!preg_match('/^[0-9a-z]+$/', $cropSessionKey)) { + throw new ApplicationException('Invalid input data'); + } + + $this->removeCropEditDir($cropSessionKey); + } + + /** + * Crop image AJAX handler + * @return array + */ + public function onCropImage() + { + $this->abortIfReadOnly(); + + $imageSrcPath = trim(Input::get('img')); + $selectionData = Input::get('selection'); + $cropSessionKey = Input::get('cropSessionKey'); + $path = Input::get('path'); + $path = MediaLibrary::validatePath($path); + + if (!strlen($imageSrcPath)) { + throw new ApplicationException('Invalid input data'); + } + + if (!preg_match('/^[0-9a-z]+$/', $cropSessionKey)) { + throw new ApplicationException('Invalid input data'); + } + + if (!is_array($selectionData)) { + throw new ApplicationException('Invalid input data'); + } + + $result = $this->cropImage($imageSrcPath, $selectionData, $cropSessionKey, $path); + + $selectionMode = Input::get('selectionMode'); + $selectionWidth = Input::get('selectionWidth'); + $selectionHeight = Input::get('selectionHeight'); + + $this->setSelectionParams($selectionMode, $selectionWidth, $selectionHeight); + + return $result; + } + + /** + * Resize image AJAX handler + * @return array + */ + public function onResizeImage() + { + $this->abortIfReadOnly(); + + $cropSessionKey = Input::get('cropSessionKey'); + if (!preg_match('/^[0-9a-z]+$/', $cropSessionKey)) { + throw new ApplicationException('Invalid input data'); + } + + $width = trim(Input::get('width')); + if (!strlen($width) || !ctype_digit($width)) { + throw new ApplicationException('Invalid input data'); + } + + $height = trim(Input::get('height')); + if (!strlen($height) || !ctype_digit($height)) { + throw new ApplicationException('Invalid input data'); + } + + $path = Input::get('path'); + $path = MediaLibrary::validatePath($path); + + $params = [ + 'width' => $width, + 'height' => $height + ]; + + return $this->getCropEditImageUrlAndSize($path, $cropSessionKey, $params); + } + + // + // Methods for internal use + // + + /** + * Internal method to prepare view variables. + * @return array + */ + protected function prepareVars() + { + clearstatcache(); + + $folder = $this->getCurrentFolder(); + $viewMode = $this->getViewMode(); + $filter = $this->getFilter(); + $sortBy = $this->getSortBy(); + $sortDirection = $this->getSortDirection(); + $searchTerm = $this->getSearchTerm(); + $searchMode = strlen($searchTerm) > 0; + + if (!$searchMode) { + $this->vars['items'] = $this->listFolderItems($folder, $filter, ['by' => $sortBy, 'direction' => $sortDirection]); + } + else { + $this->vars['items'] = $this->findFiles($searchTerm, $filter, ['by' => $sortBy, 'direction' => $sortDirection]); + } + + $this->vars['currentFolder'] = $folder; + $this->vars['isRootFolder'] = $folder == self::FOLDER_ROOT; + $this->vars['pathSegments'] = $this->splitPathToSegments($folder); + $this->vars['viewMode'] = $viewMode; + $this->vars['thumbnailParams'] = $this->getThumbnailParams($viewMode); + $this->vars['currentFilter'] = $filter; + $this->vars['sortBy'] = $sortBy; + $this->vars['sortDirection'] = $sortDirection; + $this->vars['searchMode'] = $searchMode; + $this->vars['searchTerm'] = $searchTerm; + $this->vars['sidebarVisible'] = $this->getSidebarVisible(); + } + + /** + * Returns a list of folders and files in a Library folder. + * @param string $searchTerm + * @param string $filter + * @param string $sortBy + * @param array[System\Classes\MediaLibraryItem] + */ + protected function listFolderItems($folder, $filter, $sortBy) + { + $filter = $filter !== self::FILTER_EVERYTHING ? $filter : null; + + return MediaLibrary::instance()->listFolderContents($folder, $sortBy, $filter); + } + + /** + * Finds files from within the media library based on supplied criteria, + * returns an array of MediaLibraryItem objects. + * @param string $searchTerm + * @param string $filter + * @param string $sortBy + * @param array[System\Classes\MediaLibraryItem] + */ + protected function findFiles($searchTerm, $filter, $sortBy) + { + $filter = $filter !== self::FILTER_EVERYTHING ? $filter : null; + + return MediaLibrary::instance()->findFiles($searchTerm, $sortBy, $filter); + } + + /** + * Sets the user current folder from the session state + * @param string $path + * @return void + */ + protected function setCurrentFolder($path) + { + $path = MediaLibrary::validatePath($path); + + $this->putSession('media_folder', $path); + } + + /** + * Gets the user current folder from the session state + * @return string + */ + protected function getCurrentFolder() + { + return $this->getSession('media_folder', self::FOLDER_ROOT); + } + + /** + * Sets the user filter from the session state + * @param string $filter + * @return void + */ + protected function setFilter($filter) + { + if (!in_array($filter, [ + self::FILTER_EVERYTHING, + MediaLibraryItem::FILE_TYPE_IMAGE, + MediaLibraryItem::FILE_TYPE_AUDIO, + MediaLibraryItem::FILE_TYPE_DOCUMENT, + MediaLibraryItem::FILE_TYPE_VIDEO + ])) { + throw new ApplicationException('Invalid input data'); + } + + $this->putSession('media_filter', $filter); + } + + /** + * Gets the user filter from the session state + * @return string + */ + protected function getFilter() + { + return $this->getSession('media_filter', self::FILTER_EVERYTHING); + } + + /** + * Sets the user search term from the session state + * @param string $searchTerm + * @return void + */ + protected function setSearchTerm($searchTerm) + { + $this->putSession('media_search', trim($searchTerm)); + } + + /** + * Gets the user search term from the session state + * @return string + */ + protected function getSearchTerm() + { + return $this->getSession('media_search', null); + } + + /** + * Sets the user sort column from the session state + * @param string $sortBy + * @return void + */ + protected function setSortBy($sortBy) + { + if (!in_array($sortBy, [ + MediaLibrary::SORT_BY_TITLE, + MediaLibrary::SORT_BY_SIZE, + MediaLibrary::SORT_BY_MODIFIED + ])) { + throw new ApplicationException('Invalid input data'); + } + + $this->putSession('media_sort_by', $sortBy); + } + + /** + * Gets the user sort column from the session state + * @return string + */ + protected function getSortBy() + { + return $this->getSession('media_sort_by', MediaLibrary::SORT_BY_TITLE); + } + + /** + * Sets the user sort direction from the session state + * @param string $sortDirection + * @return void + */ + protected function setSortDirection($sortDirection) + { + if (!in_array($sortDirection, [ + MediaLibrary::SORT_DIRECTION_ASC, + MediaLibrary::SORT_DIRECTION_DESC + ])) { + throw new ApplicationException('Invalid input data'); + } + + $this->putSession('media_sort_direction', $sortDirection); + } + + /** + * Gets the user sort direction from the session state + * @return string + */ + protected function getSortDirection() + { + return $this->getSession('media_sort_direction', MediaLibrary::SORT_DIRECTION_ASC); + } + + /** + * Gets the user selection parameters from the session state + * @return array + */ + protected function getSelectionParams() + { + $result = $this->getSession('media_crop_selection_params'); + + if ($result) { + if (!isset($result['mode'])) { + $result['mode'] = self::SELECTION_MODE_NORMAL; + } + + if (!isset($result['width'])) { + $result['width'] = null; + } + + if (!isset($result['height'])) { + $result['height'] = null; + } + + return $result; + } + + return [ + 'mode' => self::SELECTION_MODE_NORMAL, + 'width' => null, + 'height' => null + ]; + } + + /** + * Stores the user selection parameters in the session state + * @param string $selectionMode + * @param int $selectionWidth + * @param int $selectionHeight + * @return void + */ + protected function setSelectionParams($selectionMode, $selectionWidth, $selectionHeight) + { + if (!in_array($selectionMode, [ + self::SELECTION_MODE_NORMAL, + self::SELECTION_MODE_FIXED_RATIO, + self::SELECTION_MODE_FIXED_SIZE + ])) { + throw new ApplicationException('Invalid input data'); + } + + if (strlen($selectionWidth) && !ctype_digit($selectionWidth)) { + throw new ApplicationException('Invalid input data'); + } + + if (strlen($selectionHeight) && !ctype_digit($selectionHeight)) { + throw new ApplicationException('Invalid input data'); + } + + $this->putSession('media_crop_selection_params', [ + 'mode' => $selectionMode, + 'width' => $selectionWidth, + 'height' => $selectionHeight + ]); + } + + /** + * Sets the sidebar visible state + * @param bool $visible + * @return void + */ + protected function setSidebarVisible($visible) + { + $this->putSession('sidebar_visible', !!$visible); + } + + /** + * Checks if the sidebar is visible + * @return bool + */ + protected function getSidebarVisible() + { + return $this->getSession('sidebar_visible', true); + } + + /** + * Returns an icon for the item type + * @param System\Classes\MediaLibraryItem $item + * @param string $itemType + * @return string + */ + protected function itemTypeToIconClass($item, $itemType) + { + if ($item->type == MediaLibraryItem::TYPE_FOLDER) { + return 'icon-folder'; + } + + switch ($itemType) { + case MediaLibraryItem::FILE_TYPE_IMAGE: + return "icon-picture-o"; + case MediaLibraryItem::FILE_TYPE_VIDEO: + return "icon-video-camera"; + case MediaLibraryItem::FILE_TYPE_AUDIO: + return "icon-volume-up"; + default: + return "icon-file"; + } + } + + /** + * Splits a path in to segments + * @param string $path + * @return array + */ + protected function splitPathToSegments($path) + { + $path = MediaLibrary::validatePath($path, true); + $path = explode('/', ltrim($path, '/')); + + $result = []; + while (count($path) > 0) { + $folder = array_pop($path); + + $result[$folder] = implode('/', $path).'/'.$folder; + if (substr($result[$folder], 0, 1) != '/') { + $result[$folder] = '/'.$result[$folder]; + } + } + + return array_reverse($result, true); + } + + /** + * Stores a view mode in the session + * @param string $viewMode + * @return void + */ + protected function setViewMode($viewMode) + { + if (!in_array($viewMode, [ + self::VIEW_MODE_GRID, + self::VIEW_MODE_LIST, + self::VIEW_MODE_TILES + ])) { + throw new ApplicationException('Invalid input data'); + } + + $this->putSession('view_mode', $viewMode); + } + + /** + * Returns the current view mode stored in the session + * @return string + */ + protected function getViewMode() + { + return $this->getSession('view_mode', self::VIEW_MODE_GRID); + } + + /** + * Returns thumbnail parameters + * @param string $viewMode + * @return array + */ + protected function getThumbnailParams($viewMode = null) + { + $result = [ + 'mode' => 'crop' + ]; + + if ($viewMode) { + if ($viewMode == self::VIEW_MODE_LIST) { + $result['width'] = 75; + $result['height'] = 75; + } + else { + $result['width'] = 165; + $result['height'] = 165; + } + } + + return $result; + } + + /** + * Generates a thumbnail image path + * @param array|null $thumbnailParams + * @param string $itemPath + * @param int $lastModified + * @return string + */ + protected function getThumbnailImagePath($thumbnailParams, $itemPath, $lastModified) + { + $itemSignature = md5($itemPath).$lastModified; + + $thumbFile = 'thumb_' . + $itemSignature . '_' . + $thumbnailParams['width'] . 'x' . + $thumbnailParams['height'] . '_' . + $thumbnailParams['mode'] . '.' . + $this->getThumbnailImageExtension($itemPath); + + $partition = implode('/', array_slice(str_split($itemSignature, 3), 0, 3)) . '/'; + + return $this->getThumbnailDirectory().$partition.$thumbFile; + } + + /** + * Preferred thumbnail image extension + * @param string $itemPath + * @return string + */ + protected function getThumbnailImageExtension($itemPath) + { + $extension = pathinfo($itemPath, PATHINFO_EXTENSION); + + if (in_array($extension, ['png', 'gif', 'webp'])) { + return $extension; + } + + return 'jpg'; + } + + /** + * Returns the URL to a thumbnail + * @param string $imagePath + * @return string + */ + protected function getThumbnailImageUrl($imagePath) + { + return Url::to('/storage/temp'.$imagePath); + } + + /** + * Check if a thumbnail exists + * @param array|null $thumbnailParams + * @param string $itemPath + * @param int $lastModified + * @return bool + */ + protected function thumbnailExists($thumbnailParams, $itemPath, $lastModified) + { + $thumbnailPath = $this->getThumbnailImagePath($thumbnailParams, $itemPath, $lastModified); + + $fullPath = temp_path(ltrim($thumbnailPath, '/')); + + if (File::exists($fullPath)) { + return $thumbnailPath; + } + + return false; + } + + /** + * Check if a thumbnail has caused an error + * @param string $thumbnailPath + * @return bool + */ + protected function thumbnailIsError($thumbnailPath) + { + $fullPath = temp_path(ltrim($thumbnailPath, '/')); + + return hash_file('crc32', $fullPath) == $this->getBrokenImageHash(); + } + + /** + * Get temporary local file path + * @param string $fileName + * @return string + */ + protected function getLocalTempFilePath($fileName) + { + $fileName = md5($fileName.uniqid().microtime()); + + $mediaFolder = Config::get('cms.storage.media.folder', 'media'); + + $path = temp_path() . MediaLibrary::validatePath($mediaFolder, true); + + if (!File::isDirectory($path)) { + File::makeDirectory($path, 0777, true, true); + } + + return $path.'/'.$fileName; + } + + /** + * Get thumbnail directory + * @return string + */ + protected function getThumbnailDirectory() + { + /* + * NOTE: Custom routing for /storage/temp/$thumbnailDirectory must be setup + * to return the thumbnail if not using default 'public' directory + */ + return MediaLibrary::validatePath(Config::get('cms.storage.media.thumbFolder', 'public'), true) . '/'; + } + + /** + * Get placeholder identifier + * @param System\Classes\MediaLibraryItem $item + * @return string + */ + protected function getPlaceholderId($item) + { + return 'placeholder'.md5($item->path.'-'.$item->lastModified.uniqid(microtime())); + } + + /** + * Generate thumbnail + * @param array $thumbnailInfo + * @param array|null $thumbnailParams + * @return array + */ + protected function generateThumbnail($thumbnailInfo, $thumbnailParams = null) + { + $tempFilePath = null; + $fullThumbnailPath = null; + $thumbnailPath = null; + $markup = null; + + try { + $path = $thumbnailInfo['path']; + + if ($this->isVector($path)) { + $markup = $this->makePartial('thumbnail-image', [ + 'isError' => false, + 'imageUrl' => Url::to(config('cms.storage.media.path') . $thumbnailInfo['path']) + ]); + } else { + /* + * Get and validate input data + */ + $width = $thumbnailInfo['width']; + $height = $thumbnailInfo['height']; + $lastModified = $thumbnailInfo['lastModified']; + + if (!is_numeric($width) || !is_numeric($height) || !is_numeric($lastModified)) { + throw new ApplicationException('Invalid input data'); + } + + if (!$thumbnailParams) { + $thumbnailParams = $this->getThumbnailParams(); + $thumbnailParams['width'] = $width; + $thumbnailParams['height'] = $height; + } + + $thumbnailPath = $this->getThumbnailImagePath($thumbnailParams, $path, $lastModified); + $fullThumbnailPath = temp_path(ltrim($thumbnailPath, '/')); + + /* + * Save the file locally + */ + $library = MediaLibrary::instance(); + $tempFilePath = $this->getLocalTempFilePath($path); + + if (!@File::put($tempFilePath, $library->get($path))) { + throw new SystemException('Error saving remote file to a temporary location'); + } + + /* + * Resize the thumbnail and save to the thumbnails directory + */ + $this->resizeImage($fullThumbnailPath, $thumbnailParams, $tempFilePath); + + /* + * Delete the temporary file + */ + File::delete($tempFilePath); + $markup = $this->makePartial('thumbnail-image', [ + 'isError' => false, + 'imageUrl' => $this->getThumbnailImageUrl($thumbnailPath) + ]); + } + } catch (Exception $ex) { + if ($tempFilePath) { + File::delete($tempFilePath); + } + + if ($fullThumbnailPath) { + $this->copyBrokenImage($fullThumbnailPath); + } + + $markup = $this->makePartial('thumbnail-image', ['isError' => true]); + + /* + * @todo We need to log all types of exceptions here + */ + traceLog($ex->getMessage()); + } + + if ($markup && ($id = $thumbnailInfo['id'])) { + return [ + 'id' => $id, + 'markup' => $markup + ]; + } + } + + /** + * Resize an image + * @param string $fullThumbnailPath + * @param array $thumbnailParams + * @param string $tempFilePath + * @return void + */ + protected function resizeImage($fullThumbnailPath, $thumbnailParams, $tempFilePath) + { + $thumbnailDir = dirname($fullThumbnailPath); + if ( + !File::isDirectory($thumbnailDir) + && File::makeDirectory($thumbnailDir, 0777, true) === false + ) { + throw new SystemException('Error creating thumbnail directory'); + } + + $targetDimensions = $this->getTargetDimensions($thumbnailParams['width'], $thumbnailParams['height'], $tempFilePath); + + $targetWidth = $targetDimensions[0]; + $targetHeight = $targetDimensions[1]; + + Resizer::open($tempFilePath) + ->resize($targetWidth, $targetHeight, [ + 'mode' => $thumbnailParams['mode'], + 'offset' => [0, 0] + ]) + ->save($fullThumbnailPath) + ; + + File::chmod($fullThumbnailPath); + } + + /** + * Returns the path for the broken image graphic + * @return string + */ + protected function getBrokenImagePath() + { + return __DIR__.'/mediamanager/assets/images/broken-thumbnail.gif'; + } + + /** + * Returns a CRC32 hash for a broken image + * @return string + */ + protected function getBrokenImageHash() + { + if ($this->brokenImageHash) { + return $this->brokenImageHash; + } + + $fullPath = $this->getBrokenImagePath(); + + return $this->brokenImageHash = hash_file('crc32', $fullPath); + } + + /** + * Copy broken image to destination + * @param string $path + * @return void + */ + protected function copyBrokenImage($path) + { + try { + $thumbnailDir = dirname($path); + if (!File::isDirectory($thumbnailDir) && File::makeDirectory($thumbnailDir, 0777, true) === false) { + return; + } + + File::copy($this->getBrokenImagePath(), $path); + } + catch (Exception $ex) { + traceLog($ex->getMessage()); + } + } + + /** + * Get target dimensions + * @param int $width + * @param int $height + * @param string $originalImagePath + * @return void + */ + protected function getTargetDimensions($width, $height, $originalImagePath) + { + $originalDimensions = [$width, $height]; + + try { + $dimensions = getimagesize($originalImagePath); + if (!$dimensions) { + return $originalDimensions; + } + + if ($dimensions[0] > $width || $dimensions[1] > $height) { + return $originalDimensions; + } + + return $dimensions; + } + catch (Exception $ex) { + return $originalDimensions; + } + } + + // + // Cropping + // + + /** + * Returns the crop session working directory path + * @param string $cropSessionKey + * @return string + */ + protected function getCropSessionDirPath($cropSessionKey) + { + return $this->getThumbnailDirectory().'edit-crop-'.$cropSessionKey; + } + + /** + * Prepares an image for cropping and returns payload containing a URL + * @param string $path + * @param string $cropSessionKey + * @param array $params + * @return array + */ + protected function getCropEditImageUrlAndSize($path, $cropSessionKey, $params = null) + { + $sessionDirectoryPath = $this->getCropSessionDirPath($cropSessionKey); + $fullSessionDirectoryPath = temp_path($sessionDirectoryPath); + $sessionDirectoryCreated = false; + + if (!File::isDirectory($fullSessionDirectoryPath)) { + File::makeDirectory($fullSessionDirectoryPath, 0777, true, true); + $sessionDirectoryCreated = true; + } + + $tempFilePath = null; + + try { + $extension = pathinfo($path, PATHINFO_EXTENSION); + $library = MediaLibrary::instance(); + $originalThumbFileName = 'original.'.$extension; + + /* + * If the target dimensions are not provided, save the original image to the + * crop session directory and return its URL. + */ + if (!$params) { + $tempFilePath = $fullSessionDirectoryPath.'/'.$originalThumbFileName; + + if (!@File::put($tempFilePath, $library->get($path))) { + throw new SystemException('Error saving remote file to a temporary location.'); + } + + $url = $this->getThumbnailImageUrl($sessionDirectoryPath.'/'.$originalThumbFileName); + $dimensions = getimagesize($tempFilePath); + + return [ + 'url' => $url, + 'dimensions' => $dimensions + ]; + } + /* + * If the target dimensions are provided, resize the original image and + * return its URL and dimensions. + */ + + $originalFilePath = $fullSessionDirectoryPath.'/'.$originalThumbFileName; + if (!File::isFile($originalFilePath)) { + throw new SystemException('The original image is not found in the cropping session directory.'); + } + + $resizedThumbFileName = 'resized-'.$params['width'].'-'.$params['height'].'.'.$extension; + $tempFilePath = $fullSessionDirectoryPath.'/'.$resizedThumbFileName; + + Resizer::open($originalFilePath) + ->resize($params['width'], $params['height'], [ + 'mode' => 'exact' + ]) + ->save($tempFilePath) + ; + + $url = $this->getThumbnailImageUrl($sessionDirectoryPath.'/'.$resizedThumbFileName); + $dimensions = getimagesize($tempFilePath); + + return [ + 'url' => $url, + 'dimensions' => $dimensions + ]; + } + catch (Exception $ex) { + if ($sessionDirectoryCreated) { + @File::deleteDirectory($fullSessionDirectoryPath); + } + + if ($tempFilePath) { + File::delete($tempFilePath); + } + + throw $ex; + } + } + + /** + * Cleans up the directory used for cropping based on the session key + * @param string $cropSessionKey + * @return void + */ + protected function removeCropEditDir($cropSessionKey) + { + $sessionDirectoryPath = $this->getCropSessionDirPath($cropSessionKey); + $fullSessionDirectoryPath = temp_path($sessionDirectoryPath); + + if (File::isDirectory($fullSessionDirectoryPath)) { + @File::deleteDirectory($fullSessionDirectoryPath); + } + } + + /** + * Business logic to crop a media library image + * @param string $imageSrcPath + * @param string $selectionData + * @param string $cropSessionKey + * @param string $path + * @return array + */ + protected function cropImage($imageSrcPath, $selectionData, $cropSessionKey, $path) + { + $originalFileName = basename($path); + + $path = rtrim(dirname($path), '/').'/'; + $fileName = basename($imageSrcPath); + + if ( + strpos($fileName, '..') !== false || + strpos($fileName, '/') !== false || + strpos($fileName, '\\') !== false + ) { + throw new SystemException('Invalid image file name.'); + } + + $selectionParams = ['x', 'y', 'w', 'h']; + + foreach ($selectionParams as $paramName) { + if (!array_key_exists($paramName, $selectionData)) { + throw new SystemException('Invalid selection data.'); + } + + if (!is_numeric($selectionData[$paramName])) { + throw new SystemException('Invalid selection data.'); + } + + $selectionData[$paramName] = (int) $selectionData[$paramName]; + } + + $sessionDirectoryPath = $this->getCropSessionDirPath($cropSessionKey); + $fullSessionDirectoryPath = temp_path($sessionDirectoryPath); + + if (!File::isDirectory($fullSessionDirectoryPath)) { + throw new SystemException('The image editing session is not found.'); + } + + /* + * Find the image on the disk and resize it + */ + $imagePath = $fullSessionDirectoryPath.'/'.$fileName; + if (!File::isFile($imagePath)) { + throw new SystemException('The image is not found on the disk.'); + } + + $extension = pathinfo($originalFileName, PATHINFO_EXTENSION); + + $targetImageName = basename($originalFileName, '.'.$extension).'-' + .$selectionData['x'].'-' + .$selectionData['y'].'-' + .$selectionData['w'].'-' + .$selectionData['h'].'-'; + + $targetImageName .= time(); + $targetImageName .= '.'.$extension; + + $targetTmpPath = $fullSessionDirectoryPath.'/'.$targetImageName; + + /* + * Crop the image, otherwise copy original to target destination. + */ + if ($selectionData['w'] == 0 || $selectionData['h'] == 0) { + File::copy($imagePath, $targetTmpPath); + } + else { + Resizer::open($imagePath) + ->crop( + $selectionData['x'], + $selectionData['y'], + $selectionData['w'], + $selectionData['h'], + $selectionData['w'], + $selectionData['h'] + ) + ->save($targetTmpPath) + ; + } + + /* + * Upload the cropped file to the Library + */ + $targetFolder = $path.'cropped-images'; + $targetPath = $targetFolder.'/'.$targetImageName; + + $library = MediaLibrary::instance(); + $library->put($targetPath, file_get_contents($targetTmpPath)); + + return [ + 'publicUrl' => $library->getPathUrl($targetPath), + 'documentType' => MediaLibraryItem::FILE_TYPE_IMAGE, + 'itemType' => MediaLibraryItem::TYPE_FILE, + 'path' => $targetPath, + 'title' => $targetImageName, + 'folder' => $targetFolder + ]; + } + + /** + * Detect if image is vector graphic (SVG) + * @param string $path + * @return boolean + */ + protected function isVector($path) + { + return (pathinfo($path, PATHINFO_EXTENSION) == 'svg'); + } +} diff --git a/modules/backend/widgets/ReportContainer.php b/modules/backend/widgets/ReportContainer.php new file mode 100644 index 0000000..add008e --- /dev/null +++ b/modules/backend/widgets/ReportContainer.php @@ -0,0 +1,513 @@ +getConfigPath($configuration); + if (File::isFile($path)) { + $configuration = $this->makeConfig($path); + } + else { + $configuration = []; + } + } + + parent::__construct($controller, $configuration); + + $this->fillFromConfig(); + $this->bindToController(); + } + + /** + * Ensure report widgets are registered so they can also be bound to + * the controller this allows their AJAX features to operate. + * @return void + */ + public function bindToController() + { + $this->defineReportWidgets(); + parent::bindToController(); + } + + /** + * Renders this widget along with its collection of report widgets. + */ + public function render() + { + $this->defineReportWidgets(); + $this->vars['widgets'] = $this->reportWidgets; + return $this->makePartial('container'); + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addCss('css/reportcontainer.css', 'core'); + $this->addJs('vendor/isotope/jquery.isotope.min.js', 'core'); + $this->addJs('js/reportcontainer.js', 'core'); + } + + // + // Event handlers + // + + public function onResetWidgets() + { + $this->resetWidgets(); + + $this->vars['widgets'] = $this->reportWidgets; + + Flash::success(Lang::get('backend::lang.dashboard.reset_layout_success')); + + return ['#'.$this->getId('container-list') => $this->makePartial('widget_list')]; + } + + public function onMakeLayoutDefault() + { + if (!BackendAuth::getUser()->hasAccess('backend.manage_default_dashboard')) { + throw new ApplicationException("You do not have permission to do that."); + } + + $widgets = $this->getWidgetsFromUserPreferences(); + + SystemParameters::set($this->getSystemParametersKey(), $widgets); + + Flash::success(Lang::get('backend::lang.dashboard.make_default_success')); + } + + public function onUpdateWidget() + { + $alias = Request::input('alias'); + + $widget = $this->findWidgetByAlias($alias); + + $widget->setProperties(json_decode(Request::input('fields'), true)); + + $this->saveWidgetProperties($alias, $widget->getProperties()); + + return [ + '#'.$alias => $widget->render() + ]; + } + + public function onRemoveWidget() + { + $alias = Request::input('alias'); + + $this->removeWidget($alias); + } + + public function onLoadAddPopup() + { + $sizes = []; + for ($i = 1; $i <= 12; $i++) { + $sizes[$i] = $i < 12 ? $i : $i.' (' . Lang::get('backend::lang.dashboard.full_width') . ')'; + } + + $this->vars['sizes'] = $sizes; + $this->vars['widgets'] = WidgetManager::instance()->listReportWidgets(); + + return $this->makePartial('new_widget_popup'); + } + + public function onAddWidget() + { + $className = trim(Request::input('className')); + $size = trim(Request::input('size')); + + if (!$className) { + throw new ApplicationException('Please select a widget to add.'); + } + + if (!class_exists($className)) { + throw new ApplicationException('The selected class doesn\'t exist.'); + } + + $widget = new $className($this->controller); + if (!($widget instanceof \Backend\Classes\ReportWidgetBase)) { + throw new ApplicationException('The selected class is not a report widget.'); + } + + $widgetInfo = $this->addWidget($widget, $size); + + return [ + '@#'.$this->getId('container-list') => $this->makePartial('widget', [ + 'widget' => $widget, + 'widgetAlias' => $widgetInfo['alias'], + 'sortOrder' => $widgetInfo['sortOrder'] + ]) + ]; + } + + public function addWidget($widget, $size) + { + if (!$this->canAddAndDelete) { + throw new ApplicationException('Access denied.'); + } + + $widgets = $this->getWidgetsFromUserPreferences(); + + $num = count($widgets); + do { + $num++; + $alias = 'report_container_'.$this->context.'_'.$num; + } + while (array_key_exists($alias, $widgets)); + + // Ensure that the widget's alias is correctly set for this request + $widget->alias = $alias; + + $sortOrder = 0; + foreach ($widgets as $widgetInfo) { + $sortOrder = max($sortOrder, $widgetInfo['sortOrder']); + } + + $sortOrder++; + + $widget->setProperty('ocWidgetWidth', $size); + + $widgets[$alias] = [ + 'class' => get_class($widget), + 'configuration' => $widget->getProperties(), + 'sortOrder' => $sortOrder + ]; + + $this->setWidgetsToUserPreferences($widgets); + + return [ + 'alias' => $alias, + 'sortOrder' => $widgets[$alias]['sortOrder'] + ]; + } + + public function onSetWidgetOrders() + { + $aliases = trim(Request::input('aliases')); + $orders = trim(Request::input('orders')); + + if (!$aliases) { + throw new ApplicationException('Invalid aliases string.'); + } + + if (!$orders) { + throw new ApplicationException('Invalid orders string.'); + } + + $aliases = explode(',', $aliases); + $orders = explode(',', $orders); + + if (count($aliases) != count($orders)) { + throw new ApplicationException('Invalid data posted.'); + } + + $widgets = $this->getWidgetsFromUserPreferences(); + foreach ($aliases as $index => $alias) { + if (isset($widgets[$alias])) { + $widgets[$alias]['sortOrder'] = $orders[$index]; + } + } + + $this->setWidgetsToUserPreferences($widgets); + } + + // + // Methods for internal use + // + + /** + * Registers the report widgets that will be included in this container. + * The chosen widgets are based on the user preferences. + */ + protected function defineReportWidgets() + { + if ($this->reportsDefined) { + return; + } + + $result = []; + $widgets = $this->getWidgetsFromUserPreferences(); + + foreach ($widgets as $alias => $widgetInfo) { + if ($widget = $this->makeReportWidget($alias, $widgetInfo)) { + $result[$alias] = $widget; + } + } + + uasort($result, function ($a, $b) { + return $a['sortOrder'] - $b['sortOrder']; + }); + + $this->reportWidgets = $result; + + $this->reportsDefined = true; + } + + /** + * Makes a single report widget object, returned array index: + * - widget: The widget object (Backend\Classes\ReportWidgetBase) + * - sortOrder: The current sort order + * + * @param string $alias + * @param array $widgetInfo + * @return array + */ + protected function makeReportWidget($alias, $widgetInfo) + { + $configuration = $widgetInfo['configuration']; + $configuration['alias'] = $alias; + + $className = $widgetInfo['class']; + $availableReportWidgets = array_keys(WidgetManager::instance()->listReportWidgets()); + if (!class_exists($className) || !in_array($className, $availableReportWidgets)) { + return; + } + + $widget = new $className($this->controller, $configuration); + $widget->bindToController(); + + return ['widget' => $widget, 'sortOrder' => $widgetInfo['sortOrder']]; + } + + protected function resetWidgets() + { + $this->resetWidgetsUserPreferences(); + + $this->reportsDefined = false; + + $this->defineReportWidgets(); + } + + protected function removeWidget($alias) + { + if (!$this->canAddAndDelete) { + throw new ApplicationException('Access denied.'); + } + + $widgets = $this->getWidgetsFromUserPreferences(); + + if (isset($widgets[$alias])) { + unset($widgets[$alias]); + } + + $this->setWidgetsToUserPreferences($widgets); + } + + protected function findWidgetByAlias($alias) + { + $this->defineReportWidgets(); + + $widgets = $this->reportWidgets; + if (!isset($widgets[$alias])) { + throw new ApplicationException('The specified widget is not found.'); + } + + return $widgets[$alias]['widget']; + } + + protected function getWidgetPropertyConfig($widget) + { + $properties = $widget->defineProperties(); + + $property = [ + 'property' => 'ocWidgetWidth', + 'title' => Lang::get('backend::lang.dashboard.widget_columns_label', ['columns' => '(1-12)']), + 'description' => Lang::get('backend::lang.dashboard.widget_columns_description'), + 'type' => 'dropdown', + 'validationPattern' => '^[0-9]+$', + 'validationMessage' => Lang::get('backend::lang.dashboard.widget_columns_error'), + 'options' => [ + 1 => '1 ' . Lang::choice('backend::lang.dashboard.columns', 1), + 2 => '2 ' . Lang::choice('backend::lang.dashboard.columns', 2), + 3 => '3 ' . Lang::choice('backend::lang.dashboard.columns', 3), + 4 => '4 ' . Lang::choice('backend::lang.dashboard.columns', 4), + 5 => '5 ' . Lang::choice('backend::lang.dashboard.columns', 5), + 6 => '6 ' . Lang::choice('backend::lang.dashboard.columns', 6), + 7 => '7 ' . Lang::choice('backend::lang.dashboard.columns', 7), + 8 => '8 ' . Lang::choice('backend::lang.dashboard.columns', 8), + 9 => '9 ' . Lang::choice('backend::lang.dashboard.columns', 9), + 10 => '10 ' . Lang::choice('backend::lang.dashboard.columns', 10), + 11 => '11 ' . Lang::choice('backend::lang.dashboard.columns', 11), + 12 => '12 ' . Lang::choice('backend::lang.dashboard.columns', 12) + ] + ]; + $result[] = $property; + + $property = [ + 'property' => 'ocWidgetNewRow', + 'title' => Lang::get('backend::lang.dashboard.widget_new_row_label'), + 'description' => Lang::get('backend::lang.dashboard.widget_new_row_description'), + 'type' => 'checkbox' + ]; + + $result[] = $property; + foreach ($properties as $name => $params) { + $property = [ + 'property' => $name, + 'title' => isset($params['title']) ? Lang::get($params['title']) : $name, + 'type' => $params['type'] ?? 'string' + ]; + + foreach ($params as $name => $value) { + if (isset($property[$name])) { + continue; + } + + $property[$name] = !is_array($value) ? Lang::get($value) : $value; + } + + $result[] = $property; + } + + return json_encode($result); + } + + protected function getWidgetPropertyValues($widget) + { + $result = []; + + $properties = $widget->defineProperties(); + foreach ($properties as $name => $params) { + $value = $widget->property($name); + if (is_string($value)) { + $value = Lang::get($value); + } + $result[$name] = $value; + } + + $result['ocWidgetWidth'] = $widget->property('ocWidgetWidth'); + $result['ocWidgetNewRow'] = $widget->property('ocWidgetNewRow'); + + return json_encode($result); + } + + // + // User and system value storage + // + + protected function getWidgetsFromUserPreferences() + { + $defaultWidgets = SystemParameters::get($this->getSystemParametersKey(), $this->defaultWidgets); + + $widgets = UserPreference::forUser() + ->get($this->getUserPreferencesKey(), $defaultWidgets); + + if (!is_array($widgets)) { + return []; + } + + return $widgets; + } + + protected function setWidgetsToUserPreferences($widgets) + { + UserPreference::forUser()->set($this->getUserPreferencesKey(), $widgets); + } + + protected function resetWidgetsUserPreferences() + { + UserPreference::forUser()->reset($this->getUserPreferencesKey()); + } + + protected function saveWidgetProperties($alias, $properties) + { + $widgets = $this->getWidgetsFromUserPreferences(); + + if (isset($widgets[$alias])) { + $widgets[$alias]['configuration'] = $properties; + + $this->setWidgetsToUserPreferences($widgets); + } + } + + protected function getUserPreferencesKey() + { + return 'backend::reportwidgets.'.$this->context; + } + + protected function getSystemParametersKey() + { + return 'backend::reportwidgets.default.'.$this->context; + } +} diff --git a/modules/backend/widgets/Search.php b/modules/backend/widgets/Search.php new file mode 100644 index 0000000..8e554fb --- /dev/null +++ b/modules/backend/widgets/Search.php @@ -0,0 +1,174 @@ +fillFromConfig([ + 'prompt', + 'partial', + 'growable', + 'scope', + 'mode', + 'searchOnEnter', + ]); + + /* + * Add CSS class styles + */ + $this->cssClasses[] = 'icon search'; + + if ($this->growable) { + $this->cssClasses[] = 'growable'; + } + } + + /** + * Renders the widget. + */ + public function render() + { + $this->prepareVars(); + + if ($this->partial) { + return $this->controller->makePartial($this->partial); + } + + return $this->makePartial('search'); + } + + /** + * Prepares the view data + */ + public function prepareVars() + { + $this->vars['cssClasses'] = implode(' ', $this->cssClasses); + $this->vars['placeholder'] = Lang::get($this->prompt); + $this->vars['value'] = $this->getActiveTerm(); + $this->vars['searchOnEnter'] = $this->searchOnEnter; + } + + /** + * Search field has been submitted. + */ + public function onSubmit() + { + /* + * Save or reset search term in session + */ + $this->setActiveTerm(post($this->getName())); + + /* + * Trigger class event, merge results as viewable array + */ + $params = func_get_args(); + try { + $result = $this->fireEvent('search.submit', [$params]); + } catch (\Throwable $e) { + // Remove the search term from the session if the search has failed. + $this->setActiveTerm(''); + throw $e; + } + + if ($result && is_array($result)) { + return call_user_func_array('array_merge', $result); + } + } + + /** + * Returns an active search term for this widget instance. + */ + public function getActiveTerm() + { + return $this->activeTerm = $this->getSession('term', ''); + } + + /** + * Sets an active search term for this widget instance. + */ + public function setActiveTerm($term) + { + if (strlen($term)) { + $this->putSession('term', $term); + } else { + $this->resetSession(); + } + + $this->activeTerm = $term; + } + + /** + * Returns a value suitable for the field name property. + * @return string + */ + public function getName() + { + return $this->alias . '[term]'; + } +} diff --git a/modules/backend/widgets/Table.php b/modules/backend/widgets/Table.php new file mode 100644 index 0000000..198f932 --- /dev/null +++ b/modules/backend/widgets/Table.php @@ -0,0 +1,328 @@ + '\Backend\Widgets\Table\ClientMemoryDataSource', + 'server' => '\Backend\Widgets\Table\ServerEventDataSource' + ]; + + /** + * Initialize the widget, called by the constructor and free from its parameters. + */ + public function init() + { + $this->columns = $this->getConfig('columns', []); + + $this->fieldName = $this->getConfig('fieldName', $this->alias); + + $this->recordsKeyFrom = $this->getConfig('keyFrom', 'id'); + + $dataSourceClass = $this->getConfig('dataSource'); + if (!strlen($dataSourceClass)) { + throw new SystemException('The Table widget data source is not specified in the configuration.'); + } + + if (array_key_exists($dataSourceClass, $this->dataSourceAliases)) { + $dataSourceClass = $this->dataSourceAliases[$dataSourceClass]; + } + + if (!class_exists($dataSourceClass)) { + throw new SystemException(sprintf('The Table widget data source class "%s" is could not be found.', $dataSourceClass)); + } + + $this->dataSource = new $dataSourceClass($this->recordsKeyFrom); + + if (Request::method() == 'POST' && $this->isClientDataSource()) { + if (strpos($this->fieldName, '[') === false) { + $requestDataField = $this->fieldName . 'TableData'; + } else { + $requestDataField = $this->fieldName . '[TableData]'; + } + + // Use dot notation for request data field + $requestDataField = implode('.', HtmlHelper::nameToArray($requestDataField)); + + if (Request::exists($requestDataField)) { + // Load data into the client memory data source on POST + $this->dataSource->purge(); + $this->dataSource->initRecords(Request::input($requestDataField)); + } + } + } + + /** + * Returns the data source object. + * @return \Backend\Widgets\Table\DataSourceBase + */ + public function getDataSource() + { + return $this->dataSource; + } + + /** + * Renders the widget. + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('table'); + } + + /** + * Prepares the view data + */ + public function prepareVars() + { + $this->vars['columns'] = $this->prepareColumnsArray(); + $this->vars['recordsKeyFrom'] = $this->recordsKeyFrom; + + $this->vars['recordsPerPage'] = $this->getConfig('recordsPerPage', false) ?: 'false'; + $this->vars['postbackHandlerName'] = $this->getConfig('postbackHandlerName'); + $this->vars['searching'] = $this->getConfig('searching', false); + $this->vars['adding'] = $this->getConfig('adding', true); + $this->vars['deleting'] = $this->getConfig('deleting', true); + $this->vars['toolbar'] = $this->getConfig('toolbar', true); + $this->vars['height'] = $this->getConfig('height', false) ?: 'false'; + $this->vars['dynamicHeight'] = $this->getConfig('dynamicHeight', false) ?: 'false'; + + $this->vars['btnAddRowLabel'] = Lang::get($this->getConfig('btnAddRowLabel', 'backend::lang.form.insert_row')); + $this->vars['btnAddRowBelowLabel'] = Lang::get($this->getConfig('btnAddRowBelowLabel', 'backend::lang.form.insert_row_below')); + $this->vars['btnDeleteRowLabel'] = Lang::get($this->getConfig('btnDeleteRowLabel', 'backend::lang.form.delete_row')); + + $isClientDataSource = $this->isClientDataSource(); + + $this->vars['clientDataSourceClass'] = $isClientDataSource ? 'client' : 'server'; + $this->vars['data'] = json_encode( + $isClientDataSource ? $this->dataSource->getAllRecords() : [] + ); + } + + // + // Internals + // + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addCss('css/table.css', 'core'); + + if (Config::get('develop.decompileBackendAssets', false)) { + $scripts = Backend::decompileAsset($this->getAssetPath('js/build.js')); + foreach ($scripts as $script) { + $this->addJs($script, 'core'); + } + } else { + $this->addJs('js/build-min.js', 'core'); + } + } + + /** + * Converts the columns associative array to a regular array and translates column headers and drop-down options. + * Working with regular arrays is much faster in JavaScript. + * References: + * - https://www.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/ + * - https://jsperf.com/performance-of-array-vs-object/3 + */ + protected function prepareColumnsArray() + { + $result = []; + + foreach ($this->columns as $key => $data) { + $data['key'] = $key; + + if (isset($data['title'])) { + $data['title'] = trans($data['title']); + } + + if (isset($data['options'])) { + foreach ($data['options'] as &$option) { + $option = trans($option); + } + } + + if (isset($data['validation'])) { + foreach ($data['validation'] as &$validation) { + if (isset($validation['message'])) { + $validation['message'] = trans($validation['message']); + } + } + } + + $result[] = $data; + } + + return $result; + } + + protected function isClientDataSource() + { + return $this->dataSource instanceof \Backend\Widgets\Table\ClientMemoryDataSource; + } + + // + // Event handlers + // + + public function onServerGetRecords() + { + // Disable asset broadcasting + $this->controller->flushAssets(); + + if ($this->isClientDataSource()) { + throw new SystemException('The Table widget is not configured to use the server data source.'); + } + + $count = post('count'); + + // Oddly, JS may pass false as a string (@todo) + if ($count === 'false') { + $count = false; + } + + return [ + 'records' => $this->dataSource->getRecords(post('offset'), $count), + 'count' => $this->dataSource->getCount() + ]; + } + + public function onServerSearchRecords() + { + // Disable asset broadcasting + $this->controller->flushAssets(); + + if ($this->isClientDataSource()) { + throw new SystemException('The Table widget is not configured to use the server data source.'); + } + + $count = post('count'); + + // Oddly, JS may pass false as a string (@todo) + if ($count === 'false') { + $count = false; + } + + return [ + 'records' => $this->dataSource->searchRecords(post('query'), post('offset'), $count), + 'count' => $this->dataSource->getCount() + ]; + } + + public function onServerCreateRecord() + { + if ($this->isClientDataSource()) { + throw new SystemException('The Table widget is not configured to use the server data source.'); + } + + $this->dataSource->createRecord( + post('recordData'), + post('placement'), + post('relativeToKey') + ); + + return $this->onServerGetRecords(); + } + + public function onServerUpdateRecord() + { + if ($this->isClientDataSource()) { + throw new SystemException('The Table widget is not configured to use the server data source.'); + } + + $this->dataSource->updateRecord(post('key'), post('recordData')); + } + + public function onServerDeleteRecord() + { + if ($this->isClientDataSource()) { + throw new SystemException('The Table widget is not configured to use the server data source.'); + } + + $this->dataSource->deleteRecord(post('key')); + + return $this->onServerGetRecords(); + } + + public function onGetDropdownOptions() + { + $columnName = Input::get('column'); + $rowData = Input::get('rowData'); + + $eventResults = $this->fireEvent('table.getDropdownOptions', [$columnName, $rowData]); + + $options = []; + if (count($eventResults)) { + $options = $eventResults[0]; + } + + return [ + 'options' => $options + ]; + } + + public function onGetAutocompleteOptions() + { + $columnName = Input::get('column'); + $rowData = Input::get('rowData'); + + $eventResults = $this->fireEvent('table.getAutocompleteOptions', [$columnName, $rowData]); + + $options = []; + if (count($eventResults)) { + $options = $eventResults[0]; + } + + return [ + 'options' => $options + ]; + } +} diff --git a/modules/backend/widgets/Toolbar.php b/modules/backend/widgets/Toolbar.php new file mode 100644 index 0000000..7d028ee --- /dev/null +++ b/modules/backend/widgets/Toolbar.php @@ -0,0 +1,106 @@ +fillFromConfig([ + 'buttons', + 'search', + ]); + + /* + * Prepare the search widget (optional) + */ + if (isset($this->search)) { + if (is_string($this->search)) { + $searchConfig = $this->makeConfig(['partial' => $this->search]); + } + else { + $searchConfig = $this->makeConfig($this->search); + } + + $searchConfig->alias = $this->alias . 'Search'; + $this->searchWidget = $this->makeWidget('Backend\Widgets\Search', $searchConfig); + $this->searchWidget->bindToController(); + } + } + + /** + * Renders the widget. + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('toolbar'); + } + + /** + * Prepares the view data + */ + public function prepareVars() + { + $this->vars['search'] = $this->searchWidget ? $this->searchWidget->render() : ''; + $this->vars['cssClasses'] = implode(' ', $this->cssClasses); + $this->vars['controlPanel'] = $this->makeControlPanel(); + } + + public function getSearchWidget() + { + return $this->searchWidget; + } + + public function makeControlPanel() + { + if (!isset($this->buttons)) { + return false; + } + + return $this->controller->makePartial($this->buttons, $this->vars); + } +} diff --git a/modules/backend/widgets/filter/partials/_filter.htm b/modules/backend/widgets/filter/partials/_filter.htm new file mode 100644 index 0000000..2d8f510 --- /dev/null +++ b/modules/backend/widgets/filter/partials/_filter.htm @@ -0,0 +1,10 @@ +
    + + makePartial('filter_scopes') ?> + +
    diff --git a/modules/backend/widgets/filter/partials/_filter_scopes.htm b/modules/backend/widgets/filter/partials/_filter_scopes.htm new file mode 100644 index 0000000..95bdf2f --- /dev/null +++ b/modules/backend/widgets/filter/partials/_filter_scopes.htm @@ -0,0 +1,3 @@ + + renderScopeElement($scope) ?> + diff --git a/modules/backend/widgets/filter/partials/_scope_checkbox.htm b/modules/backend/widgets/filter/partials/_scope_checkbox.htm new file mode 100644 index 0000000..3b618af --- /dev/null +++ b/modules/backend/widgets/filter/partials/_scope_checkbox.htm @@ -0,0 +1,7 @@ + +
    + value ? 'checked' : '' ?> /> + +
    diff --git a/modules/backend/widgets/filter/partials/_scope_date.htm b/modules/backend/widgets/filter/partials/_scope_date.htm new file mode 100644 index 0000000..b8a0191 --- /dev/null +++ b/modules/backend/widgets/filter/partials/_scope_date.htm @@ -0,0 +1,17 @@ + +ignoreTimezone ? 'data-ignore-timezone' : ''; ?> +> + label)) ?>: + + diff --git a/modules/backend/widgets/filter/partials/_scope_daterange.htm b/modules/backend/widgets/filter/partials/_scope_daterange.htm new file mode 100644 index 0000000..9c33638 --- /dev/null +++ b/modules/backend/widgets/filter/partials/_scope_daterange.htm @@ -0,0 +1,17 @@ + +ignoreTimezone ? 'data-ignore-timezone' : ''; ?> +> + label)) ?>: + + diff --git a/modules/backend/widgets/filter/partials/_scope_group.htm b/modules/backend/widgets/filter/partials/_scope_group.htm new file mode 100644 index 0000000..c5cc726 --- /dev/null +++ b/modules/backend/widgets/filter/partials/_scope_group.htm @@ -0,0 +1,10 @@ + +getScopeDepends($scope)): ?>data-scope-depends="" +> + label)) ?>: + value ? count($scope->value) : e(trans('backend::lang.filter.all')) ?> + diff --git a/modules/backend/widgets/filter/partials/_scope_number.htm b/modules/backend/widgets/filter/partials/_scope_number.htm new file mode 100644 index 0000000..be83619 --- /dev/null +++ b/modules/backend/widgets/filter/partials/_scope_number.htm @@ -0,0 +1,12 @@ + + + label)) ?>: + + diff --git a/modules/backend/widgets/filter/partials/_scope_numberrange.htm b/modules/backend/widgets/filter/partials/_scope_numberrange.htm new file mode 100644 index 0000000..d6747b8 --- /dev/null +++ b/modules/backend/widgets/filter/partials/_scope_numberrange.htm @@ -0,0 +1,12 @@ + + + label)) ?>: + + diff --git a/modules/backend/widgets/filter/partials/_scope_switch.htm b/modules/backend/widgets/filter/partials/_scope_switch.htm new file mode 100644 index 0000000..0a9bf2d --- /dev/null +++ b/modules/backend/widgets/filter/partials/_scope_switch.htm @@ -0,0 +1,7 @@ + +
    + + +
    diff --git a/modules/backend/widgets/filter/partials/_scope_text.htm b/modules/backend/widgets/filter/partials/_scope_text.htm new file mode 100644 index 0000000..c1dcdab --- /dev/null +++ b/modules/backend/widgets/filter/partials/_scope_text.htm @@ -0,0 +1,15 @@ +
    + +
    diff --git a/modules/backend/widgets/form/assets/js/october.form.js b/modules/backend/widgets/form/assets/js/october.form.js new file mode 100644 index 0000000..f412f6b --- /dev/null +++ b/modules/backend/widgets/form/assets/js/october.form.js @@ -0,0 +1,371 @@ +/* + * Form Widget + * + * Dependences: + * - Nil + */ ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var FormWidget = function (element, options) { + this.$el = $(element) + this.options = options || {} + this.fieldElementCache = null + + /* + * Throttle dependency updating + */ + this.dependantUpdateInterval = 300 + this.dependantUpdateTimers = {} + + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + this.init() + } + + FormWidget.prototype = Object.create(BaseProto) + FormWidget.prototype.constructor = FormWidget + + FormWidget.prototype.init = function() { + + this.$form = this.$el.closest('form') + + this.bindDependants() + this.bindCheckboxlist() + this.toggleEmptyTabs() + this.bindLazyTabs() + this.bindCollapsibleSections() + + this.$el.on('oc.triggerOn.afterUpdate', this.proxy(this.toggleEmptyTabs)) + this.$el.one('dispose-control', this.proxy(this.dispose)) + } + + FormWidget.prototype.dispose = function() { + this.unbindDependants() + this.unbindCheckboxList() + this.unbindLazyTabs() + this.unbindCollapsibleSections() + + this.$el.off('dispose-control', this.proxy(this.dispose)) + this.$el.removeData('oc.formwidget') + + this.$el = null + this.$form = null + this.options = null + this.fieldElementCache = null + + BaseProto.dispose.call(this) + } + + /* + * Logic for checkboxlist + */ + FormWidget.prototype.bindCheckboxlist = function() { + + var checkAllBoxes = function($field, flag) { + $('input[type=checkbox]', $field) + .prop('checked', flag) + .first() + .trigger('change') + } + + this.$el.on('click', '[data-field-checkboxlist-all]', function() { + checkAllBoxes($(this).closest('.field-checkboxlist'), true) + }) + + this.$el.on('click', '[data-field-checkboxlist-none]', function() { + checkAllBoxes($(this).closest('.field-checkboxlist'), false) + }) + + } + + /* + * Unbind checkboxlist handlers + */ + FormWidget.prototype.unbindCheckboxList = function() { + this.$el.off('click', '[data-field-checkboxlist-all]') + this.$el.off('click', '[data-field-checkboxlist-none]') + } + + /* + * Get all fields elements that belong to this form, nested form + * fields are removed from this collection. + */ + FormWidget.prototype.getFieldElements = function() { + if (this.fieldElementCache !== null) { + return this.fieldElementCache + } + + var form = this.$el, + nestedFields = form.find('[data-control="formwidget"] [data-field-name]') + + return this.fieldElementCache = form.find('[data-field-name]').not(nestedFields) + } + + /* + * Bind dependant fields + */ + FormWidget.prototype.bindDependants = function() { + var self = this, + fieldMap = this._getDependants() + + /* + * When a field is updated, refresh its dependents + */ + $.each(fieldMap, function(fieldName, toRefresh) { + $(document).on('change.oc.formwidget', + '[data-field-name="' + fieldName + '"]', + $.proxy(self.onRefreshDependants, self, fieldName, toRefresh) + ) + }) + } + + /* + * Dispose of the dependant field handlers + */ + FormWidget.prototype.unbindDependants = function() { + var fieldMap = this._getDependants() + + $.each(fieldMap, function(fieldName, toRefresh) { + $(document).off('change.oc.formwidget', '[data-field-name="' + fieldName + '"]') + }) + } + + /* + * Retrieve the dependant fields + */ + FormWidget.prototype._getDependants = function() { + if (!$('[data-field-depends]', this.$el).length) { + return; + } + + var fieldMap = {}, + fieldElements = this.getFieldElements() + + /* + * Map master and slave fields + */ + fieldElements.filter('[data-field-depends]').each(function() { + var name = $(this).data('field-name'), + depends = $(this).data('field-depends') + + $.each(depends, function(index, depend){ + if (!fieldMap[depend]) { + fieldMap[depend] = { fields: [] } + } + + fieldMap[depend].fields.push(name) + }) + }) + + return fieldMap + } + + /* + * Refresh a dependancy field + * Uses a throttle to prevent duplicate calls and click spamming + */ + FormWidget.prototype.onRefreshDependants = function(fieldName, toRefresh) { + var self = this, + form = this.$el, + formEl = this.$form, + fieldElements = this.getFieldElements() + + if (this.dependantUpdateTimers[fieldName] !== undefined) { + window.clearTimeout(this.dependantUpdateTimers[fieldName]) + } + + this.dependantUpdateTimers[fieldName] = window.setTimeout(function() { + var refreshData = $.extend({}, + toRefresh, + paramToObj('data-refresh-data', self.options.refreshData) + ) + + formEl.request(self.options.refreshHandler, { + data: refreshData + }).success(function() { + self.toggleEmptyTabs() + $.each(toRefresh.fields, function(key, field) { + $('[data-field-name="' + field + '"]').trigger('change') + }) + }) + }, this.dependantUpdateInterval) + + $.each(toRefresh.fields, function(index, field) { + fieldElements.filter('[data-field-name="'+field+'"]:visible') + .addClass('loading-indicator-container size-form-field') + .loadIndicator() + }) + } + + /* + * Render tab form fields once a lazy tab is selected. + */ + FormWidget.prototype.bindLazyTabs = function() { + var tabControl = $('[data-control=tab]', this.$el), + tabContainer = $('.nav-tabs', tabControl) + + tabContainer.on('click', '.tab-lazy [data-toggle="tab"]', function() { + var $el = $(this), + handlerName = $el.data('tab-lazy-handler') + + $.request(handlerName, { + data: { + target: $el.data('target'), + name: $el.data('tab-name'), + section: $el.data('tab-section'), + }, + success: function(data) { + this.success(data) + $el.parent().removeClass('tab-lazy') + // Trigger all input presets to populate new fields. + setTimeout(function() { + $('[data-input-preset]').each(function() { + var preset = $(this).data('oc.inputPreset') + if (preset && preset.$src) { + preset.$src.trigger('input') + } + }) + }, 0) + } + }) + }) + + // If initial active tab is lazy loaded, load it immediately + if ($('> li.active.tab-lazy', tabContainer).length) { + $('> li.active.tab-lazy > [data-toggle="tab"]', tabContainer).trigger('click') + } + } + + /* + * Unbind the lazy tab handlers + */ + FormWidget.prototype.unbindLazyTabs = function() { + var tabControl = $('[data-control=tab]', this.$el) + + $('.nav-tabs', tabControl).off('click', '.tab-lazy [data-toggle="tab"]') + } + + /* + * Hides tabs that have no content, it is possible this can be + * called multiple times in a single cycle due to input.trigger. + */ + FormWidget.prototype.toggleEmptyTabs = function() { + var self = this, + form = this.$el + + if (this.toggleEmptyTabsTimer !== undefined) { + window.clearTimeout(this.toggleEmptyTabsTimer) + } + + this.toggleEmptyTabsTimer = window.setTimeout(function() { + + var tabControl = $('[data-control=tab]', self.$el), + tabContainer = $('.nav-tabs', tabControl) + + if (!tabControl.length || !form || !form.length || !$.contains(form.get(0), tabControl.get(0))) + return + + /* + * Check each tab pane for form field groups + */ + $('.tab-pane:not(.lazy)', tabControl).each(function() { + $('[data-target="#' + $(this).attr('id') + '"]', tabControl) + .closest('li') + .toggle(!!$('> .form-group:not(:empty):not(.hide)', $(this)).length) + }) + + /* + * If a hidden tab was selected, select the first visible tab + */ + if (!$('> li.active:visible', tabContainer).length) { + $('> li:visible:first', tabContainer) + .find('> a:first') + .tab('show') + } + + }, 1) + } + + /* + * Makes sections collapsible by targeting every field after + * up until the next section + */ + FormWidget.prototype.bindCollapsibleSections = function() { + $('.section-field[data-field-collapsible]', this.$form) + .addClass('collapsed') + .find('.field-section:first') + .addClass('is-collapsible') + .end() + .on('click', function() { + $(this) + .toggleClass('collapsed') + .nextUntil('.section-field').toggle() + }) + .nextUntil('.section-field').hide() + } + + /* + * Unbinds collapsible section handlers + */ + FormWidget.prototype.unbindCollapsibleSections = function() { + $('.section-field[data-field-collapsible]', this.$form).off('click') + } + + FormWidget.DEFAULTS = { + refreshHandler: null, + refreshData: {} + } + + // FORM WIDGET PLUGIN DEFINITION + // ============================ + + var old = $.fn.formWidget + + $.fn.formWidget = function (option) { + var args = arguments, + result + + this.each(function () { + var $this = $(this) + var data = $this.data('oc.formwidget') + var options = $.extend({}, FormWidget.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.formwidget', (data = new FormWidget(this, options))) + if (typeof option == 'string') result = data[option].call($this) + if (typeof result != 'undefined') return false + }) + + return result ? result : this + } + + $.fn.formWidget.Constructor = FormWidget + + // FORM WIDGET NO CONFLICT + // ================= + + $.fn.formWidget.noConflict = function () { + $.fn.formWidget = old + return this + } + + // FORM WIDGET DATA-API + // ============== + + function paramToObj(name, value) { + if (value === undefined) value = '' + if (typeof value == 'object') return value + + try { + return ocJSON("{" + value + "}") + } + catch (e) { + throw new Error('Error parsing the '+name+' attribute value. '+e) + } + } + + $(document).render(function() { + $('[data-control="formwidget"]').formWidget(); + }) + +}(window.jQuery); diff --git a/modules/backend/widgets/form/partials/_field-container.htm b/modules/backend/widgets/form/partials/_field-container.htm new file mode 100644 index 0000000..98c6e4e --- /dev/null +++ b/modules/backend/widgets/form/partials/_field-container.htm @@ -0,0 +1,9 @@ +
    getFieldDepends($field)): ?>data-field-depends="" + data-field-name="fieldName ?>" + getAttributes('container') ?> + id="getId('group') ?>">makePartial('field', ['field' => $field])) +?>
    \ No newline at end of file diff --git a/modules/backend/widgets/form/partials/_field.htm b/modules/backend/widgets/form/partials/_field.htm new file mode 100644 index 0000000..4b52b9a --- /dev/null +++ b/modules/backend/widgets/form/partials/_field.htm @@ -0,0 +1,30 @@ +hidden): ?> + + showFieldLabels($field)): ?> + + renderFieldElement($field) ?> + + + commentHtml ? trans($field->comment) : e(trans($field->comment)); + ?> + + label): ?> + + + + comment && $field->commentPosition == 'above'): ?> +

    + + + renderFieldElement($field) ?> + + comment && $field->commentPosition == 'below'): ?> +

    + + + + + \ No newline at end of file diff --git a/modules/backend/widgets/form/partials/_field_balloon-selector.htm b/modules/backend/widgets/form/partials/_field_balloon-selector.htm new file mode 100644 index 0000000..de4717c --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_balloon-selector.htm @@ -0,0 +1,22 @@ +options(); +?> + +
    getAttributes() ?>> +
      + $text): ?> +
    • + +
    + + +
    diff --git a/modules/backend/widgets/form/partials/_field_checkbox.htm b/modules/backend/widgets/form/partials/_field_checkbox.htm new file mode 100644 index 0000000..8303506 --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_checkbox.htm @@ -0,0 +1,23 @@ + +
    + previewMode ? 'disabled="disabled"' : '' ?>> + previewMode ? 'disabled="disabled"' : '' ?> + isSelected() ? 'checked="checked"' : '' ?> + getAttributes() ?>> + + + comment): ?> +

    commentHtml ? trans($field->comment) : e(trans($field->comment)) ?>

    + +
    diff --git a/modules/backend/widgets/form/partials/_field_checkboxlist.htm b/modules/backend/widgets/form/partials/_field_checkboxlist.htm new file mode 100644 index 0000000..bb9be94 --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_checkboxlist.htm @@ -0,0 +1,109 @@ +options(); + $checkedValues = (array) $field->value; + $isScrollable = count($fieldOptions) > 10; + $readOnly = $this->previewMode || $field->readOnly || $field->disabled; + $quickselectEnabled = $field->getConfig('quickselect', $isScrollable); +?> + +value): ?> + +
    + $option): ?> + getId().'_'.$index; + if (!in_array($value, $checkedValues)) continue; + if (!is_array($option)) $option = [$option]; + ?> +
    + + + + +

    + +
    + +
    + + + +
    + + +
    +
    + + + +
    +
    + + + +
    +
    + + +
    + + + +
    +
    + + + + + $option): ?> + getId().'_'.$index; + if (!is_array($option)) $option = [$option]; + ?> +
    + > + + + +

    + +
    + + + +
    +
    + + +
    + +
    + + + + + placeholder): ?> +

    placeholder)) ?>

    + + + diff --git a/modules/backend/widgets/form/partials/_field_dropdown.htm b/modules/backend/widgets/form/partials/_field_dropdown.htm new file mode 100644 index 0000000..423d05a --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_dropdown.htm @@ -0,0 +1,51 @@ +options(); + $useSearch = $field->getConfig('showSearch', true); + $emptyOption = $field->getConfig('emptyOption', $field->placeholder); +?> + +previewMode || $field->readOnly): ?> +
    readOnly ? 'disabled="disabled"' : ''; ?>> + value]) && is_array($fieldOptions[$field->value])): ?> + value][1], '.')): ?> + + value][0])) ?> + + + value][0])) ?> + + value]) && !is_array($fieldOptions[$field->value])): ?> + value])) ?> + + + +
    + readOnly): ?> + + + + + diff --git a/modules/backend/widgets/form/partials/_field_email.htm b/modules/backend/widgets/form/partials/_field_email.htm new file mode 100644 index 0000000..8be4bde --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_email.htm @@ -0,0 +1,14 @@ + +previewMode): ?> + value ? e($field->value) : ' ' ?> + + getAttributes() ?> + /> + diff --git a/modules/backend/widgets/form/partials/_field_hint.htm b/modules/backend/widgets/form/partials/_field_hint.htm new file mode 100644 index 0000000..ac8e299 --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_hint.htm @@ -0,0 +1,8 @@ +controller->makeHintPartial($field->getId(), $field->path ?: $field->fieldName, [ + 'formModel' => $formModel, + 'formField' => $field, + 'formValue' => $field->value, + 'model' => $formModel, + 'field' => $field, + 'value' => $field->value +]) ?> \ No newline at end of file diff --git a/modules/backend/widgets/form/partials/_field_number.htm b/modules/backend/widgets/form/partials/_field_number.htm new file mode 100644 index 0000000..437d945 --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_number.htm @@ -0,0 +1,26 @@ + +previewMode): ?> + value) ? e($field->value) : ' ' ?> + + config['min']) ? $field->config['min'] : false; + $max = isset($field->config['max']) ? $field->config['max'] : false; + $step = isset($field->config['step']) ? $field->config['step'] : 'any'; + ?> + + + + hasAttribute('pattern') ? '' : 'pattern="-?\d+(\.\d+)?"' ?> + hasAttribute('maxlength') ? '' : 'maxlength="255"' ?> + getAttributes() ?> + /> + diff --git a/modules/backend/widgets/form/partials/_field_partial.htm b/modules/backend/widgets/form/partials/_field_partial.htm new file mode 100644 index 0000000..631c56d --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_partial.htm @@ -0,0 +1,8 @@ +controller->makePartial($field->path ?: $field->fieldName, [ + 'formModel' => $formModel, + 'formField' => $field, + 'formValue' => $field->value, + 'model' => $formModel, + 'field' => $field, + 'value' => $field->value +]) ?> \ No newline at end of file diff --git a/modules/backend/widgets/form/partials/_field_password.htm b/modules/backend/widgets/form/partials/_field_password.htm new file mode 100644 index 0000000..86f361d --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_password.htm @@ -0,0 +1,16 @@ + +previewMode): ?> +
    ********
    + + hasAttribute('maxlength') ? '' : 'maxlength="255"' ?> + getAttributes() ?> + /> + diff --git a/modules/backend/widgets/form/partials/_field_radio.htm b/modules/backend/widgets/form/partials/_field_radio.htm new file mode 100644 index 0000000..e60a9e9 --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_radio.htm @@ -0,0 +1,42 @@ +options(); +?> + + + + $option): ?> + getId($index), true)); + ?> +
    + + isSelected($value) ? 'checked="checked"' : '' ?> + previewMode ? 'disabled="disabled"' : '' ?> + getAttributes() ?>> + + + +

    + +
    + + + + + + placeholder): ?> +

    placeholder)) ?>

    + + + diff --git a/modules/backend/widgets/form/partials/_field_section.htm b/modules/backend/widgets/form/partials/_field_section.htm new file mode 100644 index 0000000..2ece19b --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_section.htm @@ -0,0 +1,10 @@ + +
    + label): ?> +

    label)) ?>

    + + + comment): ?> +

    commentHtml ? trans($field->comment) : e(trans($field->comment)) ?>

    + +
    \ No newline at end of file diff --git a/modules/backend/widgets/form/partials/_field_switch.htm b/modules/backend/widgets/form/partials/_field_switch.htm new file mode 100644 index 0000000..a11c4b4 --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_switch.htm @@ -0,0 +1,36 @@ +previewMode || $field->readOnly) { + $previewMode = true; + } +?> + +config['on']) ? $field->config['on'] : 'backend::lang.form.field_on'; + $off = isset($field->config['off']) ? $field->config['off'] : 'backend::lang.form.field_off'; +?> +
    + + comment): ?> +

    commentHtml ? trans($field->comment) : e(trans($field->comment)) ?>

    + +
    + +> + + diff --git a/modules/backend/widgets/form/partials/_field_text.htm b/modules/backend/widgets/form/partials/_field_text.htm new file mode 100644 index 0000000..ab89423 --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_text.htm @@ -0,0 +1,16 @@ + +previewMode): ?> + value ? e($field->value) : ' ' ?> + + hasAttribute('maxlength') ? '' : 'maxlength="255"' ?> + getAttributes() ?> + /> + diff --git a/modules/backend/widgets/form/partials/_field_textarea.htm b/modules/backend/widgets/form/partials/_field_textarea.htm new file mode 100644 index 0000000..9dea13b --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_textarea.htm @@ -0,0 +1,12 @@ + +previewMode): ?> +
    value)) ?>
    + + + \ No newline at end of file diff --git a/modules/backend/widgets/form/partials/_field_widget.htm b/modules/backend/widgets/form/partials/_field_widget.htm new file mode 100644 index 0000000..1612ce9 --- /dev/null +++ b/modules/backend/widgets/form/partials/_field_widget.htm @@ -0,0 +1,5 @@ + +makeFormFieldWidget($field); +?> +render() ?> \ No newline at end of file diff --git a/modules/backend/widgets/form/partials/_form-container.htm b/modules/backend/widgets/form/partials/_form-container.htm new file mode 100644 index 0000000..119185e --- /dev/null +++ b/modules/backend/widgets/form/partials/_form-container.htm @@ -0,0 +1,10 @@ +
    + + makePartial('form') ?> + +
    diff --git a/modules/backend/widgets/form/partials/_form.htm b/modules/backend/widgets/form/partials/_form.htm new file mode 100644 index 0000000..cd6ed96 --- /dev/null +++ b/modules/backend/widgets/form/partials/_form.htm @@ -0,0 +1,12 @@ + +hasFields()): ?> + makePartial('section', ['tabs' => $outsideTabs]) ?> + + +hasFields()): ?> + makePartial('section', ['tabs' => $primaryTabs]) ?> + + +hasFields()): ?> + makePartial('section', ['tabs' => $secondaryTabs]) ?> + \ No newline at end of file diff --git a/modules/backend/widgets/form/partials/_form_fields.htm b/modules/backend/widgets/form/partials/_form_fields.htm new file mode 100644 index 0000000..9ff1aa6 --- /dev/null +++ b/modules/backend/widgets/form/partials/_form_fields.htm @@ -0,0 +1,3 @@ + + makePartial('field-container', ['field' => $field]) ?> + diff --git a/modules/backend/widgets/form/partials/_form_tabs.htm b/modules/backend/widgets/form/partials/_form_tabs.htm new file mode 100644 index 0000000..810dab4 --- /dev/null +++ b/modules/backend/widgets/form/partials/_form_tabs.htm @@ -0,0 +1,56 @@ +section; + + $navCss = ''; + $contentCss = ''; + $paneCss = ''; + + if ($tabs->stretch) { + $navCss = 'layout-row min-size'; + $contentCss = 'layout-row'; + $paneCss = 'layout-cell'; + } +?> +
    + +
    + +
    + $fields): + $lazy = in_array($name, $tabs->lazy); + ?> +
    + + makePartial('form_tabs_lazy', ['fields' => $fields]) ?> + + makePartial('form_fields', ['fields' => $fields]) ?> + +
    + +
    diff --git a/modules/backend/widgets/form/partials/_form_tabs_lazy.htm b/modules/backend/widgets/form/partials/_form_tabs_lazy.htm new file mode 100644 index 0000000..4d75345 --- /dev/null +++ b/modules/backend/widgets/form/partials/_form_tabs_lazy.htm @@ -0,0 +1,33 @@ +
    +
    + +
    +
    +type, $ignoredTypes)) continue; + + $isMultiValue = is_array($field->value); + foreach (array_wrap($field->value) as $index => $value): + // Use array field names if the field has multiple values (repeater, checkboxlist, etc.). + $fieldName = $isMultiValue ? sprintf('%s[%s]', $field->getName(), $index) : $field->getName(); + + $valueIsArray = is_array($value); + foreach (array_wrap($value) as $index => $value): + // Set the correct array keys if the value is an array (repeater form fields). + $currentFieldName = $valueIsArray ? sprintf('%s[%s]', $fieldName, $index) : $fieldName; +?> + getAttributes() ?> + /> + + + diff --git a/modules/backend/widgets/form/partials/_section-container.htm b/modules/backend/widgets/form/partials/_section-container.htm new file mode 100644 index 0000000..40ee61f --- /dev/null +++ b/modules/backend/widgets/form/partials/_section-container.htm @@ -0,0 +1,20 @@ +
    + + + makePartial('section', ['tabs' => $outsideTabs]) ?> + + + + makePartial('section', ['tabs' => $primaryTabs]) ?> + + + + makePartial('section', ['tabs' => $secondaryTabs]) ?> + + +
    \ No newline at end of file diff --git a/modules/backend/widgets/form/partials/_section.htm b/modules/backend/widgets/form/partials/_section.htm new file mode 100644 index 0000000..149e1f9 --- /dev/null +++ b/modules/backend/widgets/form/partials/_section.htm @@ -0,0 +1,30 @@ +section; + + $containerCss = 'layout-row min-size'; + + if ($tabs->stretch) { + $containerCss = 'layout-row'; + } +?> + +
    + suppressTabs): ?> + +
    + makePartial('form_fields', ['fields' => $tabs]) ?> +
    + + + +
    + makePartial('form_tabs', ['tabs' => $tabs]) ?> +
    + + +
    diff --git a/modules/backend/widgets/lists/assets/js/october.list.js b/modules/backend/widgets/lists/assets/js/october.list.js new file mode 100644 index 0000000..ad30498 --- /dev/null +++ b/modules/backend/widgets/lists/assets/js/october.list.js @@ -0,0 +1,144 @@ +/* + * List Widget + * + * Dependences: + * - Row Link Plugin (system/assets/ui/js/list.rowlink.js) + */ ++function ($) { "use strict"; + + var ListWidget = function (element, options) { + + var $el = this.$el = $(element); + + this.options = options || {}; + + var scrollClassContainer = options.scrollClassContainer !== undefined + ? options.scrollClassContainer + : $el.parent() + + $el.dragScroll({ + scrollClassContainer: scrollClassContainer, + scrollSelector: 'thead', + dragSelector: 'thead' + }) + + this.update() + } + + ListWidget.DEFAULTS = { + } + + ListWidget.prototype.update = function() { + var + list = this.$el, + head = $('thead', list), + body = $('tbody', list), + foot = $('tfoot', list) + + /* + * Bind check boxes + */ + $('.list-checkbox input[type="checkbox"]', body).each(function(){ + var $el = $(this) + if ($el.is(':checked')) + $el.closest('tr').addClass('active') + }) + + head.on('change', '.list-checkbox input[type="checkbox"]', function(){ + var $el = $(this), + checked = $el.is(':checked') + + $('.list-checkbox input[type="checkbox"]', body).prop('checked', checked) + if (checked) + $('tr', body).addClass('active') + else + $('tr', body).removeClass('active') + }) + + body.on('change', '.list-checkbox input[type="checkbox"]', function(){ + var $el = $(this), + checked = $el.is(':checked') + + if (checked) { + $el.closest('tr').addClass('active') + } + else { + $('.list-checkbox input[type="checkbox"]', head).prop('checked', false) + $el.closest('tr').removeClass('active') + } + }) + } + + ListWidget.prototype.getChecked = function() { + var + list = this.$el, + body = $('tbody', list) + + return $('.list-checkbox input[type="checkbox"]', body).map(function(){ + var $el = $(this) + if ($el.is(':checked')) + return $el.val() + }).get(); + } + + ListWidget.prototype.toggleChecked = function(el) { + var $checkbox = $('.list-checkbox input[type="checkbox"]', $(el).closest('tr')) + $checkbox.prop('checked', !$checkbox.is(':checked')).trigger('change') + } + + // LIST WIDGET PLUGIN DEFINITION + // ============================ + + var old = $.fn.listWidget + + $.fn.listWidget = function (option) { + var args = Array.prototype.slice.call(arguments, 1), result + + this.each(function () { + var $this = $(this) + var data = $this.data('oc.listwidget') + var options = $.extend({}, ListWidget.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.listwidget', (data = new ListWidget(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : this + } + + $.fn.listWidget.Constructor = ListWidget + + // LIST WIDGET NO CONFLICT + // ================= + + $.fn.listWidget.noConflict = function () { + $.fn.listWidget = old + return this + } + + // LIST WIDGET HELPERS + // ================= + + if ($.oc === undefined) + $.oc = {} + + $.oc.listToggleChecked = function(el) { + $(el) + .closest('[data-control="listwidget"]') + .listWidget('toggleChecked', el) + } + + $.oc.listGetChecked = function(el) { + return $(el) + .closest('[data-control="listwidget"]') + .listWidget('getChecked') + } + + // LIST WIDGET DATA-API + // ============== + + $(document).render(function(){ + $('[data-control="listwidget"]').listWidget(); + }) + +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/lists/partials/_list-container.htm b/modules/backend/widgets/lists/partials/_list-container.htm new file mode 100644 index 0000000..1f49426 --- /dev/null +++ b/modules/backend/widgets/lists/partials/_list-container.htm @@ -0,0 +1,3 @@ +
    + makePartial('list') ?> +
    \ No newline at end of file diff --git a/modules/backend/widgets/lists/partials/_list.htm b/modules/backend/widgets/lists/partials/_list.htm new file mode 100644 index 0000000..5b3e50e --- /dev/null +++ b/modules/backend/widgets/lists/partials/_list.htm @@ -0,0 +1,29 @@ +
    + + + makePartial('list_head_row') ?> + + + + makePartial('list_body_rows') ?> + + + + + + +
    + + + +
    diff --git a/modules/backend/widgets/lists/partials/_list_body_checkbox.htm b/modules/backend/widgets/lists/partials/_list_body_checkbox.htm new file mode 100644 index 0000000..176c111 --- /dev/null +++ b/modules/backend/widgets/lists/partials/_list_body_checkbox.htm @@ -0,0 +1,11 @@ + +
    + + +
    + diff --git a/modules/backend/widgets/lists/partials/_list_body_row.htm b/modules/backend/widgets/lists/partials/_list_body_row.htm new file mode 100644 index 0000000..55111e0 --- /dev/null +++ b/modules/backend/widgets/lists/partials/_list_body_row.htm @@ -0,0 +1,39 @@ +isTreeNodeExpanded($record) : null; + $childRecords = $showTree ? $record->getChildren() : null; + $treeLevelClass = $showTree ? 'list-tree-level-'.$treeLevel : ''; +?> + + + makePartial('list_body_checkbox', ['record' => $record]) ?> + + + + makePartial('list_body_tree', [ + 'record' => $record, + 'expanded' => $expanded, + 'childCount' => $record->getChildCount() + ]) ?> + + + $column): ?> + + + clickable && !$url && ($url = $this->getRecordUrl($record))): ?> + getRecordOnClick($record) ?> href=""> + getColumnValue($record, $column) ?> + + + getColumnValue($record, $column) ?> + + + + + +   + + + + + makePartial('list_body_rows', ['records' => $childRecords, 'treeLevel' => $treeLevel+1]) ?> + diff --git a/modules/backend/widgets/lists/partials/_list_body_rows.htm b/modules/backend/widgets/lists/partials/_list_body_rows.htm new file mode 100644 index 0000000..9d5f68f --- /dev/null +++ b/modules/backend/widgets/lists/partials/_list_body_rows.htm @@ -0,0 +1,3 @@ + + makePartial('list_body_row', ['record' => $record, 'treeLevel' => $treeLevel]) ?> + \ No newline at end of file diff --git a/modules/backend/widgets/lists/partials/_list_body_tree.htm b/modules/backend/widgets/lists/partials/_list_body_tree.htm new file mode 100644 index 0000000..48b52f7 --- /dev/null +++ b/modules/backend/widgets/lists/partials/_list_body_tree.htm @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/modules/backend/widgets/lists/partials/_list_head_row.htm b/modules/backend/widgets/lists/partials/_list_head_row.htm new file mode 100644 index 0000000..c962b49 --- /dev/null +++ b/modules/backend/widgets/lists/partials/_list_head_row.htm @@ -0,0 +1,49 @@ + + + +
    + + +
    + + + + + + + + + + $column): ?> + sortable): ?> + width): ?>style="width: width ?>" + class="sortColumn==$column->columnName?'sort-'.$this->sortDirection.' active':'sort-desc' ?> list-cell-name-getName() ?> list-cell-type-type ?> getAlignClass() ?> headCssClass ?>" + > + + getHeaderValue($column) ?> + + + + width): ?>style="width: width ?>" + class="list-cell-name-getName() ?> list-cell-type-type ?> getAlignClass() ?> headCssClass ?>" + > + getHeaderValue($column) ?> + + + + + + + + + + diff --git a/modules/backend/widgets/lists/partials/_list_pagination.htm b/modules/backend/widgets/lists/partials/_list_pagination.htm new file mode 100644 index 0000000..1f81e88 --- /dev/null +++ b/modules/backend/widgets/lists/partials/_list_pagination.htm @@ -0,0 +1,71 @@ +
    +
    + + $pageFrom, 'to' => $pageTo, 'total' => $recordTotal])) ?> + + 1): ?> + 1): ?> + + + + + 1): ?> + + + + + + $pageCurrent): ?> + + + + + $pageCurrent): ?> + + + + + +
    +
    diff --git a/modules/backend/widgets/lists/partials/_list_pagination_simple.htm b/modules/backend/widgets/lists/partials/_list_pagination_simple.htm new file mode 100644 index 0000000..1735143 --- /dev/null +++ b/modules/backend/widgets/lists/partials/_list_pagination_simple.htm @@ -0,0 +1,50 @@ +
    +
    + 1): ?> + + + + + 1): ?> + + + + + + + + + + +
    +
    diff --git a/modules/backend/widgets/lists/partials/_setup_form.htm b/modules/backend/widgets/lists/partials/_setup_form.htm new file mode 100644 index 0000000..7bffb53 --- /dev/null +++ b/modules/backend/widgets/lists/partials/_setup_form.htm @@ -0,0 +1,74 @@ + + + + + diff --git a/modules/backend/widgets/mediamanager/assets/css/mediamanager.css b/modules/backend/widgets/mediamanager/assets/css/mediamanager.css new file mode 100644 index 0000000..c98ed5a --- /dev/null +++ b/modules/backend/widgets/mediamanager/assets/css/mediamanager.css @@ -0,0 +1,129 @@ +div[data-control="media-manager"]:focus {outline:none} +div[data-control="media-manager"] audio, +div[data-control="media-manager"] video {width:100%} +div[data-control="media-manager"] video {background:#ecf0f1;max-height:225px} +div[data-control="media-manager"] .media-player-fallback {font-size:13px;color:#95a5a6;background:#ecf0f1;line-height:180%} +div[data-control="media-manager"] .media-player-fallback.panel-embedded {padding:20px;margin:-20px -20px 0 -20px} +div[data-control="media-manager"] .empty-library {padding:20px;text-align:center} +div[data-control="media-manager"] p.thumbnail-error-message {font-size:12px;margin:10px;line-height:160%;color:#bdc3c7} +div[data-control="media-manager"] .media-list {padding:0 0 0 20px;margin:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} +div[data-control="media-manager"] .media-list li {display:inline-block;vertical-align:top;margin:0 20px 20px 0;overflow:hidden;cursor:pointer;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +div[data-control="media-manager"] .media-list li:focus {outline:none} +div[data-control="media-manager"] .media-list li .icon-container {display:table} +div[data-control="media-manager"] .media-list li .icon-container i {color:#95a5a6;display:inline-block} +div[data-control="media-manager"] .media-list li .icon-container div {display:table-cell;text-align:center;vertical-align:middle} +div[data-control="media-manager"] .media-list li .icon-container.image >div.icon-wrapper {display:none} +div[data-control="media-manager"] .media-list li h4 {font-weight:600;font-size:13px;color:#2b3e50;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:150%;margin:15px 0 5px 0;padding-right:0;-webkit-transition:padding 0.1s;transition:padding 0.1s;position:relative} +div[data-control="media-manager"] .media-list li h4 a {position:absolute;right:0;top:0;font-size:15px;color:#2b3e50;display:none} +div[data-control="media-manager"] .media-list li h4 a:hover {color:#0181b9;text-decoration:none} +div[data-control="media-manager"] .media-list li p.size {font-size:12px;color:#95a5a6} +div[data-control="media-manager"] .media-list li .image-placeholder {position:relative} +div[data-control="media-manager"] .media-list li .image-placeholder i {padding-top:0;padding-left:2px} +div[data-control="media-manager"] .media-list li .image-placeholder[data-loading] i {display:none} +div[data-control="media-manager"] .media-list li .image-placeholder[data-loading]:after {background-image:url('../../../../../../modules/system/assets/ui/images/loader-transparent.svg');background-position:50% 50%;content:' ';-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite;background-size:28px 28px;position:absolute;width:28px;height:28px;top:50%;left:50%;margin-top:-14px;margin-left:-14px} +div[data-control="media-manager"] .media-list li i.icon-chain-broken {padding:0;color:#bdc3c7} +div[data-control="media-manager"] .media-list li[data-item-type=folder] i {color:#4ea5e0} +div[data-control="media-manager"] .media-list.list li {height:75px;width:260px;border:1px solid #ecf0f1;background:#f6f8f9;box-sizing:content-box} +div[data-control="media-manager"] .media-list.list li .icon-container {border-right:1px solid #f6f8f9;width:75px;height:75px;float:left} +div[data-control="media-manager"] .media-list.list li .icon-container img {max-height:75px} +div[data-control="media-manager"] .media-list.list li .icon-container i {font-size:35px} +div[data-control="media-manager"] .media-list.list li .icon-container.image {border-right:1px solid #ecf0f1!important} +div[data-control="media-manager"] .media-list.list li .icon-container p.thumbnail-error-message {display:none} +div[data-control="media-manager"] .media-list.list .icon-wrapper {width:75px} +div[data-control="media-manager"] .media-list.list li .info {margin-left:90px} +div[data-control="media-manager"] .media-list.list li .image-placeholder {width:75px;height:75px} +div[data-control="media-manager"] .media-list.list li[data-root] h4 {margin-top:27px} +div[data-control="media-manager"] .media-list.list li.selected {background:#4ea5e0 !important} +div[data-control="media-manager"] .media-list.list li.selected i, +div[data-control="media-manager"] .media-list.list li.selected p.size {color:#ecf0f1} +div[data-control="media-manager"] .media-list.list li.selected h4 {color:white} +div[data-control="media-manager"] .media-list.list li.selected .icon-container {border-right-color:#4ea5e0 !important} +div[data-control="media-manager"] .media-list.list h4 {padding-right:15px} +div[data-control="media-manager"] .media-list.list h4 a {right:15px} +div[data-control="media-manager"] .media-list.tiles li {width:167px;margin-bottom:25px} +div[data-control="media-manager"] .media-list.tiles .icon-wrapper {width:167px} +div[data-control="media-manager"] .media-list.tiles li .image-placeholder {width:165px;height:165px} +div[data-control="media-manager"] .media-list.tiles li .image-placeholder[data-loading]:after {background-image:url('../../../../../../modules/system/assets/ui/images/loader-transparent.svg');background-position:50% 50%;content:' ';-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite;background-size:55px 55px;position:absolute;width:55px;height:55px;top:50%;left:50%;margin-top:-27.5px;margin-left:-27.5px} +div[data-control="media-manager"] .media-list.tiles li .icon-container {width:165px;height:165px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;border:1px solid #ecf0f1;overflow:hidden;background:#f6f8f9;box-sizing:content-box} +div[data-control="media-manager"] .media-list.tiles li .icon-container img {max-height:165px} +div[data-control="media-manager"] .media-list.tiles li .icon-container i {font-size:55px} +div[data-control="media-manager"] .media-list.tiles li .icon-container p {font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"} +div[data-control="media-manager"] .media-list.tiles li.selected .icon-container {background:#4ea5e0 !important;border-color:#2581b8} +div[data-control="media-manager"] .media-list.tiles li.selected .icon-container i, +div[data-control="media-manager"] .media-list.tiles li.selected .icon-container p {color:#ecf0f1} +div[data-control="media-manager"] .media-list.tiles li.selected h4 {color:#2581b8} +div[data-control="media-manager"] .media-list.tiles i.icon-chain-broken {margin-top:47px} +div[data-control="media-manager"] .media-list.tiles p.size {margin-bottom:0} +div[data-control="media-manager"] [data-control="sidebar-labels"] {word-wrap:break-word} +div[data-control="media-manager"] .sidebar-group {margin-bottom:20px} +div[data-control="media-manager"] .sidebar-image-placeholder-container {display:table;width:100%} +div[data-control="media-manager"] .sidebar-image-placeholder {display:table-cell;height:225px;position:relative;vertical-align:middle;text-align:center;border-bottom:1px solid #ecf0f1;box-sizing:content-box} +div[data-control="media-manager"] .sidebar-image-placeholder[data-loading] {background:#ecf0f1} +div[data-control="media-manager"] .sidebar-image-placeholder[data-loading]:after {background-image:url('../../../../../../modules/system/assets/ui/images/loader-transparent.svg');background-position:50% 50%;content:' ';-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite;background-size:62px 62px;position:absolute;width:62px;height:62px;top:50%;left:50%;margin-top:-31px;margin-left:-31px} +div[data-control="media-manager"] .sidebar-image-placeholder i.icon-chain-broken, +div[data-control="media-manager"] .sidebar-image-placeholder i.icon-crop, +div[data-control="media-manager"] .sidebar-image-placeholder i.icon-asterisk, +div[data-control="media-manager"] .sidebar-image-placeholder i.icon-level-up {color:#bdc3c7;font-size:55px} +div[data-control="media-manager"] .sidebar-image-placeholder.no-border {border-bottom:none} +div[data-control="media-manager"] .sidebar-image-placeholder p {font-size:12px;margin:10px;line-height:160%;color:#bdc3c7;margin-top:25px} +div[data-control="media-manager"] .sidebar-image-placeholder img {max-width:100%;max-height:225px} +div[data-control="media-manager"] .list-container {position:relative;z-index:100} +div[data-control="media-manager"] .list-container .no-data {font-size:13px} +div[data-control="media-manager"] .list-container p.no-data {padding:0 20px 20px 20px} +div[data-control="media-manager"] .list-container li.no-data {padding-top:20px;display:block !important;width:100% !important;border:none !important;background:transparent !important;cursor:default !important} +div[data-control="media-manager"] .list-container table.table.data tbody tr:not(.no-data):active td {background:#4ea5e0 !important} +div[data-control="media-manager"] [data-control="item-list"] {position:relative;display:table-cell} +div[data-control="media-manager"] .control-scrollpad {position:absolute;left:0;top:0;min-height:300px} +div[data-control="media-manager"] .scroll-wrapper {position:relative} +div[data-control="media-manager"] table.table {table-layout:fixed;margin-bottom:0;white-space:nowrap} +div[data-control="media-manager"] table.table div.no-wrap-text {overflow:hidden;text-overflow:ellipsis} +div[data-control="media-manager"] table.table div.item-title {position:relative;padding-right:0;-webkit-transition:padding 0.1s;transition:padding 0.1s} +div[data-control="media-manager"] table.table div.item-title a {position:absolute;right:0;top:0;display:none} +div[data-control="media-manager"] table.table tr:hover div.item-title {padding-right:25px} +div[data-control="media-manager"] table.table tr:hover div.item-title a {display:block} +div[data-control="media-manager"] table.table tr[data-item-type=folder] i.icon-folder {color:#4ea5e0} +div[data-control="media-manager"] table.table tr:focus {outline:none} +div[data-control="media-manager"] div[data-control="selection-marker"] {position:absolute;z-index:250;border:1px dashed #95a5a6;background:rgba(0,0,0,0.1)} +div[data-control="media-manager"] .upload-progress {background:#f9f9f9;padding:0 20px} +div[data-control="media-manager"] .upload-progress h5 {margin:0 0 10px 0;font-size:13px;color:#2b3e50;font-weight:600} +div[data-control="media-manager"] .upload-progress h5 span {display:inline-block;margin-left:10px;color:#95a5a6;font-size:15px} +div[data-control="media-manager"] .upload-progress .progress-controls {padding-right:30px;position:relative} +div[data-control="media-manager"] .upload-progress .progress-controls .controls {position:absolute;right:0;bottom:0} +div[data-control="media-manager"] .upload-progress .progress-controls .controls a {display:block;position:relative;top:7px;right:3px;color:#95a5a6;font-size:16px;cursor:pointer !important} +div[data-control="media-manager"] .upload-progress .progress-controls .controls a:hover {text-decoration:none;color:#0181b9} +div[data-control="media-manager"] .dz-preview {display:none} +div[data-control="media-manager"] button[data-command="toggle-sidebar"].sidebar-hidden {-webkit-transform:rotate(180deg) translate(0,0);-ms-transform:rotate(180deg) translate(0,0);transform:rotate(180deg) translate(0,0)} +[data-control="media-manager-crop-tool"] .image_area {position:absolute;width:100%;height:100%;overflow:auto} +[data-control="media-manager-crop-tool"] .image_area .jcrop-holder {background-color:transparent !important} +[data-control="media-manager-crop-tool"] img {cursor:crosshair;display:block} +[data-control="media-manager-crop-tool"].has-rulers .ruler-container .layout-relative {overflow:hidden} +[data-control="media-manager-crop-tool"].has-rulers .ruler-container.horizontal .layout-cell {height:20px} +[data-control="media-manager-crop-tool"].has-rulers .ruler-container.horizontal .layout-relative {width:100%} +[data-control="media-manager-crop-tool"].has-rulers .ruler-container.vertical {width:20px} +[data-control="media-manager-crop-tool"].has-rulers .ruler-container.vertical .layout-relative {height:100%} +[data-control="media-manager-crop-tool"].has-rulers .ruler {position:absolute;height:20px;margin-left:-3px;background:#555} +[data-control="media-manager-crop-tool"].has-rulers .ruler ul {margin:0;padding:0;white-space:nowrap;font-size:0} +[data-control="media-manager-crop-tool"].has-rulers .ruler li {margin:0;padding:0 0 0 40px;list-style:none;display:inline-block;width:24px;margin:0 -10px 0 -14px;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;text-align:left;position:relative;font-size:10px;line-height:20px;color:#ecf0f1;font-family:Arial,sans-serif} +[data-control="media-manager-crop-tool"].has-rulers .ruler li:before, +[data-control="media-manager-crop-tool"].has-rulers .ruler li:after {content:' ';position:absolute;border-left:1px solid #8e8e8e} +[data-control="media-manager-crop-tool"].has-rulers .ruler li:before {height:20px;top:0;left:-3px} +[data-control="media-manager-crop-tool"].has-rulers .ruler li:after {height:3px;bottom:0;left:20px} +[data-control="media-manager-crop-tool"].has-rulers .ruler li:first-child:after {display:none} +[data-control="media-manager-crop-tool"].has-rulers .ruler[data-control=v-ruler] {-webkit-transform:rotateZ(90deg);-ms-transform:rotateZ(90deg);transform:rotateZ(90deg);-webkit-transform-origin:left top;-moz-transform-origin:left top;-ms-transform-origin:left top;transform-origin:left top;left:23px;top:-23px} +[data-control="media-manager-crop-tool"].has-rulers .ruler[data-control=v-ruler] li:after {top:0;left:auto} +body:not(.no-select) div[data-control="media-manager"] .media-list.tiles li:hover .icon-container {background:#4ea5e0 !important;border-color:#2581b8} +body:not(.no-select) div[data-control="media-manager"] .media-list.tiles li:hover .icon-container i, +body:not(.no-select) div[data-control="media-manager"] .media-list.tiles li:hover .icon-container p {color:#ecf0f1} +body:not(.no-select) div[data-control="media-manager"] .media-list.tiles li:hover h4 {color:#2581b8} +body:not(.no-select) div[data-control="media-manager"] .media-list.tiles li:hover h4 {padding-right:20px !important} +body:not(.no-select) div[data-control="media-manager"] .media-list.list li:hover {background:#4ea5e0 !important} +body:not(.no-select) div[data-control="media-manager"] .media-list.list li:hover i, +body:not(.no-select) div[data-control="media-manager"] .media-list.list li:hover p.size {color:#ecf0f1} +body:not(.no-select) div[data-control="media-manager"] .media-list.list li:hover h4 {color:white} +body:not(.no-select) div[data-control="media-manager"] .media-list.list li:hover .icon-container {border-right-color:#4ea5e0 !important} +body:not(.no-select) div[data-control="media-manager"] .media-list.list li:hover h4 {padding-right:35px !important} +body:not(.no-select) div[data-control="media-manager"] .media-list li:hover h4 a {display:block} +@media (max-width:1280px) {div[data-control="media-manager"] .media-list.list li {width:230px }} +@media (max-width:1024px) {div[data-control="media-manager"] .media-list.list li {display:block;width:auto }} +@media (max-width:768px) {div[data-control="media-manager"] [data-control="preview-sidebar"],div[data-control="media-manager"] [data-command="toggle-sidebar"] {display:none !important }div[data-control="media-manager"] .media-list.list {padding:0 }div[data-control="media-manager"] .media-list.list li {-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;margin:0;border-right:none;border-left:none;border-bottom:none }} +@media (max-width:480px) {div[data-control="media-manager"] [data-control="left-sidebar"] {display:none !important }} \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/assets/images/broken-thumbnail.gif b/modules/backend/widgets/mediamanager/assets/images/broken-thumbnail.gif new file mode 100644 index 0000000..44519d0 Binary files /dev/null and b/modules/backend/widgets/mediamanager/assets/images/broken-thumbnail.gif differ diff --git a/modules/backend/widgets/mediamanager/assets/images/video-poster.png b/modules/backend/widgets/mediamanager/assets/images/video-poster.png new file mode 100644 index 0000000..c3f5401 Binary files /dev/null and b/modules/backend/widgets/mediamanager/assets/images/video-poster.png differ diff --git a/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser-min.js b/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser-min.js new file mode 100644 index 0000000..cef2f0f --- /dev/null +++ b/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser-min.js @@ -0,0 +1,665 @@ + ++function($){"use strict";if($.oc.mediaManager===undefined) +$.oc.mediaManager={} +var Base=$.oc.foundation.base,BaseProto=Base.prototype +var MediaManager=function(element,options){this.$el=$(element) +this.$form=this.$el.closest('form') +this.options=options +Base.call(this) +this.selectTimer=null +this.sidebarPreviewElement=null +this.itemListElement=null +this.scrollContentElement=null +this.thumbnailQueue=[] +this.activeThumbnailQueueLength=0 +this.sidebarThumbnailAjax=null +this.selectionMarker=null +this.dropzone=null +this.searchTrackInputTimer=null +this.navigationAjax=null +this.dblTouchTimer=null +this.dblTouchFlag=null +this.itemListPosition=null +this.init()} +MediaManager.prototype=Object.create(BaseProto) +MediaManager.prototype.constructor=MediaManager +MediaManager.prototype.dispose=function(){this.unregisterHandlers() +this.clearSelectTimer() +this.destroyUploader() +this.clearSearchTrackInputTimer() +this.releaseNavigationAjax() +this.clearDblTouchTimer() +this.removeAttachedControls() +this.removeScroll() +this.$el.removeData('oc.mediaManager') +this.$el=null +this.$form=null +this.sidebarPreviewElement=null +this.itemListElement=null +this.scrollContentElement=null +this.sidebarThumbnailAjax=null +this.selectionMarker=null +this.thumbnailQueue=[] +this.navigationAjax=null +BaseProto.dispose.call(this)} +MediaManager.prototype.getSelectedItems=function(returnNotProcessed,allowRootItem){var items=this.$el.get(0).querySelectorAll('[data-type="media-item"].selected'),result=[] +if(!allowRootItem){var filteredItems=[] +for(var i=0,len=items.length;i=0;i--) +this.thumbnailQueue.push({id:placeholders[i].getAttribute('id'),width:placeholders[i].getAttribute('data-width'),height:placeholders[i].getAttribute('data-height'),path:placeholders[i].getAttribute('data-path'),lastModified:placeholders[i].getAttribute('data-last-modified')}) +this.handleThumbnailQueue()} +MediaManager.prototype.handleThumbnailQueue=function(){var maxThumbnailQueueLength=2,maxThumbnailBatchLength=3 +if(this.activeThumbnailQueueLength>=maxThumbnailQueueLength) +return +for(var i=this.activeThumbnailQueueLength;i0;i++){var batch=[] +for(var j=0;j0;j++) +batch.push(this.thumbnailQueue.pop()) +this.activeThumbnailQueueLength++ +this.handleThumbnailBatch(batch).always(this.proxy(this.placeholdersUpdated))}} +MediaManager.prototype.handleThumbnailBatch=function(batch){var data={batch:batch} +for(var i=0,len=batch.length;i(bTop+bHeight))||((aLeft+aWidth)(bLeft+bWidth)))} +MediaManager.prototype.initUploader=function(){if(!this.itemListElement||this.options.readOnly) +return +var uploaderOptions={clickable:this.$el.find('[data-control="upload"]').get(0),url:this.options.url,paramName:'file_data',timeout:0,headers:{},createImageThumbnails:false} +var token=$('meta[name="csrf-token"]').attr('content') +if(token){uploaderOptions.headers['X-CSRF-TOKEN']=token} +this.dropzone=new Dropzone(this.$el.get(0),uploaderOptions) +this.dropzone.on('addedfile',this.proxy(this.uploadFileAdded)) +this.dropzone.on('totaluploadprogress',this.proxy(this.uploadUpdateTotalProgress)) +this.dropzone.on('queuecomplete',this.proxy(this.uploadQueueComplete)) +this.dropzone.on('sending',this.proxy(this.uploadSending)) +this.dropzone.on('error',this.proxy(this.uploadError)) +this.dropzone.on('success',this.proxy(this.uploadSuccess))} +MediaManager.prototype.destroyUploader=function(){if(!this.dropzone) +return +this.dropzone.destroy() +this.dropzone=null} +MediaManager.prototype.uploadFileAdded=function(){this.showUploadUi() +this.setUploadProgress(0) +this.$el.find('[data-command="cancel-uploading"]').removeClass('hide') +this.$el.find('[data-command="close-uploader"]').addClass('hide')} +MediaManager.prototype.showUploadUi=function(){this.$el.find('[data-control="upload-ui"]').removeClass('hide')} +MediaManager.prototype.hideUploadUi=function(){this.$el.find('[data-control="upload-ui"]').addClass('hide')} +MediaManager.prototype.uploadUpdateTotalProgress=function(uploadProgress,totalBytes,totalBytesSent){this.setUploadProgress(uploadProgress) +var fileNumberLabel=this.$el.get(0).querySelector('[data-label="file-number-and-progress"]'),messageTemplate=fileNumberLabel.getAttribute('data-message-template'),fileNumber=this.dropzone.getUploadingFiles().length+this.dropzone.getQueuedFiles().length +if(uploadProgress>=100){uploadProgress=99} +fileNumberLabel.innerHTML=messageTemplate.replace(':number',fileNumber).replace(':percents',Math.round(uploadProgress)+'%')} +MediaManager.prototype.setUploadProgress=function(value){var progressBar=this.$el.get(0).querySelector('[data-control="upload-progress-bar"]') +progressBar.setAttribute('style','width: '+value+'%') +progressBar.setAttribute('class','progress-bar')} +MediaManager.prototype.uploadQueueComplete=function(){this.$el.find('[data-command="cancel-uploading"]').addClass('hide') +this.$el.find('[data-command="close-uploader"]').removeClass('hide') +this.refresh()} +MediaManager.prototype.uploadSending=function(file,xhr,formData){formData.append('path',this.$el.find('[data-type="current-folder"]').val()) +xhr.setRequestHeader('X-OCTOBER-REQUEST-HANDLER',this.options.uploadHandler)} +MediaManager.prototype.uploadCancelAll=function(){this.dropzone.removeAllFiles(true) +this.hideUploadUi()} +MediaManager.prototype.updateUploadBar=function(templateName,classNames){var fileNumberLabel=this.$el.get(0).querySelector('[data-label="file-number-and-progress"]'),successTemplate=fileNumberLabel.getAttribute('data-'+templateName+'-template'),progressBar=this.$el.get(0).querySelector('[data-control="upload-progress-bar"]') +fileNumberLabel.innerHTML=successTemplate;progressBar.setAttribute('class',classNames)} +MediaManager.prototype.uploadSuccess=function(){this.updateUploadBar('success','progress-bar progress-bar-success');} +MediaManager.prototype.uploadError=function(file,message){this.updateUploadBar('error','progress-bar progress-bar-danger');if(file.xhr.status===413){message='Server rejected the file because it was too large, try increasing post_max_size';} +if(!message){message='Error uploading file'} +$.oc.alert(message)} +MediaManager.prototype.cropSelectedImage=function(callback){var selectedItems=this.getSelectedItems(true) +if(selectedItems.length!=1){alert(this.options.selectSingleImage) +return} +if(selectedItems[0].getAttribute('data-document-type')!=='image'){alert(this.options.selectionNotImage) +return} +var path=selectedItems[0].getAttribute('data-path') +new $.oc.mediaManager.imageCropPopup(path,{alias:this.options.alias,onDone:callback})} +MediaManager.prototype.onImageCropped=function(result){this.$el.trigger('popupcommand',['insert-cropped',result])} +MediaManager.prototype.clearSearchTrackInputTimer=function(){if(this.searchTrackInputTimer===null) +return +clearTimeout(this.searchTrackInputTimer) +this.searchTrackInputTimer=null} +MediaManager.prototype.updateSearchResults=function(){var $searchField=this.$el.find('[data-control="search"]'),data={search:$searchField.val()} +this.execNavigationRequest('onSearch',data,$searchField)} +MediaManager.prototype.resetSearch=function(){this.$el.find('[data-control="search"]').val('')} +MediaManager.prototype.onSearchChanged=function(ev){var value=ev.currentTarget.value +if(this.lastSearchValue!==undefined&&this.lastSearchValue==value) +return +this.lastSearchValue=value +this.clearSearchTrackInputTimer() +this.searchTrackInputTimer=window.setTimeout(this.proxy(this.updateSearchResults),300)} +MediaManager.prototype.deleteItems=function(){var items=this.$el.get(0).querySelectorAll('[data-type="media-item"].selected') +if(!items.length){$.oc.alert(this.options.deleteEmpty) +return} +$.oc.confirm(this.options.deleteConfirm,this.proxy(this.deleteConfirmation))} +MediaManager.prototype.deleteConfirmation=function(confirmed){if(!confirmed) +return +var items=this.$el.get(0).querySelectorAll('[data-type="media-item"].selected'),paths=[] +for(var i=0,len=items.length;i2||Math.abs(deltaY)>2)){this.createSelectionMarker() +this.selectionMarker.setAttribute('class','') +this.selectionStarted=true +$(document.body).addClass('no-select')} +if(this.selectionStarted){if(deltaX>=0){this.selectionMarker.style.left=this.selectionStartPoint.x+'px' +this.selectionMarker.style.width=deltaX+'px'} +else{this.selectionMarker.style.left=relativePosition.x+'px' +this.selectionMarker.style.width=Math.abs(deltaX)+'px'} +if(deltaY>=0){this.selectionMarker.style.height=deltaY+'px' +this.selectionMarker.style.top=this.selectionStartPoint.y+'px'} +else{this.selectionMarker.style.top=relativePosition.y+'px' +this.selectionMarker.style.height=Math.abs(deltaY)+'px'}}} +MediaManager.prototype.onSortingChanged=function(ev){var $target=$(ev.target),data={path:this.$el.find('[data-type="current-folder"]').val()} +if($target.data('sort')=='by'){data.sortBy=$target.val();}else if($target.data('sort')=='direction'){data.sortDirection=$target.val()} +this.execNavigationRequest('onSetSorting',data)} +MediaManager.prototype.onKeyDown=function(ev){var eventHandled=false +switch(ev.key){case'Enter':var items=this.getSelectedItems(true,true) +if(items.length>0) +this.navigateToItem($(items[0])) +eventHandled=true +break;case'ArrowRight':case'ArrowDown':this.selectRelative(true,ev.shiftKey) +eventHandled=true +break;case'ArrowLeft':case'ArrowUp':this.selectRelative(false,ev.shiftKey) +eventHandled=true +break;} +if(eventHandled){ev.preventDefault() +ev.stopPropagation()}} +MediaManager.DEFAULTS={url:window.location,uploadHandler:null,alias:'',deleteEmpty:'Please select files to delete.',deleteConfirm:'Delete the selected file(s)?',moveEmpty:'Please select files to move.',selectSingleImage:'Please select a single image.',selectionNotImage:'The selected item is not an image.',bottomToolbar:false,cropAndInsertButton:false} +var old=$.fn.mediaManager +$.fn.mediaManager=function(option){var args=Array.prototype.slice.call(arguments,1),result=undefined +this.each(function(){var $this=$(this) +var data=$this.data('oc.mediaManager') +var options=$.extend({},MediaManager.DEFAULTS,$this.data(),typeof option=='object'&&option) +if(!data)$this.data('oc.mediaManager',(data=new MediaManager(this,options))) +if(typeof option=='string')result=data[option].apply(data,args) +if(typeof result!='undefined')return false}) +return result?result:this} +$.fn.mediaManager.Constructor=MediaManager +$.fn.mediaManager.noConflict=function(){$.fn.mediaManager=old +return this} +$(document).on('render',function(){$('div[data-control=media-manager]').mediaManager()})}(window.jQuery);+function($){"use strict";if($.oc.mediaManager===undefined) +$.oc.mediaManager={} +var Base=$.oc.foundation.base,BaseProto=Base.prototype +var MediaManagerImageCropPopup=function(path,options){this.$popupRootElement=null +this.$popupElement=null +this.selectionSizeLabel=null +this.imageArea=null +this.hRulerHolder=null +this.vRulerHolder=null +this.rulersVisible=false +this.prevScrollTop=0 +this.prevScrollLeft=0 +this.jCrop=null +this.options=$.extend({},MediaManagerImageCropPopup.DEFAULTS,options) +this.path=path +Base.call(this) +this.init() +this.show()} +MediaManagerImageCropPopup.prototype=Object.create(BaseProto) +MediaManagerImageCropPopup.prototype.constructor=MediaManagerImageCropPopup +MediaManagerImageCropPopup.prototype.dispose=function(){this.unregisterHandlers() +this.removeAttachedControls() +this.$popupRootElement.remove() +this.$popupRootElement=null +this.$popupElement=null +this.selectionSizeLabel=null +this.imageArea=null +this.hRulerHolder=null +this.vRulerHolder=null +BaseProto.dispose.call(this)} +MediaManagerImageCropPopup.prototype.init=function(){if(this.options.alias===undefined) +throw new Error('Media Manager image crop popup option "alias" is not set.') +this.$popupRootElement=$('
    ') +this.registerHandlers()} +MediaManagerImageCropPopup.prototype.show=function(){var data={path:this.path} +this.$popupRootElement.popup({extraData:data,size:'adaptive',adaptiveHeight:true,handler:this.options.alias+'::onLoadImageCropPopup',zIndex:1200})} +MediaManagerImageCropPopup.prototype.registerHandlers=function(){this.$popupRootElement.one('hide.oc.popup',this.proxy(this.onPopupHidden)) +this.$popupRootElement.one('shown.oc.popup',this.proxy(this.onPopupShown))} +MediaManagerImageCropPopup.prototype.unregisterHandlers=function(){this.$popupElement.off('change','[data-control="selection-mode"]',this.proxy(this.onSelectionModeChanged)) +this.$popupElement.off('click','[data-command]',this.proxy(this.onCommandClick)) +this.$popupElement.off('shown.oc.popup','button[data-command=resize]',this.proxy(this.onResizePopupShown)) +this.$popupElement.off('hidden.oc.popup','button[data-command=resize]',this.proxy(this.onResizePopupHidden)) +if(this.rulersVisible){var $cropToolRoot=this.$popupElement.find('[data-control=media-manager-crop-tool]') +this.imageArea.removeEventListener('scroll',this.proxy(this.onImageScroll))} +this.getWidthInput().off('change',this.proxy(this.onSizeInputChange)) +this.getHeightInput().off('change',this.proxy(this.onSizeInputChange))} +MediaManagerImageCropPopup.prototype.removeAttachedControls=function(){if(this.$popupElement){this.$popupElement.find('[data-control="selection-mode"]').select2('destroy').remove() +this.$popupElement.find('[data-control=toolbar]').toolbar('dispose').remove() +this.jCrop.destroy()} +this.jCrop=null} +MediaManagerImageCropPopup.prototype.hide=function(){if(this.$popupElement) +this.$popupElement.trigger('close.oc.popup')} +MediaManagerImageCropPopup.prototype.getSelectionMode=function(){return this.$popupElement.find('[data-control="selection-mode"]').val()} +MediaManagerImageCropPopup.prototype.initRulers=function(){if(!Modernizr.csstransforms) +return +var $cropToolRoot=this.$popupElement.find('[data-control=media-manager-crop-tool]'),width=$cropToolRoot.data('image-width'),height=$cropToolRoot.data('image-height') +if(!width||!height) +return +if($cropToolRoot.width()>width) +width=$(window).width() +if($cropToolRoot.height()>height) +height=$(window).height() +$cropToolRoot.find('.ruler-container').removeClass('hide') +$cropToolRoot.addClass('has-rulers') +var $hRuler=$cropToolRoot.find('[data-control=h-ruler]'),$vRuler=$cropToolRoot.find('[data-control=v-ruler]'),hTicks=width/40+1,vTicks=height/40+1 +this.createRulerTicks($hRuler,hTicks) +this.createRulerTicks($vRuler,vTicks) +this.rulersVisible=true +this.imageArea.addEventListener('scroll',this.proxy(this.onImageScroll)) +this.hRulerHolder=$cropToolRoot.find('.ruler-container.horizontal .layout-relative').get(0) +this.vRulerHolder=$cropToolRoot.find('.ruler-container.vertical .layout-relative').get(0)} +MediaManagerImageCropPopup.prototype.createRulerTicks=function($rulerElement,count){var list=document.createElement('ul') +for(var i=0;i<=count;i++){var li=document.createElement('li') +li.textContent=i*40 +list.appendChild(li)} +$rulerElement.append(list)} +MediaManagerImageCropPopup.prototype.initJCrop=function(){this.jCrop=$.Jcrop($(this.imageArea).find('img').get(0),{shade:true,onChange:this.proxy(this.onSelectionChanged)})} +MediaManagerImageCropPopup.prototype.fixDimensionValue=function(value){var result=value.replace(/[^0-9]+/,'') +if(!result.length) +result=200 +if(result=='0') +result=1 +return result} +MediaManagerImageCropPopup.prototype.getWidthInput=function(){return this.$popupElement.find('[data-control="crop-width-input"]')} +MediaManagerImageCropPopup.prototype.getHeightInput=function(){return this.$popupElement.find('[data-control="crop-height-input"]')} +MediaManagerImageCropPopup.prototype.applySelectionMode=function(){if(!this.jCrop) +return +var $widthInput=this.getWidthInput(),$heightInput=this.getHeightInput(),width=this.fixDimensionValue($widthInput.val()),height=this.fixDimensionValue($heightInput.val()),mode=this.getSelectionMode() +switch(mode){case'fixed-ratio':this.jCrop.setOptions({aspectRatio:width/height,minSize:[0,0],maxSize:[0,0],allowResize:true}) +break +case'fixed-size':this.jCrop.setOptions({aspectRatio:0,minSize:[width,height],maxSize:[width,height],allowResize:false}) +break +case'normal':this.jCrop.setOptions({aspectRatio:0,minSize:[0,0],maxSize:[0,0],allowResize:true}) +break}} +MediaManagerImageCropPopup.prototype.cropAndInsert=function(){var data={img:$(this.imageArea).find('img').attr('src'),selection:this.jCrop.tellSelect()} +$.oc.stripeLoadIndicator.show() +this.$popupElement.find('form').request(this.options.alias+'::onCropImage',{data:data}).always(function(){$.oc.stripeLoadIndicator.hide()}).done(this.proxy(this.onImageCropped))} +MediaManagerImageCropPopup.prototype.onImageCropped=function(response){this.hide() +if(this.options.onDone!==undefined){this.options.onDone(response)}} +MediaManagerImageCropPopup.prototype.showResizePopup=function(){this.$popupElement.find('button[data-command=resize]').popup({content:this.$popupElement.find('[data-control="resize-template"]').html(),zIndex:1220})} +MediaManagerImageCropPopup.prototype.onResizePopupShown=function(ev,button,popup){var $popup=$(popup),$widthControl=$popup.find('input[name=width]'),$heightControl=$popup.find('input[name=height]'),imageWidth=this.fixDimensionValue(this.$popupElement.find('input[data-control=dimension-width]').val()),imageHeight=this.fixDimensionValue(this.$popupElement.find('input[data-control=dimension-height]').val()) +$widthControl.val(imageWidth) +$heightControl.val(imageHeight) +$widthControl.focus() +$popup.on('submit.media','form',this.proxy(this.onResizeSubmit)) +$widthControl.on('keyup.media',this.proxy(this.onResizeDimensionKeyUp)) +$heightControl.on('keyup.media',this.proxy(this.onResizeDimensionKeyUp)) +$widthControl.on('change.media',this.proxy(this.onResizeDimensionChanged)) +$heightControl.on('change.media',this.proxy(this.onResizeDimensionChanged))} +MediaManagerImageCropPopup.prototype.onResizePopupHidden=function(ev,button,popup){var $popup=$(popup),$widthControl=$popup.find('input[name=width]'),$heightControl=$popup.find('input[name=height]') +$popup.off('.media','form') +$widthControl.off('.media') +$heightControl.off('.media')} +MediaManagerImageCropPopup.prototype.onResizeDimensionKeyUp=function(ev){var $target=$(ev.target),targetValue=this.fixDimensionValue($target.val()),otherDimensionName=$target.attr('name')=='width'?'height':'width',$otherInput=$target.closest('form').find('input[name='+otherDimensionName+']'),ratio=this.$popupElement.find('[data-control=original-ratio]').val(),value=otherDimensionName=='height'?targetValue/ratio:targetValue*ratio +$otherInput.val(Math.round(value))} +MediaManagerImageCropPopup.prototype.onResizeDimensionChanged=function(ev){var $target=$(ev.target) +$target.val(this.fixDimensionValue($target.val()))} +MediaManagerImageCropPopup.prototype.onResizeSubmit=function(ev){var data={cropSessionKey:this.$popupElement.find('input[name=cropSessionKey]').val(),path:this.$popupElement.find('input[name=path]').val()} +$.oc.stripeLoadIndicator.show() +$(ev.target).request(this.options.alias+'::onResizeImage',{data:data}).always(function(){$.oc.stripeLoadIndicator.hide()}).done(this.proxy(this.imageResized)) +ev.preventDefault() +return false} +MediaManagerImageCropPopup.prototype.imageResized=function(response){this.$popupElement.find('button[data-command=resize]').popup('hide') +this.updateImage(response.url,response.dimensions[0],response.dimensions[1])} +MediaManagerImageCropPopup.prototype.updateImage=function(url,width,hegiht){this.jCrop.destroy() +this.$popupElement.find('span[data-label=width]').text(width) +this.$popupElement.find('span[data-label=height]').text(hegiht) +this.$popupElement.find('input[data-control=dimension-width]').val(width) +this.$popupElement.find('input[data-control=dimension-height]').val(hegiht) +var $imageArea=$(this.imageArea) +$imageArea.find('img').remove() +var $img=$('').attr('src',url) +$img.one('load',this.proxy(this.initJCrop)) +$imageArea.append($img) +this.imageArea.scrollTop=0 +this.imageArea.scrollLeft=0 +this.onImageScroll()} +MediaManagerImageCropPopup.prototype.undoResizing=function(){this.updateImage(this.$popupElement.find('input[data-control=original-url]').val(),this.$popupElement.find('input[data-control=original-width]').val(),this.$popupElement.find('input[data-control=original-height]').val())} +MediaManagerImageCropPopup.prototype.updateSelectionSizeLabel=function(width,height){if(width==0&&height==0){this.selectionSizeLabel.setAttribute('class','hide') +return} +this.selectionSizeLabel.setAttribute('class','') +this.selectionSizeLabel.querySelector('[data-label=selection-width]').textContent=parseInt(width) +this.selectionSizeLabel.querySelector('[data-label=selection-height]').textContent=parseInt(height)} +MediaManagerImageCropPopup.prototype.onPopupHidden=function(event,element,popup){this.$popupElement.find('form').request(this.options.alias+'::onEndCroppingSession') +$(document).trigger('mousedown') +this.dispose()} +MediaManagerImageCropPopup.prototype.onPopupShown=function(event,element,popup){this.$popupElement=popup +this.$popupElement.on('change','[data-control="selection-mode"]',this.proxy(this.onSelectionModeChanged)) +this.$popupElement.on('click','[data-command]',this.proxy(this.onCommandClick)) +this.$popupElement.on('shown.oc.popup','button[data-command=resize]',this.proxy(this.onResizePopupShown)) +this.$popupElement.on('hidden.oc.popup','button[data-command=resize]',this.proxy(this.onResizePopupHidden)) +this.imageArea=popup.find('[data-control=media-manager-crop-tool]').get(0).querySelector('.image_area') +this.selectionSizeLabel=popup.find('[data-label="selection-size"]').get(0) +this.getWidthInput().on('change',this.proxy(this.onSizeInputChange)) +this.getHeightInput().on('change',this.proxy(this.onSizeInputChange)) +this.initRulers() +this.initJCrop() +this.applySelectionMode()} +MediaManagerImageCropPopup.prototype.onSelectionModeChanged=function(){var mode=this.getSelectionMode(),$widthInput=this.getWidthInput(),$heightInput=this.getHeightInput() +if(mode==='normal'){$widthInput.attr('disabled','disabled') +$heightInput.attr('disabled','disabled')} +else{$widthInput.removeAttr('disabled') +$heightInput.removeAttr('disabled') +$widthInput.val(this.fixDimensionValue($widthInput.val())) +$heightInput.val(this.fixDimensionValue($heightInput.val()))} +this.applySelectionMode()} +MediaManagerImageCropPopup.prototype.onImageScroll=function(){var scrollTop=this.imageArea.scrollTop,scrollLeft=this.imageArea.scrollLeft +if(this.prevScrollTop!=scrollTop){this.prevScrollTop=scrollTop +this.vRulerHolder.scrollTop=scrollTop} +if(this.prevScrollLeft!=scrollLeft){this.prevScrollLeft=scrollLeft +this.hRulerHolder.scrollLeft=scrollLeft}} +MediaManagerImageCropPopup.prototype.onSizeInputChange=function(ev){var $target=$(ev.target) +$target.val(this.fixDimensionValue($target.val())) +this.applySelectionMode()} +MediaManagerImageCropPopup.prototype.onCommandClick=function(ev){var command=$(ev.currentTarget).data('command') +switch(command){case'insert':this.cropAndInsert() +break +case'resize':this.showResizePopup() +break +case'undo-resizing':this.undoResizing() +break}} +MediaManagerImageCropPopup.prototype.onSelectionChanged=function(c){this.updateSelectionSizeLabel(c.w,c.h)} +MediaManagerImageCropPopup.DEFAULTS={alias:undefined,onDone:undefined} +$.oc.mediaManager.imageCropPopup=MediaManagerImageCropPopup}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser.js b/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser.js new file mode 100644 index 0000000..7cdb81c --- /dev/null +++ b/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser.js @@ -0,0 +1,13 @@ +/* + * This is a bundle file, you can compile this in two ways: + * (1) Using your favorite JS combiner + * (2) Using CLI command: + * php artisan october:util compile assets + * + * @see build-min.js + * + +=require mediamanager.js +=require mediamanager.imagecroppopup.js + +*/ diff --git a/modules/backend/widgets/mediamanager/assets/js/mediamanager-global.js b/modules/backend/widgets/mediamanager/assets/js/mediamanager-global.js new file mode 100644 index 0000000..049a806 --- /dev/null +++ b/modules/backend/widgets/mediamanager/assets/js/mediamanager-global.js @@ -0,0 +1,6 @@ +/* +These scripts will be included globally as part of the backend. + +=require mediamanager.popup.js + +*/ diff --git a/modules/backend/widgets/mediamanager/assets/js/mediamanager.imagecroppopup.js b/modules/backend/widgets/mediamanager/assets/js/mediamanager.imagecroppopup.js new file mode 100644 index 0000000..a631307 --- /dev/null +++ b/modules/backend/widgets/mediamanager/assets/js/mediamanager.imagecroppopup.js @@ -0,0 +1,480 @@ +/* + * Media manager image editor popup + */ ++function ($) { "use strict"; + + if ($.oc.mediaManager === undefined) + $.oc.mediaManager = {} + + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var MediaManagerImageCropPopup = function(path, options) { + this.$popupRootElement = null + this.$popupElement = null + this.selectionSizeLabel = null + this.imageArea = null + this.hRulerHolder = null + this.vRulerHolder = null + + this.rulersVisible = false + this.prevScrollTop = 0 + this.prevScrollLeft = 0 + + this.jCrop = null + + this.options = $.extend({}, MediaManagerImageCropPopup.DEFAULTS, options) + this.path = path + + Base.call(this) + + this.init() + this.show() + } + + MediaManagerImageCropPopup.prototype = Object.create(BaseProto) + MediaManagerImageCropPopup.prototype.constructor = MediaManagerImageCropPopup + + MediaManagerImageCropPopup.prototype.dispose = function() { + this.unregisterHandlers() + this.removeAttachedControls() + + this.$popupRootElement.remove() + this.$popupRootElement = null + this.$popupElement = null + this.selectionSizeLabel = null + this.imageArea = null + this.hRulerHolder = null + this.vRulerHolder = null + + BaseProto.dispose.call(this) + } + + MediaManagerImageCropPopup.prototype.init = function() { + if (this.options.alias === undefined) + throw new Error('Media Manager image crop popup option "alias" is not set.') + + this.$popupRootElement = $('
    ') + this.registerHandlers() + } + + MediaManagerImageCropPopup.prototype.show = function() { + var data = { + path: this.path + } + + this.$popupRootElement.popup({ + extraData: data, + size: 'adaptive', + adaptiveHeight: true, + handler: this.options.alias + '::onLoadImageCropPopup', + zIndex: 1200 // Media Manager can be opened in a popup, so this new popup should have a higher z-index + }) + } + + MediaManagerImageCropPopup.prototype.registerHandlers = function() { + this.$popupRootElement.one('hide.oc.popup', this.proxy(this.onPopupHidden)) + this.$popupRootElement.one('shown.oc.popup', this.proxy(this.onPopupShown)) + } + + MediaManagerImageCropPopup.prototype.unregisterHandlers = function() { + this.$popupElement.off('change', '[data-control="selection-mode"]', this.proxy(this.onSelectionModeChanged)) + this.$popupElement.off('click', '[data-command]', this.proxy(this.onCommandClick)) + this.$popupElement.off('shown.oc.popup', 'button[data-command=resize]', this.proxy(this.onResizePopupShown)) + this.$popupElement.off('hidden.oc.popup', 'button[data-command=resize]', this.proxy(this.onResizePopupHidden)) + + if (this.rulersVisible) { + var $cropToolRoot = this.$popupElement.find('[data-control=media-manager-crop-tool]') + this.imageArea.removeEventListener('scroll', this.proxy(this.onImageScroll)) + } + + this.getWidthInput().off('change', this.proxy(this.onSizeInputChange)) + this.getHeightInput().off('change', this.proxy(this.onSizeInputChange)) + } + + MediaManagerImageCropPopup.prototype.removeAttachedControls = function() { + if (this.$popupElement) { + // Note - the controls are destroyed and removed from DOM. If they're just destroyed, + // the JS plugins could be re-attached to them on window.onresize. -ab + this.$popupElement.find('[data-control="selection-mode"]').select2('destroy').remove() + this.$popupElement.find('[data-control=toolbar]').toolbar('dispose').remove() + + this.jCrop.destroy() + } + + this.jCrop = null + } + + MediaManagerImageCropPopup.prototype.hide = function() { + if (this.$popupElement) + this.$popupElement.trigger('close.oc.popup') + } + + MediaManagerImageCropPopup.prototype.getSelectionMode = function() { + return this.$popupElement.find('[data-control="selection-mode"]').val() + } + + MediaManagerImageCropPopup.prototype.initRulers = function() { + if (!Modernizr.csstransforms) + return + + var $cropToolRoot = this.$popupElement.find('[data-control=media-manager-crop-tool]'), + width = $cropToolRoot.data('image-width'), + height = $cropToolRoot.data('image-height') + + if (!width || !height) + return + + if ($cropToolRoot.width() > width) + width = $(window).width() + + if ($cropToolRoot.height() > height) + height = $(window).height() + + $cropToolRoot.find('.ruler-container').removeClass('hide') + + $cropToolRoot.addClass('has-rulers') + + var $hRuler = $cropToolRoot.find('[data-control=h-ruler]'), + $vRuler = $cropToolRoot.find('[data-control=v-ruler]'), + hTicks = width / 40 + 1, + vTicks = height / 40 + 1 + + this.createRulerTicks($hRuler, hTicks) + this.createRulerTicks($vRuler, vTicks) + + this.rulersVisible = true + + this.imageArea.addEventListener('scroll', this.proxy(this.onImageScroll)) + + this.hRulerHolder = $cropToolRoot.find('.ruler-container.horizontal .layout-relative').get(0) + this.vRulerHolder = $cropToolRoot.find('.ruler-container.vertical .layout-relative').get(0) + } + + MediaManagerImageCropPopup.prototype.createRulerTicks = function($rulerElement, count) { + var list = document.createElement('ul') + + for (var i=0; i <= count; i++) { + var li = document.createElement('li') + li.textContent = i*40 + + list.appendChild(li) + } + + $rulerElement.append(list) + } + + MediaManagerImageCropPopup.prototype.initJCrop = function() { + this.jCrop = $.Jcrop($(this.imageArea).find('img').get(0), { + shade: true, + onChange: this.proxy(this.onSelectionChanged) + }) + } + + MediaManagerImageCropPopup.prototype.fixDimensionValue = function(value) { + var result = value.replace(/[^0-9]+/, '') + + if (!result.length) + result = 200 + + if (result == '0') + result = 1 + + return result + } + + MediaManagerImageCropPopup.prototype.getWidthInput = function() { + return this.$popupElement.find('[data-control="crop-width-input"]') + } + + MediaManagerImageCropPopup.prototype.getHeightInput = function() { + return this.$popupElement.find('[data-control="crop-height-input"]') + } + + MediaManagerImageCropPopup.prototype.applySelectionMode = function() { + if (!this.jCrop) + return + + var $widthInput = this.getWidthInput(), + $heightInput = this.getHeightInput(), + width = this.fixDimensionValue($widthInput.val()), + height = this.fixDimensionValue($heightInput.val()), + mode = this.getSelectionMode() + + switch (mode) { + case 'fixed-ratio' : + this.jCrop.setOptions({ + aspectRatio: width/height, + minSize: [0, 0], + maxSize: [0, 0], + allowResize: true + }) + break + case 'fixed-size' : + this.jCrop.setOptions({ + aspectRatio: 0, + minSize: [width, height], + maxSize: [width, height], + allowResize: false + }) + break + case 'normal' : + this.jCrop.setOptions({ + aspectRatio: 0, + minSize: [0, 0], + maxSize: [0, 0], + allowResize: true + }) + break + } + } + + MediaManagerImageCropPopup.prototype.cropAndInsert = function() { + var data = { + img: $(this.imageArea).find('img').attr('src'), + selection: this.jCrop.tellSelect() + } + + $.oc.stripeLoadIndicator.show() + + this.$popupElement + .find('form') + .request(this.options.alias+'::onCropImage', { + data: data + }) + .always(function() { + $.oc.stripeLoadIndicator.hide() + }) + .done(this.proxy(this.onImageCropped)) + } + + MediaManagerImageCropPopup.prototype.onImageCropped = function(response) { + this.hide() + + if (this.options.onDone !== undefined) { + this.options.onDone(response) + } + } + + MediaManagerImageCropPopup.prototype.showResizePopup = function() { + this.$popupElement.find('button[data-command=resize]').popup({ + content: this.$popupElement.find('[data-control="resize-template"]').html(), + zIndex: 1220 + }) + } + + MediaManagerImageCropPopup.prototype.onResizePopupShown = function(ev, button, popup) { + var $popup = $(popup), + $widthControl = $popup.find('input[name=width]'), + $heightControl = $popup.find('input[name=height]'), + imageWidth = this.fixDimensionValue(this.$popupElement.find('input[data-control=dimension-width]').val()), + imageHeight = this.fixDimensionValue(this.$popupElement.find('input[data-control=dimension-height]').val()) + + $widthControl.val(imageWidth) + $heightControl.val(imageHeight) + + $widthControl.focus() + + $popup.on('submit.media', 'form', this.proxy(this.onResizeSubmit)) + $widthControl.on('keyup.media', this.proxy(this.onResizeDimensionKeyUp)) + $heightControl.on('keyup.media', this.proxy(this.onResizeDimensionKeyUp)) + + $widthControl.on('change.media', this.proxy(this.onResizeDimensionChanged)) + $heightControl.on('change.media', this.proxy(this.onResizeDimensionChanged)) + } + + MediaManagerImageCropPopup.prototype.onResizePopupHidden = function(ev, button, popup) { + var $popup = $(popup), + $widthControl = $popup.find('input[name=width]'), + $heightControl = $popup.find('input[name=height]') + + $popup.off('.media', 'form') + $widthControl.off('.media') + $heightControl.off('.media') + } + + MediaManagerImageCropPopup.prototype.onResizeDimensionKeyUp = function(ev) { + var $target = $(ev.target), + targetValue = this.fixDimensionValue($target.val()), + otherDimensionName = $target.attr('name') == 'width' ? 'height' : 'width', + $otherInput = $target.closest('form').find('input[name='+otherDimensionName+']'), + ratio = this.$popupElement.find('[data-control=original-ratio]').val(), + value = otherDimensionName == 'height' ? targetValue / ratio : targetValue * ratio + + $otherInput.val(Math.round(value)) + } + + MediaManagerImageCropPopup.prototype.onResizeDimensionChanged = function(ev) { + var $target = $(ev.target) + + $target.val(this.fixDimensionValue($target.val())) + } + + MediaManagerImageCropPopup.prototype.onResizeSubmit = function(ev) { + var data = { + cropSessionKey: this.$popupElement.find('input[name=cropSessionKey]').val(), + path: this.$popupElement.find('input[name=path]').val() + } + + $.oc.stripeLoadIndicator.show() + $(ev.target).request(this.options.alias+'::onResizeImage', { + data: data + }).always(function() { + $.oc.stripeLoadIndicator.hide() + }).done(this.proxy(this.imageResized)) + + ev.preventDefault() + return false + } + + MediaManagerImageCropPopup.prototype.imageResized = function(response) { + this.$popupElement.find('button[data-command=resize]').popup('hide') + + this.updateImage(response.url, response.dimensions[0], response.dimensions[1]) + } + + MediaManagerImageCropPopup.prototype.updateImage = function(url, width, hegiht) { + this.jCrop.destroy() + + this.$popupElement.find('span[data-label=width]').text(width) + this.$popupElement.find('span[data-label=height]').text(hegiht) + + this.$popupElement.find('input[data-control=dimension-width]').val(width) + this.$popupElement.find('input[data-control=dimension-height]').val(hegiht) + + var $imageArea = $(this.imageArea) + $imageArea.find('img').remove() + + var $img = $('').attr('src', url) + $img.one('load', this.proxy(this.initJCrop)) + + $imageArea.append($img) + + this.imageArea.scrollTop = 0 + this.imageArea.scrollLeft = 0 + this.onImageScroll() + } + + MediaManagerImageCropPopup.prototype.undoResizing = function() { + this.updateImage( + this.$popupElement.find('input[data-control=original-url]').val(), + this.$popupElement.find('input[data-control=original-width]').val(), + this.$popupElement.find('input[data-control=original-height]').val() + ) + } + + MediaManagerImageCropPopup.prototype.updateSelectionSizeLabel = function(width, height) { + if (width == 0 && height == 0) { + this.selectionSizeLabel.setAttribute('class', 'hide') + return + } + + this.selectionSizeLabel.setAttribute('class', '') + this.selectionSizeLabel.querySelector('[data-label=selection-width]').textContent = parseInt(width) + this.selectionSizeLabel.querySelector('[data-label=selection-height]').textContent = parseInt(height) + } + + // EVENT HANDLERS + // ============================ + + MediaManagerImageCropPopup.prototype.onPopupHidden = function(event, element, popup) { + this.$popupElement.find('form').request(this.options.alias+'::onEndCroppingSession') + + // Release clickedElement reference inside redactor.js + // If we don't do it, the image editor popup DOM elements + // won't be removed from the memory. + $(document).trigger('mousedown') + + this.dispose() + } + + MediaManagerImageCropPopup.prototype.onPopupShown = function(event, element, popup) { + this.$popupElement = popup + this.$popupElement.on('change', '[data-control="selection-mode"]', this.proxy(this.onSelectionModeChanged)) + this.$popupElement.on('click', '[data-command]', this.proxy(this.onCommandClick)) + this.$popupElement.on('shown.oc.popup', 'button[data-command=resize]', this.proxy(this.onResizePopupShown)) + this.$popupElement.on('hidden.oc.popup', 'button[data-command=resize]', this.proxy(this.onResizePopupHidden)) + + this.imageArea = popup.find('[data-control=media-manager-crop-tool]').get(0).querySelector('.image_area') + this.selectionSizeLabel = popup.find('[data-label="selection-size"]').get(0) + + this.getWidthInput().on('change', this.proxy(this.onSizeInputChange)) + this.getHeightInput().on('change', this.proxy(this.onSizeInputChange)) + + this.initRulers() + this.initJCrop() + this.applySelectionMode() + } + + MediaManagerImageCropPopup.prototype.onSelectionModeChanged = function() { + var mode = this.getSelectionMode(), + $widthInput = this.getWidthInput(), + $heightInput = this.getHeightInput() + + if (mode === 'normal') { + $widthInput.attr('disabled', 'disabled') + $heightInput.attr('disabled', 'disabled') + } + else { + $widthInput.removeAttr('disabled') + $heightInput.removeAttr('disabled') + + $widthInput.val(this.fixDimensionValue($widthInput.val())) + $heightInput.val(this.fixDimensionValue($heightInput.val())) + } + + this.applySelectionMode() + } + + MediaManagerImageCropPopup.prototype.onImageScroll = function() { + var scrollTop = this.imageArea.scrollTop, + scrollLeft = this.imageArea.scrollLeft + + if (this.prevScrollTop != scrollTop) { + this.prevScrollTop = scrollTop + + this.vRulerHolder.scrollTop = scrollTop + } + + if (this.prevScrollLeft != scrollLeft) { + this.prevScrollLeft = scrollLeft + + this.hRulerHolder.scrollLeft = scrollLeft + } + } + + MediaManagerImageCropPopup.prototype.onSizeInputChange = function(ev) { + var $target = $(ev.target) + + $target.val(this.fixDimensionValue($target.val())) + + this.applySelectionMode() + } + + MediaManagerImageCropPopup.prototype.onCommandClick = function(ev) { + var command = $(ev.currentTarget).data('command') + + switch (command) { + case 'insert': + this.cropAndInsert() + break + case 'resize': + this.showResizePopup() + break + case 'undo-resizing': + this.undoResizing() + break + } + } + + MediaManagerImageCropPopup.prototype.onSelectionChanged = function(c) { + this.updateSelectionSizeLabel(c.w, c.h) + } + + MediaManagerImageCropPopup.DEFAULTS = { + alias: undefined, + onDone: undefined + } + + $.oc.mediaManager.imageCropPopup = MediaManagerImageCropPopup +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/assets/js/mediamanager.js b/modules/backend/widgets/mediamanager/assets/js/mediamanager.js new file mode 100644 index 0000000..178d915 --- /dev/null +++ b/modules/backend/widgets/mediamanager/assets/js/mediamanager.js @@ -0,0 +1,1333 @@ +/* + * Media manager control class + * + * Dependences: + * - Scrollpad (october.scrollpad.js) + */ ++function ($) { "use strict"; + + if ($.oc.mediaManager === undefined) + $.oc.mediaManager = {} + + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + // MEDIA MANAGER CLASS DEFINITION + // ============================ + + var MediaManager = function(element, options) { + this.$el = $(element) + this.$form = this.$el.closest('form') + + this.options = options + Base.call(this) + + // State properties + this.selectTimer = null + this.sidebarPreviewElement = null + this.itemListElement = null + this.scrollContentElement = null + this.thumbnailQueue = [] + this.activeThumbnailQueueLength = 0 + this.sidebarThumbnailAjax = null + this.selectionMarker = null + this.dropzone = null + this.searchTrackInputTimer = null + this.navigationAjax = null + this.dblTouchTimer = null + this.dblTouchFlag = null + this.itemListPosition = null + + // + // Initialization + // + + this.init() + } + + MediaManager.prototype = Object.create(BaseProto) + MediaManager.prototype.constructor = MediaManager + + MediaManager.prototype.dispose = function() { + this.unregisterHandlers() + this.clearSelectTimer() + this.destroyUploader() + this.clearSearchTrackInputTimer() + this.releaseNavigationAjax() + this.clearDblTouchTimer() + this.removeAttachedControls() + this.removeScroll() + + this.$el.removeData('oc.mediaManager') + this.$el = null + this.$form = null + + this.sidebarPreviewElement = null + this.itemListElement = null + this.scrollContentElement = null + this.sidebarThumbnailAjax = null + this.selectionMarker = null + this.thumbnailQueue = [] + this.navigationAjax = null + + BaseProto.dispose.call(this) + } + + MediaManager.prototype.getSelectedItems = function(returnNotProcessed, allowRootItem) { + var items = this.$el.get(0).querySelectorAll('[data-type="media-item"].selected'), + result = [] + + if (!allowRootItem) { + var filteredItems = [] + + for (var i=0, len=items.length; i < len; i++) { + var item = items[i] + if (!item.hasAttribute('data-root')) + filteredItems.push(item) + } + + items = filteredItems + } + + if (returnNotProcessed === true) + return items + + for (var i=0, len=items.length; i < len; i++) { + var item = items[i], + itemDetails = { + itemType: item.getAttribute('data-item-type'), + path: item.getAttribute('data-path'), + title: item.getAttribute('data-title'), + documentType: item.getAttribute('data-document-type'), + folder: item.getAttribute('data-folder'), + publicUrl: item.getAttribute('data-public-url') + } + + result.push(itemDetails) + } + + return result + } + + // MEDIA MANAGER INTERNAL METHODS + // ============================ + + MediaManager.prototype.init = function() { + this.itemListElement = this.$el.find('[data-control="item-list"]').get(0) + this.scrollContentElement = this.itemListElement.querySelector('.scroll-wrapper') + + if (this.options.bottomToolbar) { + this.$el.find('[data-control="bottom-toolbar"]').removeClass('hide') + + if (this.options.cropAndInsertButton) + this.$el.find('[data-popup-command="crop-and-insert"]').removeClass('hide') + } + + this.registerHandlers() + + this.updateSidebarPreview() + this.generateThumbnails() + this.initUploader() + this.initScroll() + } + + MediaManager.prototype.registerHandlers = function() { + this.$el.on('dblclick', this.proxy(this.onNavigate)) + this.$el.on('click.tree-path', 'ul.tree-path, [data-control="sidebar-labels"]', this.proxy(this.onNavigate)) + + this.$el.on('click.command', '[data-command]', this.proxy(this.onCommandClick)) + + // Touch devices use double-tap for the navigation and single tap for selecting. + // Another option is checkboxes visible only on touch devices, but this approach + // will require more significant changes in the code for the touch device support. + this.$el.on('click.item', '[data-type="media-item"]', this.proxy(this.onItemClick)) + this.$el.on('touchend', '[data-type="media-item"]', this.proxy(this.onItemTouch)) + + this.$el.on('change', '[data-control="sorting"]', this.proxy(this.onSortingChanged)) + this.$el.on('input', '[data-control="search"]', this.proxy(this.onSearchChanged)) + this.$el.on('mediarefresh', this.proxy(this.refresh)) + this.$el.on('shown.oc.popup', '[data-command="create-folder"]', this.proxy(this.onFolderPopupShown)) + this.$el.on('hidden.oc.popup', '[data-command="create-folder"]', this.proxy(this.onFolderPopupHidden)) + this.$el.on('shown.oc.popup', '[data-command="move"]', this.proxy(this.onMovePopupShown)) + this.$el.on('hidden.oc.popup', '[data-command="move"]', this.proxy(this.onMovePopupHidden)) + this.$el.on('keydown', this.proxy(this.onKeyDown)) + + if (this.itemListElement) + this.itemListElement.addEventListener('mousedown', this.proxy(this.onListMouseDown)) + } + + MediaManager.prototype.unregisterHandlers = function() { + this.$el.off('dblclick', this.proxy(this.onNavigate)) + this.$el.off('click.tree-path', this.proxy(this.onNavigate)) + this.$el.off('click.command', this.proxy(this.onCommandClick)) + + this.$el.off('click.item', this.proxy(this.onItemClick)) + this.$el.off('touchend', '[data-type="media-item"]', this.proxy(this.onItemTouch)) + + this.$el.off('change', '[data-control="sorting"]', this.proxy(this.onSortingChanged)) + this.$el.off('keyup', '[data-control="search"]', this.proxy(this.onSearchChanged)) + this.$el.off('shown.oc.popup', '[data-command="create-folder"]', this.proxy(this.onFolderPopupShown)) + this.$el.off('hidden.oc.popup', '[data-command="create-folder"]', this.proxy(this.onFolderPopupHidden)) + this.$el.off('shown.oc.popup', '[data-command="move"]', this.proxy(this.onMovePopupShown)) + this.$el.off('hidden.oc.popup', '[data-command="move"]', this.proxy(this.onMovePopupHidden)) + this.$el.off('keydown', this.proxy(this.onKeyDown)) + + if (this.itemListElement) { + this.itemListElement.removeEventListener('mousedown', this.proxy(this.onListMouseDown)) + this.itemListElement.removeEventListener('mousemove', this.proxy(this.onListMouseMove)) + } + + document.removeEventListener('mouseup', this.proxy(this.onListMouseUp)) + } + + MediaManager.prototype.changeView = function(view) { + var data = { + view: view, + path: this.$el.find('[data-type="current-folder"]').val() + } + + this.execNavigationRequest('onChangeView', data) + } + + MediaManager.prototype.setFilter = function(filter) { + var data = { + filter: filter, + path: this.$el.find('[data-type="current-folder"]').val() + } + + this.execNavigationRequest('onSetFilter', data) + } + + MediaManager.prototype.isSearchMode = function() { + return this.$el.find('[data-type="search-mode"]').val() == 'true' + } + + MediaManager.prototype.initScroll = function() { + this.$el.find('.control-scrollpad').scrollpad() + } + + MediaManager.prototype.updateScroll = function() { + this.$el.find('.control-scrollpad').scrollpad('update') + } + + MediaManager.prototype.removeScroll = function() { + this.$el.find('.control-scrollpad').scrollpad('dispose') + } + + MediaManager.prototype.scrollToTop = function() { + this.$el.find('.control-scrollpad').scrollpad('scrollToStart') + } + + // + // Disposing + // + + MediaManager.prototype.removeAttachedControls = function() { + this.$el.find('[data-control=toolbar]').toolbar('dispose') + this.$el.find('[data-control=sorting]').select2('destroy') + } + + // + // Selecting + // + + MediaManager.prototype.clearSelectTimer = function() { + if (this.selectTimer === null) + return + + clearTimeout(this.selectTimer) + this.selectTimer = null + } + + MediaManager.prototype.selectItem = function(node, expandSelection) { + if (!expandSelection) { + var items = this.$el.get(0).querySelectorAll('[data-type="media-item"].selected') + + // The class attribute is used only for selecting, it's safe to clear it + for (var i = 0, len = items.length; i < len; i++) { + items[i].setAttribute('class', '') + } + + node.setAttribute('class', 'selected') + } + else { + if (node.getAttribute('class') == 'selected') + node.setAttribute('class', '') + else + node.setAttribute('class', 'selected') + } + + node.focus() + + this.clearSelectTimer() + + if (this.isPreviewSidebarVisible()) { + // Use the timeout to prevent too many AJAX requests + // when the selection changes too quickly (with the keyboard arrows) + this.selectTimer = setTimeout(this.proxy(this.updateSidebarPreview), 100) + } + + // Disable delete and move buttons + if (node.hasAttribute('data-root') && !expandSelection) { + this.toggleMoveAndDelete(true) + } + else { + this.toggleMoveAndDelete(false) + } + + // Always unselect root when selecting multiples + if (expandSelection) { + this.unselectRoot() + } + } + + MediaManager.prototype.toggleMoveAndDelete = function(value) { + $('[data-command=delete]', this.$el).prop('disabled', value) + $('[data-command=move]', this.$el).prop('disabled', value) + } + + MediaManager.prototype.unselectRoot = function() { + var rootItem = this.$el.get(0).querySelector('[data-type="media-item"][data-root].selected') + + if (rootItem) + rootItem.setAttribute('class', '') + } + + MediaManager.prototype.clearDblTouchTimer = function() { + if (this.dblTouchTimer === null) + return + + clearTimeout(this.dblTouchTimer) + this.dblTouchTimer = null + } + + MediaManager.prototype.clearDblTouchFlag = function() { + this.dblTouchFlag = false + } + + MediaManager.prototype.selectFirstItem = function() { + var firstItem = this.itemListElement.querySelector('[data-type="media-item"]:first-child') + if (firstItem) { + this.selectItem(firstItem) + } + } + + MediaManager.prototype.selectRelative = function(next, expandSelection) { + var currentSelection = this.getSelectedItems(true, true) + + if (currentSelection.length == 0) { + this.selectFirstItem() + + return + } + + var itemToSelect = null + if (next) { + var lastItem = currentSelection[currentSelection.length-1] + + if (lastItem) + itemToSelect = lastItem.nextElementSibling + } + else { + var firstItem = currentSelection[0] + + if (firstItem) + itemToSelect = firstItem.previousElementSibling + } + + if (itemToSelect) + this.selectItem(itemToSelect, expandSelection) + } + + // + // Navigation + // + + MediaManager.prototype.gotoFolder = function(path, resetSearch) { + var data = { + path: path, + resetSearch: resetSearch !== undefined ? 1 : 0 + } + + this.execNavigationRequest('onGoToFolder', data) + } + + MediaManager.prototype.afterNavigate = function() { + this.scrollToTop() + this.generateThumbnails() + this.updateSidebarPreview(true) + this.selectFirstItem() + this.updateScroll() + } + + MediaManager.prototype.refresh = function() { + var data = { + path: this.$el.find('[data-type="current-folder"]').val(), + clearCache: true + } + + this.execNavigationRequest('onGoToFolder', data) + } + + MediaManager.prototype.execNavigationRequest = function(handler, data, element) + { + if (element === undefined) + element = this.$form + + if (this.navigationAjax !== null) { + try { + this.navigationAjax.abort() + } + catch (e) {} + this.releaseNavigationAjax() + } + + $.oc.stripeLoadIndicator.show() + this.navigationAjax = element.request(this.options.alias+'::' + handler, { + data: data + }).always(function() { + $.oc.stripeLoadIndicator.hide() + }) + .done(this.proxy(this.afterNavigate)) + .always(this.proxy(this.releaseNavigationAjax)) + } + + MediaManager.prototype.releaseNavigationAjax = function() { + this.navigationAjax = null + } + + MediaManager.prototype.navigateToItem = function($item) { + if (!$item.length || !$item.data('path').length) + return + + if ($item.data('item-type') == 'folder') { + if (!$item.data('clear-search')) + this.gotoFolder($item.data('path')) + else { + this.resetSearch() + this.gotoFolder($item.data('path'), true) + } + } + else if ($item.data('item-type') == 'file') { + // Trigger the Insert popup command if a file item + // was double clicked or Enter key was pressed. + this.$el.trigger('popupcommand', ['insert']) + } + } + + // + // Sidebar + // + + MediaManager.prototype.isPreviewSidebarVisible = function() { + return !this.$el.find('[data-control="preview-sidebar"]').hasClass('hide') + } + + MediaManager.prototype.toggleSidebar = function(ev) { + var isVisible = this.isPreviewSidebarVisible(), + $sidebar = this.$el.find('[data-control="preview-sidebar"]'), + $button = $(ev.target) + + if (!isVisible) { + $sidebar.removeClass('hide') + this.updateSidebarPreview() + $button.removeClass('sidebar-hidden') + } + else { + $sidebar.addClass('hide') + $button.addClass('sidebar-hidden') + } + + this.$form.request(this.options.alias+'::onSetSidebarVisible', { + data: { + visible: (isVisible ? 0 : 1) + } + }) + } + + MediaManager.prototype.updateSidebarMediaPreview = function(items) { + var previewPanel = this.sidebarPreviewElement, + previewContainer = previewPanel.querySelector('[data-control="media-preview-container"]'), + template = '' + + for (var i = 0, len = previewContainer.children.length; i < len; i++) { + previewContainer.removeChild(previewContainer.children[i]) + } + + // Single item selected + if (items.length == 1 && !items[0].hasAttribute('data-root')) { + var item = items[0], + documentType = item.getAttribute('data-document-type') + + switch (documentType) { + case 'audio' : + template = previewPanel.querySelector('[data-control="audio-template"]').innerHTML + break; + case 'video' : + template = previewPanel.querySelector('[data-control="video-template"]').innerHTML + break; + case 'image' : + template = previewPanel.querySelector('[data-control="image-template"]').innerHTML + break; + } + + previewContainer.innerHTML = template + .replace('{src}', item.getAttribute('data-public-url')) + .replace('{path}', item.getAttribute('data-path')) + .replace('{last-modified}', item.getAttribute('data-last-modified-ts')) + + if (documentType == 'image') + this.loadSidebarThumbnail() + } + // "Go up" is selected + else if (items.length == 1 && items[0].hasAttribute('data-root')) { + template = previewPanel.querySelector('[data-control="go-up"]').innerHTML + previewContainer.innerHTML = template + } + // No selection + else if (items.length == 0) { + template = previewPanel.querySelector('[data-control="no-selection-template"]').innerHTML + previewContainer.innerHTML = template + } + // Multiple selection + else { + template = previewPanel.querySelector('[data-control="multi-selection-template"]').innerHTML + previewContainer.innerHTML = template + } + } + + MediaManager.prototype.updateSidebarPreview = function(resetSidebar) { + if (!this.sidebarPreviewElement) + this.sidebarPreviewElement = this.$el.get(0).querySelector('[data-control="preview-sidebar"]') + + var items = resetSidebar === undefined ? this.$el.get(0).querySelectorAll('[data-type="media-item"].selected') : [], + previewPanel = this.sidebarPreviewElement + + // No items are selected + if (items.length == 0) { + this.sidebarPreviewElement.querySelector('[data-control="sidebar-labels"]').setAttribute('class', 'hide') + } + // One item is selected - display the details + else if (items.length == 1 && !items[0].hasAttribute('data-root')) { + this.sidebarPreviewElement.querySelector('[data-control="sidebar-labels"]').setAttribute('class', 'panel') + + var item = items[0], + lastModified = item.getAttribute('data-last-modified') + + previewPanel.querySelector('[data-label="size"]').textContent = item.getAttribute('data-size') + previewPanel.querySelector('[data-label="title"]').textContent = item.getAttribute('data-title') + previewPanel.querySelector('[data-label="last-modified"]').textContent = lastModified + previewPanel.querySelector('[data-label="public-url"]').setAttribute('href', item.getAttribute('data-public-url')) + + if (lastModified) + previewPanel.querySelector('[data-control="last-modified"]').setAttribute('class', '') + else + previewPanel.querySelector('[data-control="last-modified"]').setAttribute('class', 'hide') + + if (this.isSearchMode()) { + previewPanel.querySelector('[data-control="item-folder"]').setAttribute('class', '') + var folderNode = previewPanel.querySelector('[data-label="folder"]') + folderNode.textContent = item.getAttribute('data-folder') + folderNode.setAttribute('data-path', item.getAttribute('data-folder')) + } + else { + previewPanel.querySelector('[data-control="item-folder"]').setAttribute('class', 'hide') + } + } + // Multiple items are selected or "Go up" is selected + else { + this.sidebarPreviewElement.querySelector('[data-control="sidebar-labels"]').setAttribute('class', 'hide') + } + + this.updateSidebarMediaPreview(items) + } + + MediaManager.prototype.loadSidebarThumbnail = function() { + if (this.sidebarThumbnailAjax) { + try { + this.sidebarThumbnailAjax.abort() + } + catch (e) {} + this.sidebarThumbnailAjax = null + } + + var sidebarThumbnail = this.sidebarPreviewElement.querySelector('[data-control="sidebar-thumbnail"]') + if (!sidebarThumbnail) + return + + var data = { + path: sidebarThumbnail.getAttribute('data-path'), + lastModified: sidebarThumbnail.getAttribute('data-last-modified') + } + + this.sidebarThumbnailAjax = this.$form.request(this.options.alias+'::onGetSidebarThumbnail', { + data: data + }) + .done(this.proxy(this.replaceSidebarPlaceholder)) + .always(this.proxy(this.releaseSidebarThumbnailAjax)) + } + + MediaManager.prototype.replaceSidebarPlaceholder = function(response) { + if (!this.sidebarPreviewElement) + return + + var sidebarThumbnail = this.sidebarPreviewElement.querySelector('[data-control="sidebar-thumbnail"]') + if (!sidebarThumbnail) + return + + if (!response.markup) + return + + sidebarThumbnail.innerHTML = response.markup + sidebarThumbnail.removeAttribute('data-loading') + } + + MediaManager.prototype.releaseSidebarThumbnailAjax = function() { + this.sidebarThumbnailAjax = null + } + + // + // Thumbnails + // + + MediaManager.prototype.generateThumbnails = function() { + this.thumbnailQueue = [] + + var placeholders = this.itemListElement.querySelectorAll('[data-type="media-item"] div.image-placeholder') + for (var i = (placeholders.length-1); i >= 0; i--) + this.thumbnailQueue.push({ + id: placeholders[i].getAttribute('id'), + width: placeholders[i].getAttribute('data-width'), + height: placeholders[i].getAttribute('data-height'), + path: placeholders[i].getAttribute('data-path'), + lastModified: placeholders[i].getAttribute('data-last-modified') + }) + + this.handleThumbnailQueue() + } + + MediaManager.prototype.handleThumbnailQueue = function() { + var maxThumbnailQueueLength = 2, + maxThumbnailBatchLength = 3 + + if (this.activeThumbnailQueueLength >= maxThumbnailQueueLength) + return + + for (var i = this.activeThumbnailQueueLength; i < maxThumbnailQueueLength && this.thumbnailQueue.length > 0; i++) { + var batch = [] + + for (var j = 0; j < maxThumbnailBatchLength && this.thumbnailQueue.length > 0; j++) + batch.push(this.thumbnailQueue.pop()) + + this.activeThumbnailQueueLength++ + + this.handleThumbnailBatch(batch).always(this.proxy(this.placeholdersUpdated)) + } + } + + MediaManager.prototype.handleThumbnailBatch = function(batch) { + var data = { + batch: batch + } + + for (var i = 0, len = batch.length; i < len; i++) { + var placeholder = document.getElementById(batch[i].id) + if (placeholder) + placeholder.setAttribute('data-loading', 'true') + } + + var promise = this.$form.request(this.options.alias+'::onGenerateThumbnails', { + data: data + }) + + promise.done(this.proxy(this.replacePlaceholder)) + + return promise + } + + MediaManager.prototype.replacePlaceholder = function(response) { + if (!response.generatedThumbnails) + return + + for (var i = 0, len = response.generatedThumbnails.length; i < len; i++) { + var thumbnailInfo = response.generatedThumbnails[i] + + if (!thumbnailInfo.id || !thumbnailInfo.markup) + continue + + var node = document.getElementById(thumbnailInfo.id) + if (!node) + continue + + var placeholderContainer = node.parentNode + if (placeholderContainer) + placeholderContainer.innerHTML = thumbnailInfo.markup + } + } + + MediaManager.prototype.placeholdersUpdated = function() { + this.activeThumbnailQueueLength-- + + this.handleThumbnailQueue() + } + + // + // Drag-select + // + + MediaManager.prototype.getRelativePosition = function(element, pageX, pageY, startPosition) { + var absolutePosition = startPosition !== undefined ? startPosition : $.oc.foundation.element.absolutePosition(element, true) + + return { + x: (pageX - absolutePosition.left), // There is no horizontal scroll + y: (pageY - absolutePosition.top + this.scrollContentElement.scrollTop) + } + } + + MediaManager.prototype.createSelectionMarker = function() { + if (this.selectionMarker) + return + + this.selectionMarker = document.createElement('div') + this.selectionMarker.setAttribute('data-control', 'selection-marker') + + this.scrollContentElement.insertBefore(this.selectionMarker, this.scrollContentElement.firstChild) + } + + MediaManager.prototype.doObjectsCollide = function(aTop, aLeft, aWidth, aHeight, bTop, bLeft, bWidth, bHeight) { + return !( + ((aTop + aHeight) < (bTop)) || + (aTop > (bTop + bHeight)) || + ((aLeft + aWidth) < bLeft) || + (aLeft > (bLeft + bWidth)) + ) + } + + // + // Uploading + // + + MediaManager.prototype.initUploader = function() { + if (!this.itemListElement || this.options.readOnly) + return + + var uploaderOptions = { + clickable: this.$el.find('[data-control="upload"]').get(0), + url: this.options.url, + paramName: 'file_data', + timeout: 0, + headers: {}, + createImageThumbnails: false + // fallback: implement method that would set a flag that the uploader is not supported by the browser + } + + /* + * Add CSRF token to headers + */ + var token = $('meta[name="csrf-token"]').attr('content') + if (token) { + uploaderOptions.headers['X-CSRF-TOKEN'] = token + } + + this.dropzone = new Dropzone(this.$el.get(0), uploaderOptions) + this.dropzone.on('addedfile', this.proxy(this.uploadFileAdded)) + this.dropzone.on('totaluploadprogress', this.proxy(this.uploadUpdateTotalProgress)) + this.dropzone.on('queuecomplete', this.proxy(this.uploadQueueComplete)) + this.dropzone.on('sending', this.proxy(this.uploadSending)) + this.dropzone.on('error', this.proxy(this.uploadError)) + this.dropzone.on('success', this.proxy(this.uploadSuccess)) + } + + MediaManager.prototype.destroyUploader = function() { + if (!this.dropzone) + return + + this.dropzone.destroy() + this.dropzone = null + } + + MediaManager.prototype.uploadFileAdded = function() { + this.showUploadUi() + this.setUploadProgress(0) + + this.$el.find('[data-command="cancel-uploading"]').removeClass('hide') + this.$el.find('[data-command="close-uploader"]').addClass('hide') + } + + MediaManager.prototype.showUploadUi = function() { + this.$el.find('[data-control="upload-ui"]').removeClass('hide') + } + + MediaManager.prototype.hideUploadUi = function() { + this.$el.find('[data-control="upload-ui"]').addClass('hide') + } + + MediaManager.prototype.uploadUpdateTotalProgress = function(uploadProgress, totalBytes, totalBytesSent) { + this.setUploadProgress(uploadProgress) + + var fileNumberLabel = this.$el.get(0).querySelector('[data-label="file-number-and-progress"]'), + messageTemplate = fileNumberLabel.getAttribute('data-message-template'), + fileNumber = this.dropzone.getUploadingFiles().length + this.dropzone.getQueuedFiles().length + + // Don't confuse users with displaying 100% + // until the operation finishes. We consider the operation + // finished when the Dropzone's 'compete' event triggers - + // when the response is received from the server. + if (uploadProgress >= 100) { + uploadProgress = 99 + } + + fileNumberLabel.innerHTML = messageTemplate.replace(':number', fileNumber).replace(':percents', Math.round(uploadProgress) + '%') + } + + MediaManager.prototype.setUploadProgress = function(value) { + var progressBar = this.$el.get(0).querySelector('[data-control="upload-progress-bar"]') + + progressBar.setAttribute('style', 'width: ' + value + '%') + progressBar.setAttribute('class', 'progress-bar') + } + + MediaManager.prototype.uploadQueueComplete = function() { + this.$el.find('[data-command="cancel-uploading"]').addClass('hide') + this.$el.find('[data-command="close-uploader"]').removeClass('hide') + + this.refresh() + } + + MediaManager.prototype.uploadSending = function(file, xhr, formData) { + formData.append('path', this.$el.find('[data-type="current-folder"]').val()) + xhr.setRequestHeader('X-OCTOBER-REQUEST-HANDLER', this.options.uploadHandler) + } + + MediaManager.prototype.uploadCancelAll = function() { + this.dropzone.removeAllFiles(true) + this.hideUploadUi() + } + + MediaManager.prototype.updateUploadBar = function(templateName, classNames) { + var fileNumberLabel = this.$el.get(0).querySelector('[data-label="file-number-and-progress"]'), + successTemplate = fileNumberLabel.getAttribute('data-' + templateName + '-template'), + progressBar = this.$el.get(0).querySelector('[data-control="upload-progress-bar"]') + + fileNumberLabel.innerHTML = successTemplate; + progressBar.setAttribute('class', classNames) + } + + MediaManager.prototype.uploadSuccess = function() { + this.updateUploadBar('success', 'progress-bar progress-bar-success'); + } + + MediaManager.prototype.uploadError = function(file, message) { + this.updateUploadBar('error', 'progress-bar progress-bar-danger'); + + if (file.xhr.status === 413) { + message = 'Server rejected the file because it was too large, try increasing post_max_size'; + } + if (!message) { + message = 'Error uploading file' + } + + $.oc.alert(message) + } + + // + // Cropping images + // + + MediaManager.prototype.cropSelectedImage = function(callback) { + var selectedItems = this.getSelectedItems(true) + + if (selectedItems.length != 1) { + alert(this.options.selectSingleImage) + return + } + + if (selectedItems[0].getAttribute('data-document-type') !== 'image') { + alert(this.options.selectionNotImage) + return + } + + var path = selectedItems[0].getAttribute('data-path') + + new $.oc.mediaManager.imageCropPopup(path, { + alias: this.options.alias, + onDone: callback + }) + } + + MediaManager.prototype.onImageCropped = function(result) { + this.$el.trigger('popupcommand', ['insert-cropped', result]) + } + + // + // Search + // + + MediaManager.prototype.clearSearchTrackInputTimer = function() { + if (this.searchTrackInputTimer === null) + return + + clearTimeout(this.searchTrackInputTimer) + this.searchTrackInputTimer = null + } + + MediaManager.prototype.updateSearchResults = function() { + var $searchField = this.$el.find('[data-control="search"]'), + data = { + search: $searchField.val() + } + + this.execNavigationRequest('onSearch', data, $searchField) + } + + MediaManager.prototype.resetSearch = function() { + this.$el.find('[data-control="search"]').val('') + } + + MediaManager.prototype.onSearchChanged = function(ev) { + var value = ev.currentTarget.value + + if (this.lastSearchValue !== undefined && this.lastSearchValue == value) + return + + this.lastSearchValue = value + + this.clearSearchTrackInputTimer() + + this.searchTrackInputTimer = window.setTimeout(this.proxy(this.updateSearchResults), 300) + } + + // + // File and folder operations + // + + MediaManager.prototype.deleteItems = function() { + var items = this.$el.get(0).querySelectorAll('[data-type="media-item"].selected') + + if (!items.length) { + $.oc.alert(this.options.deleteEmpty) + return + } + + $.oc.confirm(this.options.deleteConfirm, this.proxy(this.deleteConfirmation)) + } + + MediaManager.prototype.deleteConfirmation = function(confirmed) { + if (!confirmed) + return + + var items = this.$el.get(0).querySelectorAll('[data-type="media-item"].selected'), + paths = [] + + for (var i=0, len=items.length; i 2 || Math.abs(deltaY) > 2)) { + // Start processing the selection only if the mouse was moved by + // at least 2 pixels. + this.createSelectionMarker() + + this.selectionMarker.setAttribute('class', '') + this.selectionStarted = true + $(document.body).addClass('no-select') + } + + if (this.selectionStarted) { + if (deltaX >= 0) { + this.selectionMarker.style.left = this.selectionStartPoint.x + 'px' + this.selectionMarker.style.width = deltaX + 'px' + } + else { + this.selectionMarker.style.left = relativePosition.x + 'px' + this.selectionMarker.style.width = Math.abs(deltaX) + 'px' + } + + if (deltaY >= 0) { + this.selectionMarker.style.height = deltaY + 'px' + this.selectionMarker.style.top = this.selectionStartPoint.y + 'px' + } + else { + this.selectionMarker.style.top = relativePosition.y + 'px' + this.selectionMarker.style.height = Math.abs(deltaY) + 'px' + } + } + } + + MediaManager.prototype.onSortingChanged = function(ev) { + var $target = $(ev.target), + data = { + path: this.$el.find('[data-type="current-folder"]').val() + } + + if ($target.data('sort') == 'by') { + data.sortBy = $target.val(); + } else if ($target.data('sort') == 'direction') { + data.sortDirection = $target.val() + } + + this.execNavigationRequest('onSetSorting', data) + } + + MediaManager.prototype.onKeyDown = function(ev) { + var eventHandled = false + + + switch (ev.key) { + case 'Enter': + var items = this.getSelectedItems(true, true) + if (items.length > 0) + this.navigateToItem($(items[0])) + + eventHandled = true + break; + case 'ArrowRight': + case 'ArrowDown': + this.selectRelative(true, ev.shiftKey) + eventHandled = true + break; + case 'ArrowLeft': + case 'ArrowUp': + this.selectRelative(false, ev.shiftKey) + eventHandled = true + break; + } + + if (eventHandled) { + ev.preventDefault() + ev.stopPropagation() + } + } + + // MEDIA MANAGER PLUGIN DEFINITION + // ============================ + + MediaManager.DEFAULTS = { + url: window.location, + uploadHandler: null, + alias: '', + deleteEmpty: 'Please select files to delete.', + deleteConfirm: 'Delete the selected file(s)?', + moveEmpty: 'Please select files to move.', + selectSingleImage: 'Please select a single image.', + selectionNotImage: 'The selected item is not an image.', + bottomToolbar: false, + cropAndInsertButton: false + } + + var old = $.fn.mediaManager + + $.fn.mediaManager = function (option) { + var args = Array.prototype.slice.call(arguments, 1), + result = undefined + + this.each(function () { + var $this = $(this) + var data = $this.data('oc.mediaManager') + var options = $.extend({}, MediaManager.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.mediaManager', (data = new MediaManager(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : this + } + + $.fn.mediaManager.Constructor = MediaManager + + // MEDIA MANAGER NO CONFLICT + // ================= + + $.fn.mediaManager.noConflict = function () { + $.fn.mediaManager = old + return this + } + + // MEDIA MANAGER DATA-API + // =============== + + $(document).on('render', function(){ + $('div[data-control=media-manager]').mediaManager() + }) + +}(window.jQuery); diff --git a/modules/backend/widgets/mediamanager/assets/js/mediamanager.popup.js b/modules/backend/widgets/mediamanager/assets/js/mediamanager.popup.js new file mode 100644 index 0000000..695d20e --- /dev/null +++ b/modules/backend/widgets/mediamanager/assets/js/mediamanager.popup.js @@ -0,0 +1,140 @@ +/* + * Media manager popup + */ ++function ($) { "use strict"; + + if ($.oc.mediaManager === undefined) + $.oc.mediaManager = {} + + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var MediaManagerPopup = function(options) { + this.$popupRootElement = null + + this.options = $.extend({}, MediaManagerPopup.DEFAULTS, options) + + Base.call(this) + + this.init() + this.show() + } + + MediaManagerPopup.prototype = Object.create(BaseProto) + MediaManagerPopup.prototype.constructor = MediaManagerPopup + + MediaManagerPopup.prototype.dispose = function() { + this.unregisterHandlers() + + this.$popupRootElement.remove() + this.$popupRootElement = null + this.$popupElement = null + + BaseProto.dispose.call(this) + } + + MediaManagerPopup.prototype.init = function() { + if (this.options.alias === undefined) + throw new Error('Media Manager popup option "alias" is not set.') + + this.$popupRootElement = $('
    ') + this.registerHandlers() + } + + MediaManagerPopup.prototype.registerHandlers = function() { + this.$popupRootElement.one('hide.oc.popup', this.proxy(this.onPopupHidden)) + this.$popupRootElement.one('shown.oc.popup', this.proxy(this.onPopupShown)) + } + + MediaManagerPopup.prototype.unregisterHandlers = function() { + this.$popupElement.off('popupcommand', this.proxy(this.onPopupCommand)) + this.$popupRootElement.off('popupcommand', this.proxy(this.onPopupCommand)) + } + + MediaManagerPopup.prototype.show = function() { + var data = { + bottomToolbar: this.options.bottomToolbar ? 1 : 0, + cropAndInsertButton: this.options.cropAndInsertButton ? 1 : 0 + } + + this.$popupRootElement.popup({ + extraData: data, + size: 'adaptive', + adaptiveHeight: true, + handler: this.options.alias + '::onLoadPopup' + }) + } + + MediaManagerPopup.prototype.hide = function() { + if (this.$popupElement) + this.$popupElement.trigger('close.oc.popup') + } + + MediaManagerPopup.prototype.getMediaManagerElement = function() { + return this.$popupElement.find('[data-control="media-manager"]') + } + + MediaManagerPopup.prototype.insertMedia = function() { + var items = this.getMediaManagerElement().mediaManager('getSelectedItems') + + if (this.options.onInsert !== undefined) + this.options.onInsert.call(this, items) + } + + MediaManagerPopup.prototype.insertCroppedImage = function(imageItem) { + if (this.options.onInsert !== undefined) + this.options.onInsert.call(this, [imageItem]) + } + + // EVENT HANDLERS + // ============================ + + MediaManagerPopup.prototype.onPopupHidden = function(event, element, popup) { + var mediaManager = this.getMediaManagerElement() + + mediaManager.mediaManager('dispose') + mediaManager.remove() + + // Release clickedElement reference inside redactor.js + // If we don't do it, the Media Manager popup DOM elements + // won't be removed from the memory. + $(document).trigger('mousedown') + + this.dispose() + + if (this.options.onClose !== undefined) + this.options.onClose.call(this) + } + + MediaManagerPopup.prototype.onPopupShown = function(event, element, popup) { + this.$popupElement = popup + this.$popupElement.on('popupcommand', this.proxy(this.onPopupCommand)) + + // Unfocus the Redactor field, otherwise all keyboard commands + // in the Media Manager popup translate to Redactor. + this.getMediaManagerElement().mediaManager('selectFirstItem') + } + + MediaManagerPopup.prototype.onPopupCommand = function(ev, command, param) { + switch (command) { + case 'insert' : + this.insertMedia() + break; + case 'insert-cropped' : + this.insertCroppedImage(param) + break; + } + + return false + } + + MediaManagerPopup.DEFAULTS = { + alias: undefined, + bottomToolbar: true, + cropAndInsertButton: false, + onInsert: undefined, + onClose: undefined + } + + $.oc.mediaManager.popup = MediaManagerPopup +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/assets/less/mediamanager.less b/modules/backend/widgets/mediamanager/assets/less/mediamanager.less new file mode 100644 index 0000000..285215d --- /dev/null +++ b/modules/backend/widgets/mediamanager/assets/less/mediamanager.less @@ -0,0 +1,704 @@ +@import "../../../../../backend/assets/less/core/boot.less"; + +@color-media-list-hover-bg: mix(white, @brand-accent, 13%); + +.media-selected-tiles() { + .icon-container { + background: @color-media-list-hover-bg !important; + border-color: #2581b8; + + i, p { + color: #ecf0f1; + } + } + + h4 { + color: #2581b8; + } +} + +.media-selected-list() { + background: @color-media-list-hover-bg !important; + + i, p.size { + color: #ecf0f1; + } + + h4 { + color: white; + } + + .icon-container { + border-right-color: @color-media-list-hover-bg !important; + } +} + +div[data-control="media-manager"] { + &:focus { + outline: none; + } + + .loading-indicator-pseudo-absolute(@size) { + background-image: url('../../../../../../modules/system/assets/ui/images/loader-transparent.svg'); + background-position: 50% 50%; + content: ' '; + .animation(spin 1s linear infinite); + + background-size: @size @size; + position: absolute; + width: @size; + height: @size; + top: 50%; + left: 50%; + margin-top: -@size/2; + margin-left: -@size/2; + } + + audio, video { + width: 100%; + } + + video { + background: #ecf0f1; + max-height: 225px; + } + + .media-player-fallback { + font-size: 13px; + color: #95a5a6; + background: #ecf0f1; + line-height: 180%; + + &.panel-embedded { + padding: 20px; + margin: -20px -20px 0 -20px; + } + } + + .icon-message() { + font-size: 12px; + margin: 10px; + line-height: 160%; + color: #bdc3c7; + } + + .empty-library { + padding: 20px; + text-align: center; + } + + p.thumbnail-error-message { + .icon-message(); + } + + .media-list { + padding: 0 0 0 20px; + margin: 0; + .user-select(none); + + li { + display: inline-block; + vertical-align: top; + margin: 0 20px 20px 0; + overflow: hidden; + cursor: pointer; + .border-radius(3px); + + &:focus { + outline: none; + } + + .icon-container { + display: table; + + i { + color: #95a5a6; + display: inline-block; + } + + div { + display: table-cell; + text-align: center; + vertical-align: middle; + } + } + + .icon-container.image { + > div.icon-wrapper { + display: none; + } + } + + h4 { + font-weight: 600; + font-size: 13px; + color: #2b3e50; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + line-height: 150%; + margin: 15px 0 5px 0; + padding-right: 0; + .transition(padding 0.1s); + + position: relative; + + a { + position: absolute; + right: 0; + top: 0; + font-size: 15px; + color: #2b3e50; + display: none; + + &:hover { + color: @link-color; + text-decoration: none; + } + } + } + + p.size { + font-size: 12px; + color: #95a5a6; + } + + .image-placeholder { + position: relative; + + i { + padding-top: 0; + padding-left: 2px; + } + + &[data-loading] { + i { + display: none; + } + } + + &[data-loading]:after { + .loading-indicator-pseudo-absolute(28px); + } + } + + i.icon-chain-broken { + padding: 0; + color: #bdc3c7; + } + + &[data-item-type=folder] i { + color: @color-media-list-hover-bg; + } + } + + &.list { + li { + height: 75px; + width: 260px; + border: 1px solid #ecf0f1; + background: #f6f8f9; + box-sizing: content-box; + } + + li .icon-container { + border-right: 1px solid #f6f8f9; + width: 75px; + height: 75px; + float: left; + + img { + max-height: 75px; + } + + i { + font-size: 35px; + } + + &.image { + border-right: 1px solid #ecf0f1!important; + } + + p.thumbnail-error-message { + display: none; + } + } + + .icon-wrapper { + width: 75px; + } + + li .info { + margin-left: 90px; + } + + li .image-placeholder { + width: 75px; + height: 75px; + } + + li[data-root] h4 { + margin-top: 27px; + } + + li.selected { + .media-selected-list(); + } + + h4 { + padding-right: 15px; + + a { + right: 15px; + } + } + } + + &.tiles { + li { + width: 167px; + margin-bottom: 25px; + } + + .icon-wrapper { + width: 167px; + } + + li .image-placeholder { + width: 165px; + height: 165px; + + &[data-loading]:after { + .loading-indicator-pseudo-absolute(55px); + } + } + + li .icon-container { + width: 165px; + height: 165px; + .border-radius(3px); + border: 1px solid #ecf0f1; + overflow: hidden; + background: #f6f8f9; + box-sizing: content-box; + + img { + max-height: 165px; + } + + i { + font-size: 55px; + } + + p { + font-family: @font-family-base; + } + } + + li.selected { + .media-selected-tiles(); + } + + i.icon-chain-broken { + margin-top: 47px; + } + + p.size { + margin-bottom: 0; + } + } + } + + [data-control="sidebar-labels"] { + word-wrap: break-word; + } + + .sidebar-group { + margin-bottom: 20px; + } + + .sidebar-image-placeholder-container { + display: table; + width: 100%; + } + + .sidebar-image-placeholder { + display: table-cell; + height: 225px; + position: relative; + vertical-align: middle; + text-align: center; + border-bottom: 1px solid #ecf0f1; + box-sizing: content-box; + + &[data-loading] { + background: #ecf0f1; + &:after { + .loading-indicator-pseudo-absolute(62px); + } + } + + i.icon-chain-broken, i.icon-crop, i.icon-asterisk, i.icon-level-up { + color: #bdc3c7; + font-size: 55px; + } + + &.no-border { + border-bottom: none; + } + + p { + .icon-message(); + margin-top: 25px; + } + + img { + max-width: 100%; + max-height: 225px; + } + } + + .list-container { + position: relative; + z-index: 100; + + .no-data { + font-size: 13px; + } + + p.no-data { + padding: 0 20px 20px 20px; + } + + li.no-data { + padding-top: 20px; + display: block !important; + width: 100% !important; + border: none !important; + background: transparent !important; + cursor: default !important; + } + + table.table.data { + tbody tr:not(.no-data):active td { + background: @color-list-hover-bg !important; + } + } + } + + [data-control="item-list"] { + position: relative; + display: table-cell; + } + + .control-scrollpad { + position: absolute; + left: 0; + top: 0; + + // Prevents erratic rendering issues when the height is + // sometimes calculated as 0 then repeatedly redrawn + min-height: 300px; + } + + .scroll-wrapper { + position: relative; + } + + table.table { + table-layout: fixed; + margin-bottom: 0; + white-space: nowrap; + + div.no-wrap-text { + overflow: hidden; + text-overflow: ellipsis; + } + + div.item-title { + position: relative; + padding-right: 0; + .transition(padding 0.1s); + + a { + position: absolute; + right: 0; + top: 0; + display: none; + } + } + + tr:hover div.item-title { + padding-right: 25px; + + a { + display: block; + } + } + + tr[data-item-type=folder] i.icon-folder { + color: @color-media-list-hover-bg; + } + + tr:focus { + outline: none; + } + } + + div[data-control="selection-marker"] { + position: absolute; + z-index: 250; + border: 1px dashed #95a5a6; + background: rgba(0,0,0,0.1); + } + + .upload-progress { + background: @body-bg; + padding: 0 20px; + + h5 { + margin: 0 0 10px 0; + font-size: 13px; + color: #2b3e50; + font-weight: 600; + + span { + display: inline-block; + margin-left: 10px; + color: #95a5a6; + font-size: 15px; + } + } + + .progress-controls { + padding-right: 30px; + position: relative; + + .controls { + position: absolute; + right: 0; + bottom: 0; + + a { + display: block; + position: relative; + top: 7px; + right: 3px; + color: #95a5a6; + font-size: 16px; + cursor: pointer!important; + + &:hover { + text-decoration: none; + color: @link-color; + } + } + } + } + } + + .dz-preview { + display: none; + } + + button[data-command="toggle-sidebar"] { + &.sidebar-hidden { + .transform( ~'rotate(180deg) translate(0, 0)' ); + } + } +} + +[data-control="media-manager-crop-tool"] { + .image_area { + position: absolute; + width: 100%; + height: 100%; + + overflow: auto; + + .jcrop-holder { + background-color: transparent!important; + } + } + + img { + cursor: crosshair; + display: block; + } + + &.has-rulers { + .ruler-container { + .layout-relative { + overflow: hidden; + } + + &.horizontal { + .layout-cell { + height: 20px; + } + + .layout-relative { + width: 100%; + } + } + + &.vertical { + width: 20px; + .layout-relative { + height: 100%; + } + } + } + + .ruler { + position: absolute; + height: 20px; + margin-left: -3px; + background: #555; + + ul { + margin: 0; + padding: 0; + white-space: nowrap; + font-size: 0; + } + + li { + margin: 0; + padding: 0 0 0 40px; + list-style: none; + display: inline-block; + width: 24px; + margin: 0px -10px 0px -14px; + .box-sizing(content-box); + text-align: left; + position: relative; + font-size: 10px; + line-height: 20px; + color: #ecf0f1; + font-family: Arial, sans-serif; + + &:before, &:after { + content: ' '; + position: absolute; + border-left: 1px solid #8e8e8e; + } + + &:before { + height: 20px; + top: 0; + left: -3px; + } + + &:after { + height: 3px; + bottom: 0; + left: 20px; + } + + &:first-child:after { + display: none; + } + } + } + + .ruler[data-control=v-ruler] { + .transform(~'rotateZ(90deg)'); + .transform-origin(~'left top'); + left: 23px; + top: -23px; + + & li:after { + top: 0; + left: auto; + } + } + + } +} + +body:not(.no-select) { + div[data-control="media-manager"] .media-list { + &.tiles { + li:hover { + .media-selected-tiles(); + } + + li:hover h4 { + padding-right: 20px !important; + } + } + + &.list { + li:hover { + .media-selected-list(); + } + + li:hover h4 { + padding-right: 35px !important; + } + } + + li { + &:hover h4 a { + display: block; + } + } + } +} + +@media (max-width: 1280px) { + div[data-control="media-manager"] { + .media-list { + &.list { + li { + width: 230px; + } + } + } + } +} + +@media (max-width: 1024px) { + div[data-control="media-manager"] { + .media-list { + &.list { + li { + display: block; + + width: auto; + } + } + } + } +} + +@media (max-width: @screen-sm) { + div[data-control="media-manager"] { + [data-control="preview-sidebar"], + [data-command="toggle-sidebar"] { + display: none!important; + } + + .media-list { + &.list { + padding: 0; + li { + .border-radius(0); + margin: 0; + border-right: none; + border-left: none; + border-bottom: none; + } + } + } + } +} + +@media (max-width: 480px) { + div[data-control="media-manager"] { + [data-control="left-sidebar"] { + display: none!important; + } + } +} diff --git a/modules/backend/widgets/mediamanager/partials/_body.htm b/modules/backend/widgets/mediamanager/partials/_body.htm new file mode 100644 index 0000000..3dd1b17 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_body.htm @@ -0,0 +1,70 @@ +
    + + makePartial('toolbar') ?> + + readOnly) ? $this->makePartial('upload-progress') : '' ?> + +
    +
    +
    +
    + makePartial('left-sidebar') ?> +
    +
    +
    + +
    + makePartial('folder-toolbar') ?> +
    +
    + +
    +
    +
    + +
    +
    +
    +
    + makePartial('item-list') ?> +
    +
    +
    +
    + +
    + + makePartial('right-sidebar') ?> +
    + +
    +
    + +
    + makePartial('bottom-toolbar') ?> +
    +
    +
    + +
    +
    +
    +
    +
    + + makePartial('new-folder-form') ?> +
    diff --git a/modules/backend/widgets/mediamanager/partials/_bottom-toolbar.htm b/modules/backend/widgets/mediamanager/partials/_bottom-toolbar.htm new file mode 100644 index 0000000..0d11400 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_bottom-toolbar.htm @@ -0,0 +1,30 @@ +
    +
    +
    + + + readOnly) : ?> + + + + +
    +
    +
    diff --git a/modules/backend/widgets/mediamanager/partials/_crop-tool-image-area.htm b/modules/backend/widgets/mediamanager/partials/_crop-tool-image-area.htm new file mode 100644 index 0000000..97cb2d4 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_crop-tool-image-area.htm @@ -0,0 +1,33 @@ +
    + data-image-width="" + data-image-height="" + +> +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_crop-toolbar.htm b/modules/backend/widgets/mediamanager/partials/_crop-toolbar.htm new file mode 100644 index 0000000..02749b1 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_crop-toolbar.htm @@ -0,0 +1,41 @@ + trans('backend::lang.media.selection_mode_normal'), + Backend\Widgets\MediaManager::SELECTION_MODE_FIXED_RATIO => trans('backend::lang.media.selection_mode_fixed_ratio'), + Backend\Widgets\MediaManager::SELECTION_MODE_FIXED_SIZE => trans('backend::lang.media.selection_mode_fixed_size') + ]; + + $sizeDisabledAttr = $currentSelectionMode == Backend\Widgets\MediaManager::SELECTION_MODE_NORMAL ? 'disabled="disabled"' : null; +?> + +
    +
    +
    + + +
    + + + +
    + + + + + + /> + + + /> + + + +
    +
    +
    \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_filters.htm b/modules/backend/widgets/mediamanager/partials/_filters.htm new file mode 100644 index 0000000..ded01d7 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_filters.htm @@ -0,0 +1,39 @@ +

    + + \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_folder-path.htm b/modules/backend/widgets/mediamanager/partials/_folder-path.htm new file mode 100644 index 0000000..b3ea297 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_folder-path.htm @@ -0,0 +1,13 @@ +
      +
    • + + + $path): ?> + +
    • + + + +
    • + +
    \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_folder-toolbar.htm b/modules/backend/widgets/mediamanager/partials/_folder-toolbar.htm new file mode 100644 index 0000000..204939c --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_folder-toolbar.htm @@ -0,0 +1,16 @@ +
    +
    +
    +
    + makePartial('folder-path') ?> +
    +
    +
    + +
    +
    +
    \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_generic-list.htm b/modules/backend/widgets/mediamanager/partials/_generic-list.htm new file mode 100644 index 0000000..e0a0901 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_generic-list.htm @@ -0,0 +1,62 @@ +getId('item-list'); +?> + +
      + 0 || !$isRootFolder): ?> + +
    • +
      +
      +
      +
      +

      +
      +
    • + + + + getFileType(); + ?> +
    • + makePartial('item-icon', ['itemType'=>$itemType, 'item'=>$item]) ?> + +
      +

      + path)) ?> + + readOnly) : ?> + + +

      +

      sizeToString()) ?>

      +
      +
    • + + + + +
    • + +
    • + +
    diff --git a/modules/backend/widgets/mediamanager/partials/_image-crop-popup-body.htm b/modules/backend/widgets/mediamanager/partials/_image-crop-popup-body.htm new file mode 100644 index 0000000..9771480 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_image-crop-popup-body.htm @@ -0,0 +1,43 @@ +'layout', 'onsubmit'=>'return false']) ?> +
    + makePartial('crop-toolbar') ?> +
    +
    + makePartial('crop-tool-image-area') ?> +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    + + + + + + + + + + + + + + makePartial('resize-image-form') ?> + \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_item-icon.htm b/modules/backend/widgets/mediamanager/partials/_item-icon.htm new file mode 100644 index 0000000..758c62f --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_item-icon.htm @@ -0,0 +1,26 @@ +
    +
    + + thumbnailExists($thumbnailParams, $item->path, $item->lastModified); + ?> +
    + +
    +
    +
    + + makePartial('thumbnail-image', [ + 'isError' => $this->thumbnailIsError($thumbnailPath), + 'imageUrl' => $this->getThumbnailImageUrl($thumbnailPath) + ]) ?> + +
    + +
    \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_item-list.htm b/modules/backend/widgets/mediamanager/partials/_item-list.htm new file mode 100644 index 0000000..f799f4f --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_item-list.htm @@ -0,0 +1,17 @@ +
    + + +
    + +
    + + + + makePartial('list-grid') ?> + + makePartial('list-list') ?> + + makePartial('list-tiles') ?> + +
    +
    \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_item-sidebar-preview.htm b/modules/backend/widgets/mediamanager/partials/_item-sidebar-preview.htm new file mode 100644 index 0000000..44b0ebe --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_item-sidebar-preview.htm @@ -0,0 +1,46 @@ +
    + + + + + + + + + + + + diff --git a/modules/backend/widgets/mediamanager/partials/_left-sidebar.htm b/modules/backend/widgets/mediamanager/partials/_left-sidebar.htm new file mode 100644 index 0000000..ff4979d --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_left-sidebar.htm @@ -0,0 +1,5 @@ +
    + makePartial('filters') ?> +
    + +makePartial('sorting') ?> \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_list-grid.htm b/modules/backend/widgets/mediamanager/partials/_list-grid.htm new file mode 100644 index 0000000..c727324 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_list-grid.htm @@ -0,0 +1,68 @@ +getId('item-list'); +?> + + + + + + + + 0 || !$isRootFolder): ?> + + + + + + + + + getFileType(); + ?> + + + + + + + + + + + +
    ..
    +
    + path)) ?> + + readOnly) : ?> + + +
    +
    sizeToString()) ?>lastModifiedAsString()) ?> +
    path)) ?>
    +
    + + +

    + +

    + diff --git a/modules/backend/widgets/mediamanager/partials/_list-list.htm b/modules/backend/widgets/mediamanager/partials/_list-list.htm new file mode 100644 index 0000000..8173507 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_list-list.htm @@ -0,0 +1 @@ +makePartial('generic-list', ['listClass'=>'list']) ?> \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_list-tiles.htm b/modules/backend/widgets/mediamanager/partials/_list-tiles.htm new file mode 100644 index 0000000..0cf9e13 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_list-tiles.htm @@ -0,0 +1 @@ +makePartial('generic-list', ['listClass'=>'tiles']) ?> \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_move-form.htm b/modules/backend/widgets/mediamanager/partials/_move-form.htm new file mode 100644 index 0000000..ab4c68e --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_move-form.htm @@ -0,0 +1,35 @@ + + + + + \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_new-folder-form.htm b/modules/backend/widgets/mediamanager/partials/_new-folder-form.htm new file mode 100644 index 0000000..9589143 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_new-folder-form.htm @@ -0,0 +1,32 @@ + diff --git a/modules/backend/widgets/mediamanager/partials/_popup-body.htm b/modules/backend/widgets/mediamanager/partials/_popup-body.htm new file mode 100644 index 0000000..e083db5 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_popup-body.htm @@ -0,0 +1,3 @@ +'layout', 'onsubmit'=>'return false']) ?> + render() ?> + \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_rename-form.htm b/modules/backend/widgets/mediamanager/partials/_rename-form.htm new file mode 100644 index 0000000..61dae77 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_rename-form.htm @@ -0,0 +1,56 @@ +getEventHandler('onApplyName'), [ + 'success' => "\$el.trigger('close.oc.popup'); \$('#".$listId."').trigger('mediarefresh');", + 'data-stripe-load-indicator' => 1, + 'id' => 'media-rename-popup-form' +]) ?> + + + + + \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_resize-image-form.htm b/modules/backend/widgets/mediamanager/partials/_resize-image-form.htm new file mode 100644 index 0000000..ca31d94 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_resize-image-form.htm @@ -0,0 +1,31 @@ + diff --git a/modules/backend/widgets/mediamanager/partials/_right-sidebar.htm b/modules/backend/widgets/mediamanager/partials/_right-sidebar.htm new file mode 100644 index 0000000..e429f76 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_right-sidebar.htm @@ -0,0 +1,26 @@ +makePartial('item-sidebar-preview') ?> + +
    + +

    + + + + + + + + + + + + + + + + + + + +
    +
    \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_sorting.htm b/modules/backend/widgets/mediamanager/partials/_sorting.htm new file mode 100644 index 0000000..d68b3f5 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_sorting.htm @@ -0,0 +1,46 @@ + trans('backend::lang.media.title'), + System\Classes\MediaLibrary::SORT_BY_SIZE => trans('backend::lang.media.size'), + System\Classes\MediaLibrary::SORT_BY_MODIFIED => trans('backend::lang.media.last_modified') + ]; + + $sortDirections = [ + System\Classes\MediaLibrary::SORT_DIRECTION_ASC => trans('backend::lang.media.direction_asc'), + System\Classes\MediaLibrary::SORT_DIRECTION_DESC => trans('backend::lang.media.direction_desc') + ]; +?> + + + + diff --git a/modules/backend/widgets/mediamanager/partials/_thumbnail-image.htm b/modules/backend/widgets/mediamanager/partials/_thumbnail-image.htm new file mode 100644 index 0000000..6e32df9 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_thumbnail-image.htm @@ -0,0 +1,6 @@ + + + + +

    + \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_toolbar.htm b/modules/backend/widgets/mediamanager/partials/_toolbar.htm new file mode 100644 index 0000000..265fb79 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_toolbar.htm @@ -0,0 +1,42 @@ +
    +
    +
    +
    + readOnly) : ?> +
    + + +
    + + + + + readOnly) : ?> +
    + + +
    + + +
    + makePartial('view-mode-buttons') ?> +
    +
    +
    +
    +
    + +
    +
    +
    +
    diff --git a/modules/backend/widgets/mediamanager/partials/_upload-progress.htm b/modules/backend/widgets/mediamanager/partials/_upload-progress.htm new file mode 100644 index 0000000..1922a92 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_upload-progress.htm @@ -0,0 +1,24 @@ +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    + + +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/modules/backend/widgets/mediamanager/partials/_view-mode-buttons.htm b/modules/backend/widgets/mediamanager/partials/_view-mode-buttons.htm new file mode 100644 index 0000000..2826b33 --- /dev/null +++ b/modules/backend/widgets/mediamanager/partials/_view-mode-buttons.htm @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/modules/backend/widgets/reportcontainer/assets/css/reportcontainer.css b/modules/backend/widgets/reportcontainer/assets/css/reportcontainer.css new file mode 100644 index 0000000..ce6c3f8 --- /dev/null +++ b/modules/backend/widgets/reportcontainer/assets/css/reportcontainer.css @@ -0,0 +1,199 @@ +.report-container { + margin-bottom: 15px; +} +.report-container > ul { + list-style: none; + padding: 0; + margin-bottom: 15px; +} +.report-container > ul .item { + float: left; + overflow: hidden; +} +.report-container > ul .item .content { + margin: 5px; + position: relative; +} +.report-container > ul .item .content .drag-handle { + width: 14px; + height: 14px; + position: absolute; + left: 15px; + top: 13px; + opacity: 0; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.2s; + transition: opacity 0.2s; + font-size: 14px; + cursor: move; +} +.report-container > ul .item .content .drag-handle:before { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + content: "\f0c9"; + color: #b6b6b6; +} +.report-container > ul .item .content .widget-control { + position: absolute; + display: none; + width: 15px; + height: 15px; + color: #b6b6b6; + opacity: 1; + filter: alpha(opacity=100); + outline: none; +} +.report-container > ul .item .content .widget-control:hover { + color: #0181b9; +} +.report-container > ul .item .content .report-widget h3 { + padding-left: 0; + -webkit-transition: padding 0.2s; + transition: padding 0.2s; +} +.report-container > ul .item .content .edit-widget { + text-indent: -10000em; + right: 15px; + top: 15px; +} +.report-container > ul .item .content .edit-widget:before { + position: absolute; + display: block; + text-indent: 0; + left: 0; + width: 15px; + height: 15px; + font-size: 16px; +} +.report-container > ul .item .content .edit-widget:hover:before { + text-decoration: none; +} +.report-container > ul .item .content .edit-widget.inspector-open { + display: block; +} +.report-container > ul .item .content .close { + right: 10px; + top: 15px; +} +.report-container > ul .item:hover .widget-control, +.report-container > ul .item.dragged .widget-control { + display: block; +} +.report-container > ul .item:hover .report-widget h3, +.report-container > ul .item.dragged .report-widget h3 { + padding-left: 18px; +} +.report-container > ul .item:hover .drag-handle, +.report-container > ul .item.dragged .drag-handle { + opacity: 1; + filter: alpha(opacity=100); +} +.report-container > ul .item.width-1 { + width: 8.33%; +} +.report-container > ul .item.width-2 { + width: 16.66%; +} +.report-container > ul .item.width-3 { + width: 24.99%; +} +.report-container > ul .item.width-4 { + width: 33.32%; +} +.report-container > ul .item.width-5 { + width: 41.65%; +} +.report-container > ul .item.width-6 { + width: 49.98%; +} +.report-container > ul .item.width-7 { + width: 58.31%; +} +.report-container > ul .item.width-8 { + width: 66.64%; +} +.report-container > ul .item.width-9 { + width: 74.97%; +} +.report-container > ul .item.width-10 { + width: 83.3%; +} +.report-container > ul .item.width-11 { + width: 91.63%; +} +.report-container > ul .item.width-12 { + width: 100%; +} +.report-container > ul .item.dragged { + -webkit-transition-duration: 0s !important; + -moz-transition-duration: 0s !important; + transition-duration: 0s !important; + -webkit-transform: translate3d(0, 0, 0) !important; + transform: translate3d(0, 0, 0) !important; + position: absolute; + opacity: 0.5; + z-index: 2000; +} +.report-container > ul .item.placeholder { + display: none; +} +.report-container > ul .item.separator { + width: 100%!important; +} +.report-container > ul.add-delete .item .content .edit-widget { + right: 30px; +} +.report-container > ul.wrapped .item { + width: 100% !important; +} +.report-container .manage-widgets { + display: inline-block; + color: #bcc3c7; + padding: 10px 15px; + font-size: 14px; + font-weight: 400; + border: 1px dashed #bcc3c7; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + margin-left: 5px; +} +.report-container .manage-widgets i { + margin-right: 5px; +} +.report-container .manage-widgets:hover { + text-decoration: none; + background-color: #0181b9; + color: white; + border: 1px solid #0181b9; +} +.report-container .dropdown.open .manage-widgets { + text-decoration: none; + background-color: #0181b9; + color: white; + border: 1px solid #0181b9; +} +.report-container.isotope, +.report-container.isotope .isotope-item { + -webkit-transition-duration: 0.8s; + -moz-transition-duration: 0.8s; + transition-duration: 0.8s; +} +.report-container.isotope { + -webkit-transition-property: height, width; + -moz-transition-property: height, width; + transition-property: height, width; +} +.report-container.isotope .isotope-item { + -webkit-transition-property: -webkit-transform, opacity; + -moz-transition-property: -moz-transform, opacity; + transition-property: transform, opacity; +} +@media (max-width: 768px) { + .report-container ul .item { + width: 100%!important; + } +} diff --git a/modules/backend/widgets/reportcontainer/assets/js/reportcontainer.js b/modules/backend/widgets/reportcontainer/assets/js/reportcontainer.js new file mode 100644 index 0000000..26fb910 --- /dev/null +++ b/modules/backend/widgets/reportcontainer/assets/js/reportcontainer.js @@ -0,0 +1,202 @@ +/* + * Report container widget + * + * Data attributes: + * - data-control="report-container" - enables the report container plugin + * + * JavaScript API: + * $('#container').reportContainer() + * + * Dependancies: + * - Isotope (isotope.js) + */ ++function ($) { "use strict"; + + // REPORTCONTAINER CLASS DEFINITION + // ============================ + + var ReportContainer = function(element, options) { + this.options = options + this.$el= $(element) + this.$form = this.$el.closest('form') + this.$toolbar = $('[data-container-toolbar]', this.$form) + this.alias = $('[data-container-alias]', this.$form).val() + + this.init(); + } + + ReportContainer.DEFAULTS = { + breakpoint: 768, + columns: 12 + } + + ReportContainer.prototype.init = function() { + var self = this + + this.$el.isotope({ + itemSelector: '.item', + resizable: false + }) + + $(window).resize($.proxy(this.updateWidth, this)) + this.updateWidth() + + if (!Modernizr.touchevents) { + this.$el.sortable({ + vertical: false, + handle: '.drag-handle', + onDrop: function($item, container, _super) { + $item.removeClass('dragged') + $('body').removeClass('dragging') + + self.updateSeparators() + self.redraw() + self.postSortOrders() + } + }) + } + + this.$el.on('hidden.oc.inspector', '[data-inspectable]', function() { + var values = $('[data-inspector-values]', this).val(), + parsedValues = JSON.parse(values), + li = $(this).closest('li').get(0) + + self.$form.request(self.alias + '::onUpdateWidget', { + data: { + 'fields': values, + 'alias': $('[data-widget-alias]', $(this).closest('div.content')).val() + }, + success: function(data) { + this.success(data).done(function() { + li.className = li.className.replace(/width\-[0-9]+/g, '') + $(li).addClass('width-'+parsedValues['ocWidgetWidth']) + $(li).toggleClass('new-line', parsedValues['ocWidgetNewRow'] == 1) + + self.updateSeparators() + self.redraw() + }) + } + }) + }) + + this.$el.on('click', '.content > button.close', function() { + var $btn = $(this) + $.oc.confirm($.oc.lang.get('alert.widget_remove_confirm'), function() { + self.$form.request(self.alias + '::onRemoveWidget', { + data: { + 'alias': $('[data-widget-alias]', $btn.closest('div.content')).val() + } + }) + + $btn.closest('li').remove() + self.redraw() + self.setSortOrders() + }) + }) + + $(window).on('oc.reportWidgetAdded', function() { + self.redraw() + self.setSortOrders() + }) + + $(window).on('oc.reportWidgetRefresh', function() { + self.redraw() + }) + + window.setTimeout(function() { + self.updateWidth() + self.redraw() + }, 200) + + this.setSortOrders() + } + + ReportContainer.prototype.updateWidth = function() { + var width = this.$el.width(), + wrapped = width <= this.options.breakpoint, + columnWidth = wrapped ? width : width / this.options.columns + + this.$el.isotope({ + masonry: { columnWidth: columnWidth } + }) + + this.$el.toggleClass('wrapped', wrapped) + } + + ReportContainer.prototype.redraw = function() { + this.$el + .isotope('reloadItems') + .isotope({ sortBy: 'original-order' }) + + var $items = $('li.item', this.$el) + + $items.css({'width': '', 'height': ''}) + + $('> .dropdown', this.$toolbar).toggleClass('dropup', !!$items.length) + } + + ReportContainer.prototype.setSortOrders = function() { + this.sortOrders = [] + + var self = this + $('[data-widget-order]', this.$el).each(function() { + self.sortOrders.push($(this).val()) + }) + } + + ReportContainer.prototype.postSortOrders = function() { + var aliases = [], + self = this + + $('[data-widget-alias]', this.$el).each(function() { + aliases.push($(this).val()) + }) + + this.$form.request(self.alias + '::onSetWidgetOrders', { + data: { + 'aliases': aliases.join(','), + 'orders': self.sortOrders.join(',') + } + }) + } + + ReportContainer.prototype.updateSeparators = function() { + $('li.item.separator', this.$el).remove() + $('li.item.new-line', this.$el).each(function() { + $(this).before('
  • ') + }) + } + + // REPORTCONTAINER PLUGIN DEFINITION + // ============================ + + var old = $.fn.reportContainer + + $.fn.reportContainer = function(option) { + return this.each(function() { + var $this = $(this) + var data = $this.data('oc.reportContainer') + var options = $.extend({}, ReportContainer.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.reportContainer', (data = new ReportContainer(this, options))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.reportContainer.Constructor = ReportContainer + + // REPORTCONTAINER NO CONFLICT + // ================= + + $.fn.reportContainer.noConflict = function() { + $.fn.reportContainer = old + return this + } + + // REPORTCONTAINER DATA-API + // =============== + + $(document).render(function() { + $('[data-control="report-container"]').reportContainer() + }) + +}(window.jQuery); diff --git a/modules/backend/widgets/reportcontainer/assets/less/reportcontainer.less b/modules/backend/widgets/reportcontainer/assets/less/reportcontainer.less new file mode 100644 index 0000000..19d0031 --- /dev/null +++ b/modules/backend/widgets/reportcontainer/assets/less/reportcontainer.less @@ -0,0 +1,198 @@ +@import "../../../../assets/less/core/boot.less"; + +.report-container { + margin-bottom: 15px; + > ul { + list-style: none; + padding: 0; + margin-bottom: 15px; + + .item { + float: left; + overflow: hidden; + display: block; + + .content { + margin: 5px; + position: relative; + + .drag-handle { + width: 14px; + height: 14px; + position: absolute; + left: 15px; + top: 13px; + .opacity(0); + .transition(opacity 0.2s); + font-size: 14px; + cursor: move; + + &:before { + .icon(@bars); + color: @color-report-widget-control-inactive; + } + } + + .widget-control { + position: absolute; + display: none; + width: 15px; + height: 15px; + color: @color-report-widget-control-inactive; + .opacity(1); + outline: none; + + &:hover { + color: @link-color; + } + } + + .report-widget h3 { + padding-left: 0; + .transition(padding 0.2s); + } + + .edit-widget { + text-indent: -10000em; + right: 15px; + top: 15px; + + &:before { + position: absolute; + display: block; + text-indent: 0; + left: 0; + width: 15px; + height: 15px; + font-size: 16px; + } + + &:hover:before { + text-decoration: none; + } + + &.inspector-open { + display: block; + } + } + + .close { + right: 10px; + top: 15px; + } + } + + &:hover, &.dragged { + .widget-control { + display: block; + } + + .report-widget h3 { + padding-left: 18px; + } + + .drag-handle { + .opacity(1); + } + } + + &.width-1 {width: 8.33%;} + &.width-2 {width: 16.66%;} + &.width-3 {width: 24.99%;} + &.width-4 {width: 33.32%;} + &.width-5 {width: 41.65%;} + &.width-6 {width: 49.98%;} + &.width-7 {width: 58.31%;} + &.width-8 {width: 66.64%;} + &.width-9 {width: 74.97%;} + &.width-10 {width: 83.3%;} + &.width-11 {width: 91.63%;} + &.width-12 {width: 100%;} + + &.dragged { + .transition-duration(0s) !important; + .translate3d(0, 0, 0) !important; + position: absolute; + opacity: 0.5; + z-index: 2000; + } + + &.placeholder { + display: none; + } + + &.separator { + width: 100% !important; + } + } + + &.add-delete .item .content .edit-widget { + right: 30px; + } + + &.wrapped { + .item { + width: 100% !important; + } + } + } + + .manage-widgets { + display: inline-block; + color: #bcc3c7; + padding: 10px 15px; + font-size: 14px; + font-weight: 400; + border: 1px dashed #bcc3c7; + .border-radius(@border-radius-base); + margin-left: 5px; + + i { + margin-right: 5px; + } + + &:hover { + text-decoration: none; + background-color: @link-color; + color: white; + border: 1px solid @link-color; + } + } + + .dropdown.open .manage-widgets { + text-decoration: none; + background-color: @link-color; + color: white; + border: 1px solid @link-color; + } + + // + // Isotope CSS3 transitions + // + + &.isotope, + &.isotope .isotope-item { + .transition-duration(0.8s); + } + + &.isotope { + .transition-property(height, width); + } + + &.isotope .isotope-item { + -webkit-transition-property: -webkit-transform, opacity; + -moz-transition-property: -moz-transform, opacity; + transition-property: transform, opacity; + } +} + +@media (max-width: @screen-sm) { + .report-container { + ul .item { + // The breakpoint should be defined in the CSS and JS, + // otherwise some widgets can't calculate the width properly, + // as the JS is applied too late. + width: 100% !important; + } + } +} diff --git a/modules/backend/widgets/reportcontainer/assets/vendor/isotope/jquery.isotope.js b/modules/backend/widgets/reportcontainer/assets/vendor/isotope/jquery.isotope.js new file mode 100644 index 0000000..d487d42 --- /dev/null +++ b/modules/backend/widgets/reportcontainer/assets/vendor/isotope/jquery.isotope.js @@ -0,0 +1,3562 @@ +/*! + * Isotope PACKAGED v3.0.6 + * + * Licensed GPLv3 for open source use + * or Isotope Commercial License for commercial use + * + * https://isotope.metafizzy.co + * Copyright 2010-2018 Metafizzy + */ + +/** + * Bridget makes jQuery widgets + * v2.0.1 + * MIT license + */ + +/* jshint browser: true, strict: true, undef: true, unused: true */ + +( function( window, factory ) { + // universal module definition + /*jshint strict: false */ /* globals define, module, require */ + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) { + return factory( window, jQuery ); + }); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory( + window, + require('jquery') + ); + } else { + // browser global + window.jQueryBridget = factory( + window, + window.jQuery + ); + } + +}( window, function factory( window, jQuery ) { +'use strict'; + +// ----- utils ----- // + +var arraySlice = Array.prototype.slice; + +// helper function for logging errors +// $.error breaks jQuery chaining +var console = window.console; +var logError = typeof console == 'undefined' ? function() {} : + function( message ) { + console.error( message ); + }; + +// ----- jQueryBridget ----- // + +function jQueryBridget( namespace, PluginClass, $ ) { + $ = $ || jQuery || window.jQuery; + if ( !$ ) { + return; + } + + // add option method -> $().plugin('option', {...}) + if ( !PluginClass.prototype.option ) { + // option setter + PluginClass.prototype.option = function( opts ) { + // bail out if not an object + if ( !$.isPlainObject( opts ) ){ + return; + } + this.options = $.extend( true, this.options, opts ); + }; + } + + // make jQuery plugin + $.fn[ namespace ] = function( arg0 /*, arg1 */ ) { + if ( typeof arg0 == 'string' ) { + // method call $().plugin( 'methodName', { options } ) + // shift arguments by 1 + var args = arraySlice.call( arguments, 1 ); + return methodCall( this, arg0, args ); + } + // just $().plugin({ options }) + plainCall( this, arg0 ); + return this; + }; + + // $().plugin('methodName') + function methodCall( $elems, methodName, args ) { + var returnValue; + var pluginMethodStr = '$().' + namespace + '("' + methodName + '")'; + + $elems.each( function( i, elem ) { + // get instance + var instance = $.data( elem, namespace ); + if ( !instance ) { + logError( namespace + ' not initialized. Cannot call methods, i.e. ' + + pluginMethodStr ); + return; + } + + var method = instance[ methodName ]; + if ( !method || methodName.charAt(0) == '_' ) { + logError( pluginMethodStr + ' is not a valid method' ); + return; + } + + // apply method, get return value + var value = method.apply( instance, args ); + // set return value if value is returned, use only first value + returnValue = returnValue === undefined ? value : returnValue; + }); + + return returnValue !== undefined ? returnValue : $elems; + } + + function plainCall( $elems, options ) { + $elems.each( function( i, elem ) { + var instance = $.data( elem, namespace ); + if ( instance ) { + // set options & init + instance.option( options ); + instance._init(); + } else { + // initialize new instance + instance = new PluginClass( elem, options ); + $.data( elem, namespace, instance ); + } + }); + } + + updateJQuery( $ ); + +} + +// ----- updateJQuery ----- // + +// set $.bridget for v1 backwards compatibility +function updateJQuery( $ ) { + if ( !$ || ( $ && $.bridget ) ) { + return; + } + $.bridget = jQueryBridget; +} + +updateJQuery( jQuery || window.jQuery ); + +// ----- ----- // + +return jQueryBridget; + +})); + +/** + * EvEmitter v1.1.0 + * Lil' event emitter + * MIT License + */ + +/* jshint unused: true, undef: true, strict: true */ + +( function( global, factory ) { + // universal module definition + /* jshint strict: false */ /* globals define, module, window */ + if ( typeof define == 'function' && define.amd ) { + // AMD - RequireJS + define( 'ev-emitter/ev-emitter',factory ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS - Browserify, Webpack + module.exports = factory(); + } else { + // Browser globals + global.EvEmitter = factory(); + } + +}( typeof window != 'undefined' ? window : this, function() { + + + +function EvEmitter() {} + +var proto = EvEmitter.prototype; + +proto.on = function( eventName, listener ) { + if ( !eventName || !listener ) { + return; + } + // set events hash + var events = this._events = this._events || {}; + // set listeners array + var listeners = events[ eventName ] = events[ eventName ] || []; + // only add once + if ( listeners.indexOf( listener ) == -1 ) { + listeners.push( listener ); + } + + return this; +}; + +proto.once = function( eventName, listener ) { + if ( !eventName || !listener ) { + return; + } + // add event + this.on( eventName, listener ); + // set once flag + // set onceEvents hash + var onceEvents = this._onceEvents = this._onceEvents || {}; + // set onceListeners object + var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; + // set flag + onceListeners[ listener ] = true; + + return this; +}; + +proto.off = function( eventName, listener ) { + var listeners = this._events && this._events[ eventName ]; + if ( !listeners || !listeners.length ) { + return; + } + var index = listeners.indexOf( listener ); + if ( index != -1 ) { + listeners.splice( index, 1 ); + } + + return this; +}; + +proto.emitEvent = function( eventName, args ) { + var listeners = this._events && this._events[ eventName ]; + if ( !listeners || !listeners.length ) { + return; + } + // copy over to avoid interference if .off() in listener + listeners = listeners.slice(0); + args = args || []; + // once stuff + var onceListeners = this._onceEvents && this._onceEvents[ eventName ]; + + for ( var i=0; i < listeners.length; i++ ) { + var listener = listeners[i] + var isOnce = onceListeners && onceListeners[ listener ]; + if ( isOnce ) { + // remove listener + // remove before trigger to prevent recursion + this.off( eventName, listener ); + // unset once flag + delete onceListeners[ listener ]; + } + // trigger listener + listener.apply( this, args ); + } + + return this; +}; + +proto.allOff = function() { + delete this._events; + delete this._onceEvents; +}; + +return EvEmitter; + +})); + +/*! + * getSize v2.0.3 + * measure size of elements + * MIT license + */ + +/* jshint browser: true, strict: true, undef: true, unused: true */ +/* globals console: false */ + +( function( window, factory ) { + /* jshint strict: false */ /* globals define, module */ + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'get-size/get-size',factory ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory(); + } else { + // browser global + window.getSize = factory(); + } + +})( window, function factory() { +'use strict'; + +// -------------------------- helpers -------------------------- // + +// get a number from a string, not a percentage +function getStyleSize( value ) { + var num = parseFloat( value ); + // not a percent like '100%', and a number + var isValid = value.indexOf('%') == -1 && !isNaN( num ); + return isValid && num; +} + +function noop() {} + +var logError = typeof console == 'undefined' ? noop : + function( message ) { + console.error( message ); + }; + +// -------------------------- measurements -------------------------- // + +var measurements = [ + 'paddingLeft', + 'paddingRight', + 'paddingTop', + 'paddingBottom', + 'marginLeft', + 'marginRight', + 'marginTop', + 'marginBottom', + 'borderLeftWidth', + 'borderRightWidth', + 'borderTopWidth', + 'borderBottomWidth' +]; + +var measurementsLength = measurements.length; + +function getZeroSize() { + var size = { + width: 0, + height: 0, + innerWidth: 0, + innerHeight: 0, + outerWidth: 0, + outerHeight: 0 + }; + for ( var i=0; i < measurementsLength; i++ ) { + var measurement = measurements[i]; + size[ measurement ] = 0; + } + return size; +} + +// -------------------------- getStyle -------------------------- // + +/** + * getStyle, get style of element, check for Firefox bug + * https://bugzilla.mozilla.org/show_bug.cgi?id=548397 + */ +function getStyle( elem ) { + var style = getComputedStyle( elem ); + if ( !style ) { + logError( 'Style returned ' + style + + '. Are you running this code in a hidden iframe on Firefox? ' + + 'See https://bit.ly/getsizebug1' ); + } + return style; +} + +// -------------------------- setup -------------------------- // + +var isSetup = false; + +var isBoxSizeOuter; + +/** + * setup + * check isBoxSizerOuter + * do on first getSize() rather than on page load for Firefox bug + */ +function setup() { + // setup once + if ( isSetup ) { + return; + } + isSetup = true; + + // -------------------------- box sizing -------------------------- // + + /** + * Chrome & Safari measure the outer-width on style.width on border-box elems + * IE11 & Firefox<29 measures the inner-width + */ + var div = document.createElement('div'); + div.style.width = '200px'; + div.style.padding = '1px 2px 3px 4px'; + div.style.borderStyle = 'solid'; + div.style.borderWidth = '1px 2px 3px 4px'; + div.style.boxSizing = 'border-box'; + + var body = document.body || document.documentElement; + body.appendChild( div ); + var style = getStyle( div ); + // round value for browser zoom. desandro/masonry#928 + isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200; + getSize.isBoxSizeOuter = isBoxSizeOuter; + + body.removeChild( div ); +} + +// -------------------------- getSize -------------------------- // + +function getSize( elem ) { + setup(); + + // use querySeletor if elem is string + if ( typeof elem == 'string' ) { + elem = document.querySelector( elem ); + } + + // do not proceed on non-objects + if ( !elem || typeof elem != 'object' || !elem.nodeType ) { + return; + } + + var style = getStyle( elem ); + + // if hidden, everything is 0 + if ( style.display == 'none' ) { + return getZeroSize(); + } + + var size = {}; + size.width = elem.offsetWidth; + size.height = elem.offsetHeight; + + var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box'; + + // get all measurements + for ( var i=0; i < measurementsLength; i++ ) { + var measurement = measurements[i]; + var value = style[ measurement ]; + var num = parseFloat( value ); + // any 'auto', 'medium' value will be 0 + size[ measurement ] = !isNaN( num ) ? num : 0; + } + + var paddingWidth = size.paddingLeft + size.paddingRight; + var paddingHeight = size.paddingTop + size.paddingBottom; + var marginWidth = size.marginLeft + size.marginRight; + var marginHeight = size.marginTop + size.marginBottom; + var borderWidth = size.borderLeftWidth + size.borderRightWidth; + var borderHeight = size.borderTopWidth + size.borderBottomWidth; + + var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter; + + // overwrite width and height if we can get it from style + var styleWidth = getStyleSize( style.width ); + if ( styleWidth !== false ) { + size.width = styleWidth + + // add padding and border unless it's already including it + ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth ); + } + + var styleHeight = getStyleSize( style.height ); + if ( styleHeight !== false ) { + size.height = styleHeight + + // add padding and border unless it's already including it + ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight ); + } + + size.innerWidth = size.width - ( paddingWidth + borderWidth ); + size.innerHeight = size.height - ( paddingHeight + borderHeight ); + + size.outerWidth = size.width + marginWidth; + size.outerHeight = size.height + marginHeight; + + return size; +} + +return getSize; + +}); + +/** + * matchesSelector v2.0.2 + * matchesSelector( element, '.selector' ) + * MIT license + */ + +/*jshint browser: true, strict: true, undef: true, unused: true */ + +( function( window, factory ) { + /*global define: false, module: false */ + 'use strict'; + // universal module definition + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'desandro-matches-selector/matches-selector',factory ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory(); + } else { + // browser global + window.matchesSelector = factory(); + } + +}( window, function factory() { + 'use strict'; + + var matchesMethod = ( function() { + var ElemProto = window.Element.prototype; + // check for the standard method name first + if ( ElemProto.matches ) { + return 'matches'; + } + // check un-prefixed + if ( ElemProto.matchesSelector ) { + return 'matchesSelector'; + } + // check vendor prefixes + var prefixes = [ 'webkit', 'moz', 'ms', 'o' ]; + + for ( var i=0; i < prefixes.length; i++ ) { + var prefix = prefixes[i]; + var method = prefix + 'MatchesSelector'; + if ( ElemProto[ method ] ) { + return method; + } + } + })(); + + return function matchesSelector( elem, selector ) { + return elem[ matchesMethod ]( selector ); + }; + +})); + +/** + * Fizzy UI utils v2.0.7 + * MIT license + */ + +/*jshint browser: true, undef: true, unused: true, strict: true */ + +( function( window, factory ) { + // universal module definition + /*jshint strict: false */ /*globals define, module, require */ + + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'fizzy-ui-utils/utils',[ + 'desandro-matches-selector/matches-selector' + ], function( matchesSelector ) { + return factory( window, matchesSelector ); + }); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory( + window, + require('desandro-matches-selector') + ); + } else { + // browser global + window.fizzyUIUtils = factory( + window, + window.matchesSelector + ); + } + +}( window, function factory( window, matchesSelector ) { + + + +var utils = {}; + +// ----- extend ----- // + +// extends objects +utils.extend = function( a, b ) { + for ( var prop in b ) { + a[ prop ] = b[ prop ]; + } + return a; +}; + +// ----- modulo ----- // + +utils.modulo = function( num, div ) { + return ( ( num % div ) + div ) % div; +}; + +// ----- makeArray ----- // + +var arraySlice = Array.prototype.slice; + +// turn element or nodeList into an array +utils.makeArray = function( obj ) { + if ( Array.isArray( obj ) ) { + // use object if already an array + return obj; + } + // return empty array if undefined or null. #6 + if ( obj === null || obj === undefined ) { + return []; + } + + var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; + if ( isArrayLike ) { + // convert nodeList to array + return arraySlice.call( obj ); + } + + // array of single index + return [ obj ]; +}; + +// ----- removeFrom ----- // + +utils.removeFrom = function( ary, obj ) { + var index = ary.indexOf( obj ); + if ( index != -1 ) { + ary.splice( index, 1 ); + } +}; + +// ----- getParent ----- // + +utils.getParent = function( elem, selector ) { + while ( elem.parentNode && elem != document.body ) { + elem = elem.parentNode; + if ( matchesSelector( elem, selector ) ) { + return elem; + } + } +}; + +// ----- getQueryElement ----- // + +// use element as selector string +utils.getQueryElement = function( elem ) { + if ( typeof elem == 'string' ) { + return document.querySelector( elem ); + } + return elem; +}; + +// ----- handleEvent ----- // + +// enable .ontype to trigger from .addEventListener( elem, 'type' ) +utils.handleEvent = function( event ) { + var method = 'on' + event.type; + if ( this[ method ] ) { + this[ method ]( event ); + } +}; + +// ----- filterFindElements ----- // + +utils.filterFindElements = function( elems, selector ) { + // make array of elems + elems = utils.makeArray( elems ); + var ffElems = []; + + elems.forEach( function( elem ) { + // check that elem is an actual element + if ( !( elem instanceof HTMLElement ) ) { + return; + } + // add elem if no selector + if ( !selector ) { + ffElems.push( elem ); + return; + } + // filter & find items if we have a selector + // filter + if ( matchesSelector( elem, selector ) ) { + ffElems.push( elem ); + } + // find children + var childElems = elem.querySelectorAll( selector ); + // concat childElems to filterFound array + for ( var i=0; i < childElems.length; i++ ) { + ffElems.push( childElems[i] ); + } + }); + + return ffElems; +}; + +// ----- debounceMethod ----- // + +utils.debounceMethod = function( _class, methodName, threshold ) { + threshold = threshold || 100; + // original method + var method = _class.prototype[ methodName ]; + var timeoutName = methodName + 'Timeout'; + + _class.prototype[ methodName ] = function() { + var timeout = this[ timeoutName ]; + clearTimeout( timeout ); + + var args = arguments; + var _this = this; + this[ timeoutName ] = setTimeout( function() { + method.apply( _this, args ); + delete _this[ timeoutName ]; + }, threshold ); + }; +}; + +// ----- docReady ----- // + +utils.docReady = function( callback ) { + var readyState = document.readyState; + if ( readyState == 'complete' || readyState == 'interactive' ) { + // do async to allow for other scripts to run. metafizzy/flickity#441 + setTimeout( callback ); + } else { + document.addEventListener( 'DOMContentLoaded', callback ); + } +}; + +// ----- htmlInit ----- // + +// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ +utils.toDashed = function( str ) { + return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) { + return $1 + '-' + $2; + }).toLowerCase(); +}; + +var console = window.console; +/** + * allow user to initialize classes via [data-namespace] or .js-namespace class + * htmlInit( Widget, 'widgetName' ) + * options are parsed from data-namespace-options + */ +utils.htmlInit = function( WidgetClass, namespace ) { + utils.docReady( function() { + var dashedNamespace = utils.toDashed( namespace ); + var dataAttr = 'data-' + dashedNamespace; + var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' ); + var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace ); + var elems = utils.makeArray( dataAttrElems ) + .concat( utils.makeArray( jsDashElems ) ); + var dataOptionsAttr = dataAttr + '-options'; + var jQuery = window.jQuery; + + elems.forEach( function( elem ) { + var attr = elem.getAttribute( dataAttr ) || + elem.getAttribute( dataOptionsAttr ); + var options; + try { + options = attr && JSON.parse( attr ); + } catch ( error ) { + // log error, do not initialize + if ( console ) { + console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className + + ': ' + error ); + } + return; + } + // initialize + var instance = new WidgetClass( elem, options ); + // make available via $().data('namespace') + if ( jQuery ) { + jQuery.data( elem, namespace, instance ); + } + }); + + }); +}; + +// ----- ----- // + +return utils; + +})); + +/** + * Outlayer Item + */ + +( function( window, factory ) { + // universal module definition + /* jshint strict: false */ /* globals define, module, require */ + if ( typeof define == 'function' && define.amd ) { + // AMD - RequireJS + define( 'outlayer/item',[ + 'ev-emitter/ev-emitter', + 'get-size/get-size' + ], + factory + ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS - Browserify, Webpack + module.exports = factory( + require('ev-emitter'), + require('get-size') + ); + } else { + // browser global + window.Outlayer = {}; + window.Outlayer.Item = factory( + window.EvEmitter, + window.getSize + ); + } + +}( window, function factory( EvEmitter, getSize ) { +'use strict'; + +// ----- helpers ----- // + +function isEmptyObj( obj ) { + for ( var prop in obj ) { + return false; + } + prop = null; + return true; +} + +// -------------------------- CSS3 support -------------------------- // + + +var docElemStyle = document.documentElement.style; + +var transitionProperty = typeof docElemStyle.transition == 'string' ? + 'transition' : 'WebkitTransition'; +var transformProperty = typeof docElemStyle.transform == 'string' ? + 'transform' : 'WebkitTransform'; + +var transitionEndEvent = { + WebkitTransition: 'webkitTransitionEnd', + transition: 'transitionend' +}[ transitionProperty ]; + +// cache all vendor properties that could have vendor prefix +var vendorProperties = { + transform: transformProperty, + transition: transitionProperty, + transitionDuration: transitionProperty + 'Duration', + transitionProperty: transitionProperty + 'Property', + transitionDelay: transitionProperty + 'Delay' +}; + +// -------------------------- Item -------------------------- // + +function Item( element, layout ) { + if ( !element ) { + return; + } + + this.element = element; + // parent layout class, i.e. Masonry, Isotope, or Packery + this.layout = layout; + this.position = { + x: 0, + y: 0 + }; + + this._create(); +} + +// inherit EvEmitter +var proto = Item.prototype = Object.create( EvEmitter.prototype ); +proto.constructor = Item; + +proto._create = function() { + // transition objects + this._transn = { + ingProperties: {}, + clean: {}, + onEnd: {} + }; + + this.css({ + position: 'absolute' + }); +}; + +// trigger specified handler for event type +proto.handleEvent = function( event ) { + var method = 'on' + event.type; + if ( this[ method ] ) { + this[ method ]( event ); + } +}; + +proto.getSize = function() { + this.size = getSize( this.element ); +}; + +/** + * apply CSS styles to element + * @param {Object} style + */ +proto.css = function( style ) { + var elemStyle = this.element.style; + + for ( var prop in style ) { + // use vendor property if available + var supportedProp = vendorProperties[ prop ] || prop; + elemStyle[ supportedProp ] = style[ prop ]; + } +}; + + // measure position, and sets it +proto.getPosition = function() { + var style = getComputedStyle( this.element ); + var isOriginLeft = this.layout._getOption('originLeft'); + var isOriginTop = this.layout._getOption('originTop'); + var xValue = style[ isOriginLeft ? 'left' : 'right' ]; + var yValue = style[ isOriginTop ? 'top' : 'bottom' ]; + var x = parseFloat( xValue ); + var y = parseFloat( yValue ); + // convert percent to pixels + var layoutSize = this.layout.size; + if ( xValue.indexOf('%') != -1 ) { + x = ( x / 100 ) * layoutSize.width; + } + if ( yValue.indexOf('%') != -1 ) { + y = ( y / 100 ) * layoutSize.height; + } + // clean up 'auto' or other non-integer values + x = isNaN( x ) ? 0 : x; + y = isNaN( y ) ? 0 : y; + // remove padding from measurement + x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight; + y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom; + + this.position.x = x; + this.position.y = y; +}; + +// set settled position, apply padding +proto.layoutPosition = function() { + var layoutSize = this.layout.size; + var style = {}; + var isOriginLeft = this.layout._getOption('originLeft'); + var isOriginTop = this.layout._getOption('originTop'); + + // x + var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight'; + var xProperty = isOriginLeft ? 'left' : 'right'; + var xResetProperty = isOriginLeft ? 'right' : 'left'; + + var x = this.position.x + layoutSize[ xPadding ]; + // set in percentage or pixels + style[ xProperty ] = this.getXValue( x ); + // reset other property + style[ xResetProperty ] = ''; + + // y + var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom'; + var yProperty = isOriginTop ? 'top' : 'bottom'; + var yResetProperty = isOriginTop ? 'bottom' : 'top'; + + var y = this.position.y + layoutSize[ yPadding ]; + // set in percentage or pixels + style[ yProperty ] = this.getYValue( y ); + // reset other property + style[ yResetProperty ] = ''; + + this.css( style ); + this.emitEvent( 'layout', [ this ] ); +}; + +proto.getXValue = function( x ) { + var isHorizontal = this.layout._getOption('horizontal'); + return this.layout.options.percentPosition && !isHorizontal ? + ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px'; +}; + +proto.getYValue = function( y ) { + var isHorizontal = this.layout._getOption('horizontal'); + return this.layout.options.percentPosition && isHorizontal ? + ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px'; +}; + +proto._transitionTo = function( x, y ) { + this.getPosition(); + // get current x & y from top/left + var curX = this.position.x; + var curY = this.position.y; + + var didNotMove = x == this.position.x && y == this.position.y; + + // save end position + this.setPosition( x, y ); + + // if did not move and not transitioning, just go to layout + if ( didNotMove && !this.isTransitioning ) { + this.layoutPosition(); + return; + } + + var transX = x - curX; + var transY = y - curY; + var transitionStyle = {}; + transitionStyle.transform = this.getTranslate( transX, transY ); + + this.transition({ + to: transitionStyle, + onTransitionEnd: { + transform: this.layoutPosition + }, + isCleaning: true + }); +}; + +proto.getTranslate = function( x, y ) { + // flip cooridinates if origin on right or bottom + var isOriginLeft = this.layout._getOption('originLeft'); + var isOriginTop = this.layout._getOption('originTop'); + x = isOriginLeft ? x : -x; + y = isOriginTop ? y : -y; + return 'translate3d(' + x + 'px, ' + y + 'px, 0)'; +}; + +// non transition + transform support +proto.goTo = function( x, y ) { + this.setPosition( x, y ); + this.layoutPosition(); +}; + +proto.moveTo = proto._transitionTo; + +proto.setPosition = function( x, y ) { + this.position.x = parseFloat( x ); + this.position.y = parseFloat( y ); +}; + +// ----- transition ----- // + +/** + * @param {Object} style - CSS + * @param {Function} onTransitionEnd + */ + +// non transition, just trigger callback +proto._nonTransition = function( args ) { + this.css( args.to ); + if ( args.isCleaning ) { + this._removeStyles( args.to ); + } + for ( var prop in args.onTransitionEnd ) { + args.onTransitionEnd[ prop ].call( this ); + } +}; + +/** + * proper transition + * @param {Object} args - arguments + * @param {Object} to - style to transition to + * @param {Object} from - style to start transition from + * @param {Boolean} isCleaning - removes transition styles after transition + * @param {Function} onTransitionEnd - callback + */ +proto.transition = function( args ) { + // redirect to nonTransition if no transition duration + if ( !parseFloat( this.layout.options.transitionDuration ) ) { + this._nonTransition( args ); + return; + } + + var _transition = this._transn; + // keep track of onTransitionEnd callback by css property + for ( var prop in args.onTransitionEnd ) { + _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ]; + } + // keep track of properties that are transitioning + for ( prop in args.to ) { + _transition.ingProperties[ prop ] = true; + // keep track of properties to clean up when transition is done + if ( args.isCleaning ) { + _transition.clean[ prop ] = true; + } + } + + // set from styles + if ( args.from ) { + this.css( args.from ); + // force redraw. http://blog.alexmaccaw.com/css-transitions + var h = this.element.offsetHeight; + // hack for JSHint to hush about unused var + h = null; + } + // enable transition + this.enableTransition( args.to ); + // set styles that are transitioning + this.css( args.to ); + + this.isTransitioning = true; + +}; + +// dash before all cap letters, including first for +// WebkitTransform => -webkit-transform +function toDashedAll( str ) { + return str.replace( /([A-Z])/g, function( $1 ) { + return '-' + $1.toLowerCase(); + }); +} + +var transitionProps = 'opacity,' + toDashedAll( transformProperty ); + +proto.enableTransition = function(/* style */) { + // HACK changing transitionProperty during a transition + // will cause transition to jump + if ( this.isTransitioning ) { + return; + } + + // make `transition: foo, bar, baz` from style object + // HACK un-comment this when enableTransition can work + // while a transition is happening + // var transitionValues = []; + // for ( var prop in style ) { + // // dash-ify camelCased properties like WebkitTransition + // prop = vendorProperties[ prop ] || prop; + // transitionValues.push( toDashedAll( prop ) ); + // } + // munge number to millisecond, to match stagger + var duration = this.layout.options.transitionDuration; + duration = typeof duration == 'number' ? duration + 'ms' : duration; + // enable transition styles + this.css({ + transitionProperty: transitionProps, + transitionDuration: duration, + transitionDelay: this.staggerDelay || 0 + }); + // listen for transition end event + this.element.addEventListener( transitionEndEvent, this, false ); +}; + +// ----- events ----- // + +proto.onwebkitTransitionEnd = function( event ) { + this.ontransitionend( event ); +}; + +proto.onotransitionend = function( event ) { + this.ontransitionend( event ); +}; + +// properties that I munge to make my life easier +var dashedVendorProperties = { + '-webkit-transform': 'transform' +}; + +proto.ontransitionend = function( event ) { + // disregard bubbled events from children + if ( event.target !== this.element ) { + return; + } + var _transition = this._transn; + // get property name of transitioned property, convert to prefix-free + var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName; + + // remove property that has completed transitioning + delete _transition.ingProperties[ propertyName ]; + // check if any properties are still transitioning + if ( isEmptyObj( _transition.ingProperties ) ) { + // all properties have completed transitioning + this.disableTransition(); + } + // clean style + if ( propertyName in _transition.clean ) { + // clean up style + this.element.style[ event.propertyName ] = ''; + delete _transition.clean[ propertyName ]; + } + // trigger onTransitionEnd callback + if ( propertyName in _transition.onEnd ) { + var onTransitionEnd = _transition.onEnd[ propertyName ]; + onTransitionEnd.call( this ); + delete _transition.onEnd[ propertyName ]; + } + + this.emitEvent( 'transitionEnd', [ this ] ); +}; + +proto.disableTransition = function() { + this.removeTransitionStyles(); + this.element.removeEventListener( transitionEndEvent, this, false ); + this.isTransitioning = false; +}; + +/** + * removes style property from element + * @param {Object} style +**/ +proto._removeStyles = function( style ) { + // clean up transition styles + var cleanStyle = {}; + for ( var prop in style ) { + cleanStyle[ prop ] = ''; + } + this.css( cleanStyle ); +}; + +var cleanTransitionStyle = { + transitionProperty: '', + transitionDuration: '', + transitionDelay: '' +}; + +proto.removeTransitionStyles = function() { + // remove transition + this.css( cleanTransitionStyle ); +}; + +// ----- stagger ----- // + +proto.stagger = function( delay ) { + delay = isNaN( delay ) ? 0 : delay; + this.staggerDelay = delay + 'ms'; +}; + +// ----- show/hide/remove ----- // + +// remove element from DOM +proto.removeElem = function() { + this.element.parentNode.removeChild( this.element ); + // remove display: none + this.css({ display: '' }); + this.emitEvent( 'remove', [ this ] ); +}; + +proto.remove = function() { + // just remove element if no transition support or no transition + if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) { + this.removeElem(); + return; + } + + // start transition + this.once( 'transitionEnd', function() { + this.removeElem(); + }); + this.hide(); +}; + +proto.reveal = function() { + delete this.isHidden; + // remove display: none + this.css({ display: '' }); + + var options = this.layout.options; + + var onTransitionEnd = {}; + var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle'); + onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd; + + this.transition({ + from: options.hiddenStyle, + to: options.visibleStyle, + isCleaning: true, + onTransitionEnd: onTransitionEnd + }); +}; + +proto.onRevealTransitionEnd = function() { + // check if still visible + // during transition, item may have been hidden + if ( !this.isHidden ) { + this.emitEvent('reveal'); + } +}; + +/** + * get style property use for hide/reveal transition end + * @param {String} styleProperty - hiddenStyle/visibleStyle + * @returns {String} + */ +proto.getHideRevealTransitionEndProperty = function( styleProperty ) { + var optionStyle = this.layout.options[ styleProperty ]; + // use opacity + if ( optionStyle.opacity ) { + return 'opacity'; + } + // get first property + for ( var prop in optionStyle ) { + return prop; + } +}; + +proto.hide = function() { + // set flag + this.isHidden = true; + // remove display: none + this.css({ display: '' }); + + var options = this.layout.options; + + var onTransitionEnd = {}; + var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle'); + onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd; + + this.transition({ + from: options.visibleStyle, + to: options.hiddenStyle, + // keep hidden stuff hidden + isCleaning: true, + onTransitionEnd: onTransitionEnd + }); +}; + +proto.onHideTransitionEnd = function() { + // check if still hidden + // during transition, item may have been un-hidden + if ( this.isHidden ) { + this.css({ display: 'none' }); + this.emitEvent('hide'); + } +}; + +proto.destroy = function() { + this.css({ + position: '', + left: '', + right: '', + top: '', + bottom: '', + transition: '', + transform: '' + }); +}; + +return Item; + +})); + +/*! + * Outlayer v2.1.1 + * the brains and guts of a layout library + * MIT license + */ + +( function( window, factory ) { + 'use strict'; + // universal module definition + /* jshint strict: false */ /* globals define, module, require */ + if ( typeof define == 'function' && define.amd ) { + // AMD - RequireJS + define( 'outlayer/outlayer',[ + 'ev-emitter/ev-emitter', + 'get-size/get-size', + 'fizzy-ui-utils/utils', + './item' + ], + function( EvEmitter, getSize, utils, Item ) { + return factory( window, EvEmitter, getSize, utils, Item); + } + ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS - Browserify, Webpack + module.exports = factory( + window, + require('ev-emitter'), + require('get-size'), + require('fizzy-ui-utils'), + require('./item') + ); + } else { + // browser global + window.Outlayer = factory( + window, + window.EvEmitter, + window.getSize, + window.fizzyUIUtils, + window.Outlayer.Item + ); + } + +}( window, function factory( window, EvEmitter, getSize, utils, Item ) { +'use strict'; + +// ----- vars ----- // + +var console = window.console; +var jQuery = window.jQuery; +var noop = function() {}; + +// -------------------------- Outlayer -------------------------- // + +// globally unique identifiers +var GUID = 0; +// internal store of all Outlayer intances +var instances = {}; + + +/** + * @param {Element, String} element + * @param {Object} options + * @constructor + */ +function Outlayer( element, options ) { + var queryElement = utils.getQueryElement( element ); + if ( !queryElement ) { + if ( console ) { + console.error( 'Bad element for ' + this.constructor.namespace + + ': ' + ( queryElement || element ) ); + } + return; + } + this.element = queryElement; + // add jQuery + if ( jQuery ) { + this.$element = jQuery( this.element ); + } + + // options + this.options = utils.extend( {}, this.constructor.defaults ); + this.option( options ); + + // add id for Outlayer.getFromElement + var id = ++GUID; + this.element.outlayerGUID = id; // expando + instances[ id ] = this; // associate via id + + // kick it off + this._create(); + + var isInitLayout = this._getOption('initLayout'); + if ( isInitLayout ) { + this.layout(); + } +} + +// settings are for internal use only +Outlayer.namespace = 'outlayer'; +Outlayer.Item = Item; + +// default options +Outlayer.defaults = { + containerStyle: { + position: 'relative' + }, + initLayout: true, + originLeft: true, + originTop: true, + resize: true, + resizeContainer: true, + // item options + transitionDuration: '0.4s', + hiddenStyle: { + opacity: 0, + transform: 'scale(0.001)' + }, + visibleStyle: { + opacity: 1, + transform: 'scale(1)' + } +}; + +var proto = Outlayer.prototype; +// inherit EvEmitter +utils.extend( proto, EvEmitter.prototype ); + +/** + * set options + * @param {Object} opts + */ +proto.option = function( opts ) { + utils.extend( this.options, opts ); +}; + +/** + * get backwards compatible option value, check old name + */ +proto._getOption = function( option ) { + var oldOption = this.constructor.compatOptions[ option ]; + return oldOption && this.options[ oldOption ] !== undefined ? + this.options[ oldOption ] : this.options[ option ]; +}; + +Outlayer.compatOptions = { + // currentName: oldName + initLayout: 'isInitLayout', + horizontal: 'isHorizontal', + layoutInstant: 'isLayoutInstant', + originLeft: 'isOriginLeft', + originTop: 'isOriginTop', + resize: 'isResizeBound', + resizeContainer: 'isResizingContainer' +}; + +proto._create = function() { + // get items from children + this.reloadItems(); + // elements that affect layout, but are not laid out + this.stamps = []; + this.stamp( this.options.stamp ); + // set container style + utils.extend( this.element.style, this.options.containerStyle ); + + // bind resize method + var canBindResize = this._getOption('resize'); + if ( canBindResize ) { + this.bindResize(); + } +}; + +// goes through all children again and gets bricks in proper order +proto.reloadItems = function() { + // collection of item elements + this.items = this._itemize( this.element.children ); +}; + + +/** + * turn elements into Outlayer.Items to be used in layout + * @param {Array or NodeList or HTMLElement} elems + * @returns {Array} items - collection of new Outlayer Items + */ +proto._itemize = function( elems ) { + + var itemElems = this._filterFindItemElements( elems ); + var Item = this.constructor.Item; + + // create new Outlayer Items for collection + var items = []; + for ( var i=0; i < itemElems.length; i++ ) { + var elem = itemElems[i]; + var item = new Item( elem, this ); + items.push( item ); + } + + return items; +}; + +/** + * get item elements to be used in layout + * @param {Array or NodeList or HTMLElement} elems + * @returns {Array} items - item elements + */ +proto._filterFindItemElements = function( elems ) { + return utils.filterFindElements( elems, this.options.itemSelector ); +}; + +/** + * getter method for getting item elements + * @returns {Array} elems - collection of item elements + */ +proto.getItemElements = function() { + return this.items.map( function( item ) { + return item.element; + }); +}; + +// ----- init & layout ----- // + +/** + * lays out all items + */ +proto.layout = function() { + this._resetLayout(); + this._manageStamps(); + + // don't animate first layout + var layoutInstant = this._getOption('layoutInstant'); + var isInstant = layoutInstant !== undefined ? + layoutInstant : !this._isLayoutInited; + this.layoutItems( this.items, isInstant ); + + // flag for initalized + this._isLayoutInited = true; +}; + +// _init is alias for layout +proto._init = proto.layout; + +/** + * logic before any new layout + */ +proto._resetLayout = function() { + this.getSize(); +}; + + +proto.getSize = function() { + this.size = getSize( this.element ); +}; + +/** + * get measurement from option, for columnWidth, rowHeight, gutter + * if option is String -> get element from selector string, & get size of element + * if option is Element -> get size of element + * else use option as a number + * + * @param {String} measurement + * @param {String} size - width or height + * @private + */ +proto._getMeasurement = function( measurement, size ) { + var option = this.options[ measurement ]; + var elem; + if ( !option ) { + // default to 0 + this[ measurement ] = 0; + } else { + // use option as an element + if ( typeof option == 'string' ) { + elem = this.element.querySelector( option ); + } else if ( option instanceof HTMLElement ) { + elem = option; + } + // use size of element, if element + this[ measurement ] = elem ? getSize( elem )[ size ] : option; + } +}; + +/** + * layout a collection of item elements + * @api public + */ +proto.layoutItems = function( items, isInstant ) { + items = this._getItemsForLayout( items ); + + this._layoutItems( items, isInstant ); + + this._postLayout(); +}; + +/** + * get the items to be laid out + * you may want to skip over some items + * @param {Array} items + * @returns {Array} items + */ +proto._getItemsForLayout = function( items ) { + return items.filter( function( item ) { + return !item.isIgnored; + }); +}; + +/** + * layout items + * @param {Array} items + * @param {Boolean} isInstant + */ +proto._layoutItems = function( items, isInstant ) { + this._emitCompleteOnItems( 'layout', items ); + + if ( !items || !items.length ) { + // no items, emit event with empty array + return; + } + + var queue = []; + + items.forEach( function( item ) { + // get x/y object from method + var position = this._getItemLayoutPosition( item ); + // enqueue + position.item = item; + position.isInstant = isInstant || item.isLayoutInstant; + queue.push( position ); + }, this ); + + this._processLayoutQueue( queue ); +}; + +/** + * get item layout position + * @param {Outlayer.Item} item + * @returns {Object} x and y position + */ +proto._getItemLayoutPosition = function( /* item */ ) { + return { + x: 0, + y: 0 + }; +}; + +/** + * iterate over array and position each item + * Reason being - separating this logic prevents 'layout invalidation' + * thx @paul_irish + * @param {Array} queue + */ +proto._processLayoutQueue = function( queue ) { + this.updateStagger(); + queue.forEach( function( obj, i ) { + this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i ); + }, this ); +}; + +// set stagger from option in milliseconds number +proto.updateStagger = function() { + var stagger = this.options.stagger; + if ( stagger === null || stagger === undefined ) { + this.stagger = 0; + return; + } + this.stagger = getMilliseconds( stagger ); + return this.stagger; +}; + +/** + * Sets position of item in DOM + * @param {Outlayer.Item} item + * @param {Number} x - horizontal position + * @param {Number} y - vertical position + * @param {Boolean} isInstant - disables transitions + */ +proto._positionItem = function( item, x, y, isInstant, i ) { + if ( isInstant ) { + // if not transition, just set CSS + item.goTo( x, y ); + } else { + item.stagger( i * this.stagger ); + item.moveTo( x, y ); + } +}; + +/** + * Any logic you want to do after each layout, + * i.e. size the container + */ +proto._postLayout = function() { + this.resizeContainer(); +}; + +proto.resizeContainer = function() { + var isResizingContainer = this._getOption('resizeContainer'); + if ( !isResizingContainer ) { + return; + } + var size = this._getContainerSize(); + if ( size ) { + this._setContainerMeasure( size.width, true ); + this._setContainerMeasure( size.height, false ); + } +}; + +/** + * Sets width or height of container if returned + * @returns {Object} size + * @param {Number} width + * @param {Number} height + */ +proto._getContainerSize = noop; + +/** + * @param {Number} measure - size of width or height + * @param {Boolean} isWidth + */ +proto._setContainerMeasure = function( measure, isWidth ) { + if ( measure === undefined ) { + return; + } + + var elemSize = this.size; + // add padding and border width if border box + if ( elemSize.isBorderBox ) { + measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight + + elemSize.borderLeftWidth + elemSize.borderRightWidth : + elemSize.paddingBottom + elemSize.paddingTop + + elemSize.borderTopWidth + elemSize.borderBottomWidth; + } + + measure = Math.max( measure, 0 ); + this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px'; +}; + +/** + * emit eventComplete on a collection of items events + * @param {String} eventName + * @param {Array} items - Outlayer.Items + */ +proto._emitCompleteOnItems = function( eventName, items ) { + var _this = this; + function onComplete() { + _this.dispatchEvent( eventName + 'Complete', null, [ items ] ); + } + + var count = items.length; + if ( !items || !count ) { + onComplete(); + return; + } + + var doneCount = 0; + function tick() { + doneCount++; + if ( doneCount == count ) { + onComplete(); + } + } + + // bind callback + items.forEach( function( item ) { + item.once( eventName, tick ); + }); +}; + +/** + * emits events via EvEmitter and jQuery events + * @param {String} type - name of event + * @param {Event} event - original event + * @param {Array} args - extra arguments + */ +proto.dispatchEvent = function( type, event, args ) { + // add original event to arguments + var emitArgs = event ? [ event ].concat( args ) : args; + this.emitEvent( type, emitArgs ); + + if ( jQuery ) { + // set this.$element + this.$element = this.$element || jQuery( this.element ); + if ( event ) { + // create jQuery event + var $event = jQuery.Event( event ); + $event.type = type; + this.$element.trigger( $event, args ); + } else { + // just trigger with type if no event available + this.$element.trigger( type, args ); + } + } +}; + +// -------------------------- ignore & stamps -------------------------- // + + +/** + * keep item in collection, but do not lay it out + * ignored items do not get skipped in layout + * @param {Element} elem + */ +proto.ignore = function( elem ) { + var item = this.getItem( elem ); + if ( item ) { + item.isIgnored = true; + } +}; + +/** + * return item to layout collection + * @param {Element} elem + */ +proto.unignore = function( elem ) { + var item = this.getItem( elem ); + if ( item ) { + delete item.isIgnored; + } +}; + +/** + * adds elements to stamps + * @param {NodeList, Array, Element, or String} elems + */ +proto.stamp = function( elems ) { + elems = this._find( elems ); + if ( !elems ) { + return; + } + + this.stamps = this.stamps.concat( elems ); + // ignore + elems.forEach( this.ignore, this ); +}; + +/** + * removes elements to stamps + * @param {NodeList, Array, or Element} elems + */ +proto.unstamp = function( elems ) { + elems = this._find( elems ); + if ( !elems ){ + return; + } + + elems.forEach( function( elem ) { + // filter out removed stamp elements + utils.removeFrom( this.stamps, elem ); + this.unignore( elem ); + }, this ); +}; + +/** + * finds child elements + * @param {NodeList, Array, Element, or String} elems + * @returns {Array} elems + */ +proto._find = function( elems ) { + if ( !elems ) { + return; + } + // if string, use argument as selector string + if ( typeof elems == 'string' ) { + elems = this.element.querySelectorAll( elems ); + } + elems = utils.makeArray( elems ); + return elems; +}; + +proto._manageStamps = function() { + if ( !this.stamps || !this.stamps.length ) { + return; + } + + this._getBoundingRect(); + + this.stamps.forEach( this._manageStamp, this ); +}; + +// update boundingLeft / Top +proto._getBoundingRect = function() { + // get bounding rect for container element + var boundingRect = this.element.getBoundingClientRect(); + var size = this.size; + this._boundingRect = { + left: boundingRect.left + size.paddingLeft + size.borderLeftWidth, + top: boundingRect.top + size.paddingTop + size.borderTopWidth, + right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ), + bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth ) + }; +}; + +/** + * @param {Element} stamp +**/ +proto._manageStamp = noop; + +/** + * get x/y position of element relative to container element + * @param {Element} elem + * @returns {Object} offset - has left, top, right, bottom + */ +proto._getElementOffset = function( elem ) { + var boundingRect = elem.getBoundingClientRect(); + var thisRect = this._boundingRect; + var size = getSize( elem ); + var offset = { + left: boundingRect.left - thisRect.left - size.marginLeft, + top: boundingRect.top - thisRect.top - size.marginTop, + right: thisRect.right - boundingRect.right - size.marginRight, + bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom + }; + return offset; +}; + +// -------------------------- resize -------------------------- // + +// enable event handlers for listeners +// i.e. resize -> onresize +proto.handleEvent = utils.handleEvent; + +/** + * Bind layout to window resizing + */ +proto.bindResize = function() { + window.addEventListener( 'resize', this ); + this.isResizeBound = true; +}; + +/** + * Unbind layout to window resizing + */ +proto.unbindResize = function() { + window.removeEventListener( 'resize', this ); + this.isResizeBound = false; +}; + +proto.onresize = function() { + this.resize(); +}; + +utils.debounceMethod( Outlayer, 'onresize', 100 ); + +proto.resize = function() { + // don't trigger if size did not change + // or if resize was unbound. See #9 + if ( !this.isResizeBound || !this.needsResizeLayout() ) { + return; + } + + this.layout(); +}; + +/** + * check if layout is needed post layout + * @returns Boolean + */ +proto.needsResizeLayout = function() { + var size = getSize( this.element ); + // check that this.size and size are there + // IE8 triggers resize on body size change, so they might not be + var hasSizes = this.size && size; + return hasSizes && size.innerWidth !== this.size.innerWidth; +}; + +// -------------------------- methods -------------------------- // + +/** + * add items to Outlayer instance + * @param {Array or NodeList or Element} elems + * @returns {Array} items - Outlayer.Items +**/ +proto.addItems = function( elems ) { + var items = this._itemize( elems ); + // add items to collection + if ( items.length ) { + this.items = this.items.concat( items ); + } + return items; +}; + +/** + * Layout newly-appended item elements + * @param {Array or NodeList or Element} elems + */ +proto.appended = function( elems ) { + var items = this.addItems( elems ); + if ( !items.length ) { + return; + } + // layout and reveal just the new items + this.layoutItems( items, true ); + this.reveal( items ); +}; + +/** + * Layout prepended elements + * @param {Array or NodeList or Element} elems + */ +proto.prepended = function( elems ) { + var items = this._itemize( elems ); + if ( !items.length ) { + return; + } + // add items to beginning of collection + var previousItems = this.items.slice(0); + this.items = items.concat( previousItems ); + // start new layout + this._resetLayout(); + this._manageStamps(); + // layout new stuff without transition + this.layoutItems( items, true ); + this.reveal( items ); + // layout previous items + this.layoutItems( previousItems ); +}; + +/** + * reveal a collection of items + * @param {Array of Outlayer.Items} items + */ +proto.reveal = function( items ) { + this._emitCompleteOnItems( 'reveal', items ); + if ( !items || !items.length ) { + return; + } + var stagger = this.updateStagger(); + items.forEach( function( item, i ) { + item.stagger( i * stagger ); + item.reveal(); + }); +}; + +/** + * hide a collection of items + * @param {Array of Outlayer.Items} items + */ +proto.hide = function( items ) { + this._emitCompleteOnItems( 'hide', items ); + if ( !items || !items.length ) { + return; + } + var stagger = this.updateStagger(); + items.forEach( function( item, i ) { + item.stagger( i * stagger ); + item.hide(); + }); +}; + +/** + * reveal item elements + * @param {Array}, {Element}, {NodeList} items + */ +proto.revealItemElements = function( elems ) { + var items = this.getItems( elems ); + this.reveal( items ); +}; + +/** + * hide item elements + * @param {Array}, {Element}, {NodeList} items + */ +proto.hideItemElements = function( elems ) { + var items = this.getItems( elems ); + this.hide( items ); +}; + +/** + * get Outlayer.Item, given an Element + * @param {Element} elem + * @param {Function} callback + * @returns {Outlayer.Item} item + */ +proto.getItem = function( elem ) { + // loop through items to get the one that matches + for ( var i=0; i < this.items.length; i++ ) { + var item = this.items[i]; + if ( item.element == elem ) { + // return item + return item; + } + } +}; + +/** + * get collection of Outlayer.Items, given Elements + * @param {Array} elems + * @returns {Array} items - Outlayer.Items + */ +proto.getItems = function( elems ) { + elems = utils.makeArray( elems ); + var items = []; + elems.forEach( function( elem ) { + var item = this.getItem( elem ); + if ( item ) { + items.push( item ); + } + }, this ); + + return items; +}; + +/** + * remove element(s) from instance and DOM + * @param {Array or NodeList or Element} elems + */ +proto.remove = function( elems ) { + var removeItems = this.getItems( elems ); + + this._emitCompleteOnItems( 'remove', removeItems ); + + // bail if no items to remove + if ( !removeItems || !removeItems.length ) { + return; + } + + removeItems.forEach( function( item ) { + item.remove(); + // remove item from collection + utils.removeFrom( this.items, item ); + }, this ); +}; + +// ----- destroy ----- // + +// remove and disable Outlayer instance +proto.destroy = function() { + // clean up dynamic styles + var style = this.element.style; + style.height = ''; + style.position = ''; + style.width = ''; + // destroy items + this.items.forEach( function( item ) { + item.destroy(); + }); + + this.unbindResize(); + + var id = this.element.outlayerGUID; + delete instances[ id ]; // remove reference to instance by id + delete this.element.outlayerGUID; + // remove data for jQuery + if ( jQuery ) { + jQuery.removeData( this.element, this.constructor.namespace ); + } + +}; + +// -------------------------- data -------------------------- // + +/** + * get Outlayer instance from element + * @param {Element} elem + * @returns {Outlayer} + */ +Outlayer.data = function( elem ) { + elem = utils.getQueryElement( elem ); + var id = elem && elem.outlayerGUID; + return id && instances[ id ]; +}; + + +// -------------------------- create Outlayer class -------------------------- // + +/** + * create a layout class + * @param {String} namespace + */ +Outlayer.create = function( namespace, options ) { + // sub-class Outlayer + var Layout = subclass( Outlayer ); + // apply new options and compatOptions + Layout.defaults = utils.extend( {}, Outlayer.defaults ); + utils.extend( Layout.defaults, options ); + Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions ); + + Layout.namespace = namespace; + + Layout.data = Outlayer.data; + + // sub-class Item + Layout.Item = subclass( Item ); + + // -------------------------- declarative -------------------------- // + + utils.htmlInit( Layout, namespace ); + + // -------------------------- jQuery bridge -------------------------- // + + // make into jQuery plugin + if ( jQuery && jQuery.bridget ) { + jQuery.bridget( namespace, Layout ); + } + + return Layout; +}; + +function subclass( Parent ) { + function SubClass() { + Parent.apply( this, arguments ); + } + + SubClass.prototype = Object.create( Parent.prototype ); + SubClass.prototype.constructor = SubClass; + + return SubClass; +} + +// ----- helpers ----- // + +// how many milliseconds are in each unit +var msUnits = { + ms: 1, + s: 1000 +}; + +// munge time-like parameter into millisecond number +// '0.4s' -> 40 +function getMilliseconds( time ) { + if ( typeof time == 'number' ) { + return time; + } + var matches = time.match( /(^\d*\.?\d*)(\w*)/ ); + var num = matches && matches[1]; + var unit = matches && matches[2]; + if ( !num.length ) { + return 0; + } + num = parseFloat( num ); + var mult = msUnits[ unit ] || 1; + return num * mult; +} + +// ----- fin ----- // + +// back in global +Outlayer.Item = Item; + +return Outlayer; + +})); + +/** + * Isotope Item +**/ + +( function( window, factory ) { + // universal module definition + /* jshint strict: false */ /*globals define, module, require */ + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'isotope-layout/js/item',[ + 'outlayer/outlayer' + ], + factory ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory( + require('outlayer') + ); + } else { + // browser global + window.Isotope = window.Isotope || {}; + window.Isotope.Item = factory( + window.Outlayer + ); + } + +}( window, function factory( Outlayer ) { +'use strict'; + +// -------------------------- Item -------------------------- // + +// sub-class Outlayer Item +function Item() { + Outlayer.Item.apply( this, arguments ); +} + +var proto = Item.prototype = Object.create( Outlayer.Item.prototype ); + +var _create = proto._create; +proto._create = function() { + // assign id, used for original-order sorting + this.id = this.layout.itemGUID++; + _create.call( this ); + this.sortData = {}; +}; + +proto.updateSortData = function() { + if ( this.isIgnored ) { + return; + } + // default sorters + this.sortData.id = this.id; + // for backward compatibility + this.sortData['original-order'] = this.id; + this.sortData.random = Math.random(); + // go thru getSortData obj and apply the sorters + var getSortData = this.layout.options.getSortData; + var sorters = this.layout._sorters; + for ( var key in getSortData ) { + var sorter = sorters[ key ]; + this.sortData[ key ] = sorter( this.element, this ); + } +}; + +var _destroy = proto.destroy; +proto.destroy = function() { + // call super + _destroy.apply( this, arguments ); + // reset display, #741 + this.css({ + display: '' + }); +}; + +return Item; + +})); + +/** + * Isotope LayoutMode + */ + +( function( window, factory ) { + // universal module definition + /* jshint strict: false */ /*globals define, module, require */ + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'isotope-layout/js/layout-mode',[ + 'get-size/get-size', + 'outlayer/outlayer' + ], + factory ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory( + require('get-size'), + require('outlayer') + ); + } else { + // browser global + window.Isotope = window.Isotope || {}; + window.Isotope.LayoutMode = factory( + window.getSize, + window.Outlayer + ); + } + +}( window, function factory( getSize, Outlayer ) { + 'use strict'; + + // layout mode class + function LayoutMode( isotope ) { + this.isotope = isotope; + // link properties + if ( isotope ) { + this.options = isotope.options[ this.namespace ]; + this.element = isotope.element; + this.items = isotope.filteredItems; + this.size = isotope.size; + } + } + + var proto = LayoutMode.prototype; + + /** + * some methods should just defer to default Outlayer method + * and reference the Isotope instance as `this` + **/ + var facadeMethods = [ + '_resetLayout', + '_getItemLayoutPosition', + '_manageStamp', + '_getContainerSize', + '_getElementOffset', + 'needsResizeLayout', + '_getOption' + ]; + + facadeMethods.forEach( function( methodName ) { + proto[ methodName ] = function() { + return Outlayer.prototype[ methodName ].apply( this.isotope, arguments ); + }; + }); + + // ----- ----- // + + // for horizontal layout modes, check vertical size + proto.needsVerticalResizeLayout = function() { + // don't trigger if size did not change + var size = getSize( this.isotope.element ); + // check that this.size and size are there + // IE8 triggers resize on body size change, so they might not be + var hasSizes = this.isotope.size && size; + return hasSizes && size.innerHeight != this.isotope.size.innerHeight; + }; + + // ----- measurements ----- // + + proto._getMeasurement = function() { + this.isotope._getMeasurement.apply( this, arguments ); + }; + + proto.getColumnWidth = function() { + this.getSegmentSize( 'column', 'Width' ); + }; + + proto.getRowHeight = function() { + this.getSegmentSize( 'row', 'Height' ); + }; + + /** + * get columnWidth or rowHeight + * segment: 'column' or 'row' + * size 'Width' or 'Height' + **/ + proto.getSegmentSize = function( segment, size ) { + var segmentName = segment + size; + var outerSize = 'outer' + size; + // columnWidth / outerWidth // rowHeight / outerHeight + this._getMeasurement( segmentName, outerSize ); + // got rowHeight or columnWidth, we can chill + if ( this[ segmentName ] ) { + return; + } + // fall back to item of first element + var firstItemSize = this.getFirstItemSize(); + this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] || + // or size of container + this.isotope.size[ 'inner' + size ]; + }; + + proto.getFirstItemSize = function() { + var firstItem = this.isotope.filteredItems[0]; + return firstItem && firstItem.element && getSize( firstItem.element ); + }; + + // ----- methods that should reference isotope ----- // + + proto.layout = function() { + this.isotope.layout.apply( this.isotope, arguments ); + }; + + proto.getSize = function() { + this.isotope.getSize(); + this.size = this.isotope.size; + }; + + // -------------------------- create -------------------------- // + + LayoutMode.modes = {}; + + LayoutMode.create = function( namespace, options ) { + + function Mode() { + LayoutMode.apply( this, arguments ); + } + + Mode.prototype = Object.create( proto ); + Mode.prototype.constructor = Mode; + + // default options + if ( options ) { + Mode.options = options; + } + + Mode.prototype.namespace = namespace; + // register in Isotope + LayoutMode.modes[ namespace ] = Mode; + + return Mode; + }; + + return LayoutMode; + +})); + +/*! + * Masonry v4.2.1 + * Cascading grid layout library + * https://masonry.desandro.com + * MIT License + * by David DeSandro + */ + +( function( window, factory ) { + // universal module definition + /* jshint strict: false */ /*globals define, module, require */ + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'masonry-layout/masonry',[ + 'outlayer/outlayer', + 'get-size/get-size' + ], + factory ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory( + require('outlayer'), + require('get-size') + ); + } else { + // browser global + window.Masonry = factory( + window.Outlayer, + window.getSize + ); + } + +}( window, function factory( Outlayer, getSize ) { + + + +// -------------------------- masonryDefinition -------------------------- // + + // create an Outlayer layout class + var Masonry = Outlayer.create('masonry'); + // isFitWidth -> fitWidth + Masonry.compatOptions.fitWidth = 'isFitWidth'; + + var proto = Masonry.prototype; + + proto._resetLayout = function() { + this.getSize(); + this._getMeasurement( 'columnWidth', 'outerWidth' ); + this._getMeasurement( 'gutter', 'outerWidth' ); + this.measureColumns(); + + // reset column Y + this.colYs = []; + for ( var i=0; i < this.cols; i++ ) { + this.colYs.push( 0 ); + } + + this.maxY = 0; + this.horizontalColIndex = 0; + }; + + proto.measureColumns = function() { + this.getContainerWidth(); + // if columnWidth is 0, default to outerWidth of first item + if ( !this.columnWidth ) { + var firstItem = this.items[0]; + var firstItemElem = firstItem && firstItem.element; + // columnWidth fall back to item of first element + this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth || + // if first elem has no width, default to size of container + this.containerWidth; + } + + var columnWidth = this.columnWidth += this.gutter; + + // calculate columns + var containerWidth = this.containerWidth + this.gutter; + var cols = containerWidth / columnWidth; + // fix rounding errors, typically with gutters + var excess = columnWidth - containerWidth % columnWidth; + // if overshoot is less than a pixel, round up, otherwise floor it + var mathMethod = excess && excess < 1 ? 'round' : 'floor'; + cols = Math[ mathMethod ]( cols ); + this.cols = Math.max( cols, 1 ); + }; + + proto.getContainerWidth = function() { + // container is parent if fit width + var isFitWidth = this._getOption('fitWidth'); + var container = isFitWidth ? this.element.parentNode : this.element; + // check that this.size and size are there + // IE8 triggers resize on body size change, so they might not be + var size = getSize( container ); + this.containerWidth = size && size.innerWidth; + }; + + proto._getItemLayoutPosition = function( item ) { + item.getSize(); + // how many columns does this brick span + var remainder = item.size.outerWidth % this.columnWidth; + var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; + // round if off by 1 pixel, otherwise use ceil + var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth ); + colSpan = Math.min( colSpan, this.cols ); + // use horizontal or top column position + var colPosMethod = this.options.horizontalOrder ? + '_getHorizontalColPosition' : '_getTopColPosition'; + var colPosition = this[ colPosMethod ]( colSpan, item ); + // position the brick + var position = { + x: this.columnWidth * colPosition.col, + y: colPosition.y + }; + // apply setHeight to necessary columns + var setHeight = colPosition.y + item.size.outerHeight; + var setMax = colSpan + colPosition.col; + for ( var i = colPosition.col; i < setMax; i++ ) { + this.colYs[i] = setHeight; + } + + return position; + }; + + proto._getTopColPosition = function( colSpan ) { + var colGroup = this._getTopColGroup( colSpan ); + // get the minimum Y value from the columns + var minimumY = Math.min.apply( Math, colGroup ); + + return { + col: colGroup.indexOf( minimumY ), + y: minimumY, + }; + }; + + /** + * @param {Number} colSpan - number of columns the element spans + * @returns {Array} colGroup + */ + proto._getTopColGroup = function( colSpan ) { + if ( colSpan < 2 ) { + // if brick spans only one column, use all the column Ys + return this.colYs; + } + + var colGroup = []; + // how many different places could this brick fit horizontally + var groupCount = this.cols + 1 - colSpan; + // for each group potential horizontal position + for ( var i = 0; i < groupCount; i++ ) { + colGroup[i] = this._getColGroupY( i, colSpan ); + } + return colGroup; + }; + + proto._getColGroupY = function( col, colSpan ) { + if ( colSpan < 2 ) { + return this.colYs[ col ]; + } + // make an array of colY values for that one group + var groupColYs = this.colYs.slice( col, col + colSpan ); + // and get the max value of the array + return Math.max.apply( Math, groupColYs ); + }; + + // get column position based on horizontal index. #873 + proto._getHorizontalColPosition = function( colSpan, item ) { + var col = this.horizontalColIndex % this.cols; + var isOver = colSpan > 1 && col + colSpan > this.cols; + // shift to next row if item can't fit on current row + col = isOver ? 0 : col; + // don't let zero-size items take up space + var hasSize = item.size.outerWidth && item.size.outerHeight; + this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex; + + return { + col: col, + y: this._getColGroupY( col, colSpan ), + }; + }; + + proto._manageStamp = function( stamp ) { + var stampSize = getSize( stamp ); + var offset = this._getElementOffset( stamp ); + // get the columns that this stamp affects + var isOriginLeft = this._getOption('originLeft'); + var firstX = isOriginLeft ? offset.left : offset.right; + var lastX = firstX + stampSize.outerWidth; + var firstCol = Math.floor( firstX / this.columnWidth ); + firstCol = Math.max( 0, firstCol ); + var lastCol = Math.floor( lastX / this.columnWidth ); + // lastCol should not go over if multiple of columnWidth #425 + lastCol -= lastX % this.columnWidth ? 0 : 1; + lastCol = Math.min( this.cols - 1, lastCol ); + // set colYs to bottom of the stamp + + var isOriginTop = this._getOption('originTop'); + var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) + + stampSize.outerHeight; + for ( var i = firstCol; i <= lastCol; i++ ) { + this.colYs[i] = Math.max( stampMaxY, this.colYs[i] ); + } + }; + + proto._getContainerSize = function() { + this.maxY = Math.max.apply( Math, this.colYs ); + var size = { + height: this.maxY + }; + + if ( this._getOption('fitWidth') ) { + size.width = this._getContainerFitWidth(); + } + + return size; + }; + + proto._getContainerFitWidth = function() { + var unusedCols = 0; + // count unused columns + var i = this.cols; + while ( --i ) { + if ( this.colYs[i] !== 0 ) { + break; + } + unusedCols++; + } + // fit container to columns that have been used + return ( this.cols - unusedCols ) * this.columnWidth - this.gutter; + }; + + proto.needsResizeLayout = function() { + var previousWidth = this.containerWidth; + this.getContainerWidth(); + return previousWidth != this.containerWidth; + }; + + return Masonry; + +})); + +/*! + * Masonry layout mode + * sub-classes Masonry + * https://masonry.desandro.com + */ + +( function( window, factory ) { + // universal module definition + /* jshint strict: false */ /*globals define, module, require */ + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'isotope-layout/js/layout-modes/masonry',[ + '../layout-mode', + 'masonry-layout/masonry' + ], + factory ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory( + require('../layout-mode'), + require('masonry-layout') + ); + } else { + // browser global + factory( + window.Isotope.LayoutMode, + window.Masonry + ); + } + +}( window, function factory( LayoutMode, Masonry ) { +'use strict'; + +// -------------------------- masonryDefinition -------------------------- // + + // create an Outlayer layout class + var MasonryMode = LayoutMode.create('masonry'); + + var proto = MasonryMode.prototype; + + var keepModeMethods = { + _getElementOffset: true, + layout: true, + _getMeasurement: true + }; + + // inherit Masonry prototype + for ( var method in Masonry.prototype ) { + // do not inherit mode methods + if ( !keepModeMethods[ method ] ) { + proto[ method ] = Masonry.prototype[ method ]; + } + } + + var measureColumns = proto.measureColumns; + proto.measureColumns = function() { + // set items, used if measuring first item + this.items = this.isotope.filteredItems; + measureColumns.call( this ); + }; + + // point to mode options for fitWidth + var _getOption = proto._getOption; + proto._getOption = function( option ) { + if ( option == 'fitWidth' ) { + return this.options.isFitWidth !== undefined ? + this.options.isFitWidth : this.options.fitWidth; + } + return _getOption.apply( this.isotope, arguments ); + }; + + return MasonryMode; + +})); + +/** + * fitRows layout mode + */ + +( function( window, factory ) { + // universal module definition + /* jshint strict: false */ /*globals define, module, require */ + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'isotope-layout/js/layout-modes/fit-rows',[ + '../layout-mode' + ], + factory ); + } else if ( typeof exports == 'object' ) { + // CommonJS + module.exports = factory( + require('../layout-mode') + ); + } else { + // browser global + factory( + window.Isotope.LayoutMode + ); + } + +}( window, function factory( LayoutMode ) { +'use strict'; + +var FitRows = LayoutMode.create('fitRows'); + +var proto = FitRows.prototype; + +proto._resetLayout = function() { + this.x = 0; + this.y = 0; + this.maxY = 0; + this._getMeasurement( 'gutter', 'outerWidth' ); +}; + +proto._getItemLayoutPosition = function( item ) { + item.getSize(); + + var itemWidth = item.size.outerWidth + this.gutter; + // if this element cannot fit in the current row + var containerWidth = this.isotope.size.innerWidth + this.gutter; + if ( this.x !== 0 && itemWidth + this.x > containerWidth ) { + this.x = 0; + this.y = this.maxY; + } + + var position = { + x: this.x, + y: this.y + }; + + this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight ); + this.x += itemWidth; + + return position; +}; + +proto._getContainerSize = function() { + return { height: this.maxY }; +}; + +return FitRows; + +})); + +/** + * vertical layout mode + */ + +( function( window, factory ) { + // universal module definition + /* jshint strict: false */ /*globals define, module, require */ + if ( typeof define == 'function' && define.amd ) { + // AMD + define( 'isotope-layout/js/layout-modes/vertical',[ + '../layout-mode' + ], + factory ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory( + require('../layout-mode') + ); + } else { + // browser global + factory( + window.Isotope.LayoutMode + ); + } + +}( window, function factory( LayoutMode ) { +'use strict'; + +var Vertical = LayoutMode.create( 'vertical', { + horizontalAlignment: 0 +}); + +var proto = Vertical.prototype; + +proto._resetLayout = function() { + this.y = 0; +}; + +proto._getItemLayoutPosition = function( item ) { + item.getSize(); + var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) * + this.options.horizontalAlignment; + var y = this.y; + this.y += item.size.outerHeight; + return { x: x, y: y }; +}; + +proto._getContainerSize = function() { + return { height: this.y }; +}; + +return Vertical; + +})); + +/*! + * Isotope v3.0.6 + * + * Licensed GPLv3 for open source use + * or Isotope Commercial License for commercial use + * + * https://isotope.metafizzy.co + * Copyright 2010-2018 Metafizzy + */ + +( function( window, factory ) { + // universal module definition + /* jshint strict: false */ /*globals define, module, require */ + if ( typeof define == 'function' && define.amd ) { + // AMD + define( [ + 'outlayer/outlayer', + 'get-size/get-size', + 'desandro-matches-selector/matches-selector', + 'fizzy-ui-utils/utils', + 'isotope-layout/js/item', + 'isotope-layout/js/layout-mode', + // include default layout modes + 'isotope-layout/js/layout-modes/masonry', + 'isotope-layout/js/layout-modes/fit-rows', + 'isotope-layout/js/layout-modes/vertical' + ], + function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) { + return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ); + }); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory( + window, + require('outlayer'), + require('get-size'), + require('desandro-matches-selector'), + require('fizzy-ui-utils'), + require('isotope-layout/js/item'), + require('isotope-layout/js/layout-mode'), + // include default layout modes + require('isotope-layout/js/layout-modes/masonry'), + require('isotope-layout/js/layout-modes/fit-rows'), + require('isotope-layout/js/layout-modes/vertical') + ); + } else { + // browser global + window.Isotope = factory( + window, + window.Outlayer, + window.getSize, + window.matchesSelector, + window.fizzyUIUtils, + window.Isotope.Item, + window.Isotope.LayoutMode + ); + } + +}( window, function factory( window, Outlayer, getSize, matchesSelector, utils, + Item, LayoutMode ) { + + + +// -------------------------- vars -------------------------- // + +var jQuery = window.jQuery; + +// -------------------------- helpers -------------------------- // + +var trim = String.prototype.trim ? + function( str ) { + return str.trim(); + } : + function( str ) { + return str.replace( /^\s+|\s+$/g, '' ); + }; + +// -------------------------- isotopeDefinition -------------------------- // + + // create an Outlayer layout class + var Isotope = Outlayer.create( 'isotope', { + layoutMode: 'masonry', + isJQueryFiltering: true, + sortAscending: true + }); + + Isotope.Item = Item; + Isotope.LayoutMode = LayoutMode; + + var proto = Isotope.prototype; + + proto._create = function() { + this.itemGUID = 0; + // functions that sort items + this._sorters = {}; + this._getSorters(); + // call super + Outlayer.prototype._create.call( this ); + + // create layout modes + this.modes = {}; + // start filteredItems with all items + this.filteredItems = this.items; + // keep of track of sortBys + this.sortHistory = [ 'original-order' ]; + // create from registered layout modes + for ( var name in LayoutMode.modes ) { + this._initLayoutMode( name ); + } + }; + + proto.reloadItems = function() { + // reset item ID counter + this.itemGUID = 0; + // call super + Outlayer.prototype.reloadItems.call( this ); + }; + + proto._itemize = function() { + var items = Outlayer.prototype._itemize.apply( this, arguments ); + // assign ID for original-order + for ( var i=0; i < items.length; i++ ) { + var item = items[i]; + item.id = this.itemGUID++; + } + this._updateItemsSortData( items ); + return items; + }; + + + // -------------------------- layout -------------------------- // + + proto._initLayoutMode = function( name ) { + var Mode = LayoutMode.modes[ name ]; + // set mode options + // HACK extend initial options, back-fill in default options + var initialOpts = this.options[ name ] || {}; + this.options[ name ] = Mode.options ? + utils.extend( Mode.options, initialOpts ) : initialOpts; + // init layout mode instance + this.modes[ name ] = new Mode( this ); + }; + + + proto.layout = function() { + // if first time doing layout, do all magic + if ( !this._isLayoutInited && this._getOption('initLayout') ) { + this.arrange(); + return; + } + this._layout(); + }; + + // private method to be used in layout() & magic() + proto._layout = function() { + // don't animate first layout + var isInstant = this._getIsInstant(); + // layout flow + this._resetLayout(); + this._manageStamps(); + this.layoutItems( this.filteredItems, isInstant ); + + // flag for initalized + this._isLayoutInited = true; + }; + + // filter + sort + layout + proto.arrange = function( opts ) { + // set any options pass + this.option( opts ); + this._getIsInstant(); + // filter, sort, and layout + + // filter + var filtered = this._filter( this.items ); + this.filteredItems = filtered.matches; + + this._bindArrangeComplete(); + + if ( this._isInstant ) { + this._noTransition( this._hideReveal, [ filtered ] ); + } else { + this._hideReveal( filtered ); + } + + this._sort(); + this._layout(); + }; + // alias to _init for main plugin method + proto._init = proto.arrange; + + proto._hideReveal = function( filtered ) { + this.reveal( filtered.needReveal ); + this.hide( filtered.needHide ); + }; + + // HACK + // Don't animate/transition first layout + // Or don't animate/transition other layouts + proto._getIsInstant = function() { + var isLayoutInstant = this._getOption('layoutInstant'); + var isInstant = isLayoutInstant !== undefined ? isLayoutInstant : + !this._isLayoutInited; + this._isInstant = isInstant; + return isInstant; + }; + + // listen for layoutComplete, hideComplete and revealComplete + // to trigger arrangeComplete + proto._bindArrangeComplete = function() { + // listen for 3 events to trigger arrangeComplete + var isLayoutComplete, isHideComplete, isRevealComplete; + var _this = this; + function arrangeParallelCallback() { + if ( isLayoutComplete && isHideComplete && isRevealComplete ) { + _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] ); + } + } + this.once( 'layoutComplete', function() { + isLayoutComplete = true; + arrangeParallelCallback(); + }); + this.once( 'hideComplete', function() { + isHideComplete = true; + arrangeParallelCallback(); + }); + this.once( 'revealComplete', function() { + isRevealComplete = true; + arrangeParallelCallback(); + }); + }; + + // -------------------------- filter -------------------------- // + + proto._filter = function( items ) { + var filter = this.options.filter; + filter = filter || '*'; + var matches = []; + var hiddenMatched = []; + var visibleUnmatched = []; + + var test = this._getFilterTest( filter ); + + // test each item + for ( var i=0; i < items.length; i++ ) { + var item = items[i]; + if ( item.isIgnored ) { + continue; + } + // add item to either matched or unmatched group + var isMatched = test( item ); + // item.isFilterMatched = isMatched; + // add to matches if its a match + if ( isMatched ) { + matches.push( item ); + } + // add to additional group if item needs to be hidden or revealed + if ( isMatched && item.isHidden ) { + hiddenMatched.push( item ); + } else if ( !isMatched && !item.isHidden ) { + visibleUnmatched.push( item ); + } + } + + // return collections of items to be manipulated + return { + matches: matches, + needReveal: hiddenMatched, + needHide: visibleUnmatched + }; + }; + + // get a jQuery, function, or a matchesSelector test given the filter + proto._getFilterTest = function( filter ) { + if ( jQuery && this.options.isJQueryFiltering ) { + // use jQuery + return function( item ) { + return jQuery( item.element ).is( filter ); + }; + } + if ( typeof filter == 'function' ) { + // use filter as function + return function( item ) { + return filter( item.element ); + }; + } + // default, use filter as selector string + return function( item ) { + return matchesSelector( item.element, filter ); + }; + }; + + // -------------------------- sorting -------------------------- // + + /** + * @params {Array} elems + * @public + */ + proto.updateSortData = function( elems ) { + // get items + var items; + if ( elems ) { + elems = utils.makeArray( elems ); + items = this.getItems( elems ); + } else { + // update all items if no elems provided + items = this.items; + } + + this._getSorters(); + this._updateItemsSortData( items ); + }; + + proto._getSorters = function() { + var getSortData = this.options.getSortData; + for ( var key in getSortData ) { + var sorter = getSortData[ key ]; + this._sorters[ key ] = mungeSorter( sorter ); + } + }; + + /** + * @params {Array} items - of Isotope.Items + * @private + */ + proto._updateItemsSortData = function( items ) { + // do not update if no items + var len = items && items.length; + + for ( var i=0; len && i < len; i++ ) { + var item = items[i]; + item.updateSortData(); + } + }; + + // ----- munge sorter ----- // + + // encapsulate this, as we just need mungeSorter + // other functions in here are just for munging + var mungeSorter = ( function() { + // add a magic layer to sorters for convienent shorthands + // `.foo-bar` will use the text of .foo-bar querySelector + // `[foo-bar]` will use attribute + // you can also add parser + // `.foo-bar parseInt` will parse that as a number + function mungeSorter( sorter ) { + // if not a string, return function or whatever it is + if ( typeof sorter != 'string' ) { + return sorter; + } + // parse the sorter string + var args = trim( sorter ).split(' '); + var query = args[0]; + // check if query looks like [an-attribute] + var attrMatch = query.match( /^\[(.+)\]$/ ); + var attr = attrMatch && attrMatch[1]; + var getValue = getValueGetter( attr, query ); + // use second argument as a parser + var parser = Isotope.sortDataParsers[ args[1] ]; + // parse the value, if there was a parser + sorter = parser ? function( elem ) { + return elem && parser( getValue( elem ) ); + } : + // otherwise just return value + function( elem ) { + return elem && getValue( elem ); + }; + + return sorter; + } + + // get an attribute getter, or get text of the querySelector + function getValueGetter( attr, query ) { + // if query looks like [foo-bar], get attribute + if ( attr ) { + return function getAttribute( elem ) { + return elem.getAttribute( attr ); + }; + } + + // otherwise, assume its a querySelector, and get its text + return function getChildText( elem ) { + var child = elem.querySelector( query ); + return child && child.textContent; + }; + } + + return mungeSorter; + })(); + + // parsers used in getSortData shortcut strings + Isotope.sortDataParsers = { + 'parseInt': function( val ) { + return parseInt( val, 10 ); + }, + 'parseFloat': function( val ) { + return parseFloat( val ); + } + }; + + // ----- sort method ----- // + + // sort filteredItem order + proto._sort = function() { + if ( !this.options.sortBy ) { + return; + } + // keep track of sortBy History + var sortBys = utils.makeArray( this.options.sortBy ); + if ( !this._getIsSameSortBy( sortBys ) ) { + // concat all sortBy and sortHistory, add to front, oldest goes in last + this.sortHistory = sortBys.concat( this.sortHistory ); + } + // sort magic + var itemSorter = getItemSorter( this.sortHistory, this.options.sortAscending ); + this.filteredItems.sort( itemSorter ); + }; + + // check if sortBys is same as start of sortHistory + proto._getIsSameSortBy = function( sortBys ) { + for ( var i=0; i < sortBys.length; i++ ) { + if ( sortBys[i] != this.sortHistory[i] ) { + return false; + } + } + return true; + }; + + // returns a function used for sorting + function getItemSorter( sortBys, sortAsc ) { + return function sorter( itemA, itemB ) { + // cycle through all sortKeys + for ( var i = 0; i < sortBys.length; i++ ) { + var sortBy = sortBys[i]; + var a = itemA.sortData[ sortBy ]; + var b = itemB.sortData[ sortBy ]; + if ( a > b || a < b ) { + // if sortAsc is an object, use the value given the sortBy key + var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc; + var direction = isAscending ? 1 : -1; + return ( a > b ? 1 : -1 ) * direction; + } + } + return 0; + }; + } + + // -------------------------- methods -------------------------- // + + // get layout mode + proto._mode = function() { + var layoutMode = this.options.layoutMode; + var mode = this.modes[ layoutMode ]; + if ( !mode ) { + // TODO console.error + throw new Error( 'No layout mode: ' + layoutMode ); + } + // HACK sync mode's options + // any options set after init for layout mode need to be synced + mode.options = this.options[ layoutMode ]; + return mode; + }; + + proto._resetLayout = function() { + // trigger original reset layout + Outlayer.prototype._resetLayout.call( this ); + this._mode()._resetLayout(); + }; + + proto._getItemLayoutPosition = function( item ) { + return this._mode()._getItemLayoutPosition( item ); + }; + + proto._manageStamp = function( stamp ) { + this._mode()._manageStamp( stamp ); + }; + + proto._getContainerSize = function() { + return this._mode()._getContainerSize(); + }; + + proto.needsResizeLayout = function() { + return this._mode().needsResizeLayout(); + }; + + // -------------------------- adding & removing -------------------------- // + + // HEADS UP overwrites default Outlayer appended + proto.appended = function( elems ) { + var items = this.addItems( elems ); + if ( !items.length ) { + return; + } + // filter, layout, reveal new items + var filteredItems = this._filterRevealAdded( items ); + // add to filteredItems + this.filteredItems = this.filteredItems.concat( filteredItems ); + }; + + // HEADS UP overwrites default Outlayer prepended + proto.prepended = function( elems ) { + var items = this._itemize( elems ); + if ( !items.length ) { + return; + } + // start new layout + this._resetLayout(); + this._manageStamps(); + // filter, layout, reveal new items + var filteredItems = this._filterRevealAdded( items ); + // layout previous items + this.layoutItems( this.filteredItems ); + // add to items and filteredItems + this.filteredItems = filteredItems.concat( this.filteredItems ); + this.items = items.concat( this.items ); + }; + + proto._filterRevealAdded = function( items ) { + var filtered = this._filter( items ); + this.hide( filtered.needHide ); + // reveal all new items + this.reveal( filtered.matches ); + // layout new items, no transition + this.layoutItems( filtered.matches, true ); + return filtered.matches; + }; + + /** + * Filter, sort, and layout newly-appended item elements + * @param {Array or NodeList or Element} elems + */ + proto.insert = function( elems ) { + var items = this.addItems( elems ); + if ( !items.length ) { + return; + } + // append item elements + var i, item; + var len = items.length; + for ( i=0; i < len; i++ ) { + item = items[i]; + this.element.appendChild( item.element ); + } + // filter new stuff + var filteredInsertItems = this._filter( items ).matches; + // set flag + for ( i=0; i < len; i++ ) { + items[i].isLayoutInstant = true; + } + this.arrange(); + // reset flag + for ( i=0; i < len; i++ ) { + delete items[i].isLayoutInstant; + } + this.reveal( filteredInsertItems ); + }; + + var _remove = proto.remove; + proto.remove = function( elems ) { + elems = utils.makeArray( elems ); + var removeItems = this.getItems( elems ); + // do regular thing + _remove.call( this, elems ); + // bail if no items to remove + var len = removeItems && removeItems.length; + // remove elems from filteredItems + for ( var i=0; len && i < len; i++ ) { + var item = removeItems[i]; + // remove item from collection + utils.removeFrom( this.filteredItems, item ); + } + }; + + proto.shuffle = function() { + // update random sortData + for ( var i=0; i < this.items.length; i++ ) { + var item = this.items[i]; + item.sortData.random = Math.random(); + } + this.options.sortBy = 'random'; + this._sort(); + this._layout(); + }; + + /** + * trigger fn without transition + * kind of hacky to have this in the first place + * @param {Function} fn + * @param {Array} args + * @returns ret + * @private + */ + proto._noTransition = function( fn, args ) { + // save transitionDuration before disabling + var transitionDuration = this.options.transitionDuration; + // disable transition + this.options.transitionDuration = 0; + // do it + var returnValue = fn.apply( this, args ); + // re-enable transition for reveal + this.options.transitionDuration = transitionDuration; + return returnValue; + }; + + // ----- helper methods ----- // + + /** + * getter method for getting filtered item elements + * @returns {Array} elems - collection of item elements + */ + proto.getFilteredItemElements = function() { + return this.filteredItems.map( function( item ) { + return item.element; + }); + }; + + // ----- ----- // + + return Isotope; + +})); \ No newline at end of file diff --git a/modules/backend/widgets/reportcontainer/assets/vendor/isotope/jquery.isotope.min.js b/modules/backend/widgets/reportcontainer/assets/vendor/isotope/jquery.isotope.min.js new file mode 100644 index 0000000..7ca671c --- /dev/null +++ b/modules/backend/widgets/reportcontainer/assets/vendor/isotope/jquery.isotope.min.js @@ -0,0 +1,12 @@ +/*! + * Isotope PACKAGED v3.0.6 + * + * Licensed GPLv3 for open source use + * or Isotope Commercial License for commercial use + * + * https://isotope.metafizzy.co + * Copyright 2010-2018 Metafizzy + */ + +!function(t,e){"function"==typeof define&&define.amd?define("jquery-bridget/jquery-bridget",["jquery"],function(i){return e(t,i)}):"object"==typeof module&&module.exports?module.exports=e(t,require("jquery")):t.jQueryBridget=e(t,t.jQuery)}(window,function(t,e){"use strict";function i(i,s,a){function u(t,e,o){var n,s="$()."+i+'("'+e+'")';return t.each(function(t,u){var h=a.data(u,i);if(!h)return void r(i+" not initialized. Cannot call methods, i.e. "+s);var d=h[e];if(!d||"_"==e.charAt(0))return void r(s+" is not a valid method");var l=d.apply(h,o);n=void 0===n?l:n}),void 0!==n?n:t}function h(t,e){t.each(function(t,o){var n=a.data(o,i);n?(n.option(e),n._init()):(n=new s(o,e),a.data(o,i,n))})}a=a||e||t.jQuery,a&&(s.prototype.option||(s.prototype.option=function(t){a.isPlainObject(t)&&(this.options=a.extend(!0,this.options,t))}),a.fn[i]=function(t){if("string"==typeof t){var e=n.call(arguments,1);return u(this,t,e)}return h(this,t),this},o(a))}function o(t){!t||t&&t.bridget||(t.bridget=i)}var n=Array.prototype.slice,s=t.console,r="undefined"==typeof s?function(){}:function(t){s.error(t)};return o(e||t.jQuery),i}),function(t,e){"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",e):"object"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},o=i[t]=i[t]||[];return o.indexOf(e)==-1&&o.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{},o=i[t]=i[t]||{};return o[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var o=i.indexOf(e);return o!=-1&&i.splice(o,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){i=i.slice(0),e=e||[];for(var o=this._onceEvents&&this._onceEvents[t],n=0;n
    diff --git a/modules/backend/widgets/reportcontainer/partials/_new_widget_popup.htm b/modules/backend/widgets/reportcontainer/partials/_new_widget_popup.htm new file mode 100644 index 0000000..aba9f70 --- /dev/null +++ b/modules/backend/widgets/reportcontainer/partials/_new_widget_popup.htm @@ -0,0 +1,44 @@ + $this->getEventHandler('onAddWidget'), + 'data-request-success' => "\$(this).trigger('close.oc.popup'); \$(window).trigger('oc.reportWidgetAdded')", + 'data-popup-load-indicator' => 1 +]) ?> + + + + diff --git a/modules/backend/widgets/reportcontainer/partials/_widget.htm b/modules/backend/widgets/reportcontainer/partials/_widget.htm new file mode 100644 index 0000000..2532271 --- /dev/null +++ b/modules/backend/widgets/reportcontainer/partials/_widget.htm @@ -0,0 +1,33 @@ +property('ocWidgetNewRow')): ?> +
  • + + +
  • +
    +
    + +
    render() ?>
    + + + + Edit + + + canAddAndDelete): ?> + + + + + +
    +
  • diff --git a/modules/backend/widgets/reportcontainer/partials/_widget_list.htm b/modules/backend/widgets/reportcontainer/partials/_widget_list.htm new file mode 100644 index 0000000..c7be705 --- /dev/null +++ b/modules/backend/widgets/reportcontainer/partials/_widget_list.htm @@ -0,0 +1,7 @@ + $widgetInfo): ?> + makePartial('widget', [ + 'widgetAlias' => $widgetAlias, + 'widget' => $widgetInfo['widget'], + 'sortOrder' => $widgetInfo['sortOrder'] + ]) ?> + diff --git a/modules/backend/widgets/reportcontainer/partials/_widget_toolbar.htm b/modules/backend/widgets/reportcontainer/partials/_widget_toolbar.htm new file mode 100644 index 0000000..83975d9 --- /dev/null +++ b/modules/backend/widgets/reportcontainer/partials/_widget_toolbar.htm @@ -0,0 +1,48 @@ + \ No newline at end of file diff --git a/modules/backend/widgets/search/partials/_search.htm b/modules/backend/widgets/search/partials/_search.htm new file mode 100644 index 0000000..f66465f --- /dev/null +++ b/modules/backend/widgets/search/partials/_search.htm @@ -0,0 +1,23 @@ +
    + + data-load-indicator + data-load-indicator-opaque + class="form-control " + autocomplete="off" /> + +
    diff --git a/modules/backend/widgets/table/ClientMemoryDataSource.php b/modules/backend/widgets/table/ClientMemoryDataSource.php new file mode 100644 index 0000000..790ca62 --- /dev/null +++ b/modules/backend/widgets/table/ClientMemoryDataSource.php @@ -0,0 +1,62 @@ +data = array_merge($this->data, $records); + } + + /** + * Returns a total number of records in the data source. + * @return integer + */ + public function getCount() + { + return count($this->data); + } + + /** + * Removes all records from the data source. + */ + public function purge() + { + $this->data = []; + } + + /** + * Return records from the data source. + * @param integer $offset Specifies the offset of the first record to return, zero-based. + * @param integer $count Specifies the number of records to return. + * @return array Returns the records. + * If there are no more records, returns an empty array. + */ + public function getRecords($offset, $count) + { + return array_slice($this->data, $offset, $count); + } + + /** + * Returns all records in the data source. + * This method is specific only for the client memory data sources. + */ + public function getAllRecords() + { + return $this->data; + } +} diff --git a/modules/backend/widgets/table/DataSourceBase.php b/modules/backend/widgets/table/DataSourceBase.php new file mode 100644 index 0000000..b404183 --- /dev/null +++ b/modules/backend/widgets/table/DataSourceBase.php @@ -0,0 +1,86 @@ +keyColumn = $keyColumn; + } + + /** + * Initializes records in the data source. + * The method doesn't replace existing records and + * could be called multiple times in order to fill + * the data source. + * @param array $records Records to initialize in the data source. + */ + abstract public function initRecords($records); + + /** + * Returns a total number of records in the data source. + * @return integer + */ + abstract public function getCount(); + + /** + * Removes all records from the data source. + */ + abstract public function purge(); + + /** + * Return records from the data source. + * @param integer $offset Specifies the offset of the first record to return, zero-based. + * @param integer $count Specifies the number of records to return. + * @return array Returns the records. + * If there are no more records, returns an empty array. + */ + abstract public function getRecords($offset, $count); + + /** + * Identical to getRecords except provided with a search query. + */ + public function searchRecords($query, $offset, $count) + { + return $this->getRecords($offset, $count); + } + + /** + * Rewinds the the data source to the first record. + * Use this method with the readRecords() method. + */ + public function reset() + { + $this->offset = 0; + } + + /** + * Returns a set of records from the data source. + * @param integer $count Specifies the number of records to return. + * @return array Returns the records. + * If there are no more records, returns an empty array. + */ + public function readRecords($count = 10) + { + $result = $this->getRecords($this->offset, $count); + $this->offset += count($result); + + return $result; + } +} diff --git a/modules/backend/widgets/table/README.md b/modules/backend/widgets/table/README.md new file mode 100644 index 0000000..d823aa4 --- /dev/null +++ b/modules/backend/widgets/table/README.md @@ -0,0 +1,412 @@ +# Client-side table widget (table.xxx.js) + +## Code organization + +### OOP pattern + +The data source and cell processor JavaScript classes use the simple parasitic combination inheritance pattern described here: + +- http://javascriptissexy.com/oop-in-javascript-what-you-need-to-know/ +- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript + + // Parent class with a method + var SuperClass = function(params) {} + SuperClass.prototype.someMethod = function() {} + + // Child class + var SubClass = function(params) { + // Call the parent constructor + SuperClass.call(this, params) + } + + SubClass.prototype = Object.create(SuperClass.prototype) + SubClass.prototype.constructor = SubClass + + // Child class methods can be defined only after the prototype + // is updated in the two previous lines + + SubClass.prototype.someMethod = function() { + // Call the parent method + SuperClass.prototype.someMethod.call(this) + }; + +### Namespaces + +All classes for the table widget are be defined in the **$.oc.table** namespace. There are several namespaces in this namespace: + +- **$.oc.table.processor** - cell processors +- **$.oc.table.datasource** - data sources +- **$.oc.table.helper** - helper classes +- **$.oc.table.validator** - validation classes + +### Client-side performance and memory usage considerations + +The classes defined for the Table widget should follow the best practices in order to achieve the high performance and avoid memory leaks: + +* All references to JavaScript objects and DOM elements should be cleared with the `dispose()` methods. +* All event handlers registered in the control should be unregistered with the `dispose()` method. +* DOM manipulations should only be performed in the detached tree with the `DocumentFragment` objects. +* The number of registered event handlers should be kept as low as possible. Cell processors should rely to delegated events registered for the table. +* Cell processors should have the `dispose()` method that unregisters the event handlers and does all required cleanup actions. +* Do not use closures for event handlers. This gives more control over the variable scope and simplifies the cleanup operations. +* If closures are used for anything, use named closures to simplify the profiling process with Chrome dev tools. + +There are several articles that provide a good insight into the high performance JavaScript code and efficient memory management: + +* http://www.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/ +* http://www.toptal.com/javascript/javascript-prototypes-scopes-and-performance-what-you-need-to-know +* http://developer.nokia.com/community/wiki/JavaScript_Performance_Best_Practices (the suggestion about the code comments is doubtful as JS engines compile code now). + +## Widget usage + +Any `DIV` elements that have the `data-control="table"` attributes are automatically picked up by the control. + +``` +
    +``` + +### Options + +The options below are listed in the JavaScript notation. Corresponding data attributes would look like `data-client-data-source-class`. + +- `clientDataSourceСlass` (default is **client**)- specifies the client-side data source class. There are two data source classes supported on the client side - **client** and **server**. +- `data` - specifies the data in JSON format for the **client**. +- `recordsPerPage` - specifies how many records per page to display. If the value is not defined or `false` or `null`, the pagination feature is disabled and all records are displayed. Pagination and `rowSorting` cannot be used in the same time. +- `columns` - column definitions in JSON format, see the server-side column definition format below. +- `rowSorting` - enables the drag & drop row sorting. The sorting cannot be used with the pagination (`recordsPerPage` is not `null` or `false`). +- `keyColumn` - specifies the name of the key column. The default value is **id**. +- `postback` - post the client-memory data source data to the server automatically when the parent form gets submitted. The default value is `true`. The option is used only with client-memory data sources. When enabled, the data source data is available in the widget's server-side data source: `$table->getDataSource()->getRecords();` The data postback occurs only of the request handler name matches the `postbackHandlerName` option value. +- `postbackHandlerName` - AJAX data handler name for the automatic data postback. The data will be posted only when the AJAX request posts data matching this handler name. The default value is **onSave**. +- `adding` - determines whether users can add new records. Default value is **true**. +- `deleting` - determines whether users can delete records. Default value is **true**. +- `toolbar` - determines whether the toolbar is visible. The default value is **true**. +- `height` - specifies the maximum height of the data table (not including the header, toolbar and pagination). If the table contains more rows than the height could fit, the data table becomes scrollable. The default value is **false** (height is not limited). + +## Client-side helper classes + +Some auxiliary code is factored out from the table class to helper classes. The helper classes are defined in the **$.oc.table.helper** namespace. + +- **table.helper.navigation.js** - implements the keyboard navigation within the table and pagination. + +## Data sources ($.oc.table.datasource) + +### Adding and removing records + +Adding and removing records is an asynchronous process that involves updating records in the dataset. + +When a user adds a record, the table object calls the `addRecord(data, offset, count, onSuccess)` method of the data source. The data source adds an empty record to the underlying data set and calls the `onSuccess` callback parameter passed to the method. In the `onSuccess` handler the table object rebuilds the table and focuses a field in the new row. + +When user deletes a record, the table object calls the `deleteRecord(index, offset, count, onSuccess)` method of the data source. The data source removes the record from the underlying dataset and calls the `onSuccess` callback parameter, passing records of the current page (determined with the `offset` and `count` parameters) to the callback. + +The `onSuccess` callback parameters are: data (records), count. + +### Client memory data source ($.oc.table.datasource.client) + +The client memory data sources keeps the data in the client memory. The data is loaded from the control element's `data` property (`data-data` attribute) and posted back with the form data. + +### Server memory data source ($.oc.table.datasource.server) + +**TODO:** document this + +## Cell processors ($.oc.table.processor) + +Cell processors are responsible for rendering the cell content, creating the cell data editors and updating the cell value in the grid control. There is a single cell processor per the table column. All rows in a specific column are handled with a same cell processor. + +Cell processors should use the table's `setCellValue()` method to update the value in the table. The table class, in turn, will commit the changes to the data source when the user navigates to another row, on the pagination event, search or form submit. The `setCellValue()` should be the only way to update the table data by cell processors. + +Cell processors should register delegated events to detect user's interaction with the cells they responsible for. The processors should unregister any event handlers in the `dispose()` method. The even handlers should be registered for the widgwet's top element, not for the table, as the table could be rebuilt completely on pagination, search, and other cases. The `click` and `keydown` events are dispatched to cell processors by the table class automatically and don't require extra handlers. + +### Removing editors from the table + +The table keeps a reference to the currently active cell processor. The cell processor objects have the `activeCell` property that is a reference to the cell which currently has an editor. The table calls the `hideEditor()` method of the active cell processor and the cell processor removes the editor from the active cell. + +### Showing editors + +The table object calls the `onFocus()` method of the cell processors when a cell is clicked or navigated (with the keyboard). The cell processor can build a cell editor when this method is called, if it's required. + +### Drop-down cell processor + +The drop-down column type can load options from the column configuration or with AJAX. Example column configuration: + + color: + title: Color + type: dropdown + options: + red: Red + green: Green + blue: Blue + width: 15% + +If the `options` element is not presented in the configuration, the options will be loaded with AJAX. + +**TODO:** Document the AJAX interface + +The drop-down options could depend on other columns. This works only with AJAX-based drop-downs. The column a drop-down depends on are defined with the `dependsOn` property: + + state: + title: State + type: dropdown + dependsOn: country + +Multiple fields are allowed as well: + + state: + title: State + type: dropdown + dependsOn: [country, language] + +**Note:** Dependent drop-down should always be defined after their master columns. + +### Autocomplete cell processor + +The autocomplete column type can load options from the column configuration or with AJAX. Example column configuration: + + color: + title: Color + type: autocomplete + options: + red: Red + green: Green + blue: Blue + +If the `options` element is not presented in the configuration, the options will be loaded with AJAX. + +**TODO:** Document the AJAX interface + +The editor can have the `dependsOn` property similar to the drop-down editor. + +# Server-side table widget (Backend\Widgets\Table) + +## Configuration + +The widget is configured with YAML file. Required parameters: + +* `columns` - the columns definitions, see below. +* `dataSource` - The data source class. Should specify the full qualified data source class name or alias. See the data source aliases below. +* `keyFrom` - name of the key column. The default value is **id**. +* `recordsPerPage` - number of records per page. If not specified, the pagination will be disabled. +* `postbackHandlerName` - AJAX data handler name for the automatic data postback. The data will be posted only when the AJAX requests posts data to this handler. The default value is **onSave**. This parameter is applicable only with client-memory data sources. +* `adding` - indicates if record deleting is allowed, default is **true**. +* `deleting` - indicates if record deleting is allowed, default is **true**. +* `toolbar` - specifies if the toolbar should be visible, default is **true**. +* `height` - specifies the data table height, in pixels. The default value is **false** - the height is not limited. +* `dynamicHeight` - determines if the `height` parameter should work as a max height. When this option is enabled and the table height is less than the `height` value, it won't be scrollable. + +The `dataSource` parameter can take aliases for some data source classes for the simpler configuration syntax. Known aliases are: + +* `client` = \Backend\Widgets\Table\ClientMemoryDataSource + +### Column definitions + +Columns are defined as array with the `columns` property. The array keys correspond the column identifiers. The array elements are associative arrays with the following keys: + +- `title` +- `type` (string, checkbox, dropdown, autocomplete) +- `width` - sets the column width, can be specified in percents (10%) or pixels (50px). There could be a single column without width specified, it will be stretched to take the available space. +- `readOnly` - prevents the cell value from being modified. Default: false. +- `options` (for drop-down elements and autocomplete types) +- `dependsOn` (from drop-down elements) +- validation - defines the column client-side validation rules. See the **Client-side validation** section below. + +## Events + +### table.getDropdownOptions + +table.getDropdownOptions - triggered when drop-down options are requested by the client. Parameters: + +- `$columnName` - specifies the drop-down column name. +- `$rowData` - an array containing values of all columns in the table row. + +Example event handler: + +``` +$table->bindEvent('table.getDropdownOptions', + function ($columnName, $rowData) { + if ($columnName == 'state') + return ['ca'=>'California', 'wa'=>'Washington']; + ... + } +); +``` + +## Initializing the data + +After the table widget is created, its data source optionally could be filled with records. Example code: + +``` +$table = new Table($this, $config); +$dataSource = $table->getDataSource(); + +$records = [ + ['id'=>1, 'first_name'=>'John', 'last_name'=>'Smith'], + ['id'=>2, 'last_name'=>'John', 'last_name'=>'Doe'] +]; + +$dataSource->initRecords($records); +``` + +Note that initializing records in the data source is required only once, when the widget object is first created and not required on the subsequent AJAX calls. + +The `initRecords()` method can be called multiple times. Each call adds records to the data source and doesn't replace the existing records. + +## Emptying the data source + +The `purge` method removes all records from the data source. This method should always be used with server memory data sources. Nonetheless, server side data sources should take care about providing the automatic ways of cleaning data with using the time-to-live mechanisms. + +``` +$table = new Table($this, $config); +$dataSource = $table->getDataSource(); +$dataSource->purge(); +``` + + +## Reading data from the data source + +The server-side data sources (PHP) automatically maintain the actual data, but that mechanism for the client-memory and server-memory data sources is different. + +In case of the client-memory data source, the table widget adds the data records to the POST, when the form is saved using the AJAX Framework (see `postback` and `postbackHandlerName` options). The table data will be injected automatically to the AJAX request when the `postback` value is `true` and the `postbackHandlerName` matches the exact handler name of the request. On the server side the data is inserted to the data source and can be accessed using the PHP example below. + +The server-memory data source always automatically maintain its contents in synch with the client using AJAX, and POSTing data is not required. + +In PHP reading data from a data source of any type looks like this (it should be in the AJAX handler that saves the data, for the client-memory data source the handler name should match the `postbackHandlerName` option value): + +``` +public function onSave() +{ + // Assuming that the widget was initialized in the + // controller constructor with the "table" alias. + $dataSource = $this->widget->table->getDataSource(); + + while ($records = $dataSource->readRecords(5)) { + traceLog($records); + } +``` + + +## Validation + +There are two ways to validate the table data - with the client-side and server-side validation. + +### Client-side validation ($.oc.table.validator) + +The client-side validation is performed before the data is sent to the server, or before the user navigates to another page (if the pagination is enabled). Client-side validation is a fast, but simple validation implementation. It can't be used for complex cases like finding duplicating records, or comparing data with records existing in the database. + +The client-side validation is configured in the widget configuration file in the column definition with the `validation` key. Example: + + state: + title: State + type: dropdown + validation: + required: + message: Please select the state + requiredWith: country + +If a validator doesn't have any options (or default option values should be used), the declaration could look like this: + + state: + title: State + type: dropdown + validation: + required: {} + +The `requiredWith` and `message` parameters are common for all validators. + +Currently implemented client-side validation rules: + +- required +- integer +- float +- length +- regex + +Validation rules can be configured with extra parameters, which depend on a specific validator. + +#### required validator ($.oc.table.validator.required) + +Checks if the user has provided a value for the cell. + +#### integer validator ($.oc.table.validator.integer) + +Checks if the value is integer. Parameters: + +* `allowNegative` - optional, determines if negative values are allowed. +* `min` - optional object, defines the minimum allowed value and error message. Object fields: + * `value` - defines the minimum value. + * `message` - optional, defines the error message. +* `max` - optional object, defines the maximum allowed value and error message. Object fields: + * `value` - defines the maximum value. + * `message` - optional, defines the error message. + +Example of defining the integer validator with the `min` parameter: + + length: + title: Length + type: string + validation: + integer: + min: + value: 3 + message: "The length cannot be less than 3" + +#### float validator ($.oc.table.validator.float) + +Checks if the value is a floating point number. The parameters for this validator match the parameters of the **integer** validator. + +Valid floating point number formats: + +* 10 +* 10.302 +* -10 (if `allowNegative` is `true`) +* -10.84 (if `allowNegative` is `true`) + +#### length validator ($.oc.table.validator.length) + +Checks if a string is not shorter or longer than specified values. Parameters: + +* `min` - optional object, defines the minimum length and error message. Object fields: + * `value` - defines the minimum length. + * `message` - optional, defines the error message. +* `max` - optional object, defines the maximum length and error message. Object fields: + * `value` - defines the maximum length. + * `message` - optional, defines the error message. + +Example column definition: + + name: + title: Name + type: string + validation: + length: + min: + value: 3 + message: "The name is too short." + +#### regex validator ($.oc.table.validator.regex) + +Checks a string against a provided regular expression: + +* `pattern` - specifies the regular expression pattern string. Example: **^[0-9a-z]+$** +* `modifiers` - optional, a string containing regular expression modifiers (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/RegExp), for example **i** for "case insensitive". + +Example: + + login: + title: Login + type: string + validation: + regex: + pattern: "^[a-z0-9]+$" + modifiers: "i" + message: "The login name can contain only Latin letters and numbers." + +Although the `message` parameter is optional for all validators it's highly recommended to provide a message for the regular expression validator as the default message "Invalid value format." is not descriptive and can be confusing. + +### Server-side validation + +TODO: document. + +Draft. In case of a validation error the AJAX response should contain the following information: + +- row key +- row offset in the data set +- error message \ No newline at end of file diff --git a/modules/backend/widgets/table/ServerEventDataSource.php b/modules/backend/widgets/table/ServerEventDataSource.php new file mode 100644 index 0000000..cfc4006 --- /dev/null +++ b/modules/backend/widgets/table/ServerEventDataSource.php @@ -0,0 +1,91 @@ +fireEvent('data.getRecords', [$offset, $count], true); + } + + /** + * Identical to getRecords except provided with a search query. + */ + public function searchRecords($query, $offset, $count) + { + return $this->fireEvent('data.searchRecords', [$query, $offset, $count], true); + } + + /** + * Returns a total number of records in the data source. + * @return integer + */ + public function getCount() + { + return $this->fireEvent('data.getCount', [], true); + } + + /** + * Updates a record in the data source. + * @return void + */ + public function createRecord($data, $placement, $relativeToKey) + { + return $this->fireEvent('data.createRecord', [$data, $placement, $relativeToKey]); + } + + /** + * Updates a record in the data source. + * @return void + */ + public function updateRecord($key, $data) + { + $this->fireEvent('data.updateRecord', [$key, $data]); + } + + /** + * Removes a record from the data source. + * @return array Returns the remaining records. + */ + public function deleteRecord($key) + { + return $this->fireEvent('data.deleteRecord', [$key], true); + } + + /** + * Initializes records in the data source. + * The method doesn't replace existing records and + * could be called multiple times in order to fill + * the data source. + * @param array $records Records to initialize in the data source. + */ + public function initRecords($records) + { + } + + /** + * Removes all records from the data source. + */ + public function purge() + { + } + + /** + * Returns all records in the data source. + * This method is specific only for the client memory data sources. + */ + public function getAllRecords() + { + } +} diff --git a/modules/backend/widgets/table/assets/css/table.css b/modules/backend/widgets/table/assets/css/table.css new file mode 100644 index 0000000..ebc7b2b --- /dev/null +++ b/modules/backend/widgets/table/assets/css/table.css @@ -0,0 +1,401 @@ +/* + * General control styling + */ +.control-table .table-container { + border: 1px solid #e0e0e0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + overflow: hidden; + margin-bottom: 15px; +} +.control-table .table-container:last-child { + margin-bottom: 0; +} +.control-table.active .table-container { + border-color: #e0e0e0; +} +.control-table table { + width: 100%; + border-collapse: collapse; + table-layout: fixed; +} +.control-table table td, +.control-table table th { + padding: 0; + font-size: 13px; + color: #555555; +} +.control-table table [data-view-container] { + padding: 5px 10px; + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + min-height: 28px; +} +.control-table table.headers:after { + content: ' '; + display: block; + position: absolute; + left: 1px; + right: 1px; + margin-top: -1px; + border-bottom: 1px solid #e0e0e0; +} +.control-table table.headers th { + padding: 7px 10px; + font-weight: normal; + text-transform: uppercase; + font-size: 11px; + color: #333333; + background: white; + border-right: 1px solid #ecf0f1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.control-table table.headers th [data-view-container] { + padding-bottom: 6px; +} +.control-table table.headers th:last-child { + border-right: none; +} +.control-table.active table.headers:after { + border-bottom-color: #e0e0e0; +} +.control-table table.data td { + border: 1px solid #ecf0f1; +} +.control-table table.data td .content-container { + position: relative; + padding: 1px; +} +.control-table table.data td.active { + border-color: #34495e !important; +} +.control-table table.data td.active .content-container { + padding: 0; + border: 1px solid #34495e; +} +.control-table table.data td.active .content-container:before, +.control-table table.data td.active .content-container:after { + content: ' '; + background: #34495e; + position: absolute; + left: -2px; + top: -2px; +} +.control-table table.data td.active .content-container:before { + width: 1px; + bottom: -2px; +} +.control-table table.data td.active .content-container:after { + right: -2px; + height: 1px; +} +.control-table table.data tr { + background-color: white; +} +.control-table table.data tr.error { + background-color: #fbecec!important; +} +.control-table table.data tr.error td.active.error { + border-color: #ec0000!important; +} +.control-table table.data tr.error td.active.error .content-container { + border-color: #ec0000!important; +} +.control-table table.data tr.error td.active.error .content-container:before, +.control-table table.data tr.error td.active.error .content-container:after { + background-color: #ec0000!important; +} +.control-table table.data tr:nth-child(2n) { + background-color: #fbfbfb; +} +.control-table table.data tr:first-child td { + border-top: none; +} +.control-table table.data tr:last-child td { + border-bottom: none; +} +.control-table table.data td:first-child { + border-left: none; +} +.control-table table.data td:last-child { + border-right: none; +} +.control-table .control-scrollbar > div { + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + overflow: hidden; +} +.control-table .control-scrollbar table.data tr:last-child td { + border-bottom: 1px solid #ecf0f1; +} +.control-table .toolbar { + background: white; + border-bottom: 1px solid #e0e0e0; +} +.control-table .toolbar a.btn { + color: #323e50; + padding: 8px 10px; + opacity: 0.5; + filter: alpha(opacity=50); + -webkit-box-shadow: none !important; + box-shadow: none !important; + text-shadow: none; +} +.control-table .toolbar a.btn:hover { + opacity: 1; + filter: alpha(opacity=100); +} +.control-table .toolbar .table-search { + float: right; + margin: 3px 3px 0 0; +} +.control-table .toolbar .table-search .table-search-input { + height: auto; + padding: 5px 13px 5px; +} +.control-table .toolbar a.table-icon:before { + display: inline-block; + content: ' '; + width: 16px; + height: 16px; + margin-right: 8px; + position: relative; + top: 3px; + background: transparent url(../images/table-icons.gif) no-repeat 0 0; + background-size: 32px auto; +} +.control-table .toolbar a.table-icon.add-table-row-above:before { + background-position: 0 -56px; +} +.control-table .toolbar a.table-icon.delete-table-row:before { + background-position: 0 -113px; +} +.control-table.active .toolbar { + border-bottom-color: #e0e0e0; +} +.control-table .pagination ul { + padding: 0; + margin-bottom: 15px; +} +.control-table .pagination ul li { + list-style: none; + padding: 4px 6px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + display: inline-block; + margin-right: 5px; + font-size: 12px; + background: #ecf0f1; + line-height: 100%; +} +.control-table .pagination ul li a { + text-decoration: none; + color: #95a5a6; +} +.control-table .pagination ul li.active { + background: #3498db; +} +.control-table .pagination ul li.active a { + color: #ffffff; +} +@media only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-devicepixel-ratio: 1.5), only screen and (min-resolution: 1.5dppx) { + .control-table .toolbar a:before { + background-position: 0px -9px; + background-size: 16px auto; + } + .control-table .toolbar a.add-table-row-above:before { + background-position: 0 -39px; + } + .control-table .toolbar a.delete-table-row:before { + background-position: 0 -66px; + } +} +/* + * String and autocomplete editors + */ +.control-table td[data-column-type=string] input[type=text], +.control-table td[data-column-type=autocomplete] input[type=text] { + width: 100%; + height: 100%; + display: block; + outline: none; + border: none; + padding: 6px 10px 7px; +} +html.chrome .control-table td[data-column-type=string] input[type=text], +html.chrome .control-table td[data-column-type=autocomplete] input[type=text] { + padding: 6px 10px 7px!important; +} +html.safari .control-table td[data-column-type=string] input[type=text], +html.gecko .control-table td[data-column-type=string] input[type=text], +html.safari .control-table td[data-column-type=autocomplete] input[type=text], +html.gecko .control-table td[data-column-type=autocomplete] input[type=text] { + padding: 5px 10px 5px; +} +ul.table-widget-autocomplete { + background: white; + font-size: 13px; + margin-top: 0; + border: 1px solid #808c8d; + border-top: 1px solid #ecf0f1; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +ul.table-widget-autocomplete li a { + padding: 5px 10px; +} +/* + * Checkbox editor + */ +.control-table td[data-column-type=checkbox] div[data-checkbox-element] { + width: 16px; + height: 16px; + border-radius: 3px; + background-color: #FFFFFF; + border: 1px solid #999999; + margin: 5px 5px 5px 10px; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.control-table td[data-column-type=checkbox] div[data-checkbox-element]:hover { + border-color: #808080; + color: #4d4d4d; +} +.control-table td[data-column-type=checkbox] div[data-checkbox-element].checked { + border-width: 2px; +} +.control-table td[data-column-type=checkbox] div[data-checkbox-element].checked:before { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; + content: "\f00c"; + font-size: 10px; + position: relative; + left: 1px; + top: -4px; +} +.control-table td[data-column-type=checkbox] div[data-checkbox-element]:focus { + border-color: #34495e; + outline: none; +} +/* + * Dropdown editor + */ +.control-table td[data-column-type=dropdown] { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.control-table td[data-column-type=dropdown] [data-view-container] { + padding-right: 20px; + position: relative; + cursor: pointer; +} +.control-table td[data-column-type=dropdown] [data-view-container]:after { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; + content: "\f107"; + font-size: 13px; + line-height: 100%; + color: #95a5a6; + position: absolute; + top: 8px; + right: 10px; +} +.control-table td[data-column-type=dropdown] [data-view-container]:hover:after { + color: #0181b9; +} +.control-table td[data-column-type=dropdown] [data-dropdown-open=true] { + background: white; +} +.control-table td[data-column-type=dropdown] [data-dropdown-open=true] [data-view-container]:after { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; + content: "\f106"; +} +.control-table td[data-column-type=dropdown] .content-container { + outline: none; +} +/* Frameless control styles start */ +.widget-field.frameless .control-table .table-container { + border-top: none; + border-left: none; + border-right: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.widget-field.frameless .control-table .toolbar { + background: transparent; +} +/* Frameless control styles end */ +html.cssanimations .control-table td[data-column-type=dropdown] [data-view-container].loading:after { + background: url('../../../../../../modules/system/assets/ui/images/loader-transparent.svg') 50% 50%; + background-size: 15px 15px; + position: absolute; + width: 15px; + height: 15px; + top: 6px; + right: 5px; + content: ' '; + -webkit-animation: spin 1s linear infinite; + animation: spin 1s linear infinite; +} +.table-control-dropdown-list { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: absolute; + background: white; + border: 1px solid #e0e0e0; + border-top: none; + padding-top: 1px; + overflow: hidden; + z-index: 1000; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +.table-control-dropdown-list ul { + border-top: 1px solid #ecf0f1; + padding: 0; + margin: 0; + max-height: 200px; + overflow: auto; +} +.table-control-dropdown-list li { + list-style: none; + font-size: 13px; + color: #555555; + padding: 5px 10px; + cursor: pointer; + outline: none; +} +.table-control-dropdown-list li:focus { + background: #34495e; + color: white; +} diff --git a/modules/backend/widgets/table/assets/images/table-icons.gif b/modules/backend/widgets/table/assets/images/table-icons.gif new file mode 100644 index 0000000..fee3716 Binary files /dev/null and b/modules/backend/widgets/table/assets/images/table-icons.gif differ diff --git a/modules/backend/widgets/table/assets/js/build-min.js b/modules/backend/widgets/table/assets/js/build-min.js new file mode 100644 index 0000000..45068e7 --- /dev/null +++ b/modules/backend/widgets/table/assets/js/build-min.js @@ -0,0 +1,1083 @@ + ++function($){"use strict";if($.oc===undefined) +$.oc={} +if($.oc.table===undefined) +$.oc.table={} +var Table=function(element,options){this.el=element +this.$el=$(element) +this.options=options +this.disposed=false +this.dataSource=null +this.cellProcessors={} +this.activeCellProcessor=null +this.activeCell=null +this.tableContainer=null +this.dataTableContainer=null +this.editedRowKey=null +this.dataTable=null +this.headerTable=null +this.toolbar=null +this.clickHandler=this.onClick.bind(this) +this.keydownHandler=this.onKeydown.bind(this) +this.documentClickHandler=this.onDocumentClick.bind(this) +this.toolbarClickHandler=this.onToolbarClick.bind(this) +if(this.options.postback&&this.options.clientDataSourceClass=='client'){if(!this.options.postbackHandlerName){var formHandler=this.$el.closest('form').data('request') +this.options.postbackHandlerName=formHandler||'onSave'} +this.formSubmitHandler=this.onFormSubmit.bind(this)} +this.navigation=null +this.search=null +this.recordsAddedOrDeleted=0 +this.disposeBound=this.dispose.bind(this) +this.init() +$.oc.foundation.controlUtils.markDisposable(element)} +Table.prototype.init=function(){this.createDataSource() +this.initCellProcessors() +this.navigation=new $.oc.table.helper.navigation(this) +this.search=new $.oc.table.helper.search(this) +this.buildUi() +this.registerHandlers()} +Table.prototype.disposeCellProcessors=function(){for(var i=0,len=this.options.columns.length;i-1?this.options.fieldName+'[TableData]':this.options.fieldName+'TableData' +data.options.data[fieldName]=this.dataSource.getAllData()}} +Table.prototype.onToolbarClick=function(ev){var target=this.getEventTarget(ev),cmd=target.getAttribute('data-cmd') +if(!cmd){return} +switch(cmd){case'record-add':case'record-add-below':this.addRecord('below') +break +case'record-add-above':this.addRecord('above') +break +case'record-delete':this.deleteRecord() +break} +this.stopEvent(ev)} +Table.prototype.onDocumentClick=function(ev){var target=this.getEventTarget(ev) +if(this.parentContainsElement(this.el,target)) +return +if(this.activeCellProcessor&&this.activeCellProcessor.elementBelongsToProcessor(target)) +return +this.unfocusTable()} +Table.prototype.dispose=function(){if(this.disposed){return} +this.disposed=true +this.disposeBound=true +this.unfocusTable() +this.dataSource.dispose() +this.dataSource=null +this.unregisterHandlers() +this.dataTable=null +this.headerTable=null +this.toolbar=null +this.disposeCellProcessors() +this.navigation.dispose() +this.navigation=null +this.disposeScrollbar() +this.el=null +this.tableContainer=null +this.$el=null +this.dataTableContainer=null +this.activeCell=null} +Table.prototype.setRowValues=function(rowIndex,rowValues){var row=this.findRowByIndex(rowIndex) +if(!row){return false} +var dataUpdated=false +for(var i=0,len=row.children.length;i0){var self=this +this.gotoPage(this.pageIndex-1,function navUpPageSuccess(){self.focusCell('bottom',cellIndex) +self=null})}}} +Navigation.prototype.navigateLeft=function(ev,isTab){if(!this.tableObj.activeCell) +return +if(!isTab&&this.tableObj.activeCellProcessor&&!this.tableObj.activeCellProcessor.keyNavigationAllowed(ev,'left')) +return +var row=this.tableObj.activeCell.parentNode,newIndex=(!ev.shiftKey||isTab)?this.tableObj.activeCell.cellIndex-1:0 +var cell=row.children[newIndex] +if(cell){this.tableObj.focusCell(cell)} +else{this.navigateUp(ev,row.children.length-1,isTab)}} +Navigation.prototype.navigateRight=function(ev,isTab){if(!this.tableObj.activeCell) +return +if(!isTab&&this.tableObj.activeCellProcessor&&!this.tableObj.activeCellProcessor.keyNavigationAllowed(ev,'right')) +return +var row=this.tableObj.activeCell.parentNode,newIndex=!ev.shiftKey?this.tableObj.activeCell.cellIndex+1:row.children.length-1 +var cell=row.children[newIndex] +if(cell){this.tableObj.focusCell(cell)} +else{this.navigateDown(ev,0)}} +Navigation.prototype.navigateNext=function(ev){if(!this.tableObj.activeCell) +return +if(this.tableObj.activeCellProcessor&&!this.tableObj.activeCellProcessor.keyNavigationAllowed(ev,'tab')) +return +if(!ev.shiftKey) +this.navigateRight(ev,true) +else +this.navigateLeft(ev,true) +this.tableObj.stopEvent(ev)} +Navigation.prototype.focusCell=function(rowReference,cellIndex){var row=null,tbody=this.tableObj.getDataTableBody() +if(typeof rowReference==='object'){row=rowReference} +else{if(rowReference=='bottom'){row=tbody.children[tbody.children.length-1]} +else if(rowReference=='top'){row=tbody.children[0]}} +if(!row) +return +var cell=row.children[cellIndex] +if(cell) +this.tableObj.focusCell(cell)} +Navigation.prototype.focusCellInReplacedRow=function(rowIndex,cellIndex){if(rowIndex==0){this.focusCell('top',cellIndex)} +else{var focusRow=this.tableObj.findRowByIndex(rowIndex) +if(!focusRow) +focusRow=this.tableObj.findRowByIndex(rowIndex-1) +if(focusRow) +this.focusCell(focusRow,cellIndex) +else +this.focusCell('top',cellIndex)}} +Navigation.prototype.onKeydown=function(ev){if(ev.key==='ArrowDown') +return this.navigateDown(ev) +else if(ev.key==='ArrowUp') +return this.navigateUp(ev) +else if(ev.key==='ArrowLeft') +return this.navigateLeft(ev) +if(ev.key==='ArrowRight') +return this.navigateRight(ev) +if(ev.key==='Tab') +return this.navigateNext(ev)} +Navigation.prototype.onClick=function(ev){var target=this.tableObj.getEventTarget(ev,'A') +if(!target||!$(target).hasClass('pagination-link')) +return +var pageIndex=parseInt(target.getAttribute('data-page-index')) +if(pageIndex===null) +return +this.gotoPage(pageIndex) +this.tableObj.stopEvent(ev) +return false} +$.oc.table.helper.navigation=Navigation;}(window.jQuery);+function($){"use strict";if($.oc.table===undefined) +throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded.");if($.oc.table.helper===undefined) +$.oc.table.helper={} +var Search=function(tableObj){this.tableObj=tableObj +this.searchForm=null +this.searchInput=null +this.inputTrackTimer=null +this.activeQuery=null +this.isActive=false +this.init()};Search.prototype.init=function(){} +Search.prototype.dispose=function(){this.tableObj=null +this.searchForm=null +this.searchInput=null} +Search.prototype.buildSearchForm=function(){if(!this.searchEnabled()) +return +var el=this.tableObj.getElement(),toolbar=this.tableObj.getToolbar(),searchForm=toolbar.querySelector('.table-search') +if(!searchForm){this.searchForm=$($('[data-table-toolbar-search]',el).html()).appendTo(toolbar).get(0) +this.searchInput=$('.table-search-input',this.searchForm).get(0)}} +Search.prototype.getQuery=function(){return $.trim(this.activeQuery)} +Search.prototype.hasQuery=function(){return this.searchEnabled()&&$.trim(this.activeQuery).length>0} +Search.prototype.searchEnabled=function(){return this.tableObj.options.searching} +Search.prototype.performSearch=function(query,onSuccess){var isDirty=this.activeQuery!=query +this.activeQuery=query +if(isDirty){this.tableObj.updateDataTable(onSuccess)}} +Search.prototype.onKeydown=function(ev){if(ev.key==='Tab'){this.onClick(ev) +return} +if(!this.isActive){return} +var self=this +this.inputTrackTimer=window.setTimeout(function(){self.performSearch(self.searchInput.value)},300)} +Search.prototype.onClick=function(ev){var target=this.tableObj.getEventTarget(ev,'INPUT') +this.isActive=target&&$(target).hasClass('table-search-input')} +$.oc.table.helper.search=Search;}(window.jQuery);+function($){"use strict";if($.oc.table===undefined) +throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded.");if($.oc.table.datasource===undefined) +$.oc.table.datasource={} +var Base=function(tableObj){this.tableObj=tableObj} +Base.prototype.dispose=function(){this.tableObj=null} +Base.prototype.getRecords=function(offset,count,onSuccess){onSuccess([])} +Base.prototype.searchRecords=function(query,offset,count,onSuccess){onSuccess([])} +Base.prototype.createRecord=function(recordData,placement,relativeToKey,offset,count,onSuccess){onSuccess([],0)} +Base.prototype.updateRecord=function(key,recordData){} +Base.prototype.deleteRecord=function(key,newRecordData,offset,count,onSuccess){onSuccess([],0)} +$.oc.table.datasource.base=Base;}(window.jQuery);+function($){"use strict";if($.oc.table===undefined) +throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded.");if($.oc.table.datasource===undefined) +throw new Error("The $.oc.table.datasource namespace is not defined. Make sure that the table.datasource.base.js script is loaded.");var Base=$.oc.table.datasource.base,BaseProto=Base.prototype +var Client=function(tableObj){Base.call(this,tableObj) +var dataString=tableObj.getElement().getAttribute('data-data') +if(dataString===null||dataString===undefined) +throw new Error('The required data-data attribute is not found on the table control element.') +this.data=JSON.parse(dataString)};Client.prototype=Object.create(BaseProto) +Client.prototype.constructor=Client +Client.prototype.dispose=function(){BaseProto.dispose.call(this) +this.data=null} +Client.prototype.getRecords=function(offset,count,onSuccess){if(!count){onSuccess(this.data,this.data.length)} +else{onSuccess(this.data.slice(offset,offset+count),this.data.length)}} +Client.prototype.createRecord=function(recordData,placement,relativeToKey,offset,count,onSuccess){if(placement==='bottom'){this.data.push(recordData)} +else if(placement=='above'||placement=='below'){var recordIndex=this.getIndexOfKey(relativeToKey) +if(placement=='below') +recordIndex++ +this.data.splice(recordIndex,0,recordData)} +this.getRecords(offset,count,onSuccess)} +Client.prototype.updateRecord=function(key,recordData){var recordIndex=this.getIndexOfKey(key) +if(recordIndex!==-1){recordData[this.tableObj.options.keyColumn]=key +this.data[recordIndex]=recordData} +else{throw new Error('Record with they key '+key+' is not found in the data set')}} +Client.prototype.deleteRecord=function(key,newRecordData,offset,count,onSuccess){var recordIndex=this.getIndexOfKey(key) +if(recordIndex!==-1){this.data.splice(recordIndex,1) +if(this.data.length==0) +this.data.push(newRecordData) +this.getRecords(offset,count,onSuccess)} +else{throw new Error('Record with they key '+key+' is not found in the data set')}} +Client.prototype.getIndexOfKey=function(key){var keyColumn=this.tableObj.options.keyColumn +return this.data.map(function(record){return record[keyColumn]+""}).indexOf(key+"")} +Client.prototype.getAllData=function(){return this.data} +$.oc.table.datasource.client=Client}(window.jQuery);+function($){"use strict";if($.oc.table===undefined) +throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded.");if($.oc.table.datasource===undefined) +throw new Error("The $.oc.table.datasource namespace is not defined. Make sure that the table.datasource.base.js script is loaded.");var Base=$.oc.table.datasource.base,BaseProto=Base.prototype +var Server=function(tableObj){Base.call(this,tableObj) +var dataString=tableObj.getElement().getAttribute('data-data') +if(dataString===null||dataString===undefined) +throw new Error('The required data-data attribute is not found on the table control element.') +this.data=JSON.parse(dataString)};Server.prototype=Object.create(BaseProto) +Server.prototype.constructor=Server +Server.prototype.dispose=function(){BaseProto.dispose.call(this) +this.data=null} +Server.prototype.getRecords=function(offset,count,onSuccess){var handlerName=this.tableObj.getAlias()+'::onServerGetRecords' +this.tableObj.$el.request(handlerName,{data:{offset:offset,count:count}}).done(function(data){onSuccess(data.records,data.count)})} +Server.prototype.searchRecords=function(query,offset,count,onSuccess){var handlerName=this.tableObj.getAlias()+'::onServerSearchRecords' +this.tableObj.$el.request(handlerName,{data:{query:query,offset:offset,count:count}}).done(function(data){onSuccess(data.records,data.count)})} +Server.prototype.createRecord=function(recordData,placement,relativeToKey,offset,count,onSuccess){var handlerName=this.tableObj.getAlias()+'::onServerCreateRecord' +this.tableObj.$el.request(handlerName,{data:{recordData:recordData,placement:placement,relativeToKey:relativeToKey,offset:offset,count:count}}).done(function(data){onSuccess(data.records,data.count)})} +Server.prototype.updateRecord=function(key,recordData){var handlerName=this.tableObj.getAlias()+'::onServerUpdateRecord' +this.tableObj.$el.request(handlerName,{data:{key:key,recordData:recordData}})} +Server.prototype.deleteRecord=function(key,newRecordData,offset,count,onSuccess){var handlerName=this.tableObj.getAlias()+'::onServerDeleteRecord' +this.tableObj.$el.request(handlerName,{data:{key:key,offset:offset,count:count}}).done(function(data){onSuccess(data.records,data.count)})} +$.oc.table.datasource.server=Server}(window.jQuery);+function($){"use strict";if($.oc.table===undefined) +throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded.");if($.oc.table.processor===undefined) +$.oc.table.processor={} +var Base=function(tableObj,columnName,columnConfiguration){this.tableObj=tableObj +this.columnName=columnName +this.columnConfiguration=columnConfiguration +this.activeCell=null +this.validators=[] +this.registerHandlers() +this.initValidators()} +Base.prototype.dispose=function(){this.unregisterHandlers() +this.tableObj=null +this.activeCell=null} +Base.prototype.renderCell=function(value,cellContentContainer){} +Base.prototype.registerHandlers=function(){} +Base.prototype.unregisterHandlers=function(){} +Base.prototype.onFocus=function(cellElement,isClick){} +Base.prototype.onUnfocus=function(){} +Base.prototype.onKeyDown=function(ev){} +Base.prototype.onClick=function(ev){} +Base.prototype.onRowValueChanged=function(columnName,cellElement){} +Base.prototype.keyNavigationAllowed=function(ev,direction){return true} +Base.prototype.isCellFocusable=function(){return true} +Base.prototype.getCellContentContainer=function(cellElement){return cellElement.querySelector('.content-container')} +Base.prototype.createViewContainer=function(cellContentContainer,value){var viewContainer=document.createElement('div') +viewContainer.setAttribute('data-view-container','data-view-container') +viewContainer.textContent=value===undefined?'':value +cellContentContainer.appendChild(viewContainer) +return viewContainer} +Base.prototype.getViewContainer=function(cellElement){return cellElement.querySelector('[data-view-container]')} +Base.prototype.showViewContainer=function(cellElement){return this.getViewContainer(cellElement).setAttribute('class','')} +Base.prototype.hideViewContainer=function(cellElement){return this.getViewContainer(cellElement).setAttribute('class','hide')} +Base.prototype.setViewContainerValue=function(cellElement,value){return this.getViewContainer(cellElement).textContent=value} +Base.prototype.elementBelongsToProcessor=function(element){return false} +Base.prototype.initValidators=function(){if(this.columnConfiguration.validation===undefined) +return +for(var validatorName in this.columnConfiguration.validation){if($.oc.table.validator===undefined||$.oc.table.validator[validatorName]==undefined) +throw new Error('The table cell validator "'+validatorName+'" for the column "'+this.columnName+'" is not '+'found in the $.oc.table.validator namespace.') +var validator=new $.oc.table.validator[validatorName](this.columnConfiguration.validation[validatorName]) +this.validators.push(validator)}} +Base.prototype.validate=function(value,rowData){for(var i=0,len=this.validators.length;i',bodyContainer:true})} +AutocompleteProcessor.prototype.prepareItems=function(items){var result={} +if($.isArray(items)){for(var i=0,len=items.length;i0} +$.oc.table.validator.base=Base;}(window.jQuery);+function($){"use strict";if($.oc.table===undefined) +throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded.");if($.oc.table.validator===undefined) +throw new Error("The $.oc.table.validator namespace is not defined. Make sure that the table.validator.base.js script is loaded.");var Base=$.oc.table.validator.base,BaseProto=Base.prototype +var Required=function(options){Base.call(this,options)};Required.prototype=Object.create(BaseProto) +Required.prototype.constructor=Required +Required.prototype.validateValue=function(value,rowData){value=this.trim(value) +if(value.length===0) +return this.getMessage("The value should not be empty.") +return} +$.oc.table.validator.required=Required}(window.jQuery);+function($){"use strict";if($.oc.table===undefined) +throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded.");if($.oc.table.validator===undefined) +throw new Error("The $.oc.table.validator namespace is not defined. Make sure that the table.validator.base.js script is loaded.");var Base=$.oc.table.validator.base,BaseProto=Base.prototype +var BaseNumber=function(options){Base.call(this,options)};BaseNumber.prototype=Object.create(BaseProto) +BaseNumber.prototype.constructor=BaseNumber +BaseNumber.prototype.doCommonChecks=function(value){if(this.options.min!==undefined||this.options.max!==undefined){if(this.options.min!==undefined){if(this.options.min.value===undefined) +throw new Error('The min.value parameter is not defined in the table validator configuration') +if(valuethis.options.max.value){return this.options.max.message!==undefined?this.options.max.message:"The value should not be more than "+this.options.max.value}}} +return} +$.oc.table.validator.baseNumber=BaseNumber}(window.jQuery);+function($){"use strict";if($.oc.table===undefined) +throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded.");if($.oc.table.validator===undefined) +throw new Error("The $.oc.table.validator namespace is not defined. Make sure that the table.validator.base.js script is loaded.");if($.oc.table.validator.baseNumber===undefined) +throw new Error("The $.oc.table.validator.baseNumber namespace is not defined. Make sure that the table.validator.baseNumber.js script is loaded.");var Base=$.oc.table.validator.baseNumber,BaseProto=Base.prototype +var Integer=function(options){Base.call(this,options)};Integer.prototype=Object.create(BaseProto) +Integer.prototype.constructor=Integer +Integer.prototype.validateValue=function(value,rowData){value=this.trim(value) +if(value.length==0) +return +var testResult=this.options.allowNegative?/^\-?[0-9]*$/.test(value):/^[0-9]*$/.test(value) +if(!testResult){var defaultMessage=this.options.allowNegative?'The value should be an integer.':'The value should be a positive integer';return this.getMessage(defaultMessage)} +return this.doCommonChecks(parseInt(value))} +$.oc.table.validator.integer=Integer}(window.jQuery);+function($){"use strict";if($.oc.table===undefined) +throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded.");if($.oc.table.validator===undefined) +throw new Error("The $.oc.table.validator namespace is not defined. Make sure that the table.validator.base.js script is loaded.");if($.oc.table.validator.baseNumber===undefined) +throw new Error("The $.oc.table.validator.baseNumber namespace is not defined. Make sure that the table.validator.baseNumber.js script is loaded.");var Base=$.oc.table.validator.baseNumber,BaseProto=Base.prototype +var Float=function(options){Base.call(this,options)};Float.prototype=Object.create(BaseProto) +Float.prototype.constructor=Float +Float.prototype.validateValue=function(value,rowData){value=this.trim(value) +if(value.length==0) +return +var testResult=this.options.allowNegative?/^[-]?([0-9]+\.[0-9]+|[0-9]+)$/.test(value):/^([0-9]+\.[0-9]+|[0-9]+)$/.test(value) +if(!testResult){var defaultMessage=this.options.allowNegative?'The value should be a floating point number.':'The value should be a positive floating point number';return this.getMessage(defaultMessage)} +return this.doCommonChecks(parseFloat(value))} +$.oc.table.validator.float=Float}(window.jQuery);+function($){"use strict";if($.oc.table===undefined) +throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded.");if($.oc.table.validator===undefined) +throw new Error("The $.oc.table.validator namespace is not defined. Make sure that the table.validator.base.js script is loaded.");var Base=$.oc.table.validator.base,BaseProto=Base.prototype +var Length=function(options){Base.call(this,options)};Length.prototype=Object.create(BaseProto) +Length.prototype.constructor=Length +Length.prototype.validateValue=function(value,rowData){value=this.trim(value) +if(value.length==0) +return +if(this.options.min!==undefined||this.options.max!==undefined){if(this.options.min!==undefined){if(this.options.min.value===undefined) +throw new Error('The min.value parameter is not defined in the Length table validator configuration') +if(value.lengththis.options.max.value){return this.options.max.message!==undefined?this.options.max.message:"The string should not be longer than "+this.options.max.value}}} +return} +$.oc.table.validator.length=Length}(window.jQuery);+function($){"use strict";if($.oc.table===undefined) +throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded.");if($.oc.table.validator===undefined) +throw new Error("The $.oc.table.validator namespace is not defined. Make sure that the table.validator.base.js script is loaded.");var Base=$.oc.table.validator.base,BaseProto=Base.prototype +var Regex=function(options){Base.call(this,options)};Regex.prototype=Object.create(BaseProto) +Regex.prototype.constructor=Regex +Regex.prototype.validateValue=function(value,rowData){value=this.trim(value) +if(value.length==0) +return +if(this.options.pattern===undefined) +throw new Error('The pattern parameter is not defined in the Regex table validator configuration') +var regexObj=new RegExp(this.options.pattern,this.options.modifiers) +if(!regexObj.test(value)) +return this.getMessage("Invalid value format.") +return} +$.oc.table.validator.regex=Regex}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/table/assets/js/build.js b/modules/backend/widgets/table/assets/js/build.js new file mode 100644 index 0000000..7e1638d --- /dev/null +++ b/modules/backend/widgets/table/assets/js/build.js @@ -0,0 +1,29 @@ +/* + * This is a bundle file, you can compile this in two ways: + * (1) Using your favorite JS combiner + * (2) Using CLI command: + * php artisan october:util compile assets + * + * @see build-min.js + * + +=require table.js +=require table.helper.navigation.js +=require table.helper.search.js +=require table.datasource.base.js +=require table.datasource.client.js +=require table.datasource.server.js +=require table.processor.base.js +=require table.processor.string.js +=require table.processor.checkbox.js +=require table.processor.dropdown.js +=require table.processor.autocomplete.js +=require table.validator.base.js +=require table.validator.required.js +=require table.validator.basenumber.js +=require table.validator.integer.js +=require table.validator.float.js +=require table.validator.length.js +=require table.validator.regex.js + +*/ diff --git a/modules/backend/widgets/table/assets/js/table.datasource.base.js b/modules/backend/widgets/table/assets/js/table.datasource.base.js new file mode 100644 index 0000000..07f1c02 --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.datasource.base.js @@ -0,0 +1,92 @@ +/* + * Base class for the table data sources. + */ ++function ($) { "use strict"; + + // DATASOURCE NAMESPACES + // ============================ + + if ($.oc.table === undefined) + throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded."); + + if ($.oc.table.datasource === undefined) + $.oc.table.datasource = {} + + // CLASS DEFINITION + // ============================ + + var Base = function(tableObj) { + // + // State properties + // + + this.tableObj = tableObj + } + + Base.prototype.dispose = function() { + this.tableObj = null + } + + /* + * Fetches records from the underlying data source and + * passes them to the onSuccess callback function. + * The onSuccess callback parameters: records, totalCount. + * Each record contains the key field which uniquely identifies + * the record. The name of the key field is defined with the table + * widget options. + */ + Base.prototype.getRecords = function(offset, count, onSuccess) { + onSuccess([]) + } + + /* + * Identical to getRecords except using a search query. + */ + Base.prototype.searchRecords = function(query, offset, count, onSuccess) { + onSuccess([]) + } + + /* + * Creates a record with the passed data and returns the updated page records + * to the onSuccess callback function. + * + * - recordData - the record fields + * - placement - "bottom" (the end of the data set), "above", "below" + * - relativeToKey - a row key, required if the placement is not "bottom" + * - offset - the current page's first record index (zero-based) + * - count - number of records to return + * - onSuccess - a callback function to execute when the updated data gets available. + * + * The onSuccess callback parameters: records, totalCount. + */ + Base.prototype.createRecord = function(recordData, placement, relativeToKey, offset, count, onSuccess) { + onSuccess([], 0) + } + + /* + * Updates a record with the specified key with the passed data + * + * - key - the record key in the dataset (primary key, etc) + * - recordData - the record fields. + */ + Base.prototype.updateRecord = function(key, recordData) { + } + + /* + * Deletes a record with the specified key. + * + * - key - the record key in the dataset (primary key, etc). + * - newRecordData - replacement record to add to the dataset if the deletion + * empties it. + * - offset - the current page's first record key (zero-based) + * - count - number of records to return + * - onSuccess - a callback function to execute when the updated data gets available. + * + * The onSuccess callback parameters: records, totalCount. + */ + Base.prototype.deleteRecord = function(key, newRecordData, offset, count, onSuccess) { + onSuccess([], 0) + } + + $.oc.table.datasource.base = Base; +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/table/assets/js/table.datasource.client.js b/modules/backend/widgets/table/assets/js/table.datasource.client.js new file mode 100644 index 0000000..4648d62 --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.datasource.client.js @@ -0,0 +1,148 @@ +/* + * Client memory data source for the table control. + */ ++function ($) { "use strict"; + + // NAMESPACE CHECK + // ============================ + + if ($.oc.table === undefined) + throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded."); + + if ($.oc.table.datasource === undefined) + throw new Error("The $.oc.table.datasource namespace is not defined. Make sure that the table.datasource.base.js script is loaded."); + + // CLASS DEFINITION + // ============================ + + var Base = $.oc.table.datasource.base, + BaseProto = Base.prototype + + var Client = function(tableObj) { + Base.call(this, tableObj) + + var dataString = tableObj.getElement().getAttribute('data-data') + + if (dataString === null || dataString === undefined) + throw new Error('The required data-data attribute is not found on the table control element.') + + this.data = JSON.parse(dataString) + }; + + Client.prototype = Object.create(BaseProto) + Client.prototype.constructor = Client + + Client.prototype.dispose = function() { + BaseProto.dispose.call(this) + this.data = null + } + + /* + * Fetches records from the underlying data source and + * passes them to the onSuccess callback function. + * The onSuccess callback parameters: records, totalCount. + * Each record contains the key field which uniquely identifies + * the record. The name of the key field is defined with the table + * widget options. + */ + Client.prototype.getRecords = function(offset, count, onSuccess) { + if (!count) { + // Return all records + onSuccess(this.data, this.data.length) + } + else { + // Return a subset of records + onSuccess(this.data.slice(offset, offset+count), this.data.length) + } + } + + /* + * Creates a record with the passed data and returns the updated page records + * to the onSuccess callback function. + * + * - recordData - the record fields + * - placement - "bottom" (the end of the data set), "above", "below" + * - relativeToKey - a row key, required if the placement is not "bottom" + * - offset - the current page's first record index (zero-based) + * - count - number of records to return + * - onSuccess - a callback function to execute when the updated data gets available. + * + * The onSuccess callback parameters: records, totalCount. + */ + Client.prototype.createRecord = function(recordData, placement, relativeToKey, offset, count, onSuccess) { + if (placement === 'bottom') { + // Add record to the bottom of the dataset + this.data.push(recordData) + } + else if (placement == 'above' || placement == 'below') { + // Add record above or below the passed record key + var recordIndex = this.getIndexOfKey(relativeToKey) + if (placement == 'below') + recordIndex ++ + + this.data.splice(recordIndex, 0, recordData) + } + + this.getRecords(offset, count, onSuccess) + } + + /* + * Updates a record with the specified key with the passed data + * + * - key - the record key in the dataset (primary key, etc) + * - recordData - the record fields. + */ + Client.prototype.updateRecord = function(key, recordData) { + var recordIndex = this.getIndexOfKey(key) + + if (recordIndex !== -1) { + recordData[this.tableObj.options.keyColumn] = key + this.data[recordIndex] = recordData + } + else { + throw new Error('Record with they key '+key+ ' is not found in the data set') + } + } + + /* + * Deletes a record with the specified key. + * + * - key - the record key in the dataset (primary key, etc). + * - newRecordData - replacement record to add to the dataset if the deletion + * empties it. + * - offset - the current page's first record key (zero-based) + * - count - number of records to return + * - onSuccess - a callback function to execute when the updated data gets available. + * + * The onSuccess callback parameters: records, totalCount. + */ + Client.prototype.deleteRecord = function(key, newRecordData, offset, count, onSuccess) { + var recordIndex = this.getIndexOfKey(key) + + if (recordIndex !== -1) { + this.data.splice(recordIndex, 1) + + if (this.data.length == 0) + this.data.push(newRecordData) + + this.getRecords(offset, count, onSuccess) + } + else { + throw new Error('Record with they key '+key+ ' is not found in the data set') + } + } + + Client.prototype.getIndexOfKey = function(key) { + var keyColumn = this.tableObj.options.keyColumn + + return this.data.map(function(record) { + return record[keyColumn] + "" + }).indexOf(key + "") + } + + Client.prototype.getAllData = function() { + return this.data + } + + $.oc.table.datasource.client = Client +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/table/assets/js/table.datasource.server.js b/modules/backend/widgets/table/assets/js/table.datasource.server.js new file mode 100644 index 0000000..acb9f5c --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.datasource.server.js @@ -0,0 +1,146 @@ +/* + * Server memory data source for the table control. + */ ++function ($) { "use strict"; + + // NAMESPACE CHECK + // ============================ + + if ($.oc.table === undefined) + throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded."); + + if ($.oc.table.datasource === undefined) + throw new Error("The $.oc.table.datasource namespace is not defined. Make sure that the table.datasource.base.js script is loaded."); + + // CLASS DEFINITION + // ============================ + + var Base = $.oc.table.datasource.base, + BaseProto = Base.prototype + + var Server = function(tableObj) { + Base.call(this, tableObj) + + var dataString = tableObj.getElement().getAttribute('data-data') + + if (dataString === null || dataString === undefined) + throw new Error('The required data-data attribute is not found on the table control element.') + + this.data = JSON.parse(dataString) + }; + + Server.prototype = Object.create(BaseProto) + Server.prototype.constructor = Server + + Server.prototype.dispose = function() { + BaseProto.dispose.call(this) + this.data = null + } + + /* + * Fetches records from the underlying data source and + * passes them to the onSuccess callback function. + * The onSuccess callback parameters: records, totalCount. + * Each record contains the key field which uniquely identifies + * the record. The name of the key field is defined with the table + * widget options. + */ + Server.prototype.getRecords = function(offset, count, onSuccess) { + var handlerName = this.tableObj.getAlias()+'::onServerGetRecords' + this.tableObj.$el.request(handlerName, { + data: { + offset: offset, + count: count + } + }).done(function(data) { + onSuccess(data.records, data.count) + }) + } + + /* + * Identical to getRecords except using a search query. + */ + Server.prototype.searchRecords = function(query, offset, count, onSuccess) { + var handlerName = this.tableObj.getAlias()+'::onServerSearchRecords' + this.tableObj.$el.request(handlerName, { + data: { + query: query, + offset: offset, + count: count + } + }).done(function(data) { + onSuccess(data.records, data.count) + }) + } + + /* + * Creates a record with the passed data and returns the updated page records + * to the onSuccess callback function. + * + * - recordData - the record fields + * - placement - "bottom" (the end of the data set), "above", "below" + * - relativeToKey - a row key, required if the placement is not "bottom" + * - offset - the current page's first record index (zero-based) + * - count - number of records to return + * - onSuccess - a callback function to execute when the updated data gets available. + * + * The onSuccess callback parameters: records, totalCount. + */ + Server.prototype.createRecord = function(recordData, placement, relativeToKey, offset, count, onSuccess) { + var handlerName = this.tableObj.getAlias()+'::onServerCreateRecord' + this.tableObj.$el.request(handlerName, { + data: { + recordData: recordData, + placement: placement, + relativeToKey: relativeToKey, + offset: offset, + count: count + } + }).done(function(data) { + onSuccess(data.records, data.count) + }) + } + + /* + * Updates a record with the specified key with the passed data + * + * - key - the record key in the dataset (primary key, etc) + * - recordData - the record fields. + */ + Server.prototype.updateRecord = function(key, recordData) { + var handlerName = this.tableObj.getAlias()+'::onServerUpdateRecord' + this.tableObj.$el.request(handlerName, { + data: { + key: key, + recordData: recordData + } + }) + } + + /* + * Deletes a record with the specified key. + * + * - key - the record key in the dataset (primary key, etc). + * - newRecordData - replacement record to add to the dataset if the deletion + * empties it. + * - offset - the current page's first record key (zero-based) + * - count - number of records to return + * - onSuccess - a callback function to execute when the updated data gets available. + * + * The onSuccess callback parameters: records, totalCount. + */ + Server.prototype.deleteRecord = function(key, newRecordData, offset, count, onSuccess) { + var handlerName = this.tableObj.getAlias()+'::onServerDeleteRecord' + this.tableObj.$el.request(handlerName, { + data: { + key: key, + offset: offset, + count: count + } + }).done(function(data) { + onSuccess(data.records, data.count) + }) + } + + $.oc.table.datasource.server = Server +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/table/assets/js/table.helper.navigation.js b/modules/backend/widgets/table/assets/js/table.helper.navigation.js new file mode 100644 index 0000000..40bed11 --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.helper.navigation.js @@ -0,0 +1,425 @@ +/* + * Navigation helper for the table widget. + * Implements the keyboard navigation within the current page + * and pagination. + */ ++function ($) { "use strict"; + + // NAMESPACE CHECK + // ============================ + + if ($.oc.table === undefined) + throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded."); + + if ($.oc.table.helper === undefined) + $.oc.table.helper = {} + + // NAVIGATION CLASS DEFINITION + // ============================ + + var Navigation = function(tableObj) { + // Reference to the table object + this.tableObj = tableObj + + // The current page index + this.pageIndex = 0 + + // Event handlers + + // Number of pages in the pagination + this.pageCount = 0 + + this.init() + }; + + Navigation.prototype.init = function() { + } + + Navigation.prototype.dispose = function() { + // Remove the reference to the table object + this.tableObj = null + } + + // PAGINATION + // ============================ + + Navigation.prototype.paginationEnabled = function() { + return this.tableObj.options.recordsPerPage != null && + this.tableObj.options.recordsPerPage != false + } + + Navigation.prototype.getPageFirstRowOffset = function() { + return this.pageIndex * this.tableObj.options.recordsPerPage + } + + Navigation.prototype.buildPagination = function(recordCount) { + if (!this.paginationEnabled()) + return + + var paginationContainer = this.tableObj.getElement().querySelector('.pagination'), + newPaginationContainer = false, + curRecordCount = 0 + + this.pageCount = this.calculatePageCount(recordCount, this.tableObj.options.recordsPerPage) + + if (!paginationContainer) { + paginationContainer = document.createElement('div') + paginationContainer.setAttribute('class', 'pagination') + newPaginationContainer = true + } + else { + curRecordCount = this.getRecordCount(paginationContainer) + } + + // Generate the new page list only if the record count has changed + if (newPaginationContainer || curRecordCount != recordCount) { + paginationContainer.setAttribute('data-record-count', recordCount) + + var pageList = this.buildPaginationLinkList( + recordCount, + this.tableObj.options.recordsPerPage, + this.pageIndex + ) + + if (!newPaginationContainer) { + paginationContainer.replaceChild(pageList, paginationContainer.children[0]) + } + else { + paginationContainer.appendChild(pageList) + this.tableObj.getElement().appendChild(paginationContainer) + } + } + else { + // Do not re-generate the pages if the record count hasn't changed, + // but mark the new active item in the pagination list + this.markActiveLinkItem(paginationContainer, this.pageIndex) + } + } + + Navigation.prototype.calculatePageCount = function(recordCount, recordsPerPage) { + var pageCount = Math.ceil(recordCount/recordsPerPage) + + if (!pageCount) + pageCount = 1 + + return pageCount + } + + Navigation.prototype.getRecordCount = function(paginationContainer) { + var container = paginationContainer ? paginationContainer : this.tableObj.getElement().querySelector('.pagination') + + return parseInt(container.getAttribute('data-record-count')) + } + + Navigation.prototype.buildPaginationLinkList = function(recordCount, recordsPerPage, pageIndex) { + // This method could be refactored and moved to a pagination + // helper if we want to support other pagination markup options. + + var pageCount = this.calculatePageCount(recordCount, recordsPerPage), + pageList = document.createElement('ul') + + for (var i=0; i < pageCount; i++) { + var item = document.createElement('li'), + link = document.createElement('a') + + if (i == pageIndex) + item.setAttribute('class', 'active') + + + link.innerText = i+1 + link.setAttribute('data-page-index', i) + link.setAttribute('href', '#') + + item.appendChild(link) + pageList.appendChild(item) + + $(link).addClass('pagination-link') + } + + return pageList + } + + Navigation.prototype.markActiveLinkItem = function(paginationContainer, pageIndex) { + // This method could be refactored and moved to a pagination + // helper if we want to support other pagination markup options. + + var activeItem = paginationContainer.querySelector('.active'), + list = paginationContainer.children[0] + + activeItem.setAttribute('class', '') + + for (var i=0, len = list.children.length; i < len; i++) { + if (i == pageIndex) { + list.children[i].setAttribute('class', 'active') + } + } + } + + Navigation.prototype.gotoPage = function(pageIndex, onSuccess) { + this.tableObj.unfocusTable() + + if (!this.tableObj.validate()) + return + + this.pageIndex = pageIndex + + this.tableObj.updateDataTable(onSuccess) + } + + Navigation.prototype.getRowCountOnPage = function(cellElement) { + return this.tableObj.getDataTableBody().children.length + } + + Navigation.prototype.getNewRowPage = function(placement, currentRowIndex) { + var curRecordCount = this.getRecordCount() + + if (placement === 'bottom') + return this.calculatePageCount(curRecordCount + 1, this.tableObj.options.recordsPerPage) - 1 + + // When a row is added above a current row, the current row just moves down, + // so it's safe to return the current page index + if (placement == 'above') + return this.pageIndex + + if (placement == 'below') { + if (currentRowIndex == (this.tableObj.options.recordsPerPage - 1)) + return this.pageIndex + 1 + + return this.pageIndex + } + + return this.pageIndex + } + + Navigation.prototype.getPageAfterDeletion = function(currentRowIndex) { + if (currentRowIndex == 0 && this.getRowCountOnPage() == 1) + return this.pageIndex == 0 ? 0 : this.pageIndex - 1 + + return this.pageIndex + } + + // KEYBOARD NAVIGATION + // ============================ + + Navigation.prototype.navigateDown = function(ev, forceCellIndex) { + if (!this.tableObj.activeCell) + return + + if (this.tableObj.activeCellProcessor && !this.tableObj.activeCellProcessor.keyNavigationAllowed(ev, 'down')) + return + + var row = this.tableObj.activeCell.parentNode, + newRow = !ev.shiftKey + ? row.nextElementSibling + : row.parentNode.children[row.parentNode.children.length - 1], + cellIndex = forceCellIndex !== undefined + ? forceCellIndex + : this.tableObj.activeCell.cellIndex + + if (newRow) { + var cell = newRow.children[cellIndex] + + if (cell) + this.tableObj.focusCell(cell) + } + else { + // Try to switch to the next page if that's possible + + if (!this.paginationEnabled()) + return + + if (this.pageIndex < this.pageCount - 1) { + var self = this + + this.gotoPage(this.pageIndex + 1, function navDownPageSuccess() { + self.focusCell('top', cellIndex) + self = null + }) + } + } + } + + Navigation.prototype.navigateUp = function(ev, forceCellIndex, isTab) { + if (!this.tableObj.activeCell) + return + + if (this.tableObj.activeCellProcessor && !this.tableObj.activeCellProcessor.keyNavigationAllowed(ev, 'up')) + return + + var row = this.tableObj.activeCell.parentNode, + newRow = (!ev.shiftKey || isTab) + ? row.previousElementSibling + : row.parentNode.children[0], + cellIndex = forceCellIndex !== undefined + ? forceCellIndex + : this.tableObj.activeCell.cellIndex + + if (newRow) { + var cell = newRow.children[cellIndex] + + if (cell) + this.tableObj.focusCell(cell) + } + else { + // Try to switch to the previous page if that's possible + + if (!this.paginationEnabled()) + return + + if (this.pageIndex > 0) { + var self = this + + this.gotoPage(this.pageIndex - 1, function navUpPageSuccess(){ + self.focusCell('bottom', cellIndex) + self = null + }) + } + } + } + + Navigation.prototype.navigateLeft = function(ev, isTab) { + if (!this.tableObj.activeCell) + return + + if (!isTab && this.tableObj.activeCellProcessor && !this.tableObj.activeCellProcessor.keyNavigationAllowed(ev, 'left')) + return + + var row = this.tableObj.activeCell.parentNode, + newIndex = (!ev.shiftKey || isTab) + ? this.tableObj.activeCell.cellIndex - 1 + : 0 + + var cell = row.children[newIndex] + + if (cell) { + this.tableObj.focusCell(cell) + } + else { + // Try to navigate up if that's possible + this.navigateUp(ev, row.children.length - 1, isTab) + } + } + + Navigation.prototype.navigateRight = function(ev, isTab) { + if (!this.tableObj.activeCell) + return + + if (!isTab && this.tableObj.activeCellProcessor && !this.tableObj.activeCellProcessor.keyNavigationAllowed(ev, 'right')) + return + + var row = this.tableObj.activeCell.parentNode, + newIndex = !ev.shiftKey + ? this.tableObj.activeCell.cellIndex + 1 + : row.children.length - 1 + + var cell = row.children[newIndex] + + if (cell) { + this.tableObj.focusCell(cell) + } + else { + // Try to navigate down if that's possible + this.navigateDown(ev, 0) + } + } + + Navigation.prototype.navigateNext = function(ev) { + if (!this.tableObj.activeCell) + return + + if (this.tableObj.activeCellProcessor && !this.tableObj.activeCellProcessor.keyNavigationAllowed(ev, 'tab')) + return + + if (!ev.shiftKey) + this.navigateRight(ev, true) + else + this.navigateLeft(ev, true) + + this.tableObj.stopEvent(ev) + } + + Navigation.prototype.focusCell = function(rowReference, cellIndex) { + var row = null, + tbody = this.tableObj.getDataTableBody() + + if (typeof rowReference === 'object') { + row = rowReference + } + else { + if (rowReference == 'bottom') { + row = tbody.children[tbody.children.length-1] + } + else if (rowReference == 'top') { + row = tbody.children[0] + } + } + + if (!row) + return + + var cell = row.children[cellIndex] + if (cell) + this.tableObj.focusCell(cell) + } + + Navigation.prototype.focusCellInReplacedRow = function(rowIndex, cellIndex) { + if (rowIndex == 0) { + this.focusCell('top', cellIndex) + } + else { + var focusRow = this.tableObj.findRowByIndex(rowIndex) + + if (!focusRow) + focusRow = this.tableObj.findRowByIndex(rowIndex-1) + + if (focusRow) + this.focusCell(focusRow, cellIndex) + else + this.focusCell('top', cellIndex) + } + } + + // EVENT HANDLERS + // ============================ + + Navigation.prototype.onKeydown = function(ev) { + // The navigation object uses the table's keydown handler + // and doesn't register own handler. + + if (ev.key === 'ArrowDown') + return this.navigateDown(ev) + else if (ev.key === 'ArrowUp') + return this.navigateUp(ev) + else if (ev.key === 'ArrowLeft') + return this.navigateLeft(ev) + + if (ev.key === 'ArrowRight') + return this.navigateRight(ev) + + if (ev.key === 'Tab') + return this.navigateNext(ev) + } + + Navigation.prototype.onClick = function(ev) { + // The navigation object uses the table's click handler + // and doesn't register own click handler. + + var target = this.tableObj.getEventTarget(ev, 'A') + + if (!target || !$(target).hasClass('pagination-link')) + return + + var pageIndex = parseInt(target.getAttribute('data-page-index')) + + if (pageIndex === null) + return + + this.gotoPage(pageIndex) + this.tableObj.stopEvent(ev) + + return false + } + + $.oc.table.helper.navigation = Navigation; + +}(window.jQuery); diff --git a/modules/backend/widgets/table/assets/js/table.helper.search.js b/modules/backend/widgets/table/assets/js/table.helper.search.js new file mode 100644 index 0000000..751abc7 --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.helper.search.js @@ -0,0 +1,116 @@ +/* + * Search helper for the table widget. + * Implements searching within the table. + */ ++function ($) { "use strict"; + + // NAMESPACE CHECK + // ============================ + + if ($.oc.table === undefined) + throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded."); + + if ($.oc.table.helper === undefined) + $.oc.table.helper = {} + + // SEARCH CLASS DEFINITION + // ============================ + + var Search = function(tableObj) { + // Reference to the table object + this.tableObj = tableObj + + // The search form element + this.searchForm = null + this.searchInput = null + + // Timer used for tracking input changes + this.inputTrackTimer = null + + // Event handlers + + // Active search query + this.activeQuery = null + + this.isActive = false + + this.init() + }; + + Search.prototype.init = function() { + } + + Search.prototype.dispose = function() { + // Remove the reference to the table object + this.tableObj = null + this.searchForm = null + this.searchInput = null + } + + Search.prototype.buildSearchForm = function() { + if (!this.searchEnabled()) + return + + var el = this.tableObj.getElement(), + toolbar = this.tableObj.getToolbar(), + searchForm = toolbar.querySelector('.table-search') + + if (!searchForm) { + this.searchForm = $($('[data-table-toolbar-search]', el).html()).appendTo(toolbar).get(0) + this.searchInput = $('.table-search-input', this.searchForm).get(0) + } + } + + Search.prototype.getQuery = function() { + return $.trim(this.activeQuery) + } + + Search.prototype.hasQuery = function() { + return this.searchEnabled() && $.trim(this.activeQuery).length > 0 + } + + Search.prototype.searchEnabled = function() { + return this.tableObj.options.searching + } + + Search.prototype.performSearch = function(query, onSuccess) { + var isDirty = this.activeQuery != query + + this.activeQuery = query + + if (isDirty) { + this.tableObj.updateDataTable(onSuccess) + } + } + + // EVENT HANDLERS + // ============================ + + Search.prototype.onKeydown = function(ev) { + // The navigation object uses the table's keydown handler + // and doesn't register own handler. + + // Tab pressed + if (ev.key === 'Tab') { + this.onClick(ev) + return + } + + if (!this.isActive) { + return + } + + var self = this + this.inputTrackTimer = window.setTimeout(function() { + self.performSearch(self.searchInput.value) + }, 300) + } + + Search.prototype.onClick = function(ev) { + var target = this.tableObj.getEventTarget(ev, 'INPUT') + this.isActive = target && $(target).hasClass('table-search-input') + } + + $.oc.table.helper.search = Search; + +}(window.jQuery); diff --git a/modules/backend/widgets/table/assets/js/table.js b/modules/backend/widgets/table/assets/js/table.js new file mode 100644 index 0000000..f20bd08 --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.js @@ -0,0 +1,1170 @@ +/* + * Table control class + * + * Dependences: + * - Scrollbar (october.scrollbar.js) + */ ++function ($) { "use strict"; + + // TABLE CONTROL NAMESPACES + // ============================ + + if ($.oc === undefined) + $.oc = {} + + if ($.oc.table === undefined) + $.oc.table = {} + + // TABLE CLASS DEFINITION + // ============================ + + var Table = function(element, options) { + this.el = element + this.$el = $(element) + + this.options = options + this.disposed = false + + // + // State properties + // + + // The data source object + this.dataSource = null + + // The cell processors list + this.cellProcessors = {} + + // A reference to the currently active cell processor + this.activeCellProcessor = null + + // A reference to the currently active table cell + this.activeCell = null + + // A reference to the tables container + this.tableContainer = null + + // A reference to the data table container + this.dataTableContainer = null + + // The key of the row which is being edited at the moment. + // This key corresponds the data source row key which + // uniquely identifies the row in the data set. When the + // table grid notices that a cell in another row is edited it commits + // the previously edited record to the data source. + this.editedRowKey = null + + // A reference to the data table + this.dataTable = null + + // A reference to the header table + this.headerTable = null + + // A reference to the toolbar + this.toolbar = null + + // Event handlers + this.clickHandler = this.onClick.bind(this) + this.keydownHandler = this.onKeydown.bind(this) + this.documentClickHandler = this.onDocumentClick.bind(this) + this.toolbarClickHandler = this.onToolbarClick.bind(this) + + if (this.options.postback && this.options.clientDataSourceClass == 'client') { + if (!this.options.postbackHandlerName) { + var formHandler = this.$el.closest('form').data('request') + this.options.postbackHandlerName = formHandler || 'onSave' + } + this.formSubmitHandler = this.onFormSubmit.bind(this) + } + + // Navigation helper + this.navigation = null + + // Search helper + this.search = null + + // Number of records added or deleted during the session + this.recordsAddedOrDeleted = 0 + + // Bound reference to dispose() - ideally the class should use the October foundation library base class + this.disposeBound = this.dispose.bind(this) + + // + // Initialization + // + + this.init() + + $.oc.foundation.controlUtils.markDisposable(element) + } + + // INTERNAL METHODS + // ============================ + + Table.prototype.init = function() { + // Create the data source object + this.createDataSource() + + // Create cell processors + this.initCellProcessors() + + // Initialize helpers + this.navigation = new $.oc.table.helper.navigation(this) + this.search = new $.oc.table.helper.search(this) + + // Create the UI + this.buildUi() + + // Register event handlers + this.registerHandlers() + } + + Table.prototype.disposeCellProcessors = function() { + // For the performance reasons cell processors are stored + // in an object structure with keys matching the column names. + // We can iterate through then with the for cycle if we know + // the column names. We use the for cycle for the performance + // reasons: http://jsperf.com/for-vs-foreach/37, + // http://jonraasch.com/blog/10-javascript-performance-boosting-tips-from-nicholas-zakas + + for (var i = 0, len = this.options.columns.length; i < len; i++) { + var column = this.options.columns[i].key + + this.cellProcessors[column].dispose() + this.cellProcessors[column] = null + } + + this.cellProcessors = null + this.activeCellProcessor = null + } + + Table.prototype.createDataSource = function() { + var dataSourceClass = this.options.clientDataSourceClass + + if ($.oc.table.datasource === undefined || $.oc.table.datasource[dataSourceClass] == undefined) + throw new Error('The table client-side data source class "'+dataSourceClass+'" is not ' + + 'found in the $.oc.table.datasource namespace.') + + this.dataSource = new $.oc.table.datasource[dataSourceClass](this) + } + + Table.prototype.registerHandlers = function() { + this.el.addEventListener('click', this.clickHandler) + this.el.addEventListener('keydown', this.keydownHandler) + this.$el.one('dispose-control', this.disposeBound) + + document.addEventListener('click', this.documentClickHandler) + + if (this.options.postback && this.options.clientDataSourceClass == 'client') + this.$el.closest('form').bind('oc.beforeRequest', this.formSubmitHandler) + + var toolbar = this.getToolbar() + if (toolbar) + toolbar.addEventListener('click', this.toolbarClickHandler); + } + + Table.prototype.unregisterHandlers = function() { + this.el.removeEventListener('click', this.clickHandler); + document.removeEventListener('click', this.documentClickHandler) + + this.clickHandler = null + + this.el.removeEventListener('keydown', this.keydownHandler); + this.keydownHandler = null + + var toolbar = this.getToolbar() + if (toolbar) + toolbar.removeEventListener('click', this.toolbarClickHandler); + + this.toolbarClickHandler = null + + if (this.formSubmitHandler) { + this.$el.closest('form').unbind('oc.beforeRequest', this.formSubmitHandler) + this.formSubmitHandler = null + } + } + + Table.prototype.initCellProcessors = function() { + for (var i = 0, len = this.options.columns.length; i < len; i++) { + var columnConfiguration = this.options.columns[i], + column = columnConfiguration.key, + columnType = columnConfiguration.type + + // Resolve the default column type to string + if (columnType === undefined) { + columnType = 'string' + this.options.columns[i].type = columnType + } + + if ($.oc.table.processor === undefined || $.oc.table.processor[columnType] == undefined) + throw new Error('The table cell processor for the column type "'+columnType+'" is not ' + + 'found in the $.oc.table.processor namespace.') + + this.cellProcessors[column] = new $.oc.table.processor[columnType](this, column, columnConfiguration) + } + } + + Table.prototype.getCellProcessor = function(columnName) { + return this.cellProcessors[columnName] + } + + Table.prototype.buildUi = function() { + this.tableContainer = document.createElement('div') + this.tableContainer.setAttribute('class', 'table-container') + + // Build the toolbar + if (this.options.toolbar) { + this.buildToolbar() + } + + // Build the headers table + this.tableContainer.appendChild(this.buildHeaderTable()) + + // Append the table container to the element + this.el.insertBefore(this.tableContainer, this.el.children[0]) + + if (!this.options.height) { + this.dataTableContainer = this.tableContainer + } + else { + this.dataTableContainer = this.buildScrollbar() + } + + // Build the data table + this.updateDataTable() + } + + Table.prototype.buildToolbar = function() { + if (!this.options.adding && !this.options.deleting) { + return + } + + this.toolbar = $($('[data-table-toolbar]', this.el).html()).appendTo(this.tableContainer).get(0) + + if (!this.options.adding) { + $('[data-cmd^="record-add"]', this.toolbar).remove() + } + else { + if (this.navigation.paginationEnabled() || !this.options.rowSorting) { + // When the pagination is enabled, or sorting is disabled, + // new records can only be added to the bottom of the + // table, so just show the general "Add row" button. + $('[data-cmd=record-add-below], [data-cmd=record-add-above]', this.toolbar).remove() + } + else { + $('[data-cmd=record-add]', this.toolbar).remove() + } + } + + if (!this.options.deleting) { + $('[data-cmd="record-delete"]', this.toolbar).remove() + } + } + + Table.prototype.buildScrollbar = function() { + var scrollbar = document.createElement('div'), + scrollbarContent = document.createElement('div') + + scrollbar.setAttribute('class', 'control-scrollbar') + + if (this.options.dynamicHeight) + scrollbar.setAttribute('style', 'max-height: ' + this.options.height + 'px') + else + scrollbar.setAttribute('style', 'height: ' + this.options.height + 'px') + + scrollbar.appendChild(scrollbarContent) + this.tableContainer.appendChild(scrollbar) + + $(scrollbar).scrollbar({animation: false}) + + return scrollbarContent + } + + Table.prototype.buildHeaderTable = function() { + var headersTable = document.createElement('table'), + row = document.createElement('tr') + + headersTable.className = 'headers' + headersTable.appendChild(row) + + for (var i = 0, len = this.options.columns.length; i < len; i++) { + var header = document.createElement('th') + + if (this.options.columns[i].width) + header.setAttribute('style', 'width: '+this.options.columns[i].width) + + header.textContent !== undefined + ? header.textContent = this.options.columns[i].title + : header.innerText = this.options.columns[i].title + + row.appendChild(header) + } + + this.headerTable = headersTable + + return headersTable + } + + Table.prototype.updateDataTable = function(onSuccess) { + var self = this + + this.unfocusTable() + + this.fetchRecords(function onUpdateDataTableSuccess(records, totalCount) { + self.buildDataTable(records, totalCount) + + if (onSuccess) + onSuccess() + + if (totalCount == 0) + self.addRecord('above', true) + + self.$el.trigger('oc.tableUpdateData', [ + records, + totalCount + ]) + + self = null + }) + } + + Table.prototype.updateColumnWidth = function() { + var headerCells = this.headerTable.querySelectorAll('th'), + dataCells = this.dataTable.querySelectorAll('tr:first-child td') + + for (var i = 0, len = headerCells.length; i < len; i++) { + if (dataCells[i]) + dataCells[i].setAttribute('style', headerCells[i].getAttribute('style')) + } + } + + Table.prototype.buildDataTable = function(records, totalCount) { + var dataTable = document.createElement('table'), + tbody = document.createElement('tbody'), + keyColumn = this.options.keyColumn + + dataTable.setAttribute('class', 'data') + + for (var i = 0, len = records.length; i < len; i++) { + var row = document.createElement('tr') + + if (records[i][keyColumn] === undefined) + throw new Error('The row attribute '+keyColumn+' is not set for the row #'+i); + + row.setAttribute('data-row', records[i][keyColumn]) + for (var j = 0, colsLen = this.options.columns.length; j < colsLen; j++) { + var cell = document.createElement('td'), + dataContainer = document.createElement('input'), + cellContentContainer = document.createElement('div'), + column = this.options.columns[j], + columnName = column.key, + cellProcessor = this.getCellProcessor(columnName) + + cell.setAttribute('data-column', columnName) + cell.setAttribute('data-column-type', column.type) + + dataContainer.setAttribute('type', 'hidden') + dataContainer.setAttribute('data-container', 'data-container') + dataContainer.value = this.formatDataContainerValue(records[i][columnName]) + + cellContentContainer.setAttribute('class', 'content-container') + + cell.appendChild(cellContentContainer) + row.appendChild(cell) + cell.appendChild(dataContainer) + + cellProcessor.renderCell(records[i][columnName], cellContentContainer) + } + + tbody.appendChild(row) + } + + dataTable.appendChild(tbody) + + // Inject the data table to the DOM or replace the existing table + if (this.dataTable !== null) + this.dataTableContainer.replaceChild(dataTable, this.dataTable) + else + this.dataTableContainer.appendChild(dataTable) + + this.dataTable = dataTable + + // Update column widths + this.updateColumnWidth() + + // Update the scrollbar + this.updateScrollbar() + + // Update the pagination links + this.navigation.buildPagination(totalCount) + + // Update the search form + this.search.buildSearchForm() + } + + Table.prototype.formatDataContainerValue = function(value) { + if (value === undefined) { + return '' + } + + if (typeof value === 'boolean') { + return value ? 1 : '' + } + + return value + } + + Table.prototype.fetchRecords = function(onSuccess) { + if (this.search.hasQuery()) { + this.dataSource.searchRecords( + this.search.getQuery(), + this.navigation.getPageFirstRowOffset(), + this.options.recordsPerPage, + onSuccess + ) + } + else { + this.dataSource.getRecords( + this.navigation.getPageFirstRowOffset(), + this.options.recordsPerPage, + onSuccess + ) + } + } + + Table.prototype.updateScrollbar = function() { + if (!this.options.height) + return + + $(this.dataTableContainer.parentNode).data('oc.scrollbar').update() + } + + Table.prototype.scrollCellIntoView = function() { + if (!this.options.height || !this.activeCell) + return + + $(this.dataTableContainer.parentNode).data('oc.scrollbar').gotoElement(this.activeCell) + } + + Table.prototype.disposeScrollbar = function() { + if (!this.options.height) + return + + $(this.dataTableContainer.parentNode).data('oc.scrollbar').dispose() + $(this.dataTableContainer.parentNode).data('oc.scrollbar', null) + } + + /* + * Makes a cell processor active and hides the previously + * active editor. + */ + Table.prototype.setActiveProcessor = function(processor) { + if (this.activeCellProcessor) + this.activeCellProcessor.onUnfocus() + + this.activeCellProcessor = processor + } + + Table.prototype.commitEditedRow = function() { + if (this.editedRowKey === null) + return + + var editedRow = this.dataTable.querySelector('tr[data-row="'+this.editedRowKey+'"]') + if (!editedRow) + return + + if (editedRow.getAttribute('data-dirty') != 1) + return + + var cells = editedRow.children, + data = {} + + for (var i=0, len = cells.length; i < len; i++) { + var cell = cells[i] + + data[cell.getAttribute('data-column')] = this.getCellValue(cell) + } + + this.dataSource.updateRecord(this.editedRowKey, data) + editedRow.setAttribute('data-dirty', 0) + } + + /* + * Removes editor from the currently edited cell and commits the row if needed. + */ + Table.prototype.unfocusTable = function() { + this.elementRemoveClass(this.el, 'active') + + if (this.activeCellProcessor) + this.activeCellProcessor.onUnfocus() + + this.commitEditedRow() + this.activeCellProcessor = null + + if (this.activeCell) + this.activeCell.setAttribute('class', '') + + this.activeCell = null + } + + /* + * Makes the table focused in the UI + */ + Table.prototype.focusTable = function() { + this.elementAddClass(this.el, 'active') + } + + /* + * Calls the onFocus() method for the cell processor responsible for the + * newly focused cell. Commit the previous edited row to the data source + * if needed. + */ + Table.prototype.focusCell = function(cellElement, isClick) { + var columnName = cellElement.getAttribute('data-column') + if (columnName === null) + return + + this.focusTable() + + var processor = this.getCellProcessor(columnName) + if (!processor) + throw new Error("Cell processor not found for the column "+columnName) + + if (this.activeCell !== cellElement) { + if (this.activeCell) + this.elementRemoveClass(this.activeCell, 'active') + + this.setActiveProcessor(processor) + this.activeCell = cellElement + + if (processor.isCellFocusable()) + this.elementAddClass(this.activeCell, 'active') + } + + // If the cell belongs to other row than the currently edited, + // commit currently edited row to the data source. Update the + // currently edited row key. + var rowKey = this.getCellRowKey(cellElement) + + if (this.editedRowKey !== null && rowKey != this.editedRowKey) + this.commitEditedRow() + + this.editedRowKey = rowKey + + processor.onFocus(cellElement, isClick) + + this.scrollCellIntoView() + } + + Table.prototype.markCellRowDirty = function(cellElement) { + cellElement.parentNode.setAttribute('data-dirty', 1) + } + + Table.prototype.addRecord = function(placement, noFocus) { + // If there is no active cell, or the pagination is enabled or + // row sorting is disabled, add the record to the bottom of + // the table (last page). + + if (!this.activeCell || this.navigation.paginationEnabled() || !this.options.rowSorting) + placement = 'bottom' + + var relativeToKey = null, + currentRowIndex = null + + if (placement == 'above' || placement == 'below') { + relativeToKey = this.getCellRowKey(this.activeCell) + currentRowIndex = this.getCellRowIndex(this.activeCell) + } + + this.unfocusTable() + + if (this.navigation.paginationEnabled()) { + var newPageIndex = this.navigation.getNewRowPage(placement, currentRowIndex) + + if (newPageIndex != this.navigation.pageIndex) { + // Validate data on the current page if adding a new record + // is going to create another page. + if (!this.validate()) + return + } + + this.navigation.pageIndex = newPageIndex + } + + this.recordsAddedOrDeleted++ + + // New records have negative keys + var keyColumn = this.options.keyColumn, + recordData = {}, + self = this + + recordData[keyColumn] = -1 * this.recordsAddedOrDeleted + + this.$el.trigger('oc.tableNewRow', [ + recordData + ]) + + this.dataSource.createRecord(recordData, placement, relativeToKey, + this.navigation.getPageFirstRowOffset(), + this.options.recordsPerPage, + function onAddRecordDataTableSuccess(records, totalCount) { + self.buildDataTable(records, totalCount) + + var row = self.findRowByKey(recordData[keyColumn]) + if (!row) + throw new Error('New row is not found in the updated table: '+recordData[keyColumn]) + + if (!noFocus) + self.navigation.focusCell(row, 0) + + self = null + } + ) + } + + Table.prototype.deleteRecord = function() { + if (!this.activeCell) + return + + var currentRowIndex = this.getCellRowIndex(this.activeCell), + key = this.getCellRowKey(this.activeCell), + self = this, + paginationEnabled = this.navigation.paginationEnabled(), + currentPageIndex = this.navigation.pageIndex, + currentCellIndex = this.activeCell.cellIndex + + if (paginationEnabled) + this.navigation.pageIndex = this.navigation.getPageAfterDeletion(currentRowIndex) + + this.recordsAddedOrDeleted++ + + // New records have negative keys + var keyColumn = this.options.keyColumn, + newRecordData = {} + + newRecordData[keyColumn] = -1 * this.recordsAddedOrDeleted + + this.dataSource.deleteRecord( + key, + newRecordData, + this.navigation.getPageFirstRowOffset(), + this.options.recordsPerPage, + function onDeleteRecordDataTableSuccess(records, totalCount) { + self.buildDataTable(records, totalCount) + + if (!paginationEnabled) + self.navigation.focusCellInReplacedRow(currentRowIndex, currentCellIndex) + else { + if (currentPageIndex != self.navigation.pageIndex) + self.navigation.focusCell('bottom', currentCellIndex) + else + self.navigation.focusCellInReplacedRow(currentRowIndex, currentCellIndex) + } + + self = null + } + ) + } + + Table.prototype.notifyRowProcessorsOnChange = function(cellElement) { + var columnName = cellElement.getAttribute('data-column'), + row = cellElement.parentNode + + for (var i = 0, len = row.children.length; i < len; i++) { + var column = this.options.columns[i].key + + this.cellProcessors[column].onRowValueChanged(columnName, row.children[i]) + } + } + + Table.prototype.getToolbar = function() { + return this.tableContainer.querySelector('div.toolbar') + } + + /* + * Validaates data on the current page + */ + Table.prototype.validate = function() { + var rows = this.dataTable.querySelectorAll('tbody tr[data-row]') + + for (var i = 0, len = rows.length; i < len; i++) { + var row = rows[i] + + this.elementRemoveClass(row, 'error') + } + + for (var i = 0, rowsLen = rows.length; i < rowsLen; i++) { + var row = rows[i], + rowData = this.getRowData(row) + + for (var j = 0, colsLen = row.children.length; j < colsLen; j++) + this.elementRemoveClass(row.children[j], 'error') + + for (var columnName in rowData) { + var cellProcessor = this.getCellProcessor(columnName), + message = cellProcessor.validate(rowData[columnName], rowData) + + if (message !== undefined) { + var cell = row.querySelector('td[data-column="'+columnName+'"]'), + self = this + + this.elementAddClass(row, 'error') + this.elementAddClass(cell, 'error') + + $.oc.flashMsg({text: message, 'class': 'error'}) + + window.setTimeout(function(){ + self.focusCell(cell, false) + cell = null + self = null + cellProcessor = null + }, 100) + return false + } + } + } + + return true + } + + // EVENT HANDLERS + // ============================ + + Table.prototype.onClick = function(ev) { + this.focusTable() + + if (this.navigation.onClick(ev) === false) + return + + if (this.search.onClick(ev) === false) + return + + for (var i = 0, len = this.options.columns.length; i < len; i++) { + var column = this.options.columns[i].key + + this.cellProcessors[column].onClick(ev) + } + + var target = this.getEventTarget(ev, 'TD') + + if (!target) { + this.unfocusTable(); + return; + } + + if (target.tagName != 'TD') { + this.unfocusTable(); + return; + } + + this.focusCell(target, true) + } + + Table.prototype.onKeydown = function(ev) { + if ((ev.key === 'a' || ev.key === 'A') && ev.altKey && this.options.adding) { + if (!ev.shiftKey) { + // alt+a - add record below + this.addRecord('below') + } + else { + // alt+shift+a - add record above + this.addRecord('above') + } + + this.stopEvent(ev) + return + } + + if ((ev.key === 'd' || ev.key === 'D') && ev.altKey && this.options.deleting) { + // alt+d - delete record + this.deleteRecord() + + this.stopEvent(ev) + return + } + + for (var i = 0, len = this.options.columns.length; i < len; i++) { + var column = this.options.columns[i].key + + if (this.cellProcessors[column].onKeyDown(ev) === false) { + return + } + } + + if (this.navigation.onKeydown(ev) === false) { + return + } + + if (this.search.onKeydown(ev) === false) { + return + } + } + + Table.prototype.onFormSubmit = function(ev, data) { + if (data.handler == this.options.postbackHandlerName) { + this.unfocusTable() + + if (!this.validate()) { + ev.preventDefault() + return + } + + var fieldName = this.options.fieldName.indexOf('[') > -1 + ? this.options.fieldName + '[TableData]' + : this.options.fieldName + 'TableData' + + data.options.data[fieldName] = this.dataSource.getAllData() + } + } + + Table.prototype.onToolbarClick = function(ev) { + var target = this.getEventTarget(ev), + cmd = target.getAttribute('data-cmd') + + if (!cmd) { + return + } + + switch (cmd) { + case 'record-add': + case 'record-add-below': + this.addRecord('below') + break + case 'record-add-above': + this.addRecord('above') + break + case 'record-delete': + this.deleteRecord() + break + } + + this.stopEvent(ev) + } + + Table.prototype.onDocumentClick = function(ev) { + var target = this.getEventTarget(ev) + + // Determine if the click was inside the table element + // and just exit if so + if (this.parentContainsElement(this.el, target)) + return + + // Request the active cell processor if the clicked + // element belongs to any extra-table element created + // by the processor + + if (this.activeCellProcessor && this.activeCellProcessor.elementBelongsToProcessor(target)) + return + + this.unfocusTable() + } + + // PUBLIC METHODS + // ============================ + + Table.prototype.dispose = function() { + if (this.disposed) { + // Prevent errors when legacy code executes the dispose() method + // directly, bypassing $.oc.foundation.controlUtils.disposeControls(container) + return + } + + this.disposed = true + + this.disposeBound = true + + // Remove an editor and commit the data if needed + this.unfocusTable() + + // Dispose the data source and clean up the reference + this.dataSource.dispose() + this.dataSource = null + + // Unregister event handlers + this.unregisterHandlers() + + // Remove references to DOM elements + this.dataTable = null + this.headerTable = null + this.toolbar = null + + // Dispose cell processors + this.disposeCellProcessors() + + // Dispose helpers and remove references + this.navigation.dispose() + this.navigation = null + + // Delete references to the control HTML elements. + // The script doesn't remove any DOM elements themselves. + // If it's needed it should be done by the outer script, + // we only make sure that the table widget doesn't hold + // references to the detached DOM tree so that the garbage + // collector can delete the elements if needed. + this.disposeScrollbar() + this.el = null + this.tableContainer = null + this.$el = null + this.dataTableContainer = null + + // Delete references to other DOM elements + this.activeCell = null + } + + /* + * Updates row values in the table. + * rowIndex is an integer value containing the row index on the current page. + * The rowValues should be a hash object containing only changed + * columns. + * Returns false if the row wasn't found. Otherwise returns true. + */ + Table.prototype.setRowValues = function(rowIndex, rowValues) { + var row = this.findRowByIndex(rowIndex) + + if (!row) { + return false + } + + var dataUpdated = false + + for (var i = 0, len = row.children.length; i < len; i++) { + var cell = row.children[i], + cellColumnName = this.getCellColumnName(cell) + + for (var rowColumnName in rowValues) { + if (rowColumnName == cellColumnName) { + this.setCellValue(cell, rowValues[rowColumnName], true) + dataUpdated = true + } + } + } + + if (dataUpdated) { + var originalEditedRowKey = this.editedRowKey + + this.editedRowKey = this.getRowKey(row) + this.commitEditedRow() + this.editedRowKey = originalEditedRowKey + } + + return true + } + + // HELPER METHODS + // ============================ + + Table.prototype.getElement = function() { + return this.el + } + + Table.prototype.getAlias = function() { + return this.options.alias + } + + Table.prototype.getTableContainer = function() { + return this.tableContainer + } + + Table.prototype.getDataTableBody = function() { + return this.dataTable.children[0] + } + + Table.prototype.getEventTarget = function(ev, tag) { + // TODO: use the foundation library + + var target = ev.target ? ev.target : ev.srcElement + + if (tag === undefined) + return target + + var tagName = target.tagName + + while (tagName != tag) { + target = target.parentNode + + if (!target) + return null + + tagName = target.tagName + } + + return target + } + + Table.prototype.stopEvent = function(ev) { + // TODO: use the foundation library + + if (ev.stopPropagation) + ev.stopPropagation() + else + ev.cancelBubble = true + + if(ev.preventDefault) + ev.preventDefault() + else + ev.returnValue = false + } + + Table.prototype.elementHasClass = function(el, className) { + // TODO: use the foundation library + + if (el.classList) + return el.classList.contains(className); + + return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className); + } + + Table.prototype.elementAddClass = function(el, className) { + // TODO: use the foundation library + + if (this.elementHasClass(el, className)) + return + + if (el.classList) + el.classList.add(className); + else + el.className += ' ' + className; + } + + Table.prototype.elementRemoveClass = function(el, className) { + // TODO: use the foundation library + + if (el.classList) + el.classList.remove(className); + else + el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); + } + + Table.prototype.parentContainsElement = function(parent, element) { + while (element && element != parent) { + element = element.parentNode + } + + return element ? true : false + } + + Table.prototype.getCellValue = function(cellElement) { + return cellElement.querySelector('[data-container]').value + } + + Table.prototype.getCellRowKey = function(cellElement) { + return parseInt(cellElement.parentNode.getAttribute('data-row')) + } + + Table.prototype.getRowKey = function(rowElement) { + return parseInt(rowElement.getAttribute('data-row')) + } + + Table.prototype.findRowByKey = function(key) { + return this.dataTable.querySelector('tbody tr[data-row="'+key+'"]') + } + + Table.prototype.findRowByIndex = function(index) { + return this.getDataTableBody().children[index] + } + + Table.prototype.getCellRowIndex = function(cellElement) { + return parseInt(cellElement.parentNode.rowIndex) + } + + Table.prototype.getRowCellValueByColumnName = function(row, columnName) { + var cell = row.querySelector('td[data-column="'+columnName+'"]') + + if (!cell) + return cell + + return this.getCellValue(cell) + } + + Table.prototype.getRowData = function(row) { + var result = {} + + for (var i = 0, len = row.children.length; i < len; i++) { + var cell = row.children[i] + result[cell.getAttribute('data-column')] = this.getCellValue(cell) + } + + return result + } + + Table.prototype.getCellColumnName = function(cellElement) { + return cellElement.getAttribute('data-column') + } + + Table.prototype.setCellValue = function(cellElement, value, suppressEvents) { + var dataContainer = cellElement.querySelector('[data-container]') + + if (dataContainer.value != value) { + dataContainer.value = value + + this.markCellRowDirty(cellElement) + + this.notifyRowProcessorsOnChange(cellElement) + + if (suppressEvents === undefined || !suppressEvents) { + this.$el.trigger('oc.tableCellChanged', [ + this.getCellColumnName(cellElement), + value, + this.getCellRowIndex(cellElement) + ]) + } + } + } + + Table.DEFAULTS = { + clientDataSourceClass: 'client', + keyColumn: 'id', + recordsPerPage: false, + data: null, + postback: true, + postbackHandlerName: null, + adding: true, + deleting: true, + toolbar: true, + searching: false, + rowSorting: false, + height: false, + dynamicHeight: false + } + + // TABLE PLUGIN DEFINITION + // ============================ + + var old = $.fn.table + + $.fn.table = function (option) { + var args = Array.prototype.slice.call(arguments, 1), + result = undefined + + this.each(function () { + var $this = $(this) + var data = $this.data('oc.table') + var options = $.extend({}, Table.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.table', (data = new Table(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : this + } + + $.fn.table.Constructor = Table + + $.oc.table.table = Table + + // TABLE NO CONFLICT + // ================= + + $.fn.table.noConflict = function () { + $.fn.table = old + return this + } + + // TABLE DATA-API + // =============== + + $(document).on('render', function(){ + $('div[data-control=table]').table() + }) + +}(window.jQuery); diff --git a/modules/backend/widgets/table/assets/js/table.processor.autocomplete.js b/modules/backend/widgets/table/assets/js/table.processor.autocomplete.js new file mode 100644 index 0000000..6f74a2f --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.processor.autocomplete.js @@ -0,0 +1,215 @@ +/* + * Autocomplete cell processor for the table control. + */ + ++function ($) { "use strict"; + + // NAMESPACE CHECK + // ============================ + + if ($.oc.table === undefined) + throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded."); + + if ($.oc.table.processor === undefined) + throw new Error("The $.oc.table.processor namespace is not defined. Make sure that the table.processor.base.js script is loaded."); + + // CLASS DEFINITION + // ============================ + + var Base = $.oc.table.processor.string, + BaseProto = Base.prototype + + var AutocompleteProcessor = function(tableObj, columnName, columnConfiguration) { + // + // State properties + // + + this.cachedOptionPromises = {} + + // + // Parent constructor + // + + Base.call(this, tableObj, columnName, columnConfiguration) + } + + AutocompleteProcessor.prototype = Object.create(BaseProto) + AutocompleteProcessor.prototype.constructor = AutocompleteProcessor + + AutocompleteProcessor.prototype.dispose = function() { + this.cachedOptionPromises = null + + BaseProto.dispose.call(this) + } + + /* + * Forces the processor to hide the editor when the user navigates + * away from the cell. Processors can update the sell value in this method. + * Processors must clear the reference to the active cell in this method. + */ + AutocompleteProcessor.prototype.onUnfocus = function() { + if (!this.activeCell) + return + + this.removeAutocomplete() + + BaseProto.onUnfocus.call(this) + } + + /* + * Renders the cell in the normal (no edit) mode + */ + AutocompleteProcessor.prototype.renderCell = function(value, cellContentContainer) { + BaseProto.renderCell.call(this, value, cellContentContainer) + + // this.fetchOptions(cellContentContainer.parentNode) + } + + AutocompleteProcessor.prototype.buildEditor = function(cellElement, cellContentContainer, isClick) { + BaseProto.buildEditor.call(this, cellElement, cellContentContainer, isClick) + + var self = this + + this.fetchOptions(cellElement, function autocompleteFetchOptions(options) { + self.buildAutoComplete(options) + + self = null + }) + } + + AutocompleteProcessor.prototype.fetchOptions = function(cellElement, onSuccess) { + if (this.columnConfiguration.options) { + if (onSuccess !== undefined) { + onSuccess(this.columnConfiguration.options) + } + } else { + // If options are not provided and not found in the cache, + // request them from the server. For dependent autocomplete editors + // the caching key contains the master column values. + + if (this.triggerGetOptions(onSuccess) === false) { + return + } + + var row = cellElement.parentNode, + cachingKey = this.createOptionsCachingKey(row), + viewContainer = this.getViewContainer(cellElement) + + // Request options from the server. When the table widget builds, + // multiple cells in the column could require loading the options. + // The AJAX promises are cached here so that we have a single + // request per caching key. + + $.oc.foundation.element.addClass(viewContainer, 'loading') + + if (!this.cachedOptionPromises[cachingKey]) { + var requestData = { + column: this.columnName, + rowData: this.tableObj.getRowData(row) + }, + handlerName = this.tableObj.getAlias()+'::onGetAutocompleteOptions' + + this.cachedOptionPromises[cachingKey] = this.tableObj.$el.request(handlerName, {data: requestData}) + } + + this.cachedOptionPromises[cachingKey].done(function onAutocompleteLoadOptionsSuccess(data){ + if (onSuccess !== undefined) { + onSuccess(data.options) + } + }).always(function onAutocompleteLoadOptionsAlways(){ + $.oc.foundation.element.removeClass(viewContainer, 'loading') + }) + } + } + + AutocompleteProcessor.prototype.createOptionsCachingKey = function(row) { + var cachingKey = 'non-dependent', + dependsOn = this.columnConfiguration.dependsOn + + if (dependsOn) { + if (typeof dependsOn == 'object') { + for (var i = 0, len = dependsOn.length; i < len; i++ ) + cachingKey += dependsOn[i] + this.tableObj.getRowCellValueByColumnName(row, dependsOn[i]) + } else + cachingKey = dependsOn + this.tableObj.getRowCellValueByColumnName(row, dependsOn) + } + + return cachingKey + } + + AutocompleteProcessor.prototype.triggerGetOptions = function(callback) { + var tableElement = this.tableObj.getElement() + if (!tableElement) { + return + } + + var optionsEvent = $.Event('autocompleteitems.oc.table'), + values = {} // TODO - implement loading values from the current row. + + $(tableElement).trigger(optionsEvent, [{ + values: values, + callback: callback, + column: this.columnName, + columnConfiguration: this.columnConfiguration + }]) + + if (optionsEvent.isDefaultPrevented()) { + return false + } + + return true + } + + AutocompleteProcessor.prototype.getInput = function() { + if (!this.activeCell) { + return null + } + + return this.activeCell.querySelector('.string-input') + } + + AutocompleteProcessor.prototype.buildAutoComplete = function(items) { + if (!this.activeCell) { + return + } + + var input = this.getInput() + if (!input) { + return + } + + if (items === undefined) { + items = [] + } + + $(input).autocomplete({ + source: this.prepareItems(items), + matchWidth: true, + menu: '', + bodyContainer: true + }) + } + + AutocompleteProcessor.prototype.prepareItems = function(items) { + var result = {} + + if ($.isArray(items)) { + for (var i = 0, len = items.length; i < len; i++) { + result[items[i]] = items[i] + } + } + else { + result = items + } + + return result + } + + AutocompleteProcessor.prototype.removeAutocomplete = function() { + var input = this.getInput() + + $(input).autocomplete('destroy') + } + + $.oc.table.processor.autocomplete = AutocompleteProcessor; +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/table/assets/js/table.processor.base.js b/modules/backend/widgets/table/assets/js/table.processor.base.js new file mode 100644 index 0000000..c6627bc --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.processor.base.js @@ -0,0 +1,210 @@ +/* + * Base class for the table cell processors. + */ ++function ($) { "use strict"; + + // PROCESSOR NAMESPACES + // ============================ + + if ($.oc.table === undefined) + throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded."); + + if ($.oc.table.processor === undefined) + $.oc.table.processor = {} + + // CLASS DEFINITION + // ============================ + + var Base = function(tableObj, columnName, columnConfiguration) { + // + // State properties + // + + this.tableObj = tableObj + + this.columnName = columnName + + this.columnConfiguration = columnConfiguration + + this.activeCell = null + + this.validators = [] + + // Register event handlers + this.registerHandlers() + + // Initialize validators + this.initValidators() + } + + Base.prototype.dispose = function() { + // Register event handlers + this.unregisterHandlers() + + // Remove references to the DOM + this.tableObj = null + + this.activeCell = null + } + + /* + * Renders the cell in the normal (no edit) mode + */ + Base.prototype.renderCell = function(value, cellContentContainer) { + } + + /* + * Registers event handlers required for the cell processor. + * Event handers should be bound to the container control element + * (not to the table element). + */ + Base.prototype.registerHandlers = function() { + } + + /* + * Unregisters event handlers previously registered with + * registerHandlers(). + */ + Base.prototype.unregisterHandlers = function() { + } + + /* + * This method is called when the cell managed by the processor + * is focused (clicked or navigated with the keyboard). + */ + Base.prototype.onFocus = function(cellElement, isClick) { + } + + + /* + * Forces the processor to hide the editor when the user navigates + * away from the cell. Processors can update the sell value in this method. + * Processors must clear the reference to the active cell in this method. + */ + Base.prototype.onUnfocus = function() { + } + + /* + * Event handler for the keydown event. The table class calls this method + * for all processors. + */ + Base.prototype.onKeyDown = function(ev) { + } + + /* + * Event handler for the click event. The table class calls this method + * for all processors. + */ + Base.prototype.onClick = function(ev) { + } + + /* + * This method is called when a cell value in the row changes. + */ + Base.prototype.onRowValueChanged = function(columnName, cellElement) { + } + + /* + * Determines if the keyboard navigation in the specified direction is allowed + * by the cell processor. Some processors could reject the navigation, for example + * the string processor could cancel the left array navigation if the caret + * in the text input is not in the beginning of the text. + */ + Base.prototype.keyNavigationAllowed = function(ev, direction) { + return true + } + + /* + * Determines if the processor's cell is focusable. + */ + Base.prototype.isCellFocusable = function() { + return true + } + + /* + * Returns the content container element of a cell + */ + Base.prototype.getCellContentContainer = function(cellElement) { + return cellElement.querySelector('.content-container') + } + + /* + * Creates a cell view data container (a DIV element that contains + * the current cell value). This functionality is required for most + * of the processors, perhaps except the checkbox cell processor. + */ + Base.prototype.createViewContainer = function(cellContentContainer, value) { + var viewContainer = document.createElement('div') + + viewContainer.setAttribute('data-view-container', 'data-view-container') + viewContainer.textContent = value === undefined ? '' : value + + cellContentContainer.appendChild(viewContainer) + + return viewContainer + } + + /* + * Returns the cell's view container element. + */ + Base.prototype.getViewContainer = function(cellElement) { + return cellElement.querySelector('[data-view-container]') + } + + /* + * Displays the view container + */ + Base.prototype.showViewContainer = function(cellElement) { + return this.getViewContainer(cellElement).setAttribute('class', '') + } + + /* + * Hides the view container + */ + Base.prototype.hideViewContainer = function(cellElement) { + return this.getViewContainer(cellElement).setAttribute('class', 'hide') + } + + /* + * Sets visual value for the view container + */ + Base.prototype.setViewContainerValue = function(cellElement, value) { + return this.getViewContainer(cellElement).textContent = value + } + + /* + * Determines whether the specified element is some element created by the + * processor. + */ + Base.prototype.elementBelongsToProcessor = function(element) { + return false + } + + Base.prototype.initValidators = function() { + if (this.columnConfiguration.validation === undefined) + return + + for (var validatorName in this.columnConfiguration.validation) { + if ($.oc.table.validator === undefined || $.oc.table.validator[validatorName] == undefined) + throw new Error('The table cell validator "'+validatorName+'" for the column "'+this.columnName+'" is not ' + + 'found in the $.oc.table.validator namespace.') + + var validator = new $.oc.table.validator[validatorName]( + this.columnConfiguration.validation[validatorName] + ) + + this.validators.push(validator) + } + } + + Base.prototype.validate = function(value, rowData) { + for (var i=0, len=this.validators.length; i 0 + } + + $.oc.table.validator.base = Base; +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/table/assets/js/table.validator.basenumber.js b/modules/backend/widgets/table/assets/js/table.validator.basenumber.js new file mode 100644 index 0000000..9a0f6c0 --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.validator.basenumber.js @@ -0,0 +1,57 @@ +/* + * Base class for number validators. + */ ++function ($) { "use strict"; + + // NAMESPACE CHECK + // ============================ + + if ($.oc.table === undefined) + throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded."); + + if ($.oc.table.validator === undefined) + throw new Error("The $.oc.table.validator namespace is not defined. Make sure that the table.validator.base.js script is loaded."); + + // CLASS DEFINITION + // ============================ + + var Base = $.oc.table.validator.base, + BaseProto = Base.prototype + + var BaseNumber = function(options) { + Base.call(this, options) + }; + + BaseNumber.prototype = Object.create(BaseProto) + BaseNumber.prototype.constructor = BaseNumber + + BaseNumber.prototype.doCommonChecks = function(value) { + if (this.options.min !== undefined || this.options.max !== undefined) { + if (this.options.min !== undefined) { + if (this.options.min.value === undefined) + throw new Error('The min.value parameter is not defined in the table validator configuration') + + if (value < this.options.min.value) { + return this.options.min.message !== undefined ? + this.options.min.message : + "The value should not be less than " + this.options.min.value + } + } + + if (this.options.max !== undefined) { + if (this.options.max.value === undefined) + throw new Error('The max.value parameter is not defined in the table validator configuration') + + if (value > this.options.max.value) { + return this.options.max.message !== undefined ? + this.options.max.message : + "The value should not be more than " + this.options.max.value + } + } + } + + return + } + + $.oc.table.validator.baseNumber = BaseNumber +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/table/assets/js/table.validator.float.js b/modules/backend/widgets/table/assets/js/table.validator.float.js new file mode 100644 index 0000000..8c44997 --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.validator.float.js @@ -0,0 +1,59 @@ +/* + * Float table validator. + */ ++function ($) { "use strict"; + + // NAMESPACE CHECK + // ============================ + + if ($.oc.table === undefined) + throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded."); + + if ($.oc.table.validator === undefined) + throw new Error("The $.oc.table.validator namespace is not defined. Make sure that the table.validator.base.js script is loaded."); + + if ($.oc.table.validator.baseNumber === undefined) + throw new Error("The $.oc.table.validator.baseNumber namespace is not defined. Make sure that the table.validator.baseNumber.js script is loaded."); + + // CLASS DEFINITION + // ============================ + + var Base = $.oc.table.validator.baseNumber, + BaseProto = Base.prototype + + var Float = function(options) { + Base.call(this, options) + }; + + Float.prototype = Object.create(BaseProto) + Float.prototype.constructor = Float + + /* + * Validates a value and returns the error message. If there + * are no errors, returns undefined. + * The rowData parameter is an object containing all values in the + * target row. + */ + Float.prototype.validateValue = function(value, rowData) { + value = this.trim(value) + + if (value.length == 0) + return + + var testResult = this.options.allowNegative ? + /^[-]?([0-9]+\.[0-9]+|[0-9]+)$/.test(value) : + /^([0-9]+\.[0-9]+|[0-9]+)$/.test(value) + + if (!testResult) { + var defaultMessage = this.options.allowNegative ? + 'The value should be a floating point number.' : + 'The value should be a positive floating point number'; + + return this.getMessage(defaultMessage) + } + + return this.doCommonChecks(parseFloat(value)) + } + + $.oc.table.validator.float = Float +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/table/assets/js/table.validator.integer.js b/modules/backend/widgets/table/assets/js/table.validator.integer.js new file mode 100644 index 0000000..4af60e6 --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.validator.integer.js @@ -0,0 +1,59 @@ +/* + * Integer table validator. + */ ++function ($) { "use strict"; + + // NAMESPACE CHECK + // ============================ + + if ($.oc.table === undefined) + throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded."); + + if ($.oc.table.validator === undefined) + throw new Error("The $.oc.table.validator namespace is not defined. Make sure that the table.validator.base.js script is loaded."); + + if ($.oc.table.validator.baseNumber === undefined) + throw new Error("The $.oc.table.validator.baseNumber namespace is not defined. Make sure that the table.validator.baseNumber.js script is loaded."); + + // CLASS DEFINITION + // ============================ + + var Base = $.oc.table.validator.baseNumber, + BaseProto = Base.prototype + + var Integer = function(options) { + Base.call(this, options) + }; + + Integer.prototype = Object.create(BaseProto) + Integer.prototype.constructor = Integer + + /* + * Validates a value and returns the error message. If there + * are no errors, returns undefined. + * The rowData parameter is an object containing all values in the + * target row. + */ + Integer.prototype.validateValue = function(value, rowData) { + value = this.trim(value) + + if (value.length == 0) + return + + var testResult = this.options.allowNegative ? + /^\-?[0-9]*$/.test(value) : + /^[0-9]*$/.test(value) + + if (!testResult) { + var defaultMessage = this.options.allowNegative ? + 'The value should be an integer.' : + 'The value should be a positive integer'; + + return this.getMessage(defaultMessage) + } + + return this.doCommonChecks(parseInt(value)) + } + + $.oc.table.validator.integer = Integer +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/table/assets/js/table.validator.length.js b/modules/backend/widgets/table/assets/js/table.validator.length.js new file mode 100644 index 0000000..0461eab --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.validator.length.js @@ -0,0 +1,68 @@ +/* + * String length table validator. + */ ++function ($) { "use strict"; + + // NAMESPACE CHECK + // ============================ + + if ($.oc.table === undefined) + throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded."); + + if ($.oc.table.validator === undefined) + throw new Error("The $.oc.table.validator namespace is not defined. Make sure that the table.validator.base.js script is loaded."); + + // CLASS DEFINITION + // ============================ + + var Base = $.oc.table.validator.base, + BaseProto = Base.prototype + + var Length = function(options) { + Base.call(this, options) + }; + + Length.prototype = Object.create(BaseProto) + Length.prototype.constructor = Length + + /* + * Validates a value and returns the error message. If there + * are no errors, returns undefined. + * The rowData parameter is an object containing all values in the + * target row. + */ + Length.prototype.validateValue = function(value, rowData) { + value = this.trim(value) + + if (value.length == 0) + return + + if (this.options.min !== undefined || this.options.max !== undefined) { + if (this.options.min !== undefined) { + if (this.options.min.value === undefined) + throw new Error('The min.value parameter is not defined in the Length table validator configuration') + + if (value.length < this.options.min.value) { + return this.options.min.message !== undefined ? + this.options.min.message : + "The string should not be shorter than " + this.options.min.value + } + } + + if (this.options.max !== undefined) { + if (this.options.max.value === undefined) + throw new Error('The max.value parameter is not defined in the Length table validator configuration') + + if (value.length > this.options.max.value) { + return this.options.max.message !== undefined ? + this.options.max.message : + "The string should not be longer than " + this.options.max.value + } + } + } + + return + } + + $.oc.table.validator.length = Length +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/table/assets/js/table.validator.regex.js b/modules/backend/widgets/table/assets/js/table.validator.regex.js new file mode 100644 index 0000000..9091450 --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.validator.regex.js @@ -0,0 +1,52 @@ +/* + * Regex length table validator. + */ ++function ($) { "use strict"; + + // NAMESPACE CHECK + // ============================ + + if ($.oc.table === undefined) + throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded."); + + if ($.oc.table.validator === undefined) + throw new Error("The $.oc.table.validator namespace is not defined. Make sure that the table.validator.base.js script is loaded."); + + // CLASS DEFINITION + // ============================ + + var Base = $.oc.table.validator.base, + BaseProto = Base.prototype + + var Regex = function(options) { + Base.call(this, options) + }; + + Regex.prototype = Object.create(BaseProto) + Regex.prototype.constructor = Regex + + /* + * Validates a value and returns the error message. If there + * are no errors, returns undefined. + * The rowData parameter is an object containing all values in the + * target row. + */ + Regex.prototype.validateValue = function(value, rowData) { + value = this.trim(value) + + if (value.length == 0) + return + + if (this.options.pattern === undefined) + throw new Error('The pattern parameter is not defined in the Regex table validator configuration') + + var regexObj = new RegExp(this.options.pattern, this.options.modifiers) + + if (!regexObj.test(value)) + return this.getMessage("Invalid value format.") + + return + } + + $.oc.table.validator.regex = Regex +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/table/assets/js/table.validator.required.js b/modules/backend/widgets/table/assets/js/table.validator.required.js new file mode 100644 index 0000000..b903579 --- /dev/null +++ b/modules/backend/widgets/table/assets/js/table.validator.required.js @@ -0,0 +1,44 @@ +/* + * Required table validator. + */ ++function ($) { "use strict"; + + // NAMESPACE CHECK + // ============================ + + if ($.oc.table === undefined) + throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded."); + + if ($.oc.table.validator === undefined) + throw new Error("The $.oc.table.validator namespace is not defined. Make sure that the table.validator.base.js script is loaded."); + + // CLASS DEFINITION + // ============================ + + var Base = $.oc.table.validator.base, + BaseProto = Base.prototype + + var Required = function(options) { + Base.call(this, options) + }; + + Required.prototype = Object.create(BaseProto) + Required.prototype.constructor = Required + + /* + * Validates a value and returns the error message. If there + * are no errors, returns undefined. + * The rowData parameter is an object containing all values in the + * target row. + */ + Required.prototype.validateValue = function(value, rowData) { + value = this.trim(value) + + if (value.length === 0) + return this.getMessage("The value should not be empty.") + + return + } + + $.oc.table.validator.required = Required +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/table/assets/less/table.less b/modules/backend/widgets/table/assets/less/table.less new file mode 100644 index 0000000..4d9fc20 --- /dev/null +++ b/modules/backend/widgets/table/assets/less/table.less @@ -0,0 +1,484 @@ +@import "../../../../../backend/assets/less/core/boot.less"; + +/* + * General control styling + */ + +@table-active-border: #e0e0e0; +@table-inactive-border: #e0e0e0; + +.control-table { + .table-container { + border: 1px solid @table-inactive-border; + .border-radius(4px); + overflow: hidden; + margin-bottom: 15px; + + &:last-child { + margin-bottom: 0; + } + } + + &.active .table-container { + border-color: @table-active-border; + } + + table { + width: 100%; + border-collapse: collapse; + table-layout: fixed; + + td, th { + padding: 0; + font-size: 13px; + color: #555555; + } + + [data-view-container] { + padding: 5px 10px; + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + min-height: 28px; + } + } + + table.headers { + &:after { + content: ' '; + display: block; + position: absolute; + left: 1px; + right: 1px; + margin-top: -1px; + border-bottom: 1px solid @table-inactive-border; + } + + th { + padding: 7px 10px; + font-weight: normal; + text-transform: uppercase; + font-size: @font-size-base - 3; + color: #333333; + background: white; + border-right: 1px solid #ecf0f1; + [data-view-container] { + padding-bottom: 6px; + } + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + &:last-child { + border-right: none; + } + } + } + + &.active table.headers:after { + border-bottom-color: @table-active-border; + } + + table.data { + td { + border: 1px solid #ecf0f1; + + .content-container { + position: relative; + padding: 1px; + } + + &.active { + border-color: @color-focus!important; + + .content-container { + padding: 0; + border: 1px solid @color-focus; + + &:before, &:after { + content: ' '; + background: @color-focus; + position: absolute; + left: -2px; + top: -2px; + } + + &:before { + width: 1px; + bottom: -2px; + } + + &:after { + right: -2px; + height: 1px; + } + } + } + } + + tr { + background-color: white; + + &.error { + background-color: #fbecec!important; + + td.active.error { + border-color: #ec0000!important; + + .content-container { + border-color: #ec0000!important; + &:before, &:after { + background-color: #ec0000!important; + } + } + } + } + } + + tr:nth-child(2n) { + background-color: #fbfbfb; + } + } + + table.data { + tr:first-child td { + border-top: none; + } + + tr:last-child td { + border-bottom: none; + } + + td:first-child { + border-left: none; + } + + td:last-child { + border-right: none; + } + } + + .control-scrollbar { + > div { + .border-bottom-radius(4px); + overflow: hidden; + } + + table.data { + tr:last-child td { + border-bottom: 1px solid #ecf0f1; + } + } + } + + .toolbar { + background: white; + border-bottom: 1px solid @table-inactive-border; + + a.btn { + color: #323e50; + padding: 8px 10px; + .opacity(0.5); + .box-shadow(none) !important; + text-shadow: none; + + &:hover { + .opacity(1); + } + } + + .table-search { + float: right; + margin: 3px 3px 0 0; + + .table-search-input { + height: auto; + padding: 5px 13px 5px; + } + } + + a.table-icon { + &:before { + display: inline-block; + content: ' '; + width: 16px; + height: 16px; + margin-right: 8px; + position: relative; + top: 3px; + background: transparent url(../images/table-icons.gif) no-repeat 0 0; + background-size: 32px auto; + } + + &.add-table-row-above:before { + background-position: 0 -56px; + } + + &.delete-table-row:before { + background-position: 0 -113px; + } + } + } + + &.active .toolbar { + border-bottom-color: @table-active-border; + } + + .pagination { + ul { + padding: 0; + margin-bottom: 15px; + + li { + list-style: none; + padding: 4px 6px; + .border-radius(2px); + display: inline-block; + margin-right: 5px; + font-size: 12px; + background: #ecf0f1; + line-height: 100%; + + a { + text-decoration: none; + color: #95a5a6; + } + + &.active { + background: @brand-accent; + + a {color: #ffffff;} + } + } + } + } +} + +@media only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-devicepixel-ratio: 1.5), only screen and (min-resolution: 1.5dppx) { + .control-table .toolbar { + a { + &:before { + background-position: 0px -9px; + background-size: 16px auto; + } + + &.add-table-row-above:before { + background-position: 0 -39px; + } + + &.delete-table-row:before { + background-position: 0 -66px; + } + } + } +} + +/* + * String and autocomplete editors + */ + +.control-table { + td[data-column-type=string], + td[data-column-type=autocomplete] { + input[type=text] { + width: 100%; + height: 100%; + display: block; + outline: none; + border: none; + padding: 6px 10px 7px; + } + } +} + +html.chrome { + .control-table { + td[data-column-type=string], + td[data-column-type=autocomplete] { + input[type=text] { + padding: 6px 10px 7px!important; + } + } + } +} + +html.safari, html.gecko { + .control-table { + td[data-column-type=string], + td[data-column-type=autocomplete] { + input[type=text] { + padding: 5px 10px 5px; + } + } + } +} + +ul.table-widget-autocomplete { + background: white; + font-size: 13px; + margin-top: 0; + border: 1px solid #808c8d; + border-top: 1px solid #ecf0f1; + .border-bottom-radius(4px); + + li a { + padding: 5px 10px; + } +} + +/* + * Checkbox editor + */ + +.control-table { + td[data-column-type=checkbox] { + div[data-checkbox-element] { + width: 16px; + height: 16px; + border-radius: @border-radius-base; + background-color: #FFFFFF; + border: 1px solid @color-custom-input-border; + margin: 5px 5px 5px 10px; + cursor: pointer; + + .user-select(none); + + &:hover { + border-color: darken(@color-custom-input-border, 10%); + color: darken(@color-custom-input-icon, 10%); + } + + &.checked { + border-width: 2px; + + &:before { + .icon(@check); + font-size: 10px; + position: relative; + left: 1px; + top: -4px; + } + } + + &:focus { + border-color: @color-focus; + outline: none; + } + } + } +} + +/* + * Dropdown editor + */ + +.control-table { + td[data-column-type=dropdown] { + .user-select(none); + + .dropdown-arrow() { + .icon(@angle-down); + font-size: 13px; + line-height: 100%; + color: #95a5a6; + position: absolute; + top: 8px; + right: 10px; + } + + [data-view-container] { + padding-right: 20px; + position: relative; + cursor: pointer; + + &:after { + .dropdown-arrow(); + } + + &:hover:after { + color: @link-color; + } + } + + [data-dropdown-open=true] { + background: white; + [data-view-container]:after { + .icon(@angle-up); + } + } + + .content-container { + outline: none; + } + } +} + +/* Frameless control styles start */ + +.widget-field.frameless .control-table { + .table-container { + border-top: none; + border-left: none; + border-right: none; + .border-radius(0); + } + + .toolbar { + background: transparent; + } +} + +/* Frameless control styles end */ + +html.cssanimations { + .control-table td[data-column-type=dropdown] { + [data-view-container].loading:after { + background: url('../../../../../../modules/system/assets/ui/images/loader-transparent.svg') 50% 50%; + background-size: 15px 15px; + position: absolute; + width: 15px; + height: 15px; + top: 6px; + right: 5px; + content: ' '; + .animation(spin 1s linear infinite); + } + } +} + +.table-control-dropdown-list { + .user-select(none); + position: absolute; + background: white; + border: 1px solid @table-active-border; + border-top: none; + padding-top: 1px; + overflow: hidden; + z-index: 1000; + .box-sizing(border-box); + .border-bottom-radius(4px); + + ul { + border-top: 1px solid #ecf0f1; + padding: 0; + margin: 0; + max-height: 200px; + overflow: auto; + } + + li { + list-style: none; + font-size: 13px; + color: #555555; + padding: 5px 10px; + cursor: pointer; + outline: none; + + &:focus { + background: @color-focus; + color: white; + } + } +} diff --git a/modules/backend/widgets/table/partials/_table.htm b/modules/backend/widgets/table/partials/_table.htm new file mode 100644 index 0000000..54fb020 --- /dev/null +++ b/modules/backend/widgets/table/partials/_table.htm @@ -0,0 +1,50 @@ +
    + data-postback-handler-name="" + + data-adding="" + data-searching="" + data-deleting="" + data-toolbar="" + data-height="" + data-records-per-page="" + data-key-column="" + data-client-data-source-class="" + data-dynamic-height="" +> + + +
    diff --git a/modules/backend/widgets/toolbar/partials/_toolbar.htm b/modules/backend/widgets/toolbar/partials/_toolbar.htm new file mode 100644 index 0000000..bf43b9d --- /dev/null +++ b/modules/backend/widgets/toolbar/partials/_toolbar.htm @@ -0,0 +1,17 @@ +
    +
    + + +
    + +
    + + + +
    + +
    + + +
    +
    \ No newline at end of file diff --git a/modules/cms/ServiceProvider.php b/modules/cms/ServiceProvider.php new file mode 100644 index 0000000..f4e54b8 --- /dev/null +++ b/modules/cms/ServiceProvider.php @@ -0,0 +1,383 @@ +registerComponents(); + $this->registerThemeLogging(); + $this->registerCombinerEvents(); + $this->registerHalcyonModels(); + + /* + * Backend specific + */ + if (App::runningInBackend()) { + $this->registerBackendNavigation(); + $this->registerBackendReportWidgets(); + $this->registerBackendPermissions(); + $this->registerBackendWidgets(); + $this->registerBackendSettings(); + } + } + + /** + * Bootstrap the module events. + * + * @return void + */ + public function boot() + { + parent::boot('cms'); + + $this->bootMenuItemEvents(); + $this->bootRichEditorEvents(); + + if (App::runningInBackend()) { + $this->bootBackendLocalization(); + } + } + + /** + * Register components. + */ + protected function registerComponents() + { + ComponentManager::instance()->registerComponents(function ($manager) { + $manager->registerComponent(\Cms\Components\ViewBag::class, 'viewBag'); + $manager->registerComponent(\Cms\Components\Resources::class, 'resources'); + }); + } + + /** + * Registers theme logging on templates. + */ + protected function registerThemeLogging() + { + CmsObject::extend(function ($model) { + ThemeLog::bindEventsToModel($model); + }); + } + + /** + * Registers events for the asset combiner. + */ + protected function registerCombinerEvents() + { + if (App::runningInBackend() || App::runningInConsole()) { + return; + } + + Event::listen('cms.combiner.beforePrepare', function ($combiner, $assets) { + $filters = array_flatten($combiner->getFilters()); + ThemeData::applyAssetVariablesToCombinerFilters($filters); + }); + + Event::listen('cms.combiner.getCacheKey', function ($combiner, $holder) { + $holder->key = $holder->key . ThemeData::getCombinerCacheKey(); + }); + } + + /* + * Register navigation + */ + protected function registerBackendNavigation() + { + BackendMenu::registerCallback(function ($manager) { + $manager->registerMenuItems('October.Cms', [ + 'cms' => [ + 'label' => 'cms::lang.cms.menu_label', + 'icon' => 'icon-magic', + 'iconSvg' => 'modules/cms/assets/images/cms-icon.svg', + 'url' => Backend::url('cms'), + 'order' => 100, + 'permissions' => [ + 'cms.manage_content', + 'cms.manage_assets', + 'cms.manage_pages', + 'cms.manage_layouts', + 'cms.manage_partials' + ], + 'sideMenu' => [ + 'pages' => [ + 'label' => 'cms::lang.page.menu_label', + 'icon' => 'icon-copy', + 'url' => 'javascript:;', + 'attributes' => ['data-menu-item' => 'pages'], + 'permissions' => ['cms.manage_pages'], + 'counterLabel' => 'cms::lang.page.unsaved_label' + ], + 'partials' => [ + 'label' => 'cms::lang.partial.menu_label', + 'icon' => 'icon-tags', + 'url' => 'javascript:;', + 'attributes' => ['data-menu-item' => 'partials'], + 'permissions' => ['cms.manage_partials'], + 'counterLabel' => 'cms::lang.partial.unsaved_label' + ], + 'layouts' => [ + 'label' => 'cms::lang.layout.menu_label', + 'icon' => 'icon-th-large', + 'url' => 'javascript:;', + 'attributes' => ['data-menu-item' => 'layouts'], + 'permissions' => ['cms.manage_layouts'], + 'counterLabel' => 'cms::lang.layout.unsaved_label' + ], + 'content' => [ + 'label' => 'cms::lang.content.menu_label', + 'icon' => 'icon-file-text-o', + 'url' => 'javascript:;', + 'attributes' => ['data-menu-item' => 'content'], + 'permissions' => ['cms.manage_content'], + 'counterLabel' => 'cms::lang.content.unsaved_label' + ], + 'assets' => [ + 'label' => 'cms::lang.asset.menu_label', + 'icon' => 'icon-picture-o', + 'url' => 'javascript:;', + 'attributes' => ['data-menu-item' => 'assets'], + 'permissions' => ['cms.manage_assets'], + 'counterLabel' => 'cms::lang.asset.unsaved_label' + ], + 'components' => [ + 'label' => 'cms::lang.component.menu_label', + 'icon' => 'icon-puzzle-piece', + 'url' => 'javascript:;', + 'attributes' => ['data-menu-item' => 'components'], + 'permissions' => ['cms.manage_pages', 'cms.manage_layouts', 'cms.manage_partials'] + ] + ] + ] + ]); + + $manager->registerQuickActions('October.Cms', [ + 'preview' => [ + 'label' => 'backend::lang.tooltips.preview_website', + 'icon' => 'icon-crosshairs', + 'url' => Url::to('/'), + 'order' => 10, + 'attributes' => [ + 'target' => '_blank', + 'rel' => 'noopener noreferrer', + ], + ], + ]); + }); + } + + /* + * Register report widgets + */ + protected function registerBackendReportWidgets() + { + WidgetManager::instance()->registerReportWidgets(function ($manager) { + $manager->registerReportWidget(\Cms\ReportWidgets\ActiveTheme::class, [ + 'label' => 'cms::lang.dashboard.active_theme.widget_title_default', + 'context' => 'dashboard' + ]); + }); + } + + /* + * Register permissions + */ + protected function registerBackendPermissions() + { + BackendAuth::registerCallback(function ($manager) { + $manager->registerPermissions('October.Cms', [ + 'cms.manage_content' => [ + 'label' => 'cms::lang.permissions.manage_content', + 'tab' => 'cms::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + 'order' => 100 + ], + 'cms.manage_assets' => [ + 'label' => 'cms::lang.permissions.manage_assets', + 'tab' => 'cms::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + 'order' => 100 + ], + 'cms.manage_pages' => [ + 'label' => 'cms::lang.permissions.manage_pages', + 'tab' => 'cms::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + 'order' => 100 + ], + 'cms.manage_layouts' => [ + 'label' => 'cms::lang.permissions.manage_layouts', + 'tab' => 'cms::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + 'order' => 100 + ], + 'cms.manage_partials' => [ + 'label' => 'cms::lang.permissions.manage_partials', + 'tab' => 'cms::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + 'order' => 100 + ], + 'cms.manage_themes' => [ + 'label' => 'cms::lang.permissions.manage_themes', + 'tab' => 'cms::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + 'order' => 100 + ], + 'cms.manage_theme_options' => [ + 'label' => 'cms::lang.permissions.manage_theme_options', + 'tab' => 'cms::lang.permissions.name', + 'order' => 100 + ], + ]); + }); + } + + /* + * Register widgets + */ + protected function registerBackendWidgets() + { + WidgetManager::instance()->registerFormWidgets(function ($manager) { + $manager->registerFormWidget(FormWidgets\Components::class); + }); + } + + /* + * Register settings + */ + protected function registerBackendSettings() + { + SettingsManager::instance()->registerCallback(function ($manager) { + $manager->registerSettingItems('October.Cms', [ + 'theme' => [ + 'label' => 'cms::lang.theme.settings_menu', + 'description' => 'cms::lang.theme.settings_menu_description', + 'category' => SettingsManager::CATEGORY_CMS, + 'icon' => 'icon-picture-o', + 'url' => Backend::url('cms/themes'), + 'permissions' => ['cms.manage_themes', 'cms.manage_theme_options'], + 'order' => 200 + ], + 'maintenance_settings' => [ + 'label' => 'cms::lang.maintenance.settings_menu', + 'description' => 'cms::lang.maintenance.settings_menu_description', + 'category' => SettingsManager::CATEGORY_CMS, + 'icon' => 'icon-plug', + 'class' => Models\MaintenanceSetting::class, + 'permissions' => ['cms.manage_themes'], + 'order' => 300 + ], + 'theme_logs' => [ + 'label' => 'cms::lang.theme_log.menu_label', + 'description' => 'cms::lang.theme_log.menu_description', + 'category' => SettingsManager::CATEGORY_LOGS, + 'icon' => 'icon-magic', + 'url' => Backend::url('cms/themelogs'), + 'permissions' => ['system.access_logs'], + 'order' => 910, + 'keywords' => 'theme change log' + ] + ]); + }); + } + + /** + * Boots localization from an active theme for backend items. + */ + protected function bootBackendLocalization() + { + $theme = CmsTheme::getActiveTheme(); + + if (is_null($theme)) { + return; + } + + $langPath = $theme->getPath() . '/lang'; + + if (File::isDirectory($langPath)) { + Lang::addNamespace('themes.' . $theme->getId(), $langPath); + } + } + + /** + * Registers events for menu items. + */ + protected function bootMenuItemEvents() + { + Event::listen('pages.menuitem.listTypes', function () { + return [ + 'cms-page' => 'cms::lang.page.cms_page' + ]; + }); + + Event::listen('pages.menuitem.getTypeInfo', function ($type) { + if ($type === 'cms-page') { + return CmsPage::getMenuTypeInfo($type); + } + }); + + Event::listen('pages.menuitem.resolveItem', function ($type, $item, $url, $theme) { + if ($type === 'cms-page') { + return CmsPage::resolveMenuItem($item, $url, $theme); + } + }); + } + + /** + * Registers events for rich editor page links. + */ + protected function bootRichEditorEvents() + { + Event::listen('backend.richeditor.listTypes', function () { + return [ + 'cms-page' => 'cms::lang.page.cms_page' + ]; + }); + + Event::listen('backend.richeditor.getTypeInfo', function ($type) { + if ($type === 'cms-page') { + return CmsPage::getRichEditorTypeInfo($type); + } + }); + } + + /** + * Registers the models to be made available to the theme database layer + */ + protected function registerHalcyonModels() + { + Event::listen('system.console.theme.sync.getAvailableModelClasses', function () { + return [ + Classes\Meta::class, + Classes\Page::class, + Classes\Layout::class, + Classes\Content::class, + Classes\Partial::class + ]; + }); + } +} diff --git a/modules/cms/assets/css/october.components.css b/modules/cms/assets/css/october.components.css new file mode 100644 index 0000000..878e71e --- /dev/null +++ b/modules/cms/assets/css/october.components.css @@ -0,0 +1,366 @@ +.draggable-component-item, +.component-list .components div.layout-cell, +div.control-componentlist div.components div.layout-cell { + font-size: 11px; + cursor: pointer; + background: #ffffff; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.draggable-component-item:hover, +.component-list .components div.layout-cell:hover, +div.control-componentlist div.components div.layout-cell:hover { + background: #3498db; +} +.draggable-component-item > div, +.component-list .components div.layout-cell > div, +div.control-componentlist div.components div.layout-cell > div { + white-space: normal; + color: #475354; + position: relative; + border-right: 1px solid #ecf0f1; +} +.draggable-component-item > div:before, +.component-list .components div.layout-cell > div:before, +div.control-componentlist div.components div.layout-cell > div:before { + position: absolute; + font-size: 16px; + left: 15px; + top: 7px; + opacity: 0.7; + filter: alpha(opacity=70); +} +.draggable-component-item > div:hover, +.component-list .components div.layout-cell > div:hover, +div.control-componentlist div.components div.layout-cell > div:hover { + color: #ffffff; +} +.draggable-component-item > div:hover:before, +.component-list .components div.layout-cell > div:hover:before, +div.control-componentlist div.components div.layout-cell > div:hover:before { + opacity: 1; + filter: alpha(opacity=100); +} +.draggable-component-item > div:after, +.component-list .components div.layout-cell > div:after, +div.control-componentlist div.components div.layout-cell > div:after { + position: absolute; + font-size: 37px; + top: 1px; + z-index: 50; + color: #ffffff; + text-shadow: 0 0 1px #475354; + width: 12px; + overflow: hidden; + text-indent: -25px; + right: -12px; + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + content: "\f12e"; +} +.draggable-component-item > div:hover:after, +.component-list .components div.layout-cell > div:hover:after, +div.control-componentlist div.components div.layout-cell > div:hover:after { + text-shadow: none; + color: #3498db; +} +.draggable-component-item > div span, +.component-list .components div.layout-cell > div span, +div.control-componentlist div.components div.layout-cell > div span { + display: block; +} +.draggable-component-item > div span.name, +.component-list .components div.layout-cell > div span.name, +div.control-componentlist div.components div.layout-cell > div span.name { + white-space: nowrap; + padding: 8px 15px 0; + font-weight: 400; + line-height: 20px; + font-size: 13px; +} +.draggable-component-item > div span.description, +.component-list .components div.layout-cell > div span.description, +div.control-componentlist div.components div.layout-cell > div span.description { + padding: 0 15px 10px; + margin-top: 8px; + font-weight: 100; + font-size: 11px; + line-height: 150%; +} +.draggable-component-item.placeholder > div, +.component-list .components div.layout-cell.placeholder > div, +div.control-componentlist div.components div.layout-cell.placeholder > div { + background: #e0e0e0; + color: #e0e0e0; +} +.draggable-component-item.placeholder > div:before, +.component-list .components div.layout-cell.placeholder > div:before, +div.control-componentlist div.components div.layout-cell.placeholder > div:before, +.draggable-component-item.placeholder > div:after, +.component-list .components div.layout-cell.placeholder > div:after, +div.control-componentlist div.components div.layout-cell.placeholder > div:after { + color: #e0e0e0 !important; + text-shadow: none !important; +} +[data-field-name="components"] + .control-tabs.primary-tabs { + margin-top: -10px; +} +div.control-componentlist { + position: relative; + padding: 0; + -webkit-transition: all 0.3s ease; + transition: all 0.3s ease; +} +div.control-componentlist.droppable { + background-color: #f0b37e; +} +div.control-componentlist.has-components { + padding: 0 20px 20px; +} +div.control-componentlist div.layout { + width: auto; +} +div.control-componentlist div.components div.layout-cell.error-component { + background: #ab2a1c; +} +div.control-componentlist div.components div.layout-cell.error-component > div { + color: #ffffff; +} +div.control-componentlist div.components div.layout-cell.error-component > div:after { + color: #ab2a1c; +} +div.control-componentlist div.components div.layout-cell.warning-component { + background: #ffc107; +} +div.control-componentlist div.components div.layout-cell.warning-component > div { + color: #343a40; +} +div.control-componentlist div.components div.layout-cell.warning-component > div:after { + color: #ffc107; +} +div.control-componentlist div.components div.layout-cell:first-child { + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; +} +div.control-componentlist div.components div.layout-cell:last-child { + margin-right: 0; + border-bottom-right-radius: 3px; + border-top-right-radius: 3px; +} +div.control-componentlist div.components div.layout-cell:last-child > div { + border-right: none; +} +div.control-componentlist div.components div.layout-cell:last-child > div:after { + display: none; +} +div.control-componentlist div.components div.layout-cell:nth-child(2n) > div:after { + top: auto; + bottom: 5px; +} +div.control-componentlist div.components div.layout-cell:first-child > div.popover-highlight { + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; +} +div.control-componentlist div.components div.layout-cell:last-child > div.popover-highlight { + border-bottom-right-radius: 3px; + border-top-right-radius: 3px; +} +div.control-componentlist div.components div.layout-cell > div { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); + -webkit-transition: -webkit-transform 0.2s; + -moz-transition: -moz-transform 0.2s; + -o-transition: -o-transform 0.2s; + transition: transform 0.2s; + max-width: 250px; + min-width: 170px; +} +div.control-componentlist div.components div.layout-cell > div.popover-highlight { + border-right-color: rgba(0, 0, 0, 0); + background: #ffffff !important; + color: #475354 !important; +} +div.control-componentlist div.components div.layout-cell > div.popover-highlight:before { + opacity: 0.7; + filter: alpha(opacity=70); +} +div.control-componentlist div.components div.layout-cell > div.popover-highlight:after { + color: #ffffff; + text-shadow: none; +} +div.control-componentlist div.components div.layout-cell > div.popover-highlight a.remove { + display: none; +} +div.control-componentlist div.components div.layout-cell > div span.name { + padding-left: 38px; +} +div.control-componentlist div.components div.layout-cell > div span.description { + padding-bottom: 35px; +} +div.control-componentlist div.components div.layout-cell > div span.alias { + padding: 0 15px; + font-weight: 500; + position: absolute; + width: 100%; + bottom: 10px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} +div.control-componentlist div.components div.layout-cell > div span.alias:before { + margin-right: 4px; + opacity: 0.55; + filter: alpha(opacity=55.00000000000001); +} +div.control-componentlist div.components div.layout-cell > div a.remove { + position: absolute; + display: inline-block; + top: 1px; + right: 5px; + color: #000000; + font-size: 17px; + font-weight: bold; + opacity: 0.3; + filter: alpha(opacity=30); +} +div.control-componentlist div.components div.layout-cell > div a.remove:hover { + opacity: 0.5; + filter: alpha(opacity=50); + text-decoration: none; +} +div.control-componentlist div.components div.layout-cell.adding > div { + -webkit-transform: translate(0, -100px) !important; + -ms-transform: translate(0, -100px) !important; + transform: translate(0, -100px) !important; +} +.draggable-component-item { + opacity: 0.6; + filter: alpha(opacity=60); +} +.draggable-component-item span.alias { + display: none; +} +.draggable-component-item a.remove { + display: none; +} +.component-list .components div.layout div.layout-row div.layout-cell { + border-top: 1px solid #ecf0f1; +} +.component-list .components div.layout div.layout-row div.layout-cell span.alias { + display: none; +} +.component-list .components div.layout div.layout-row div.layout-cell a.remove { + display: none; +} +.component-list .components div.layout div.layout-row div.layout-cell:last-child > div { + border-right: none; +} +.component-list .components div.layout div.layout-row div.layout-cell:last-child > div:after { + display: none; +} +.component-list .components div.layout div.layout-row div.layout-cell > div:before { + position: absolute; + font-size: 37px; + top: 1px; + z-index: 50; + color: #ffffff; + text-shadow: 0 0 1px #475354; + width: 12px; + overflow: hidden; + text-indent: -25px; + right: -12px; + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + content: "\f12e"; + -webkit-transform: rotate(-90deg); + -ms-transform: rotate(-90deg); + transform: rotate(-90deg); + opacity: 1; + filter: alpha(opacity=100); + left: auto; + top: -17px; + right: 15px; +} +.component-list .components div.layout div.layout-row div.layout-cell > div:hover:before { + text-shadow: none; + color: #3498db; +} +.component-list .components div.layout div.layout-row:first-child div.layout-cell > div:before { + display: none; +} +.component-list .components div.layout.single div.layout-row > div.layout-cell > div { + border-right: none; +} +.component-list .components div.layout.single div.layout-row > div.layout-cell > div:before { + display: block; + right: 55.5%; +} +.control-filelist.component-list ul li div.group { + background: #f1f3f4; + border-top: 1px solid #e6ebed; + padding: 10px 15px 10px 10px; + position: relative; + cursor: pointer; +} +.control-filelist.component-list ul li div.group h4 { + text-transform: uppercase; + font-size: 14px; + margin-top: 3px; +} +.control-filelist.component-list ul li div.group h4 a { + padding-left: 33px; +} +.control-filelist.component-list ul li div.group h4 a:before { + left: 0; +} +.control-filelist.component-list ul li div.group h4 a:after { + display: none; +} +.control-filelist.component-list ul li div.group span.description { + display: block; + font-size: 13px; + padding-left: 33px; + color: #8f8f8f; +} +.control-filelist.component-list ul li div.group i { + position: absolute; + left: 22px; + top: 21px; + font-size: 16px; + opacity: 0.7; + filter: alpha(opacity=70); + color: #405261; +} +.touch div.control-componentlist div.components div.layout-cell > div:hover, +.touch div.control-componentlist div.components div.layout-cell > div:active, +.touch div.control-componentlist div.components div.layout-cell > div:active:focus { + background: #ffffff; + color: #475354; +} +.touch div.control-componentlist div.components div.layout-cell > div:hover:after, +.touch div.control-componentlist div.components div.layout-cell > div:active:after, +.touch div.control-componentlist div.components div.layout-cell > div:active:focus:after { + text-shadow: 0 0 1px #475354 !important; + color: #ffffff !important; +} +body.drag div.control-componentlist div.components div.layout-cell > div, +body.drag div.control-componentlist div.components div.layout-cell > div:hover, +body.drag div.control-componentlist div.components div.layout-cell > div:active { + background: #ffffff; + color: #475354; +} +body.drag div.control-componentlist div.components div.layout-cell > div:after, +body.drag div.control-componentlist div.components div.layout-cell > div:hover:after, +body.drag div.control-componentlist div.components div.layout-cell > div:active:after { + text-shadow: 0 0 1px #475354 !important; + color: #ffffff !important; +} diff --git a/modules/cms/assets/css/october.theme-selector.css b/modules/cms/assets/css/october.theme-selector.css new file mode 100644 index 0000000..b501774 --- /dev/null +++ b/modules/cms/assets/css/october.theme-selector.css @@ -0,0 +1,131 @@ +.theme-selector-layout .layout-cell { + padding: 24px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.theme-selector-layout .theme-thumbnail { + width: 288px; + background: #ecf0f1; + border-top: 1px solid #e3e7e9; +} +.theme-selector-layout .theme-thumbnail img { + opacity: 0.6; + filter: alpha(opacity=60); + width: 240px; +} +.theme-selector-layout .theme-description { + border-top: 1px solid #f2f3f4; +} +.theme-selector-layout .theme-description h3, +.theme-selector-layout .theme-description p { + opacity: 0.6; + filter: alpha(opacity=60); +} +.theme-selector-layout .theme-description h3 { + margin: 0 0 25px 0; + font-size: 28px; + color: #2b3e50; + display: inline-block; +} +.theme-selector-layout .theme-description p.author { + font-size: 13px; + display: inline-block; + color: #808c8d; +} +.theme-selector-layout .theme-description p.description { + color: #2b3e50; + font-size: 14px; + line-height: 180%; + margin-bottom: 30px; +} +.theme-selector-layout .theme-description .controls .btn > i { + margin-right: 5px; + font-size: 16px; + position: relative; + top: 1px; +} +.theme-selector-layout .theme-description .controls .btn > i.icon-star { + color: #f1a84e; +} +.theme-selector-layout .theme-description .controls .dropdown { + display: inline-block; +} +.theme-selector-layout .layout-row.active .theme-thumbnail { + background: #bdc3c7; + border-top-color: #bdc3c7; +} +.theme-selector-layout .layout-row.active .thumbnail-container { + position: relative; +} +.theme-selector-layout .layout-row.active .thumbnail-container:after { + content: ''; + display: block; + width: 0; + height: 0; + border-top: 14px solid transparent; + border-bottom: 14px solid transparent; + border-left: 15px solid #bdc3c7; + position: absolute; + right: -35px; + top: 50%; + margin-top: -14px; +} +.theme-selector-layout .layout-row.active .theme-description h3, +.theme-selector-layout .layout-row:hover .theme-description h3, +.theme-selector-layout .layout-row.active .theme-description p, +.theme-selector-layout .layout-row:hover .theme-description p { + opacity: 1; + filter: alpha(opacity=100); +} +.theme-selector-layout .layout-row.active .theme-thumbnail img, +.theme-selector-layout .layout-row:hover .theme-thumbnail img { + opacity: 1; + filter: alpha(opacity=100); +} +.theme-selector-layout .layout-row:first-child .theme-description, +.theme-selector-layout .layout-row.links .theme-description, +.theme-selector-layout .layout-row:first-child .theme-thumbnail, +.theme-selector-layout .layout-row.links .theme-thumbnail { + border-top: none; +} +.theme-selector-layout .layout-row.links .theme-thumbnail { + border-bottom: 1px solid #e3e7e9; +} +.theme-selector-layout .layout-row.links .theme-description { + border-bottom: 1px solid #f2f3f4; +} +.theme-selector-layout .create-new-theme { + margin-bottom: 10px; +} +.theme-selector-layout .create-new-theme, +.theme-selector-layout .find-more-themes { + background: #ecf0f1; + color: #2b3e50; + text-decoration: none; + display: block; + padding: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.theme-selector-layout .create-new-theme:hover, +.theme-selector-layout .find-more-themes:hover { + background: #0181b9; + color: white; +} +@media (max-width: 768px) { + .theme-selector-layout .layout-cell, + .theme-selector-layout .layout-row { + display: block!important; + width: auto!important; + height: auto!important; + } + .theme-selector-layout .theme-thumbnail img { + width: 100%; + } + .theme-selector-layout .layout-row.links .theme-thumbnail { + background: transparent; + padding: 0; + } +} diff --git a/modules/cms/assets/css/themelogs/template-diff.css b/modules/cms/assets/css/themelogs/template-diff.css new file mode 100644 index 0000000..e97c8af --- /dev/null +++ b/modules/cms/assets/css/themelogs/template-diff.css @@ -0,0 +1,10 @@ +del { + text-decoration: none; + color: #b30000; + background: #fadad7; +} +ins { + background: #eaf2c2; + color: #406619; + text-decoration: none; +} diff --git a/modules/cms/assets/images/cms-icon.svg b/modules/cms/assets/images/cms-icon.svg new file mode 100644 index 0000000..c3cba5d --- /dev/null +++ b/modules/cms/assets/images/cms-icon.svg @@ -0,0 +1,27 @@ + + + + cms-icon + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/cms/assets/images/default-theme-preview.png b/modules/cms/assets/images/default-theme-preview.png new file mode 100644 index 0000000..4776059 Binary files /dev/null and b/modules/cms/assets/images/default-theme-preview.png differ diff --git a/modules/cms/assets/js/october.cmspage.js b/modules/cms/assets/js/october.cmspage.js new file mode 100644 index 0000000..6e6735e --- /dev/null +++ b/modules/cms/assets/js/october.cmspage.js @@ -0,0 +1,718 @@ +/* + * Scripts for the CMS page. + */ ++function ($) { "use strict"; + + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var CmsPage = function() { + + Base.call(this) + + // + // Initialization + // + + this.init() + } + + CmsPage.prototype = Object.create(BaseProto) + CmsPage.prototype.constructor = CmsPage + + CmsPage.prototype.init = function() { + $(document).ready(this.proxy(this.registerHandlers)) + } + + CmsPage.prototype.updateTemplateList = function(type) { + var $form = $('#cms-side-panel form[data-template-type='+type+']'), + templateList = type + 'List' + + $form.request(templateList + '::onUpdate', { + complete: function() { + $('button[data-control=delete-template]', $form).trigger('oc.triggerOn.update') + } + }) + } + + CmsPage.prototype.registerHandlers = function() { + var $document = $(document), + $masterTabs = $('#cms-master-tabs') + + $masterTabs.on('closed.oc.tab', this.proxy(this.onTabClosed)) + $masterTabs.on('beforeClose.oc.tab', this.proxy(this.onBeforeTabClose)) + $masterTabs.on('oc.beforeRequest', this.proxy(this.onBeforeRequest)) + $masterTabs.on('shown.bs.tab', this.proxy(this.onTabShown)) + $masterTabs.on('initTab.oc.tab', this.proxy(this.onInitTab)) + $masterTabs.on('afterAllClosed.oc.tab', this.proxy(this.onAfterAllTabsClosed)) + + $(window).on('ajaxInvalidField', this.proxy(this.ajaxInvalidField)) + $document.on('open.oc.list', '#cms-side-panel', this.proxy(this.onOpenDocument)) + $document.on('ajaxUpdate', '[data-control=filelist], [data-control=assetlist]', this.proxy(this.onAjaxUpdate)) + $document.on('ajaxError', '#cms-master-tabs form', this.proxy(this.onAjaxError)) + $document.on('ajaxSuccess', '#cms-master-tabs form', this.proxy(this.onAjaxSuccess)) + $document.on('click', '#cms-side-panel form button[data-control=create-template], #cms-side-panel form li a[data-control=create-template]', this.proxy(this.onCreateTemplateClick)) + $document.on('click', '#cms-side-panel form button[data-control=delete-template]', this.proxy(this.onDeleteTemplateClick)) + $document.on('showing.oc.inspector', '[data-inspectable]', this.proxy(this.onInspectorShowing)) + $document.on('hidden.oc.inspector', '[data-inspectable]', this.proxy(this.onInspectorHidden)) + $document.on('hiding.oc.inspector', '[data-inspectable]', this.proxy(this.onInspectorHiding)) + $document.on('click', '#cms-master-tabs > div.tab-content > .tab-pane.active .control-componentlist a.remove', this.proxy(this.onComponentRemove)) + $document.on('click', '#cms-component-list [data-component]', this.proxy(this.onComponentClick)) + } + + // EVENT HANDLERS + // ============================ + + CmsPage.prototype.onOpenDocument = function(event) { + /* + * Open a document when it's clicked in the sidebar + */ + + var $item = $(event.relatedTarget), + $form = $item.closest('[data-template-type]'), + data = { + type: $form.data('template-type'), + theme: $item.data('item-theme'), + path: $item.data('item-path') + }, + tabId = data.type + '-' + data.theme + '-' + data.path + + if (data.type == 'asset' && $item.data('editable') === undefined) + return true + + if ($form.length == 0) + return false + + /* + * Find if the tab is already opened + */ + if ($('#cms-master-tabs').data('oc.tab').goTo(tabId)) + return false + + /* + * Open a new tab + */ + $.oc.stripeLoadIndicator.show() + + $form.request('onOpenTemplate', { + data: data + }).done(function(data) { + $.oc.stripeLoadIndicator.hide() + $('#cms-master-tabs').ocTab('addTab', data.tabTitle, data.tab, tabId, $form.data('type-icon')) + }).always(function() { + $.oc.stripeLoadIndicator.hide() + }).fail(function(jqXHR, textStatus, errorThrown) { + $.oc.stripeLoadIndicator.hide() + }) + + return false + } + + CmsPage.prototype.ajaxInvalidField = function(ev, element, name, messages, isFirst) { + /* + * Detect invalid fields, uncollapse the panel + */ + if (!isFirst) + return + + ev.preventDefault() + + var $el = $(element), + $panel = $el.closest('.form-tabless-fields.collapsed'), + $primaryPanel = $el.closest('.control-tabs.primary-tabs.collapsed') + + if ($panel.length > 0) + $panel.removeClass('collapsed') + + if ($primaryPanel.length > 0) { + $primaryPanel.removeClass('collapsed') + + var pane = $primaryPanel.closest('.tab-pane'), + $secondaryPanel = $('.control-tabs.secondary-tabs', pane) + + $secondaryPanel.removeClass('primary-collapsed') + } + + $el.focus() + } + + CmsPage.prototype.onTabClosed = function(ev) { + this.updateModifiedCounter() + + if ($('> div.tab-content > div.tab-pane', '#cms-master-tabs').length == 0) + this.setPageTitle('') + } + + CmsPage.prototype.onBeforeTabClose = function(ev) { + if ($.fn.table !== undefined) + $('[data-control=table]', ev.relatedTarget).table('dispose') + + $.oc.foundation.controlUtils.disposeControls(ev.relatedTarget.get(0)) + } + + CmsPage.prototype.onBeforeRequest = function(ev) { + var $form = $(ev.target) + + if ($('.components .layout-cell.error-component', $form).length > 0) { + if (!confirm('The form contains unknown components. Their properties will be lost on save. Do you want to save the form?')) + ev.preventDefault() + } + } + + CmsPage.prototype.onTabShown = function(ev) { + /* + * Listen for the tabs "shown" event to track the current template in the list + */ + + var $target = $(ev.target) + + if ($target.closest('[data-control=tab]').attr('id') != 'cms-master-tabs') + return + + var dataId = $target.closest('li').attr('data-tab-id'), + title = $target.attr('title'), + $sidePanel = $('#cms-side-panel') + + if (title) + this.setPageTitle(title) + + $sidePanel.find('[data-control=filelist]').fileList('markActive', dataId) + $sidePanel.find('form').trigger('oc.list.setActiveItem', [dataId]) + } + + CmsPage.prototype.onInitTab = function(ev, data) { + /* + * Listen for the tabs "initTab" event to inject extra controls to the tab + */ + + if ($(ev.target).attr('id') != 'cms-master-tabs') + return + + var $collapseIcon = $(''), + $panel = $('.form-tabless-fields', data.pane) + + $panel.append($collapseIcon); + + $collapseIcon.click(function(){ + $panel.toggleClass('collapsed') + + if (typeof(localStorage) !== 'undefined') + localStorage.ocCmsTablessCollapsed = $panel.hasClass('collapsed') ? 1 : 0 + + window.setTimeout(function(){ + $(window).trigger('oc.updateUi') + }, 500) + + return false + }) + + var $primaryCollapseIcon = $(''), + $primaryPanel = $('.control-tabs.primary-tabs', data.pane), + $secondaryPanel = $('.control-tabs.secondary-tabs', data.pane) + + if ($primaryPanel.length > 0) { + $secondaryPanel.append($primaryCollapseIcon); + + $primaryCollapseIcon.click(function(){ + $primaryPanel.toggleClass('collapsed') + $secondaryPanel.toggleClass('primary-collapsed') + $(window).trigger('oc.updateUi') + if (typeof(localStorage) !== 'undefined') + localStorage.ocCmsPrimaryCollapsed = $primaryPanel.hasClass('collapsed') ? 1 : 0 + return false + }) + } + + if (typeof(localStorage) !== 'undefined') { + if (!$('a', data.tab).hasClass('new-template') && localStorage.ocCmsTablessCollapsed == 1) + $panel.addClass('collapsed') + + if (localStorage.ocCmsPrimaryCollapsed == 1) { + $primaryPanel.addClass('collapsed') + $secondaryPanel.addClass('primary-collapsed') + } + } + + var $componentListFormGroup = $('.control-componentlist', data.pane).closest('.form-group') + if ($primaryPanel.length > 0) + $primaryPanel.before($componentListFormGroup) + else + $secondaryPanel.parent().before($componentListFormGroup) + + $componentListFormGroup.removeClass() + $componentListFormGroup.addClass('layout-row min-size') + this.updateComponentListClass(data.pane) + this.updateFormEditorMode(data.pane, true) + + var $form = $('form', data.pane), + self = this + + $form.on('changed.oc.changeMonitor', function() { + $panel.trigger('modified.oc.tab') + $panel.find('[data-control=commit-button]').addClass('hide'); + $panel.find('[data-control=reset-button]').addClass('hide'); + self.updateModifiedCounter() + }) + + $form.on('unchanged.oc.changeMonitor', function() { + $panel.trigger('unmodified.oc.tab') + self.updateModifiedCounter() + }) + + this.addTokenExpanderToEditor(data.pane, $form) + } + + CmsPage.prototype.onAfterAllTabsClosed = function(ev) { + var $sidePanel = $('#cms-side-panel') + + $sidePanel.find('[data-control=filelist]').fileList('markActive', null) + $sidePanel.find('form').trigger('oc.list.setActiveItem', [null]) + } + + CmsPage.prototype.onAjaxUpdate = function(ev) { + var dataId = $('#cms-master-tabs .nav-tabs li.active').attr('data-tab-id'), + $sidePanel = $('#cms-side-panel') + + $sidePanel.find('[data-control=filelist]').fileList('markActive', dataId) + $sidePanel.find('form').trigger('oc.list.setActiveItem', [dataId]) + } + + CmsPage.prototype.onAjaxSuccess = function(ev, context, data) { + var element = ev.target + + // Update the visibilities of the commit & reset buttons + $('[data-control=commit-button]', element).toggleClass('hide', !data.canCommit) + $('[data-control=reset-button]', element).toggleClass('hide', !data.canReset) + + if (data.templatePath !== undefined) { + $('input[name=templatePath]', element).val(data.templatePath) + $('input[name=templateMtime]', element).val(data.templateMtime) + $('[data-control=delete-button]', element).removeClass('hide') + $('[data-control=preview-button]', element).removeClass('hide') + + if (data.pageUrl !== undefined) + $('[data-control=preview-button]', element).attr('href', data.pageUrl) + } + + if (data.tabTitle !== undefined) { + $('#cms-master-tabs').ocTab('updateTitle', $(element).closest('.tab-pane'), data.tabTitle) + this.setPageTitle(data.tabTitle) + } + + var tabId = $('input[name=templateType]', element).val() + '-' + + $('input[name=theme]', element).val() + '-' + + $('input[name=templatePath]', element).val(); + + $('#cms-master-tabs').ocTab('updateIdentifier', $(element).closest('.tab-pane'), tabId) + + var templateType = $('input[name=templateType]', element).val() + if (templateType.length > 0) { + $.oc.cmsPage.updateTemplateList(templateType) + + if (templateType == 'layout') + this.updateLayouts(element) + } + + this.updateFormEditorMode($(element).closest('.tab-pane'), false) + + if (context.handler == 'onSave' && (!data['X_OCTOBER_ERROR_FIELDS'] && !data['X_OCTOBER_ERROR_MESSAGE'])) { + $(element).trigger('unchange.oc.changeMonitor') + } + + // Reload the form if the server has requested it + if (data.forceReload) { + this.reloadForm(element) + } + } + + CmsPage.prototype.onAjaxError = function(ev, context, message, data, jqXHR) { + if (context.handler == 'onSave') { + if (jqXHR.responseText == 'mtime-mismatch') { + ev.preventDefault() + this.handleMtimeMismatch(ev.target) + } + } + } + + CmsPage.prototype.onCreateTemplateClick = function(ev) { + var $form = $(ev.target).closest('[data-template-type]'), + type = $form.data('template-type'), + tabId = type + Math.random(), + self = this + + $.oc.stripeLoadIndicator.show() + + $form.request('onCreateTemplate', { + data: {type: type} + }).done(function(data) { + $('#cms-master-tabs').ocTab('addTab', data.tabTitle, data.tab, tabId, $form.data('type-icon') + ' new-template') + $('#layout-side-panel').trigger('close.oc.sidePanel') + self.setPageTitle(data.tabTitle) + }).always(function(){ + $.oc.stripeLoadIndicator.hide() + }) + } + + CmsPage.prototype.onDeleteTemplateClick = function(ev) { + var $el = $(ev.currentTarget), + $form = $el.closest('form'), + templateType = $form.data('template-type'), + self = this + + if (!confirm($el.data('confirmation'))) + return + + $.oc.stripeLoadIndicator.show() + + $form.request('onDeleteTemplates', { + data: {type: templateType} + }).done(function(data) { + var tabs = $('#cms-master-tabs').data('oc.tab'); + $.each(data.deleted, function(index, path){ + var + tabId = templateType + '-' + data.theme + '-' + path, + tab = tabs.findByIdentifier(tabId) + + $('#cms-master-tabs').ocTab('closeTab', tab, true) + }) + + if (data.error !== undefined && $.type(data.error) === 'string' && data.error.length) + $.oc.flashMsg({text: data.error, 'class': 'error'}) + }).always(function(){ + self.updateTemplateList(templateType) + $.oc.stripeLoadIndicator.hide() + }) + } + + CmsPage.prototype.onInspectorShowing = function(ev, data) { + var $dragScroll = $(ev.currentTarget).closest('[data-control="toolbar"]').data('oc.dragScroll') + if ($dragScroll) { + $dragScroll.goToElement(ev.currentTarget, data.callback) + } else { + data.callback(); + } + + ev.stopPropagation() + } + + CmsPage.prototype.onInspectorHidden = function(ev) { + var element = ev.target, + values = JSON.parse($('[data-inspector-values]', element).val()) + + $('[name="component_aliases[]"]', element).val(values['oc.alias']) + $('span.alias', element).text(values['oc.alias']) + } + + CmsPage.prototype.onInspectorHiding = function(ev, values) { + var element = ev.target, + values = JSON.parse($('[data-inspector-values]', element).val()), + alias = values['oc.alias'], + $componentList = $('#cms-master-tabs > div.tab-content > .tab-pane.active .control-componentlist .layout'), + $cell = $(ev.target).parent() + + $('div.layout-cell', $componentList).each(function(){ + if ($cell.get(0) == this) + return true + + var $input = $('input[name="component_aliases[]"]', this) + + if ($input.val() == alias) { + ev.preventDefault() + alert('The component alias "'+alias+'" is already used.') + return false + } + }) + } + + CmsPage.prototype.onComponentRemove = function(ev) { + var element = ev.currentTarget + + $(element).trigger('change') + var pane = $(element).closest('.tab-pane'), + component = $(element).closest('div.layout-cell') + + /* + * Remove any {% component %} tags in the editor for this component + */ + var editor = $('[data-control=codeeditor]', pane) + if (editor.length) { + var alias = $('input[name="component_aliases[]"]', component).val().replace(/^@/, ''), + codeEditor = editor.codeEditor('getEditorObject') + + codeEditor.replace('', { + needle: "{% component '" + alias + "' %}" + }) + } + + component.remove() + $(window).trigger('oc.updateUi') + + this.updateComponentListClass(pane) + return false + } + + CmsPage.prototype.onComponentClick = function(ev) { + /* + * Determine if a page or layout is open in the master tabs + */ + + var $componentList = $('#cms-master-tabs > div.tab-content > .tab-pane.active .control-componentlist .layout') + if ($componentList.length == 0) { + alert('Components can be added only to pages, partials and layouts.') + return; + } + + var $component = $(ev.currentTarget).clone(), + $iconInput = $component.find('[data-component-icon]'), + $componentContainer = $('.layout-relative', $component), + $configInput = $component.find('[data-inspector-config]'), + $aliasInput = $component.find('[data-component-default-alias]'), + $valuesInput = $component.find('[data-inspector-values]'), + $nameInput = $component.find('[data-component-name]'), + $classInput = $component.find('[data-inspector-class]'), + alias = $aliasInput.val(), + originalAlias = alias, + counter = 2, + existingAliases = [] + + $('div.layout-cell input[name="component_aliases[]"]', $componentList).each(function(){ + existingAliases.push($(this).val()) + }) + + while($.inArray(alias, existingAliases) !== -1) { + alias = originalAlias + counter + counter++ + } + + // Set the last alias used so dragComponents can use it + $('input[name="component_aliases[]"]', $(ev.currentTarget)).val(alias) + + $component.attr('data-component-attached', true) + $componentContainer.addClass($iconInput.val()) + $iconInput.remove() + + $componentContainer.attr({ + 'data-inspectable': '', + 'data-inspector-title': $component.find('span.name').text(), + 'data-inspector-description': $component.find('span.description').text(), + 'data-inspector-config': $configInput.val(), + 'data-inspector-class': $classInput.val() + }) + + $configInput.remove() + $('input[name="component_names[]"]', $component).val($nameInput.val()) + $nameInput.remove() + $('input[name="component_aliases[]"]', $component).val(alias) + $component.find('span.alias').text(alias) + $valuesInput.val($valuesInput.val().replace('--alias--', alias)) + $aliasInput.remove() + + $component.addClass('adding') + $componentList.append($component) + $componentList.closest('[data-control="toolbar"]').data('oc.dragScroll').goToElement($component) + $component.removeClass('adding') + $component.trigger('change') + + this.updateComponentListClass($component.closest('.tab-pane')) + + $(window).trigger('oc.updateUi') + } + + // INTERNAL METHODS + // ============================ + + CmsPage.prototype.updateComponentListClass = function(pane) { + var $componentList = $('.control-componentlist', pane), + $primaryPanel = $('.control-tabs.primary-tabs', pane), + $primaryTabContainer = $('.nav-tabs', $primaryPanel), + hasComponents = $('.layout', $componentList).children(':not(.hidden)').length > 0 + + $primaryTabContainer.toggleClass('component-area', hasComponents) + $componentList.toggleClass('has-components', hasComponents) + } + + CmsPage.prototype.updateFormEditorMode = function(pane, initialization) { + var $contentTypeElement = $('[data-toolbar-type]', pane) + if ($contentTypeElement.length == 0) + return + + if ($contentTypeElement.data('toolbar-type') != 'content') + return + + var fileName = $('input[name=fileName]', pane).val(), + parts = fileName.split('.'), + extension = 'txt', + mode = 'plain_text', + modes = $.oc.codeEditorExtensionModes, + editor = $('[data-control=codeeditor]', pane) + + if (parts.length >= 2) + extension = parts.pop().toLowerCase() + + if (modes[extension] !== undefined) + mode = modes[extension]; + + var setEditorMode = function() { + window.setTimeout(function(){ + editor.data('oc.codeEditor').editor.getSession().setMode({path: 'ace/mode/'+mode}) + }, 200) + } + + if (initialization) + editor.on('oc.codeEditorReady', setEditorMode) + else + setEditorMode() + } + + CmsPage.prototype.updateModifiedCounter = function() { + var counters = { + page: { menu: 'pages', count: 0 }, + partial: { menu: 'partials', count: 0 }, + layout: { menu: 'layouts', count: 0 }, + content: { menu: 'content', count: 0 }, + asset: { menu: 'assets', count: 0} + } + + $('> div.tab-content > div.tab-pane[data-modified]', '#cms-master-tabs').each(function(){ + var inputType = $('> form > input[name=templateType]', this).val() + counters[inputType].count++ + }) + + $.each(counters, function(type, data){ + $.oc.sideNav.setCounter('cms/' + data.menu, data.count); + }) + } + + CmsPage.prototype.addTokenExpanderToEditor = function(pane, $form) { + var group = $('[data-field-name=markup]', pane), + editor = $('[data-control=codeeditor]', group), + canExpand = false, + self = this + + if (!editor.length || editor.data('oc.tokenexpander')) + return + + var toolbar = editor.codeEditor('getToolbar') + + editor.tokenExpander() + + var breakButton = $('
  • ').prop({ 'class': 'tokenexpander-button' }).append( + $('').prop({ 'href': 'javascript:; '}).append( + $('').prop({ 'class': 'icon-code-fork' }) + ) + ) + + breakButton.hide().on('click', function(){ + self.handleExpandToken(editor, $form) + return false + }) + + $('ul:first', toolbar).prepend(breakButton) + + editor + .on('show.oc.tokenexpander', function(){ + canExpand = true + breakButton.show() + }) + .on('hide.oc.tokenexpander', function(){ + canExpand = false + breakButton.hide() + }) + .on('dblclick', function(ev){ + if ((ev.metaKey || ev.ctrlKey) && canExpand) { + self.handleExpandToken(editor, $form) + } + }) + } + + CmsPage.prototype.handleExpandToken = function(editor, $form) { + editor.tokenExpander('expandToken', function(token, value){ + return $form.request('onExpandMarkupToken', { + data: { tokenType: token, tokenName: value } + }) + }) + } + + CmsPage.prototype.handleMtimeMismatch = function(form) { + var $form = $(form) + $form.popup({ handler: 'onOpenConcurrencyResolveForm' }) + + var popup = $form.data('oc.popup'), + self = this + + $(popup.$content).on('click', 'button[data-action=reload]', function(){ + popup.hide() + self.reloadForm(form) + }) + + $(popup.$content).on('click', 'button[data-action=save]', function(){ + popup.hide() + + $('input[name=templateForceSave]', $form).val(1) + $('a[data-request=onSave]', $form).trigger('click') + $('input[name=templateForceSave]', $form).val(0) + }) + } + + CmsPage.prototype.reloadForm = function(form) { + var + $form = $(form), + data = { + type: $('[name=templateType]', $form).val(), + theme: $('[name=theme]', $form).val(), + path: $('[name=templatePath]', $form).val(), + }, + tabId = data.type + '-' + data.theme + '-' + data.path, + tabs = $('#cms-master-tabs').data('oc.tab'), + tab = tabs.findByIdentifier(tabId), + self = this + + /* + * Update tab + */ + + $.oc.stripeLoadIndicator.show() + + $form.request('onOpenTemplate', { + data: data + }).done(function(data) { + $('#cms-master-tabs').ocTab('updateTab', tab, data.tabTitle, data.tab) + $('#cms-master-tabs').ocTab('unmodifyTab', tab) + self.updateModifiedCounter() + }).always(function() { + $.oc.stripeLoadIndicator.hide() + }).fail(function(jqXHR, textStatus, errorThrown) { + alert(jqXHR.responseText.length ? jqXHR.responseText : jqXHR.statusText) + }) + } + + CmsPage.prototype.setPageTitle = function(title) { + if (title.length) + $.oc.layout.setPageTitle(title + ' | ') + else + $.oc.layout.setPageTitle(title) + } + + CmsPage.prototype.updateLayouts = function(form) { + $(form).request('onGetTemplateList', { + success: function(data) { + $('#cms-master-tabs > .tab-content select[name="settings[layout]"]').each(function(){ + var + $select = $(this), + value = $select.val() + + $select.find('option').remove() + $.each(data.layouts, function(layoutFile, layoutName){ + $select.append($('
    ').html(oldValue).text() + newValue = $('
    ').html(newValue).text() + + this.diffStrings(oldValue, newValue) + } + + TemplateDiff.prototype.diffStrings = function(oldValue, newValue) { + var result = this.$el.get(0) + var diffType = 'diff' + this.options.diffType[0].toUpperCase() + this.options.diffType.slice(1) + var diff = JsDiff[diffType](oldValue, newValue) + var fragment = document.createDocumentFragment(); + for (var i=0; i < diff.length; i++) { + + if (diff[i].added && diff[i + 1] && diff[i + 1].removed) { + var swap = diff[i]; + diff[i] = diff[i + 1]; + diff[i + 1] = swap; + } + + var node; + if (diff[i].removed) { + node = document.createElement('del'); + node.appendChild(document.createTextNode(diff[i].value)); + } + else if (diff[i].added) { + node = document.createElement('ins'); + node.appendChild(document.createTextNode(diff[i].value)); + } + else { + node = document.createTextNode(diff[i].value); + } + fragment.appendChild(node); + } + + result.textContent = ''; + result.appendChild(fragment); + } + + // TEMPALTE DIFF PLUGIN DEFINITION + // ============================ + + var old = $.fn.templateDiff + + $.fn.templateDiff = function (option) { + var args = Array.prototype.slice.call(arguments, 1), result + this.each(function () { + var $this = $(this) + var data = $this.data('oc.example') + var options = $.extend({}, TemplateDiff.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.example', (data = new TemplateDiff(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : this + } + + $.fn.templateDiff.Constructor = TemplateDiff + + // TEMPALTE DIFF NO CONFLICT + // ================= + + $.fn.templateDiff.noConflict = function () { + $.fn.templateDiff = old + return this + } + + // TEMPALTE DIFF DATA-API + // =============== + + $(document).render(function () { + $('[data-plugin="template-diff"]').templateDiff() + }); + +}(window.jQuery); diff --git a/modules/cms/assets/less/october.components.less b/modules/cms/assets/less/october.components.less new file mode 100644 index 0000000..5f8edb0 --- /dev/null +++ b/modules/cms/assets/less/october.components.less @@ -0,0 +1,406 @@ +@import "../../../backend/assets/less/core/boot.less"; + +// +// Component list +// -------------------------------------------------- + +@color-component-list-bg: @brand-secondary; +@color-component-bg: #ffffff; +@color-component-text: #475354; +@color-component-hover-bg: #3498db; +@color-component-hover-text: #ffffff; +@color-component-placeholder: #e0e0e0; +@color-group-bg: #f1f3f4; +@color-error-component-bg: #ab2a1c; +@color-error-component-text: #ffffff; +@color-warning-component-bg: #ffc107; +@color-warning-component-text: #343a40; + +.component-lego-icon() { + position: absolute; + font-size: 37px; + top: 1px; + z-index: 50; + color: @color-component-bg; + text-shadow: 0 0 1px @color-component-text; + width: 12px; + overflow: hidden; + text-indent: -25px; + right: -12px; + + .icon(@puzzle-piece); +} + +.draggable-component-item, +.component-list .components div.layout-cell, +div.control-componentlist div.components div.layout-cell { + font-size: 11px; + cursor: pointer; + background: @color-component-bg; + .user-select(none); + + &:hover { + background: @color-component-hover-bg; + } + + > div { + white-space: normal; + color: @color-component-text; + position: relative; + border-right: 1px solid @color-panel-light; + + &:before { + position: absolute; + font-size: 16px; + left: 15px; + top: 7px; + .opacity(0.7); + } + + &:hover { + color: @color-component-hover-text; + &:before { + .opacity(1); + } + } + + &:after { + .component-lego-icon(); + } + + &:hover:after { + text-shadow: none; + color: @color-component-hover-bg; + } + + span { + display: block; + + &.name { + white-space: nowrap; + padding: 8px 15px 0; + font-weight: 400; + line-height: 20px; + font-size: @font-size-base - 1; + } + + &.description { + padding: 0 15px 10px; + margin-top: 8px; + font-weight: 400; + font-size: @font-size-base - 3; + line-height: 150%; + } + } + } + + &.placeholder > div { + background: @color-component-placeholder; + color: @color-component-placeholder; + &:before, &:after { + color: @color-component-placeholder !important; + text-shadow: none !important; + } + } +} + +// Reduce the double standard padding, since the tabs have padding +// at the top and the components field has padding at the bottom. +[data-field-name="components"] + .control-tabs.primary-tabs { + margin-top: -(@padding-standard / 2); +} + +div.control-componentlist { + position: relative; + padding: 0; + .transition(all 0.3s ease); + + &.droppable { + background-color: lighten(@color-component-list-bg, 20%); + } + + &.has-components { + padding: 0 @padding-standard @padding-standard; + } + + div.layout { + width: auto; + } + + div.components { + div.layout-cell { + &.error-component { + background: @color-error-component-bg; + + > div { + color: @color-error-component-text; + + &:after { + color: @color-error-component-bg; + } + } + } + + &.warning-component { + background: @color-warning-component-bg; + + > div { + color: @color-warning-component-text; + + &:after { + color: @color-warning-component-bg; + } + } + } + + &:first-child { + .border-left-radius(3px); + } + + &:last-child { + margin-right: 0; + .border-right-radius(3px); + + > div { + border-right: none; + + &:after { + display: none; + } + } + } + + &:nth-child(2n) > div:after { + top: auto; + bottom: 5px; + } + + &:first-child { + > div.popover-highlight { + .border-left-radius(3px); + } + } + + &:last-child { + > div.popover-highlight { + .border-right-radius(3px); + } + } + + > div { + .translate(0, 0); + .transition-transform(0.2s); + + max-width: 250px; + min-width: 170px; + + &.popover-highlight { + border-right-color: rgba(0,0,0,0); + background: @color-component-bg!important; + color: @color-component-text!important; + &:before { + .opacity(0.7); + } + + &:after { + color: @color-component-bg; + text-shadow: none; + } + + a.remove { + display: none; + } + } + + span { + &.name { + padding-left: 38px; + } + + &.description { + padding-bottom: 35px; + } + + &.alias { + padding: 0 15px; + font-weight: 500; + position: absolute; + width: 100%; + bottom: 10px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + + &:before { + margin-right: 4px; + .opacity(0.55); + } + } + } + + a.remove { + position: absolute; + display: inline-block; + top: 1px; + right: 5px; + color: @close-color; + font-size: 17px; + font-weight: @close-font-weight; + .opacity(.3); + + &:hover { + .opacity(.5); + text-decoration: none; + } + } + } + + &.adding > div { + .translate(0, -100px)!important; + } + } + } +} + +.draggable-component-item { + .opacity(.6); + span.alias { display: none; } + a.remove { display: none; } +} + +.component-list .components { + div.layout { + div.layout-row { + div.layout-cell { + border-top: 1px solid @color-panel-light; + span.alias { display: none; } + a.remove { display: none; } + + &:last-child > div { + border-right: none; + &:after { + display: none; + } + } + + > div { + &:before { + .component-lego-icon(); + .rotate(-90deg); + .opacity(1); + left: auto; + top: -17px; + right: 15px; + } + + &:hover:before { + text-shadow: none; + color: @color-component-hover-bg; + } + } + } + + &:first-child { + div.layout-cell { + > div { + &:before {display: none;} + } + } + } + } + } + + div.layout.single { + div.layout-row > div.layout-cell > div { + border-right: none; + &:before { + display: block; + right: 55.5%; + } + } + } +} + +.control-filelist.component-list { + ul li { + div.group { + background: @color-group-bg; + border-top: 1px solid darken(@color-panel-light, 2%); + padding: 10px 15px 10px 10px; + position: relative; + cursor: pointer; + + h4 { + text-transform: uppercase; + font-size: 14px; + margin-top: 3px; + + a { + padding-left: 33px; + + &:before { + left: 0; + } + + &:after { + display: none; + } + } + } + + span.description { + display: block; + font-size: 13px; + padding-left: 33px; + color: @color-text-description; + } + + i { + position: absolute; + left: 22px; + top: 21px; + font-size: 16px; + .opacity(0.7); + color: @color-text-title; + } + } + } +} + +.disable-component-list-hover() { + background: @color-component-bg; + color: @color-component-text; + + &:after { + text-shadow: 0 0 1px @color-component-text!important; + color: @color-component-bg!important; + } +} + +.touch { + div.control-componentlist div.components div.layout-cell { + > div:hover, > div:active, > div:active:focus { + .disable-component-list-hover(); + } + } +} + +// Modifies the color of the tab background when components are present +// this is no longer required since the colors are the same! :-) -sg +// .fancy-layout { +// .control-tabs, &.control-tabs { +// &.primary-tabs { +// > div > ul.nav-tabs { +// &.component-area { +// background: @color-component-list-bg; +// } +// } +// } +// } +// } + +body.drag div.control-componentlist div.components div.layout-cell { + > div, > div:hover, > div:active { + .disable-component-list-hover(); + } +} diff --git a/modules/cms/assets/less/october.theme-selector.less b/modules/cms/assets/less/october.theme-selector.less new file mode 100644 index 0000000..7e0a6cb --- /dev/null +++ b/modules/cms/assets/less/october.theme-selector.less @@ -0,0 +1,160 @@ +@import "../../../backend/assets/less/core/boot.less"; + +.theme-selector-layout { + .layout-cell { + padding: 24px; + .box-sizing(border-box); + } + + .theme-thumbnail { + width: 288px; + background: #ecf0f1; + border-top: 1px solid #e3e7e9; + + img { + .opacity(0.6); + width: 240px; + } + } + + .theme-description { + border-top: 1px solid #f2f3f4; + + h3, p { + .opacity(0.6); + } + + h3 { + margin: 0 0 25px 0; + font-size: 28px; + color: #2b3e50; + display: inline-block; + } + + p.author { + font-size: 13px; + display: inline-block; + color: #808c8d; + } + + p.description { + color: #2b3e50; + font-size: 14px; + line-height: 180%; + margin-bottom: 30px; + } + + .controls { + .btn > i { + margin-right: 5px; + font-size: 16px; + position: relative; + top: 1px; + + &.icon-star { + color: #f1a84e; + } + } + + .dropdown { + display: inline-block; + } + } + } + + .layout-row.active { + .theme-thumbnail { + background: #bdc3c7; + border-top-color: #bdc3c7; + } + + .thumbnail-container { + position: relative; + + &:after { + .triangle(right, 15px, 28px, #bdc3c7); + position: absolute; + right: -35px; + top: 50%; + margin-top: -14px; + } + } + } + + .layout-row { + &.active, &:hover { + .theme-description { + h3, p { + .opacity(1); + } + } + + .theme-thumbnail { + img { + .opacity(1); + } + } + } + + &:first-child, &.links { + .theme-description, .theme-thumbnail { + border-top: none; + } + } + + &.links { + .theme-thumbnail { + border-bottom: 1px solid #e3e7e9; + } + .theme-description { + border-bottom: 1px solid #f2f3f4; + } + } + } + + .create-new-theme { + margin-bottom: 10px; + } + + .create-new-theme, + .find-more-themes { + background: #ecf0f1; + color: #2b3e50; + text-decoration: none; + display: block; + padding: 20px; + .border-radius(4px); + + &:hover { + background: @link-color; + color: white; + } + } +} + +// +// Screen specific +// + +@media (max-width: @screen-sm) { + .theme-selector-layout { + .layout-cell, .layout-row { + display: block!important; + width: auto!important; + height: auto!important; + } + + .theme-thumbnail { + img { + width: 100%; + } + } + + .layout-row.links { + .theme-thumbnail { + background: transparent; + padding: 0; + } + } + } +} \ No newline at end of file diff --git a/modules/cms/assets/vendor/jsdiff/diff.js b/modules/cms/assets/vendor/jsdiff/diff.js new file mode 100644 index 0000000..d3be759 --- /dev/null +++ b/modules/cms/assets/vendor/jsdiff/diff.js @@ -0,0 +1,1407 @@ +/*! + + diff v3.2.0 + +Software License Agreement (BSD License) + +Copyright (c) 2009-2015, Kevin Decker + +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of Kevin Decker nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +@license +*/ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["JsDiff"] = factory(); + else + root["JsDiff"] = factory(); +})(this, function() { +return (function(modules) { // webpackBootstrap + // The module cache + var installedModules = {}; + + // The require function + function __webpack_require__(moduleId) { + + // Check if module is in cache + if(installedModules[moduleId]) + return installedModules[moduleId].exports; + + // Create a new module (and put it into the cache) + var module = installedModules[moduleId] = { + exports: {}, + id: moduleId, + loaded: false + }; + + // Execute the module function + modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + + // Flag the module as loaded + module.loaded = true; + + // Return the exports of the module + return module.exports; + } + + + // expose the modules object (__webpack_modules__) + __webpack_require__.m = modules; + + // expose the module cache + __webpack_require__.c = installedModules; + + // __webpack_public_path__ + __webpack_require__.p = ""; + + // Load entry module and return exports + return __webpack_require__(0); +}) +/************************************************************************/ +([ +/* 0 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + exports.canonicalize = exports.convertChangesToXML = exports.convertChangesToDMP = exports.parsePatch = exports.applyPatches = exports.applyPatch = exports.createPatch = exports.createTwoFilesPatch = exports.structuredPatch = exports.diffArrays = exports.diffJson = exports.diffCss = exports.diffSentences = exports.diffTrimmedLines = exports.diffLines = exports.diffWordsWithSpace = exports.diffWords = exports.diffChars = exports.Diff = undefined; + + var _base = __webpack_require__(1) ; + + + var _base2 = _interopRequireDefault(_base); + + + var _character = __webpack_require__(2) ; + + var _word = __webpack_require__(3) ; + + var _line = __webpack_require__(5) ; + + var _sentence = __webpack_require__(6) ; + + var _css = __webpack_require__(7) ; + + var _json = __webpack_require__(8) ; + + var _array = __webpack_require__(9) ; + + var _apply = __webpack_require__(10) ; + + var _parse = __webpack_require__(11) ; + + var _create = __webpack_require__(13) ; + + var _dmp = __webpack_require__(14) ; + + var _xml = __webpack_require__(15) ; + + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + exports. Diff = _base2['default']; + exports. diffChars = _character.diffChars; + exports. diffWords = _word.diffWords; + exports. diffWordsWithSpace = _word.diffWordsWithSpace; + exports. diffLines = _line.diffLines; + exports. diffTrimmedLines = _line.diffTrimmedLines; + exports. diffSentences = _sentence.diffSentences; + exports. diffCss = _css.diffCss; + exports. diffJson = _json.diffJson; + exports. diffArrays = _array.diffArrays; + exports. structuredPatch = _create.structuredPatch; + exports. createTwoFilesPatch = _create.createTwoFilesPatch; + exports. createPatch = _create.createPatch; + exports. applyPatch = _apply.applyPatch; + exports. applyPatches = _apply.applyPatches; + exports. parsePatch = _parse.parsePatch; + exports. convertChangesToDMP = _dmp.convertChangesToDMP; + exports. convertChangesToXML = _xml.convertChangesToXML; + exports. canonicalize = _json.canonicalize; /* See LICENSE file for terms of use */ + + /* + * Text diff implementation. + * + * This library supports the following APIS: + * JsDiff.diffChars: Character by character diff + * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace + * JsDiff.diffLines: Line based diff + * + * JsDiff.diffCss: Diff targeted at CSS content + * + * These methods are based on the implementation proposed in + * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). + * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 + */ + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQWdCQSxJLHlCQUFBLDhCLHdCQUFBOzs7Ozs7QUFDQSxJLHlCQUFBLHdDLHdCQUFBOztBQUNBLEkseUJBQUEsOEIsd0JBQUE7O0FBQ0EsSSx5QkFBQSw4Qix3QkFBQTs7QUFDQSxJLHlCQUFBLHNDLHdCQUFBOztBQUVBLEkseUJBQUEsNEIsd0JBQUE7O0FBQ0EsSSx5QkFBQSw4Qix3QkFBQTs7QUFFQSxJLHlCQUFBLGdDLHdCQUFBOztBQUVBLEkseUJBQUEsaUMsd0JBQUE7O0FBQ0EsSSx5QkFBQSxpQyx3QkFBQTs7QUFDQSxJLHlCQUFBLG1DLHdCQUFBOztBQUVBLEkseUJBQUEsK0Isd0JBQUE7O0FBQ0EsSSx5QkFBQSwrQix3QkFBQTs7Ozs7Z0NBR0UsSTt5REFFQSxTO3lEQUNBLFM7eURBQ0Esa0I7eURBQ0EsUzt5REFDQSxnQjt5REFDQSxhO3lEQUVBLE87eURBQ0EsUTt5REFFQSxVO3lEQUVBLGU7eURBQ0EsbUI7eURBQ0EsVzt5REFDQSxVO3lEQUNBLFk7eURBQ0EsVTt5REFDQSxtQjt5REFDQSxtQjt5REFDQSxZIiwiZmlsZSI6ImluZGV4LmpzIiwic291cmNlc0NvbnRlbnQiOlsiLyogU2VlIExJQ0VOU0UgZmlsZSBmb3IgdGVybXMgb2YgdXNlICovXG5cbi8qXG4gKiBUZXh0IGRpZmYgaW1wbGVtZW50YXRpb24uXG4gKlxuICogVGhpcyBsaWJyYXJ5IHN1cHBvcnRzIHRoZSBmb2xsb3dpbmcgQVBJUzpcbiAqIEpzRGlmZi5kaWZmQ2hhcnM6IENoYXJhY3RlciBieSBjaGFyYWN0ZXIgZGlmZlxuICogSnNEaWZmLmRpZmZXb3JkczogV29yZCAoYXMgZGVmaW5lZCBieSBcXGIgcmVnZXgpIGRpZmYgd2hpY2ggaWdub3JlcyB3aGl0ZXNwYWNlXG4gKiBKc0RpZmYuZGlmZkxpbmVzOiBMaW5lIGJhc2VkIGRpZmZcbiAqXG4gKiBKc0RpZmYuZGlmZkNzczogRGlmZiB0YXJnZXRlZCBhdCBDU1MgY29udGVudFxuICpcbiAqIFRoZXNlIG1ldGhvZHMgYXJlIGJhc2VkIG9uIHRoZSBpbXBsZW1lbnRhdGlvbiBwcm9wb3NlZCBpblxuICogXCJBbiBPKE5EKSBEaWZmZXJlbmNlIEFsZ29yaXRobSBhbmQgaXRzIFZhcmlhdGlvbnNcIiAoTXllcnMsIDE5ODYpLlxuICogaHR0cDovL2NpdGVzZWVyeC5pc3QucHN1LmVkdS92aWV3ZG9jL3N1bW1hcnk/ZG9pPTEwLjEuMS40LjY5MjdcbiAqL1xuaW1wb3J0IERpZmYgZnJvbSAnLi9kaWZmL2Jhc2UnO1xuaW1wb3J0IHtkaWZmQ2hhcnN9IGZyb20gJy4vZGlmZi9jaGFyYWN0ZXInO1xuaW1wb3J0IHtkaWZmV29yZHMsIGRpZmZXb3Jkc1dpdGhTcGFjZX0gZnJvbSAnLi9kaWZmL3dvcmQnO1xuaW1wb3J0IHtkaWZmTGluZXMsIGRpZmZUcmltbWVkTGluZXN9IGZyb20gJy4vZGlmZi9saW5lJztcbmltcG9ydCB7ZGlmZlNlbnRlbmNlc30gZnJvbSAnLi9kaWZmL3NlbnRlbmNlJztcblxuaW1wb3J0IHtkaWZmQ3NzfSBmcm9tICcuL2RpZmYvY3NzJztcbmltcG9ydCB7ZGlmZkpzb24sIGNhbm9uaWNhbGl6ZX0gZnJvbSAnLi9kaWZmL2pzb24nO1xuXG5pbXBvcnQge2RpZmZBcnJheXN9IGZyb20gJy4vZGlmZi9hcnJheSc7XG5cbmltcG9ydCB7YXBwbHlQYXRjaCwgYXBwbHlQYXRjaGVzfSBmcm9tICcuL3BhdGNoL2FwcGx5JztcbmltcG9ydCB7cGFyc2VQYXRjaH0gZnJvbSAnLi9wYXRjaC9wYXJzZSc7XG5pbXBvcnQge3N0cnVjdHVyZWRQYXRjaCwgY3JlYXRlVHdvRmlsZXNQYXRjaCwgY3JlYXRlUGF0Y2h9IGZyb20gJy4vcGF0Y2gvY3JlYXRlJztcblxuaW1wb3J0IHtjb252ZXJ0Q2hhbmdlc1RvRE1QfSBmcm9tICcuL2NvbnZlcnQvZG1wJztcbmltcG9ydCB7Y29udmVydENoYW5nZXNUb1hNTH0gZnJvbSAnLi9jb252ZXJ0L3htbCc7XG5cbmV4cG9ydCB7XG4gIERpZmYsXG5cbiAgZGlmZkNoYXJzLFxuICBkaWZmV29yZHMsXG4gIGRpZmZXb3Jkc1dpdGhTcGFjZSxcbiAgZGlmZkxpbmVzLFxuICBkaWZmVHJpbW1lZExpbmVzLFxuICBkaWZmU2VudGVuY2VzLFxuXG4gIGRpZmZDc3MsXG4gIGRpZmZKc29uLFxuXG4gIGRpZmZBcnJheXMsXG5cbiAgc3RydWN0dXJlZFBhdGNoLFxuICBjcmVhdGVUd29GaWxlc1BhdGNoLFxuICBjcmVhdGVQYXRjaCxcbiAgYXBwbHlQYXRjaCxcbiAgYXBwbHlQYXRjaGVzLFxuICBwYXJzZVBhdGNoLFxuICBjb252ZXJ0Q2hhbmdlc1RvRE1QLFxuICBjb252ZXJ0Q2hhbmdlc1RvWE1MLFxuICBjYW5vbmljYWxpemVcbn07XG4iXX0= + + +/***/ }, +/* 1 */ +/***/ function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + exports['default'] = Diff; + function Diff() {} + + Diff.prototype = { + diff: function diff(oldString, newString) { + var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; + + var callback = options.callback; + if (typeof options === 'function') { + callback = options; + options = {}; + } + this.options = options; + + var self = this; + + function done(value) { + if (callback) { + setTimeout(function () { + callback(undefined, value); + }, 0); + return true; + } else { + return value; + } + } + + // Allow subclasses to massage the input prior to running + oldString = this.castInput(oldString); + newString = this.castInput(newString); + + oldString = this.removeEmpty(this.tokenize(oldString)); + newString = this.removeEmpty(this.tokenize(newString)); + + var newLen = newString.length, + oldLen = oldString.length; + var editLength = 1; + var maxEditLength = newLen + oldLen; + var bestPath = [{ newPos: -1, components: [] }]; + + // Seed editLength = 0, i.e. the content starts with the same values + var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); + if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) { + // Identity per the equality and tokenizer + return done([{ value: this.join(newString), count: newString.length }]); + } + + // Main worker method. checks all permutations of a given edit length for acceptance. + function execEditLength() { + for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) { + var basePath = void 0 ; + var addPath = bestPath[diagonalPath - 1], + removePath = bestPath[diagonalPath + 1], + _oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; + if (addPath) { + // No one else is going to attempt to use this value, clear it + bestPath[diagonalPath - 1] = undefined; + } + + var canAdd = addPath && addPath.newPos + 1 < newLen, + canRemove = removePath && 0 <= _oldPos && _oldPos < oldLen; + if (!canAdd && !canRemove) { + // If this path is a terminal then prune + bestPath[diagonalPath] = undefined; + continue; + } + + // Select the diagonal that we want to branch from. We select the prior + // path whose position in the new string is the farthest from the origin + // and does not pass the bounds of the diff graph + if (!canAdd || canRemove && addPath.newPos < removePath.newPos) { + basePath = clonePath(removePath); + self.pushComponent(basePath.components, undefined, true); + } else { + basePath = addPath; // No need to clone, we've pulled it from the list + basePath.newPos++; + self.pushComponent(basePath.components, true, undefined); + } + + _oldPos = self.extractCommon(basePath, newString, oldString, diagonalPath); + + // If we have hit the end of both strings, then we are done + if (basePath.newPos + 1 >= newLen && _oldPos + 1 >= oldLen) { + return done(buildValues(self, basePath.components, newString, oldString, self.useLongestToken)); + } else { + // Otherwise track this path as a potential candidate and continue. + bestPath[diagonalPath] = basePath; + } + } + + editLength++; + } + + // Performs the length of edit iteration. Is a bit fugly as this has to support the + // sync and async mode which is never fun. Loops over execEditLength until a value + // is produced. + if (callback) { + (function exec() { + setTimeout(function () { + // This should not happen, but we want to be safe. + /* istanbul ignore next */ + if (editLength > maxEditLength) { + return callback(); + } + + if (!execEditLength()) { + exec(); + } + }, 0); + })(); + } else { + while (editLength <= maxEditLength) { + var ret = execEditLength(); + if (ret) { + return ret; + } + } + } + }, + pushComponent: function pushComponent(components, added, removed) { + var last = components[components.length - 1]; + if (last && last.added === added && last.removed === removed) { + // We need to clone here as the component clone operation is just + // as shallow array clone + components[components.length - 1] = { count: last.count + 1, added: added, removed: removed }; + } else { + components.push({ count: 1, added: added, removed: removed }); + } + }, + extractCommon: function extractCommon(basePath, newString, oldString, diagonalPath) { + var newLen = newString.length, + oldLen = oldString.length, + newPos = basePath.newPos, + oldPos = newPos - diagonalPath, + commonCount = 0; + while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newString[newPos + 1], oldString[oldPos + 1])) { + newPos++; + oldPos++; + commonCount++; + } + + if (commonCount) { + basePath.components.push({ count: commonCount }); + } + + basePath.newPos = newPos; + return oldPos; + }, + equals: function equals(left, right) { + return left === right; + }, + removeEmpty: function removeEmpty(array) { + var ret = []; + for (var i = 0; i < array.length; i++) { + if (array[i]) { + ret.push(array[i]); + } + } + return ret; + }, + castInput: function castInput(value) { + return value; + }, + tokenize: function tokenize(value) { + return value.split(''); + }, + join: function join(chars) { + return chars.join(''); + } + }; + + function buildValues(diff, components, newString, oldString, useLongestToken) { + var componentPos = 0, + componentLen = components.length, + newPos = 0, + oldPos = 0; + + for (; componentPos < componentLen; componentPos++) { + var component = components[componentPos]; + if (!component.removed) { + if (!component.added && useLongestToken) { + var value = newString.slice(newPos, newPos + component.count); + value = value.map(function (value, i) { + var oldValue = oldString[oldPos + i]; + return oldValue.length > value.length ? oldValue : value; + }); + + component.value = diff.join(value); + } else { + component.value = diff.join(newString.slice(newPos, newPos + component.count)); + } + newPos += component.count; + + // Common case + if (!component.added) { + oldPos += component.count; + } + } else { + component.value = diff.join(oldString.slice(oldPos, oldPos + component.count)); + oldPos += component.count; + + // Reverse add and remove so removes are output first to match common convention + // The diffing algorithm is tied to add then remove output and this is the simplest + // route to get the desired output with minimal overhead. + if (componentPos && components[componentPos - 1].added) { + var tmp = components[componentPos - 1]; + components[componentPos - 1] = components[componentPos]; + components[componentPos] = tmp; + } + } + } + + // Special case handle for when one terminal is ignored. For this case we merge the + // terminal into the prior string and drop the change. + var lastComponent = components[componentLen - 1]; + if (componentLen > 1 && (lastComponent.added || lastComponent.removed) && diff.equals('', lastComponent.value)) { + components[componentLen - 2].value += lastComponent.value; + components.pop(); + } + + return components; + } + + function clonePath(path) { + return { newPos: path.newPos, components: path.components.slice(0) }; + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kaWZmL2Jhc2UuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OzRDQUF3QixJO0FBQVQsU0FBUyxJQUFULEdBQWdCLENBQUU7O0FBRWpDLEtBQUssU0FBTCxHQUFpQixFO3lCQUNmLElBRGUsZ0JBQ1YsU0FEVSxFQUNDLFNBREQsRUFDMEI7NkJBQUEsSSx1QkFBZCxPQUFjLHlEQUFKLEVBQUk7O0FBQ3ZDLFFBQUksV0FBVyxRQUFRLFFBQXZCO0FBQ0EsUUFBSSxPQUFPLE9BQVAsS0FBbUIsVUFBdkIsRUFBbUM7QUFDakMsaUJBQVcsT0FBWDtBQUNBLGdCQUFVLEVBQVY7QUFDRDtBQUNELFNBQUssT0FBTCxHQUFlLE9BQWY7O0FBRUEsUUFBSSxPQUFPLElBQVg7O0FBRUEsYUFBUyxJQUFULENBQWMsS0FBZCxFQUFxQjtBQUNuQixVQUFJLFFBQUosRUFBYztBQUNaLG1CQUFXLFlBQVc7QUFBRSxtQkFBUyxTQUFULEVBQW9CLEtBQXBCO0FBQTZCLFNBQXJELEVBQXVELENBQXZEO0FBQ0EsZUFBTyxJQUFQO0FBQ0QsT0FIRCxNQUdPO0FBQ0wsZUFBTyxLQUFQO0FBQ0Q7QUFDRjs7O0FBR0QsZ0JBQVksS0FBSyxTQUFMLENBQWUsU0FBZixDQUFaO0FBQ0EsZ0JBQVksS0FBSyxTQUFMLENBQWUsU0FBZixDQUFaOztBQUVBLGdCQUFZLEtBQUssV0FBTCxDQUFpQixLQUFLLFFBQUwsQ0FBYyxTQUFkLENBQWpCLENBQVo7QUFDQSxnQkFBWSxLQUFLLFdBQUwsQ0FBaUIsS0FBSyxRQUFMLENBQWMsU0FBZCxDQUFqQixDQUFaOztBQUVBLFFBQUksU0FBUyxVQUFVLE1BQXZCO0FBQUEsUUFBK0IsU0FBUyxVQUFVLE1BQWxEO0FBQ0EsUUFBSSxhQUFhLENBQWpCO0FBQ0EsUUFBSSxnQkFBZ0IsU0FBUyxNQUE3QjtBQUNBLFFBQUksV0FBVyxDQUFDLEVBQUUsUUFBUSxDQUFDLENBQVgsRUFBYyxZQUFZLEVBQTFCLEVBQUQsQ0FBZjs7O0FBR0EsUUFBSSxTQUFTLEtBQUssYUFBTCxDQUFtQixTQUFTLENBQVQsQ0FBbkIsRUFBZ0MsU0FBaEMsRUFBMkMsU0FBM0MsRUFBc0QsQ0FBdEQsQ0FBYjtBQUNBLFFBQUksU0FBUyxDQUFULEVBQVksTUFBWixHQUFxQixDQUFyQixJQUEwQixNQUExQixJQUFvQyxTQUFTLENBQVQsSUFBYyxNQUF0RCxFQUE4RDs7QUFFNUQsYUFBTyxLQUFLLENBQUMsRUFBQyxPQUFPLEtBQUssSUFBTCxDQUFVLFNBQVYsQ0FBUixFQUE4QixPQUFPLFVBQVUsTUFBL0MsRUFBRCxDQUFMLENBQVA7QUFDRDs7O0FBR0QsYUFBUyxjQUFULEdBQTBCO0FBQ3hCLFdBQUssSUFBSSxlQUFlLENBQUMsQ0FBRCxHQUFLLFVBQTdCLEVBQXlDLGdCQUFnQixVQUF6RCxFQUFxRSxnQkFBZ0IsQ0FBckYsRUFBd0Y7QUFDdEYsWUFBSSxXLHlCQUFBLE0sd0JBQUo7QUFDQSxZQUFJLFVBQVUsU0FBUyxlQUFlLENBQXhCLENBQWQ7QUFBQSxZQUNJLGFBQWEsU0FBUyxlQUFlLENBQXhCLENBRGpCO0FBQUEsWUFFSSxVQUFTLENBQUMsYUFBYSxXQUFXLE1BQXhCLEdBQWlDLENBQWxDLElBQXVDLFlBRnBEO0FBR0EsWUFBSSxPQUFKLEVBQWE7O0FBRVgsbUJBQVMsZUFBZSxDQUF4QixJQUE2QixTQUE3QjtBQUNEOztBQUVELFlBQUksU0FBUyxXQUFXLFFBQVEsTUFBUixHQUFpQixDQUFqQixHQUFxQixNQUE3QztBQUFBLFlBQ0ksWUFBWSxjQUFjLEtBQUssT0FBbkIsSUFBNkIsVUFBUyxNQUR0RDtBQUVBLFlBQUksQ0FBQyxNQUFELElBQVcsQ0FBQyxTQUFoQixFQUEyQjs7QUFFekIsbUJBQVMsWUFBVCxJQUF5QixTQUF6QjtBQUNBO0FBQ0Q7Ozs7O0FBS0QsWUFBSSxDQUFDLE1BQUQsSUFBWSxhQUFhLFFBQVEsTUFBUixHQUFpQixXQUFXLE1BQXpELEVBQWtFO0FBQ2hFLHFCQUFXLFVBQVUsVUFBVixDQUFYO0FBQ0EsZUFBSyxhQUFMLENBQW1CLFNBQVMsVUFBNUIsRUFBd0MsU0FBeEMsRUFBbUQsSUFBbkQ7QUFDRCxTQUhELE1BR087QUFDTCxxQkFBVyxPQUFYLEM7QUFDQSxtQkFBUyxNQUFUO0FBQ0EsZUFBSyxhQUFMLENBQW1CLFNBQVMsVUFBNUIsRUFBd0MsSUFBeEMsRUFBOEMsU0FBOUM7QUFDRDs7QUFFRCxrQkFBUyxLQUFLLGFBQUwsQ0FBbUIsUUFBbkIsRUFBNkIsU0FBN0IsRUFBd0MsU0FBeEMsRUFBbUQsWUFBbkQsQ0FBVDs7O0FBR0EsWUFBSSxTQUFTLE1BQVQsR0FBa0IsQ0FBbEIsSUFBdUIsTUFBdkIsSUFBaUMsVUFBUyxDQUFULElBQWMsTUFBbkQsRUFBMkQ7QUFDekQsaUJBQU8sS0FBSyxZQUFZLElBQVosRUFBa0IsU0FBUyxVQUEzQixFQUF1QyxTQUF2QyxFQUFrRCxTQUFsRCxFQUE2RCxLQUFLLGVBQWxFLENBQUwsQ0FBUDtBQUNELFNBRkQsTUFFTzs7QUFFTCxtQkFBUyxZQUFULElBQXlCLFFBQXpCO0FBQ0Q7QUFDRjs7QUFFRDtBQUNEOzs7OztBQUtELFFBQUksUUFBSixFQUFjO0FBQ1gsZ0JBQVMsSUFBVCxHQUFnQjtBQUNmLG1CQUFXLFlBQVc7OztBQUdwQixjQUFJLGFBQWEsYUFBakIsRUFBZ0M7QUFDOUIsbUJBQU8sVUFBUDtBQUNEOztBQUVELGNBQUksQ0FBQyxnQkFBTCxFQUF1QjtBQUNyQjtBQUNEO0FBQ0YsU0FWRCxFQVVHLENBVkg7QUFXRCxPQVpBLEdBQUQ7QUFhRCxLQWRELE1BY087QUFDTCxhQUFPLGNBQWMsYUFBckIsRUFBb0M7QUFDbEMsWUFBSSxNQUFNLGdCQUFWO0FBQ0EsWUFBSSxHQUFKLEVBQVM7QUFDUCxpQkFBTyxHQUFQO0FBQ0Q7QUFDRjtBQUNGO0FBQ0YsR0E5R2M7bURBZ0hmLGFBaEhlLHlCQWdIRCxVQWhIQyxFQWdIVyxLQWhIWCxFQWdIa0IsT0FoSGxCLEVBZ0gyQjtBQUN4QyxRQUFJLE9BQU8sV0FBVyxXQUFXLE1BQVgsR0FBb0IsQ0FBL0IsQ0FBWDtBQUNBLFFBQUksUUFBUSxLQUFLLEtBQUwsS0FBZSxLQUF2QixJQUFnQyxLQUFLLE9BQUwsS0FBaUIsT0FBckQsRUFBOEQ7OztBQUc1RCxpQkFBVyxXQUFXLE1BQVgsR0FBb0IsQ0FBL0IsSUFBb0MsRUFBQyxPQUFPLEtBQUssS0FBTCxHQUFhLENBQXJCLEVBQXdCLE9BQU8sS0FBL0IsRUFBc0MsU0FBUyxPQUEvQyxFQUFwQztBQUNELEtBSkQsTUFJTztBQUNMLGlCQUFXLElBQVgsQ0FBZ0IsRUFBQyxPQUFPLENBQVIsRUFBVyxPQUFPLEtBQWxCLEVBQXlCLFNBQVMsT0FBbEMsRUFBaEI7QUFDRDtBQUNGLEdBekhjO21EQTBIZixhQTFIZSx5QkEwSEQsUUExSEMsRUEwSFMsU0ExSFQsRUEwSG9CLFNBMUhwQixFQTBIK0IsWUExSC9CLEVBMEg2QztBQUMxRCxRQUFJLFNBQVMsVUFBVSxNQUF2QjtBQUFBLFFBQ0ksU0FBUyxVQUFVLE1BRHZCO0FBQUEsUUFFSSxTQUFTLFNBQVMsTUFGdEI7QUFBQSxRQUdJLFNBQVMsU0FBUyxZQUh0QjtBQUFBLFFBS0ksY0FBYyxDQUxsQjtBQU1BLFdBQU8sU0FBUyxDQUFULEdBQWEsTUFBYixJQUF1QixTQUFTLENBQVQsR0FBYSxNQUFwQyxJQUE4QyxLQUFLLE1BQUwsQ0FBWSxVQUFVLFNBQVMsQ0FBbkIsQ0FBWixFQUFtQyxVQUFVLFNBQVMsQ0FBbkIsQ0FBbkMsQ0FBckQsRUFBZ0g7QUFDOUc7QUFDQTtBQUNBO0FBQ0Q7O0FBRUQsUUFBSSxXQUFKLEVBQWlCO0FBQ2YsZUFBUyxVQUFULENBQW9CLElBQXBCLENBQXlCLEVBQUMsT0FBTyxXQUFSLEVBQXpCO0FBQ0Q7O0FBRUQsYUFBUyxNQUFULEdBQWtCLE1BQWxCO0FBQ0EsV0FBTyxNQUFQO0FBQ0QsR0E3SWM7bURBK0lmLE1BL0llLGtCQStJUixJQS9JUSxFQStJRixLQS9JRSxFQStJSztBQUNsQixXQUFPLFNBQVMsS0FBaEI7QUFDRCxHQWpKYzttREFrSmYsV0FsSmUsdUJBa0pILEtBbEpHLEVBa0pJO0FBQ2pCLFFBQUksTUFBTSxFQUFWO0FBQ0EsU0FBSyxJQUFJLElBQUksQ0FBYixFQUFnQixJQUFJLE1BQU0sTUFBMUIsRUFBa0MsR0FBbEMsRUFBdUM7QUFDckMsVUFBSSxNQUFNLENBQU4sQ0FBSixFQUFjO0FBQ1osWUFBSSxJQUFKLENBQVMsTUFBTSxDQUFOLENBQVQ7QUFDRDtBQUNGO0FBQ0QsV0FBTyxHQUFQO0FBQ0QsR0ExSmM7bURBMkpmLFNBM0plLHFCQTJKTCxLQTNKSyxFQTJKRTtBQUNmLFdBQU8sS0FBUDtBQUNELEdBN0pjO21EQThKZixRQTlKZSxvQkE4Sk4sS0E5Sk0sRUE4SkM7QUFDZCxXQUFPLE1BQU0sS0FBTixDQUFZLEVBQVosQ0FBUDtBQUNELEdBaEtjO21EQWlLZixJQWpLZSxnQkFpS1YsS0FqS1UsRUFpS0g7QUFDVixXQUFPLE1BQU0sSUFBTixDQUFXLEVBQVgsQ0FBUDtBQUNEO0FBbktjLENBQWpCOztBQXNLQSxTQUFTLFdBQVQsQ0FBcUIsSUFBckIsRUFBMkIsVUFBM0IsRUFBdUMsU0FBdkMsRUFBa0QsU0FBbEQsRUFBNkQsZUFBN0QsRUFBOEU7QUFDNUUsTUFBSSxlQUFlLENBQW5CO0FBQUEsTUFDSSxlQUFlLFdBQVcsTUFEOUI7QUFBQSxNQUVJLFNBQVMsQ0FGYjtBQUFBLE1BR0ksU0FBUyxDQUhiOztBQUtBLFNBQU8sZUFBZSxZQUF0QixFQUFvQyxjQUFwQyxFQUFvRDtBQUNsRCxRQUFJLFlBQVksV0FBVyxZQUFYLENBQWhCO0FBQ0EsUUFBSSxDQUFDLFVBQVUsT0FBZixFQUF3QjtBQUN0QixVQUFJLENBQUMsVUFBVSxLQUFYLElBQW9CLGVBQXhCLEVBQXlDO0FBQ3ZDLFlBQUksUUFBUSxVQUFVLEtBQVYsQ0FBZ0IsTUFBaEIsRUFBd0IsU0FBUyxVQUFVLEtBQTNDLENBQVo7QUFDQSxnQkFBUSxNQUFNLEdBQU4sQ0FBVSxVQUFTLEtBQVQsRUFBZ0IsQ0FBaEIsRUFBbUI7QUFDbkMsY0FBSSxXQUFXLFVBQVUsU0FBUyxDQUFuQixDQUFmO0FBQ0EsaUJBQU8sU0FBUyxNQUFULEdBQWtCLE1BQU0sTUFBeEIsR0FBaUMsUUFBakMsR0FBNEMsS0FBbkQ7QUFDRCxTQUhPLENBQVI7O0FBS0Esa0JBQVUsS0FBVixHQUFrQixLQUFLLElBQUwsQ0FBVSxLQUFWLENBQWxCO0FBQ0QsT0FSRCxNQVFPO0FBQ0wsa0JBQVUsS0FBVixHQUFrQixLQUFLLElBQUwsQ0FBVSxVQUFVLEtBQVYsQ0FBZ0IsTUFBaEIsRUFBd0IsU0FBUyxVQUFVLEtBQTNDLENBQVYsQ0FBbEI7QUFDRDtBQUNELGdCQUFVLFVBQVUsS0FBcEI7OztBQUdBLFVBQUksQ0FBQyxVQUFVLEtBQWYsRUFBc0I7QUFDcEIsa0JBQVUsVUFBVSxLQUFwQjtBQUNEO0FBQ0YsS0FsQkQsTUFrQk87QUFDTCxnQkFBVSxLQUFWLEdBQWtCLEtBQUssSUFBTCxDQUFVLFVBQVUsS0FBVixDQUFnQixNQUFoQixFQUF3QixTQUFTLFVBQVUsS0FBM0MsQ0FBVixDQUFsQjtBQUNBLGdCQUFVLFVBQVUsS0FBcEI7Ozs7O0FBS0EsVUFBSSxnQkFBZ0IsV0FBVyxlQUFlLENBQTFCLEVBQTZCLEtBQWpELEVBQXdEO0FBQ3RELFlBQUksTUFBTSxXQUFXLGVBQWUsQ0FBMUIsQ0FBVjtBQUNBLG1CQUFXLGVBQWUsQ0FBMUIsSUFBK0IsV0FBVyxZQUFYLENBQS9CO0FBQ0EsbUJBQVcsWUFBWCxJQUEyQixHQUEzQjtBQUNEO0FBQ0Y7QUFDRjs7OztBQUlELE1BQUksZ0JBQWdCLFdBQVcsZUFBZSxDQUExQixDQUFwQjtBQUNBLE1BQUksZUFBZSxDQUFmLEtBQ0ksY0FBYyxLQUFkLElBQXVCLGNBQWMsT0FEekMsS0FFRyxLQUFLLE1BQUwsQ0FBWSxFQUFaLEVBQWdCLGNBQWMsS0FBOUIsQ0FGUCxFQUU2QztBQUMzQyxlQUFXLGVBQWUsQ0FBMUIsRUFBNkIsS0FBN0IsSUFBc0MsY0FBYyxLQUFwRDtBQUNBLGVBQVcsR0FBWDtBQUNEOztBQUVELFNBQU8sVUFBUDtBQUNEOztBQUVELFNBQVMsU0FBVCxDQUFtQixJQUFuQixFQUF5QjtBQUN2QixTQUFPLEVBQUUsUUFBUSxLQUFLLE1BQWYsRUFBdUIsWUFBWSxLQUFLLFVBQUwsQ0FBZ0IsS0FBaEIsQ0FBc0IsQ0FBdEIsQ0FBbkMsRUFBUDtBQUNEIiwiZmlsZSI6ImJhc2UuanMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBEaWZmKCkge31cblxuRGlmZi5wcm90b3R5cGUgPSB7XG4gIGRpZmYob2xkU3RyaW5nLCBuZXdTdHJpbmcsIG9wdGlvbnMgPSB7fSkge1xuICAgIGxldCBjYWxsYmFjayA9IG9wdGlvbnMuY2FsbGJhY2s7XG4gICAgaWYgKHR5cGVvZiBvcHRpb25zID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICBjYWxsYmFjayA9IG9wdGlvbnM7XG4gICAgICBvcHRpb25zID0ge307XG4gICAgfVxuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG5cbiAgICBsZXQgc2VsZiA9IHRoaXM7XG5cbiAgICBmdW5jdGlvbiBkb25lKHZhbHVlKSB7XG4gICAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHsgY2FsbGJhY2sodW5kZWZpbmVkLCB2YWx1ZSk7IH0sIDApO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBBbGxvdyBzdWJjbGFzc2VzIHRvIG1hc3NhZ2UgdGhlIGlucHV0IHByaW9yIHRvIHJ1bm5pbmdcbiAgICBvbGRTdHJpbmcgPSB0aGlzLmNhc3RJbnB1dChvbGRTdHJpbmcpO1xuICAgIG5ld1N0cmluZyA9IHRoaXMuY2FzdElucHV0KG5ld1N0cmluZyk7XG5cbiAgICBvbGRTdHJpbmcgPSB0aGlzLnJlbW92ZUVtcHR5KHRoaXMudG9rZW5pemUob2xkU3RyaW5nKSk7XG4gICAgbmV3U3RyaW5nID0gdGhpcy5yZW1vdmVFbXB0eSh0aGlzLnRva2VuaXplKG5ld1N0cmluZykpO1xuXG4gICAgbGV0IG5ld0xlbiA9IG5ld1N0cmluZy5sZW5ndGgsIG9sZExlbiA9IG9sZFN0cmluZy5sZW5ndGg7XG4gICAgbGV0IGVkaXRMZW5ndGggPSAxO1xuICAgIGxldCBtYXhFZGl0TGVuZ3RoID0gbmV3TGVuICsgb2xkTGVuO1xuICAgIGxldCBiZXN0UGF0aCA9IFt7IG5ld1BvczogLTEsIGNvbXBvbmVudHM6IFtdIH1dO1xuXG4gICAgLy8gU2VlZCBlZGl0TGVuZ3RoID0gMCwgaS5lLiB0aGUgY29udGVudCBzdGFydHMgd2l0aCB0aGUgc2FtZSB2YWx1ZXNcbiAgICBsZXQgb2xkUG9zID0gdGhpcy5leHRyYWN0Q29tbW9uKGJlc3RQYXRoWzBdLCBuZXdTdHJpbmcsIG9sZFN0cmluZywgMCk7XG4gICAgaWYgKGJlc3RQYXRoWzBdLm5ld1BvcyArIDEgPj0gbmV3TGVuICYmIG9sZFBvcyArIDEgPj0gb2xkTGVuKSB7XG4gICAgICAvLyBJZGVudGl0eSBwZXIgdGhlIGVxdWFsaXR5IGFuZCB0b2tlbml6ZXJcbiAgICAgIHJldHVybiBkb25lKFt7dmFsdWU6IHRoaXMuam9pbihuZXdTdHJpbmcpLCBjb3VudDogbmV3U3RyaW5nLmxlbmd0aH1dKTtcbiAgICB9XG5cbiAgICAvLyBNYWluIHdvcmtlciBtZXRob2QuIGNoZWNrcyBhbGwgcGVybXV0YXRpb25zIG9mIGEgZ2l2ZW4gZWRpdCBsZW5ndGggZm9yIGFjY2VwdGFuY2UuXG4gICAgZnVuY3Rpb24gZXhlY0VkaXRMZW5ndGgoKSB7XG4gICAgICBmb3IgKGxldCBkaWFnb25hbFBhdGggPSAtMSAqIGVkaXRMZW5ndGg7IGRpYWdvbmFsUGF0aCA8PSBlZGl0TGVuZ3RoOyBkaWFnb25hbFBhdGggKz0gMikge1xuICAgICAgICBsZXQgYmFzZVBhdGg7XG4gICAgICAgIGxldCBhZGRQYXRoID0gYmVzdFBhdGhbZGlhZ29uYWxQYXRoIC0gMV0sXG4gICAgICAgICAgICByZW1vdmVQYXRoID0gYmVzdFBhdGhbZGlhZ29uYWxQYXRoICsgMV0sXG4gICAgICAgICAgICBvbGRQb3MgPSAocmVtb3ZlUGF0aCA/IHJlbW92ZVBhdGgubmV3UG9zIDogMCkgLSBkaWFnb25hbFBhdGg7XG4gICAgICAgIGlmIChhZGRQYXRoKSB7XG4gICAgICAgICAgLy8gTm8gb25lIGVsc2UgaXMgZ29pbmcgdG8gYXR0ZW1wdCB0byB1c2UgdGhpcyB2YWx1ZSwgY2xlYXIgaXRcbiAgICAgICAgICBiZXN0UGF0aFtkaWFnb25hbFBhdGggLSAxXSA9IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBjYW5BZGQgPSBhZGRQYXRoICYmIGFkZFBhdGgubmV3UG9zICsgMSA8IG5ld0xlbixcbiAgICAgICAgICAgIGNhblJlbW92ZSA9IHJlbW92ZVBhdGggJiYgMCA8PSBvbGRQb3MgJiYgb2xkUG9zIDwgb2xkTGVuO1xuICAgICAgICBpZiAoIWNhbkFkZCAmJiAhY2FuUmVtb3ZlKSB7XG4gICAgICAgICAgLy8gSWYgdGhpcyBwYXRoIGlzIGEgdGVybWluYWwgdGhlbiBwcnVuZVxuICAgICAgICAgIGJlc3RQYXRoW2RpYWdvbmFsUGF0aF0gPSB1bmRlZmluZWQ7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTZWxlY3QgdGhlIGRpYWdvbmFsIHRoYXQgd2Ugd2FudCB0byBicmFuY2ggZnJvbS4gV2Ugc2VsZWN0IHRoZSBwcmlvclxuICAgICAgICAvLyBwYXRoIHdob3NlIHBvc2l0aW9uIGluIHRoZSBuZXcgc3RyaW5nIGlzIHRoZSBmYXJ0aGVzdCBmcm9tIHRoZSBvcmlnaW5cbiAgICAgICAgLy8gYW5kIGRvZXMgbm90IHBhc3MgdGhlIGJvdW5kcyBvZiB0aGUgZGlmZiBncmFwaFxuICAgICAgICBpZiAoIWNhbkFkZCB8fCAoY2FuUmVtb3ZlICYmIGFkZFBhdGgubmV3UG9zIDwgcmVtb3ZlUGF0aC5uZXdQb3MpKSB7XG4gICAgICAgICAgYmFzZVBhdGggPSBjbG9uZVBhdGgocmVtb3ZlUGF0aCk7XG4gICAgICAgICAgc2VsZi5wdXNoQ29tcG9uZW50KGJhc2VQYXRoLmNvbXBvbmVudHMsIHVuZGVmaW5lZCwgdHJ1ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYmFzZVBhdGggPSBhZGRQYXRoOyAgIC8vIE5vIG5lZWQgdG8gY2xvbmUsIHdlJ3ZlIHB1bGxlZCBpdCBmcm9tIHRoZSBsaXN0XG4gICAgICAgICAgYmFzZVBhdGgubmV3UG9zKys7XG4gICAgICAgICAgc2VsZi5wdXNoQ29tcG9uZW50KGJhc2VQYXRoLmNvbXBvbmVudHMsIHRydWUsIHVuZGVmaW5lZCk7XG4gICAgICAgIH1cblxuICAgICAgICBvbGRQb3MgPSBzZWxmLmV4dHJhY3RDb21tb24oYmFzZVBhdGgsIG5ld1N0cmluZywgb2xkU3RyaW5nLCBkaWFnb25hbFBhdGgpO1xuXG4gICAgICAgIC8vIElmIHdlIGhhdmUgaGl0IHRoZSBlbmQgb2YgYm90aCBzdHJpbmdzLCB0aGVuIHdlIGFyZSBkb25lXG4gICAgICAgIGlmIChiYXNlUGF0aC5uZXdQb3MgKyAxID49IG5ld0xlbiAmJiBvbGRQb3MgKyAxID49IG9sZExlbikge1xuICAgICAgICAgIHJldHVybiBkb25lKGJ1aWxkVmFsdWVzKHNlbGYsIGJhc2VQYXRoLmNvbXBvbmVudHMsIG5ld1N0cmluZywgb2xkU3RyaW5nLCBzZWxmLnVzZUxvbmdlc3RUb2tlbikpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIE90aGVyd2lzZSB0cmFjayB0aGlzIHBhdGggYXMgYSBwb3RlbnRpYWwgY2FuZGlkYXRlIGFuZCBjb250aW51ZS5cbiAgICAgICAgICBiZXN0UGF0aFtkaWFnb25hbFBhdGhdID0gYmFzZVBhdGg7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgZWRpdExlbmd0aCsrO1xuICAgIH1cblxuICAgIC8vIFBlcmZvcm1zIHRoZSBsZW5ndGggb2YgZWRpdCBpdGVyYXRpb24uIElzIGEgYml0IGZ1Z2x5IGFzIHRoaXMgaGFzIHRvIHN1cHBvcnQgdGhlXG4gICAgLy8gc3luYyBhbmQgYXN5bmMgbW9kZSB3aGljaCBpcyBuZXZlciBmdW4uIExvb3BzIG92ZXIgZXhlY0VkaXRMZW5ndGggdW50aWwgYSB2YWx1ZVxuICAgIC8vIGlzIHByb2R1Y2VkLlxuICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgKGZ1bmN0aW9uIGV4ZWMoKSB7XG4gICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgLy8gVGhpcyBzaG91bGQgbm90IGhhcHBlbiwgYnV0IHdlIHdhbnQgdG8gYmUgc2FmZS5cbiAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgIGlmIChlZGl0TGVuZ3RoID4gbWF4RWRpdExlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCFleGVjRWRpdExlbmd0aCgpKSB7XG4gICAgICAgICAgICBleGVjKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9LCAwKTtcbiAgICAgIH0oKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHdoaWxlIChlZGl0TGVuZ3RoIDw9IG1heEVkaXRMZW5ndGgpIHtcbiAgICAgICAgbGV0IHJldCA9IGV4ZWNFZGl0TGVuZ3RoKCk7XG4gICAgICAgIGlmIChyZXQpIHtcbiAgICAgICAgICByZXR1cm4gcmV0O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9LFxuXG4gIHB1c2hDb21wb25lbnQoY29tcG9uZW50cywgYWRkZWQsIHJlbW92ZWQpIHtcbiAgICBsZXQgbGFzdCA9IGNvbXBvbmVudHNbY29tcG9uZW50cy5sZW5ndGggLSAxXTtcbiAgICBpZiAobGFzdCAmJiBsYXN0LmFkZGVkID09PSBhZGRlZCAmJiBsYXN0LnJlbW92ZWQgPT09IHJlbW92ZWQpIHtcbiAgICAgIC8vIFdlIG5lZWQgdG8gY2xvbmUgaGVyZSBhcyB0aGUgY29tcG9uZW50IGNsb25lIG9wZXJhdGlvbiBpcyBqdXN0XG4gICAgICAvLyBhcyBzaGFsbG93IGFycmF5IGNsb25lXG4gICAgICBjb21wb25lbnRzW2NvbXBvbmVudHMubGVuZ3RoIC0gMV0gPSB7Y291bnQ6IGxhc3QuY291bnQgKyAxLCBhZGRlZDogYWRkZWQsIHJlbW92ZWQ6IHJlbW92ZWQgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29tcG9uZW50cy5wdXNoKHtjb3VudDogMSwgYWRkZWQ6IGFkZGVkLCByZW1vdmVkOiByZW1vdmVkIH0pO1xuICAgIH1cbiAgfSxcbiAgZXh0cmFjdENvbW1vbihiYXNlUGF0aCwgbmV3U3RyaW5nLCBvbGRTdHJpbmcsIGRpYWdvbmFsUGF0aCkge1xuICAgIGxldCBuZXdMZW4gPSBuZXdTdHJpbmcubGVuZ3RoLFxuICAgICAgICBvbGRMZW4gPSBvbGRTdHJpbmcubGVuZ3RoLFxuICAgICAgICBuZXdQb3MgPSBiYXNlUGF0aC5uZXdQb3MsXG4gICAgICAgIG9sZFBvcyA9IG5ld1BvcyAtIGRpYWdvbmFsUGF0aCxcblxuICAgICAgICBjb21tb25Db3VudCA9IDA7XG4gICAgd2hpbGUgKG5ld1BvcyArIDEgPCBuZXdMZW4gJiYgb2xkUG9zICsgMSA8IG9sZExlbiAmJiB0aGlzLmVxdWFscyhuZXdTdHJpbmdbbmV3UG9zICsgMV0sIG9sZFN0cmluZ1tvbGRQb3MgKyAxXSkpIHtcbiAgICAgIG5ld1BvcysrO1xuICAgICAgb2xkUG9zKys7XG4gICAgICBjb21tb25Db3VudCsrO1xuICAgIH1cblxuICAgIGlmIChjb21tb25Db3VudCkge1xuICAgICAgYmFzZVBhdGguY29tcG9uZW50cy5wdXNoKHtjb3VudDogY29tbW9uQ291bnR9KTtcbiAgICB9XG5cbiAgICBiYXNlUGF0aC5uZXdQb3MgPSBuZXdQb3M7XG4gICAgcmV0dXJuIG9sZFBvcztcbiAgfSxcblxuICBlcXVhbHMobGVmdCwgcmlnaHQpIHtcbiAgICByZXR1cm4gbGVmdCA9PT0gcmlnaHQ7XG4gIH0sXG4gIHJlbW92ZUVtcHR5KGFycmF5KSB7XG4gICAgbGV0IHJldCA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYXJyYXkubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChhcnJheVtpXSkge1xuICAgICAgICByZXQucHVzaChhcnJheVtpXSk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG4gIH0sXG4gIGNhc3RJbnB1dCh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZTtcbiAgfSxcbiAgdG9rZW5pemUodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUuc3BsaXQoJycpO1xuICB9LFxuICBqb2luKGNoYXJzKSB7XG4gICAgcmV0dXJuIGNoYXJzLmpvaW4oJycpO1xuICB9XG59O1xuXG5mdW5jdGlvbiBidWlsZFZhbHVlcyhkaWZmLCBjb21wb25lbnRzLCBuZXdTdHJpbmcsIG9sZFN0cmluZywgdXNlTG9uZ2VzdFRva2VuKSB7XG4gIGxldCBjb21wb25lbnRQb3MgPSAwLFxuICAgICAgY29tcG9uZW50TGVuID0gY29tcG9uZW50cy5sZW5ndGgsXG4gICAgICBuZXdQb3MgPSAwLFxuICAgICAgb2xkUG9zID0gMDtcblxuICBmb3IgKDsgY29tcG9uZW50UG9zIDwgY29tcG9uZW50TGVuOyBjb21wb25lbnRQb3MrKykge1xuICAgIGxldCBjb21wb25lbnQgPSBjb21wb25lbnRzW2NvbXBvbmVudFBvc107XG4gICAgaWYgKCFjb21wb25lbnQucmVtb3ZlZCkge1xuICAgICAgaWYgKCFjb21wb25lbnQuYWRkZWQgJiYgdXNlTG9uZ2VzdFRva2VuKSB7XG4gICAgICAgIGxldCB2YWx1ZSA9IG5ld1N0cmluZy5zbGljZShuZXdQb3MsIG5ld1BvcyArIGNvbXBvbmVudC5jb3VudCk7XG4gICAgICAgIHZhbHVlID0gdmFsdWUubWFwKGZ1bmN0aW9uKHZhbHVlLCBpKSB7XG4gICAgICAgICAgbGV0IG9sZFZhbHVlID0gb2xkU3RyaW5nW29sZFBvcyArIGldO1xuICAgICAgICAgIHJldHVybiBvbGRWYWx1ZS5sZW5ndGggPiB2YWx1ZS5sZW5ndGggPyBvbGRWYWx1ZSA6IHZhbHVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBjb21wb25lbnQudmFsdWUgPSBkaWZmLmpvaW4odmFsdWUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29tcG9uZW50LnZhbHVlID0gZGlmZi5qb2luKG5ld1N0cmluZy5zbGljZShuZXdQb3MsIG5ld1BvcyArIGNvbXBvbmVudC5jb3VudCkpO1xuICAgICAgfVxuICAgICAgbmV3UG9zICs9IGNvbXBvbmVudC5jb3VudDtcblxuICAgICAgLy8gQ29tbW9uIGNhc2VcbiAgICAgIGlmICghY29tcG9uZW50LmFkZGVkKSB7XG4gICAgICAgIG9sZFBvcyArPSBjb21wb25lbnQuY291bnQ7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbXBvbmVudC52YWx1ZSA9IGRpZmYuam9pbihvbGRTdHJpbmcuc2xpY2Uob2xkUG9zLCBvbGRQb3MgKyBjb21wb25lbnQuY291bnQpKTtcbiAgICAgIG9sZFBvcyArPSBjb21wb25lbnQuY291bnQ7XG5cbiAgICAgIC8vIFJldmVyc2UgYWRkIGFuZCByZW1vdmUgc28gcmVtb3ZlcyBhcmUgb3V0cHV0IGZpcnN0IHRvIG1hdGNoIGNvbW1vbiBjb252ZW50aW9uXG4gICAgICAvLyBUaGUgZGlmZmluZyBhbGdvcml0aG0gaXMgdGllZCB0byBhZGQgdGhlbiByZW1vdmUgb3V0cHV0IGFuZCB0aGlzIGlzIHRoZSBzaW1wbGVzdFxuICAgICAgLy8gcm91dGUgdG8gZ2V0IHRoZSBkZXNpcmVkIG91dHB1dCB3aXRoIG1pbmltYWwgb3ZlcmhlYWQuXG4gICAgICBpZiAoY29tcG9uZW50UG9zICYmIGNvbXBvbmVudHNbY29tcG9uZW50UG9zIC0gMV0uYWRkZWQpIHtcbiAgICAgICAgbGV0IHRtcCA9IGNvbXBvbmVudHNbY29tcG9uZW50UG9zIC0gMV07XG4gICAgICAgIGNvbXBvbmVudHNbY29tcG9uZW50UG9zIC0gMV0gPSBjb21wb25lbnRzW2NvbXBvbmVudFBvc107XG4gICAgICAgIGNvbXBvbmVudHNbY29tcG9uZW50UG9zXSA9IHRtcDtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBTcGVjaWFsIGNhc2UgaGFuZGxlIGZvciB3aGVuIG9uZSB0ZXJtaW5hbCBpcyBpZ25vcmVkLiBGb3IgdGhpcyBjYXNlIHdlIG1lcmdlIHRoZVxuICAvLyB0ZXJtaW5hbCBpbnRvIHRoZSBwcmlvciBzdHJpbmcgYW5kIGRyb3AgdGhlIGNoYW5nZS5cbiAgbGV0IGxhc3RDb21wb25lbnQgPSBjb21wb25lbnRzW2NvbXBvbmVudExlbiAtIDFdO1xuICBpZiAoY29tcG9uZW50TGVuID4gMVxuICAgICAgJiYgKGxhc3RDb21wb25lbnQuYWRkZWQgfHwgbGFzdENvbXBvbmVudC5yZW1vdmVkKVxuICAgICAgJiYgZGlmZi5lcXVhbHMoJycsIGxhc3RDb21wb25lbnQudmFsdWUpKSB7XG4gICAgY29tcG9uZW50c1tjb21wb25lbnRMZW4gLSAyXS52YWx1ZSArPSBsYXN0Q29tcG9uZW50LnZhbHVlO1xuICAgIGNvbXBvbmVudHMucG9wKCk7XG4gIH1cblxuICByZXR1cm4gY29tcG9uZW50cztcbn1cblxuZnVuY3Rpb24gY2xvbmVQYXRoKHBhdGgpIHtcbiAgcmV0dXJuIHsgbmV3UG9zOiBwYXRoLm5ld1BvcywgY29tcG9uZW50czogcGF0aC5jb21wb25lbnRzLnNsaWNlKDApIH07XG59XG4iXX0= + + +/***/ }, +/* 2 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + exports.characterDiff = undefined; + exports. diffChars = diffChars; + + var _base = __webpack_require__(1) ; + + + var _base2 = _interopRequireDefault(_base); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + var characterDiff = exports. characterDiff = new _base2['default']() ; + function diffChars(oldStr, newStr, callback) { + return characterDiff.diff(oldStr, newStr, callback); + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kaWZmL2NoYXJhY3Rlci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O2dDQUdnQixTLEdBQUEsUzs7QUFIaEIsSSx5QkFBQSx5Qix3QkFBQTs7Ozs7Ozt1QkFFTyxJQUFNLGdCLHlCQUFBLFEsd0JBQUEsZ0JBQWdCLEkseUJBQUEsbUIsd0JBQXRCO0FBQ0EsU0FBUyxTQUFULENBQW1CLE1BQW5CLEVBQTJCLE1BQTNCLEVBQW1DLFFBQW5DLEVBQTZDO0FBQUUsU0FBTyxjQUFjLElBQWQsQ0FBbUIsTUFBbkIsRUFBMkIsTUFBM0IsRUFBbUMsUUFBbkMsQ0FBUDtBQUFzRCIsImZpbGUiOiJjaGFyYWN0ZXIuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgRGlmZiBmcm9tICcuL2Jhc2UnO1xuXG5leHBvcnQgY29uc3QgY2hhcmFjdGVyRGlmZiA9IG5ldyBEaWZmKCk7XG5leHBvcnQgZnVuY3Rpb24gZGlmZkNoYXJzKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjaykgeyByZXR1cm4gY2hhcmFjdGVyRGlmZi5kaWZmKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjayk7IH1cbiJdfQ== + + +/***/ }, +/* 3 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + exports.wordDiff = undefined; + exports. diffWords = diffWords; + exports. diffWordsWithSpace = diffWordsWithSpace; + + var _base = __webpack_require__(1) ; + + + var _base2 = _interopRequireDefault(_base); + + + var _params = __webpack_require__(4) ; + + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + + + // Based on https://en.wikipedia.org/wiki/Latin_script_in_Unicode + // + // Ranges and exceptions: + // Latin-1 Supplement, 0080–00FF + // - U+00D7 × Multiplication sign + // - U+00F7 ÷ Division sign + // Latin Extended-A, 0100–017F + // Latin Extended-B, 0180–024F + // IPA Extensions, 0250–02AF + // Spacing Modifier Letters, 02B0–02FF + // - U+02C7 ˇ ˇ Caron + // - U+02D8 ˘ ˘ Breve + // - U+02D9 ˙ ˙ Dot Above + // - U+02DA ˚ ˚ Ring Above + // - U+02DB ˛ ˛ Ogonek + // - U+02DC ˜ ˜ Small Tilde + // - U+02DD ˝ ˝ Double Acute Accent + // Latin Extended Additional, 1E00–1EFF + var extendedWordChars = /^[A-Za-z\xC0-\u02C6\u02C8-\u02D7\u02DE-\u02FF\u1E00-\u1EFF]+$/; + + var reWhitespace = /\S/; + + var wordDiff = exports. wordDiff = new _base2['default']() ; + wordDiff.equals = function (left, right) { + return left === right || this.options.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right); + }; + wordDiff.tokenize = function (value) { + var tokens = value.split(/(\s+|\b)/); + + // Join the boundary splits that we do not consider to be boundaries. This is primarily the extended Latin character set. + for (var i = 0; i < tokens.length - 1; i++) { + // If we have an empty string in the next field and we have only word chars before and after, merge + if (!tokens[i + 1] && tokens[i + 2] && extendedWordChars.test(tokens[i]) && extendedWordChars.test(tokens[i + 2])) { + tokens[i] += tokens[i + 2]; + tokens.splice(i + 1, 2); + i--; + } + } + + return tokens; + }; + + function diffWords(oldStr, newStr, callback) { + var options = (0, _params.generateOptions) (callback, { ignoreWhitespace: true }); + return wordDiff.diff(oldStr, newStr, options); + } + function diffWordsWithSpace(oldStr, newStr, callback) { + return wordDiff.diff(oldStr, newStr, callback); + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kaWZmL3dvcmQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztnQ0ErQ2dCLFMsR0FBQSxTO3lEQUlBLGtCLEdBQUEsa0I7O0FBbkRoQixJLHlCQUFBLHlCLHdCQUFBOzs7Ozs7QUFDQSxJLHlCQUFBLG1DLHdCQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBb0JBLElBQU0sb0JBQW9CLCtEQUExQjs7QUFFQSxJQUFNLGVBQWUsSUFBckI7O0FBRU8sSUFBTSxXLHlCQUFBLFEsd0JBQUEsV0FBVyxJLHlCQUFBLG1CLHdCQUFqQjtBQUNQLFNBQVMsTUFBVCxHQUFrQixVQUFTLElBQVQsRUFBZSxLQUFmLEVBQXNCO0FBQ3RDLFNBQU8sU0FBUyxLQUFULElBQW1CLEtBQUssT0FBTCxDQUFhLGdCQUFiLElBQWlDLENBQUMsYUFBYSxJQUFiLENBQWtCLElBQWxCLENBQWxDLElBQTZELENBQUMsYUFBYSxJQUFiLENBQWtCLEtBQWxCLENBQXhGO0FBQ0QsQ0FGRDtBQUdBLFNBQVMsUUFBVCxHQUFvQixVQUFTLEtBQVQsRUFBZ0I7QUFDbEMsTUFBSSxTQUFTLE1BQU0sS0FBTixDQUFZLFVBQVosQ0FBYjs7O0FBR0EsT0FBSyxJQUFJLElBQUksQ0FBYixFQUFnQixJQUFJLE9BQU8sTUFBUCxHQUFnQixDQUFwQyxFQUF1QyxHQUF2QyxFQUE0Qzs7QUFFMUMsUUFBSSxDQUFDLE9BQU8sSUFBSSxDQUFYLENBQUQsSUFBa0IsT0FBTyxJQUFJLENBQVgsQ0FBbEIsSUFDSyxrQkFBa0IsSUFBbEIsQ0FBdUIsT0FBTyxDQUFQLENBQXZCLENBREwsSUFFSyxrQkFBa0IsSUFBbEIsQ0FBdUIsT0FBTyxJQUFJLENBQVgsQ0FBdkIsQ0FGVCxFQUVnRDtBQUM5QyxhQUFPLENBQVAsS0FBYSxPQUFPLElBQUksQ0FBWCxDQUFiO0FBQ0EsYUFBTyxNQUFQLENBQWMsSUFBSSxDQUFsQixFQUFxQixDQUFyQjtBQUNBO0FBQ0Q7QUFDRjs7QUFFRCxTQUFPLE1BQVA7QUFDRCxDQWhCRDs7QUFrQk8sU0FBUyxTQUFULENBQW1CLE1BQW5CLEVBQTJCLE1BQTNCLEVBQW1DLFFBQW5DLEVBQTZDO0FBQ2xELE1BQUksVSx5QkFBVSw0Qix3QkFBQSxDQUFnQixRQUFoQixFQUEwQixFQUFDLGtCQUFrQixJQUFuQixFQUExQixDQUFkO0FBQ0EsU0FBTyxTQUFTLElBQVQsQ0FBYyxNQUFkLEVBQXNCLE1BQXRCLEVBQThCLE9BQTlCLENBQVA7QUFDRDtBQUNNLFNBQVMsa0JBQVQsQ0FBNEIsTUFBNUIsRUFBb0MsTUFBcEMsRUFBNEMsUUFBNUMsRUFBc0Q7QUFDM0QsU0FBTyxTQUFTLElBQVQsQ0FBYyxNQUFkLEVBQXNCLE1BQXRCLEVBQThCLFFBQTlCLENBQVA7QUFDRCIsImZpbGUiOiJ3b3JkLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IERpZmYgZnJvbSAnLi9iYXNlJztcbmltcG9ydCB7Z2VuZXJhdGVPcHRpb25zfSBmcm9tICcuLi91dGlsL3BhcmFtcyc7XG5cbi8vIEJhc2VkIG9uIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xhdGluX3NjcmlwdF9pbl9Vbmljb2RlXG4vL1xuLy8gUmFuZ2VzIGFuZCBleGNlcHRpb25zOlxuLy8gTGF0aW4tMSBTdXBwbGVtZW50LCAwMDgw4oCTMDBGRlxuLy8gIC0gVSswMEQ3ICDDlyBNdWx0aXBsaWNhdGlvbiBzaWduXG4vLyAgLSBVKzAwRjcgIMO3IERpdmlzaW9uIHNpZ25cbi8vIExhdGluIEV4dGVuZGVkLUEsIDAxMDDigJMwMTdGXG4vLyBMYXRpbiBFeHRlbmRlZC1CLCAwMTgw4oCTMDI0RlxuLy8gSVBBIEV4dGVuc2lvbnMsIDAyNTDigJMwMkFGXG4vLyBTcGFjaW5nIE1vZGlmaWVyIExldHRlcnMsIDAyQjDigJMwMkZGXG4vLyAgLSBVKzAyQzcgIMuHICYjNzExOyAgQ2Fyb25cbi8vICAtIFUrMDJEOCAgy5ggJiM3Mjg7ICBCcmV2ZVxuLy8gIC0gVSswMkQ5ICDLmSAmIzcyOTsgIERvdCBBYm92ZVxuLy8gIC0gVSswMkRBICDLmiAmIzczMDsgIFJpbmcgQWJvdmVcbi8vICAtIFUrMDJEQiAgy5sgJiM3MzE7ICBPZ29uZWtcbi8vICAtIFUrMDJEQyAgy5wgJiM3MzI7ICBTbWFsbCBUaWxkZVxuLy8gIC0gVSswMkREICDLnSAmIzczMzsgIERvdWJsZSBBY3V0ZSBBY2NlbnRcbi8vIExhdGluIEV4dGVuZGVkIEFkZGl0aW9uYWwsIDFFMDDigJMxRUZGXG5jb25zdCBleHRlbmRlZFdvcmRDaGFycyA9IC9eW2EtekEtWlxcdXtDMH0tXFx1e0ZGfVxcdXtEOH0tXFx1e0Y2fVxcdXtGOH0tXFx1ezJDNn1cXHV7MkM4fS1cXHV7MkQ3fVxcdXsyREV9LVxcdXsyRkZ9XFx1ezFFMDB9LVxcdXsxRUZGfV0rJC91O1xuXG5jb25zdCByZVdoaXRlc3BhY2UgPSAvXFxTLztcblxuZXhwb3J0IGNvbnN0IHdvcmREaWZmID0gbmV3IERpZmYoKTtcbndvcmREaWZmLmVxdWFscyA9IGZ1bmN0aW9uKGxlZnQsIHJpZ2h0KSB7XG4gIHJldHVybiBsZWZ0ID09PSByaWdodCB8fCAodGhpcy5vcHRpb25zLmlnbm9yZVdoaXRlc3BhY2UgJiYgIXJlV2hpdGVzcGFjZS50ZXN0KGxlZnQpICYmICFyZVdoaXRlc3BhY2UudGVzdChyaWdodCkpO1xufTtcbndvcmREaWZmLnRva2VuaXplID0gZnVuY3Rpb24odmFsdWUpIHtcbiAgbGV0IHRva2VucyA9IHZhbHVlLnNwbGl0KC8oXFxzK3xcXGIpLyk7XG5cbiAgLy8gSm9pbiB0aGUgYm91bmRhcnkgc3BsaXRzIHRoYXQgd2UgZG8gbm90IGNvbnNpZGVyIHRvIGJlIGJvdW5kYXJpZXMuIFRoaXMgaXMgcHJpbWFyaWx5IHRoZSBleHRlbmRlZCBMYXRpbiBjaGFyYWN0ZXIgc2V0LlxuICBmb3IgKGxldCBpID0gMDsgaSA8IHRva2Vucy5sZW5ndGggLSAxOyBpKyspIHtcbiAgICAvLyBJZiB3ZSBoYXZlIGFuIGVtcHR5IHN0cmluZyBpbiB0aGUgbmV4dCBmaWVsZCBhbmQgd2UgaGF2ZSBvbmx5IHdvcmQgY2hhcnMgYmVmb3JlIGFuZCBhZnRlciwgbWVyZ2VcbiAgICBpZiAoIXRva2Vuc1tpICsgMV0gJiYgdG9rZW5zW2kgKyAyXVxuICAgICAgICAgICYmIGV4dGVuZGVkV29yZENoYXJzLnRlc3QodG9rZW5zW2ldKVxuICAgICAgICAgICYmIGV4dGVuZGVkV29yZENoYXJzLnRlc3QodG9rZW5zW2kgKyAyXSkpIHtcbiAgICAgIHRva2Vuc1tpXSArPSB0b2tlbnNbaSArIDJdO1xuICAgICAgdG9rZW5zLnNwbGljZShpICsgMSwgMik7XG4gICAgICBpLS07XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRva2Vucztcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBkaWZmV29yZHMob2xkU3RyLCBuZXdTdHIsIGNhbGxiYWNrKSB7XG4gIGxldCBvcHRpb25zID0gZ2VuZXJhdGVPcHRpb25zKGNhbGxiYWNrLCB7aWdub3JlV2hpdGVzcGFjZTogdHJ1ZX0pO1xuICByZXR1cm4gd29yZERpZmYuZGlmZihvbGRTdHIsIG5ld1N0ciwgb3B0aW9ucyk7XG59XG5leHBvcnQgZnVuY3Rpb24gZGlmZldvcmRzV2l0aFNwYWNlKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjaykge1xuICByZXR1cm4gd29yZERpZmYuZGlmZihvbGRTdHIsIG5ld1N0ciwgY2FsbGJhY2spO1xufVxuIl19 + + +/***/ }, +/* 4 */ +/***/ function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + exports. generateOptions = generateOptions; + function generateOptions(options, defaults) { + if (typeof options === 'function') { + defaults.callback = options; + } else if (options) { + for (var name in options) { + /* istanbul ignore else */ + if (options.hasOwnProperty(name)) { + defaults[name] = options[name]; + } + } + } + return defaults; + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlsL3BhcmFtcy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Z0NBQWdCLGUsR0FBQSxlO0FBQVQsU0FBUyxlQUFULENBQXlCLE9BQXpCLEVBQWtDLFFBQWxDLEVBQTRDO0FBQ2pELE1BQUksT0FBTyxPQUFQLEtBQW1CLFVBQXZCLEVBQW1DO0FBQ2pDLGFBQVMsUUFBVCxHQUFvQixPQUFwQjtBQUNELEdBRkQsTUFFTyxJQUFJLE9BQUosRUFBYTtBQUNsQixTQUFLLElBQUksSUFBVCxJQUFpQixPQUFqQixFQUEwQjs7QUFFeEIsVUFBSSxRQUFRLGNBQVIsQ0FBdUIsSUFBdkIsQ0FBSixFQUFrQztBQUNoQyxpQkFBUyxJQUFULElBQWlCLFFBQVEsSUFBUixDQUFqQjtBQUNEO0FBQ0Y7QUFDRjtBQUNELFNBQU8sUUFBUDtBQUNEIiwiZmlsZSI6InBhcmFtcy5qcyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZU9wdGlvbnMob3B0aW9ucywgZGVmYXVsdHMpIHtcbiAgaWYgKHR5cGVvZiBvcHRpb25zID09PSAnZnVuY3Rpb24nKSB7XG4gICAgZGVmYXVsdHMuY2FsbGJhY2sgPSBvcHRpb25zO1xuICB9IGVsc2UgaWYgKG9wdGlvbnMpIHtcbiAgICBmb3IgKGxldCBuYW1lIGluIG9wdGlvbnMpIHtcbiAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBlbHNlICovXG4gICAgICBpZiAob3B0aW9ucy5oYXNPd25Qcm9wZXJ0eShuYW1lKSkge1xuICAgICAgICBkZWZhdWx0c1tuYW1lXSA9IG9wdGlvbnNbbmFtZV07XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBkZWZhdWx0cztcbn1cbiJdfQ== + + +/***/ }, +/* 5 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + exports.lineDiff = undefined; + exports. diffLines = diffLines; + exports. diffTrimmedLines = diffTrimmedLines; + + var _base = __webpack_require__(1) ; + + + var _base2 = _interopRequireDefault(_base); + + + var _params = __webpack_require__(4) ; + + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + var lineDiff = exports. lineDiff = new _base2['default']() ; + lineDiff.tokenize = function (value) { + var retLines = [], + linesAndNewlines = value.split(/(\n|\r\n)/); + + // Ignore the final empty token that occurs if the string ends with a new line + if (!linesAndNewlines[linesAndNewlines.length - 1]) { + linesAndNewlines.pop(); + } + + // Merge the content and line separators into single tokens + for (var i = 0; i < linesAndNewlines.length; i++) { + var line = linesAndNewlines[i]; + + if (i % 2 && !this.options.newlineIsToken) { + retLines[retLines.length - 1] += line; + } else { + if (this.options.ignoreWhitespace) { + line = line.trim(); + } + retLines.push(line); + } + } + + return retLines; + }; + + function diffLines(oldStr, newStr, callback) { + return lineDiff.diff(oldStr, newStr, callback); + } + function diffTrimmedLines(oldStr, newStr, callback) { + var options = (0, _params.generateOptions) (callback, { ignoreWhitespace: true }); + return lineDiff.diff(oldStr, newStr, options); + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kaWZmL2xpbmUuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztnQ0E4QmdCLFMsR0FBQSxTO3lEQUNBLGdCLEdBQUEsZ0I7O0FBL0JoQixJLHlCQUFBLHlCLHdCQUFBOzs7Ozs7QUFDQSxJLHlCQUFBLG1DLHdCQUFBOzs7Ozt1QkFFTyxJQUFNLFcseUJBQUEsUSx3QkFBQSxXQUFXLEkseUJBQUEsbUIsd0JBQWpCO0FBQ1AsU0FBUyxRQUFULEdBQW9CLFVBQVMsS0FBVCxFQUFnQjtBQUNsQyxNQUFJLFdBQVcsRUFBZjtBQUFBLE1BQ0ksbUJBQW1CLE1BQU0sS0FBTixDQUFZLFdBQVosQ0FEdkI7OztBQUlBLE1BQUksQ0FBQyxpQkFBaUIsaUJBQWlCLE1BQWpCLEdBQTBCLENBQTNDLENBQUwsRUFBb0Q7QUFDbEQscUJBQWlCLEdBQWpCO0FBQ0Q7OztBQUdELE9BQUssSUFBSSxJQUFJLENBQWIsRUFBZ0IsSUFBSSxpQkFBaUIsTUFBckMsRUFBNkMsR0FBN0MsRUFBa0Q7QUFDaEQsUUFBSSxPQUFPLGlCQUFpQixDQUFqQixDQUFYOztBQUVBLFFBQUksSUFBSSxDQUFKLElBQVMsQ0FBQyxLQUFLLE9BQUwsQ0FBYSxjQUEzQixFQUEyQztBQUN6QyxlQUFTLFNBQVMsTUFBVCxHQUFrQixDQUEzQixLQUFpQyxJQUFqQztBQUNELEtBRkQsTUFFTztBQUNMLFVBQUksS0FBSyxPQUFMLENBQWEsZ0JBQWpCLEVBQW1DO0FBQ2pDLGVBQU8sS0FBSyxJQUFMLEVBQVA7QUFDRDtBQUNELGVBQVMsSUFBVCxDQUFjLElBQWQ7QUFDRDtBQUNGOztBQUVELFNBQU8sUUFBUDtBQUNELENBeEJEOztBQTBCTyxTQUFTLFNBQVQsQ0FBbUIsTUFBbkIsRUFBMkIsTUFBM0IsRUFBbUMsUUFBbkMsRUFBNkM7QUFBRSxTQUFPLFNBQVMsSUFBVCxDQUFjLE1BQWQsRUFBc0IsTUFBdEIsRUFBOEIsUUFBOUIsQ0FBUDtBQUFpRDtBQUNoRyxTQUFTLGdCQUFULENBQTBCLE1BQTFCLEVBQWtDLE1BQWxDLEVBQTBDLFFBQTFDLEVBQW9EO0FBQ3pELE1BQUksVSx5QkFBVSw0Qix3QkFBQSxDQUFnQixRQUFoQixFQUEwQixFQUFDLGtCQUFrQixJQUFuQixFQUExQixDQUFkO0FBQ0EsU0FBTyxTQUFTLElBQVQsQ0FBYyxNQUFkLEVBQXNCLE1BQXRCLEVBQThCLE9BQTlCLENBQVA7QUFDRCIsImZpbGUiOiJsaW5lLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IERpZmYgZnJvbSAnLi9iYXNlJztcbmltcG9ydCB7Z2VuZXJhdGVPcHRpb25zfSBmcm9tICcuLi91dGlsL3BhcmFtcyc7XG5cbmV4cG9ydCBjb25zdCBsaW5lRGlmZiA9IG5ldyBEaWZmKCk7XG5saW5lRGlmZi50b2tlbml6ZSA9IGZ1bmN0aW9uKHZhbHVlKSB7XG4gIGxldCByZXRMaW5lcyA9IFtdLFxuICAgICAgbGluZXNBbmROZXdsaW5lcyA9IHZhbHVlLnNwbGl0KC8oXFxufFxcclxcbikvKTtcblxuICAvLyBJZ25vcmUgdGhlIGZpbmFsIGVtcHR5IHRva2VuIHRoYXQgb2NjdXJzIGlmIHRoZSBzdHJpbmcgZW5kcyB3aXRoIGEgbmV3IGxpbmVcbiAgaWYgKCFsaW5lc0FuZE5ld2xpbmVzW2xpbmVzQW5kTmV3bGluZXMubGVuZ3RoIC0gMV0pIHtcbiAgICBsaW5lc0FuZE5ld2xpbmVzLnBvcCgpO1xuICB9XG5cbiAgLy8gTWVyZ2UgdGhlIGNvbnRlbnQgYW5kIGxpbmUgc2VwYXJhdG9ycyBpbnRvIHNpbmdsZSB0b2tlbnNcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBsaW5lc0FuZE5ld2xpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgbGV0IGxpbmUgPSBsaW5lc0FuZE5ld2xpbmVzW2ldO1xuXG4gICAgaWYgKGkgJSAyICYmICF0aGlzLm9wdGlvbnMubmV3bGluZUlzVG9rZW4pIHtcbiAgICAgIHJldExpbmVzW3JldExpbmVzLmxlbmd0aCAtIDFdICs9IGxpbmU7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuaWdub3JlV2hpdGVzcGFjZSkge1xuICAgICAgICBsaW5lID0gbGluZS50cmltKCk7XG4gICAgICB9XG4gICAgICByZXRMaW5lcy5wdXNoKGxpbmUpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiByZXRMaW5lcztcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBkaWZmTGluZXMob2xkU3RyLCBuZXdTdHIsIGNhbGxiYWNrKSB7IHJldHVybiBsaW5lRGlmZi5kaWZmKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjayk7IH1cbmV4cG9ydCBmdW5jdGlvbiBkaWZmVHJpbW1lZExpbmVzKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjaykge1xuICBsZXQgb3B0aW9ucyA9IGdlbmVyYXRlT3B0aW9ucyhjYWxsYmFjaywge2lnbm9yZVdoaXRlc3BhY2U6IHRydWV9KTtcbiAgcmV0dXJuIGxpbmVEaWZmLmRpZmYob2xkU3RyLCBuZXdTdHIsIG9wdGlvbnMpO1xufVxuIl19 + + +/***/ }, +/* 6 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + exports.sentenceDiff = undefined; + exports. diffSentences = diffSentences; + + var _base = __webpack_require__(1) ; + + + var _base2 = _interopRequireDefault(_base); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + var sentenceDiff = exports. sentenceDiff = new _base2['default']() ; + sentenceDiff.tokenize = function (value) { + return value.split(/(\S.+?[.!?])(?=\s+|$)/); + }; + + function diffSentences(oldStr, newStr, callback) { + return sentenceDiff.diff(oldStr, newStr, callback); + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kaWZmL3NlbnRlbmNlLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Z0NBUWdCLGEsR0FBQSxhOztBQVJoQixJLHlCQUFBLHlCLHdCQUFBOzs7Ozs7O3VCQUdPLElBQU0sZSx5QkFBQSxRLHdCQUFBLGVBQWUsSSx5QkFBQSxtQix3QkFBckI7QUFDUCxhQUFhLFFBQWIsR0FBd0IsVUFBUyxLQUFULEVBQWdCO0FBQ3RDLFNBQU8sTUFBTSxLQUFOLENBQVksdUJBQVosQ0FBUDtBQUNELENBRkQ7O0FBSU8sU0FBUyxhQUFULENBQXVCLE1BQXZCLEVBQStCLE1BQS9CLEVBQXVDLFFBQXZDLEVBQWlEO0FBQUUsU0FBTyxhQUFhLElBQWIsQ0FBa0IsTUFBbEIsRUFBMEIsTUFBMUIsRUFBa0MsUUFBbEMsQ0FBUDtBQUFxRCIsImZpbGUiOiJzZW50ZW5jZS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBEaWZmIGZyb20gJy4vYmFzZSc7XG5cblxuZXhwb3J0IGNvbnN0IHNlbnRlbmNlRGlmZiA9IG5ldyBEaWZmKCk7XG5zZW50ZW5jZURpZmYudG9rZW5pemUgPSBmdW5jdGlvbih2YWx1ZSkge1xuICByZXR1cm4gdmFsdWUuc3BsaXQoLyhcXFMuKz9bLiE/XSkoPz1cXHMrfCQpLyk7XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gZGlmZlNlbnRlbmNlcyhvbGRTdHIsIG5ld1N0ciwgY2FsbGJhY2spIHsgcmV0dXJuIHNlbnRlbmNlRGlmZi5kaWZmKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjayk7IH1cbiJdfQ== + + +/***/ }, +/* 7 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + exports.cssDiff = undefined; + exports. diffCss = diffCss; + + var _base = __webpack_require__(1) ; + + + var _base2 = _interopRequireDefault(_base); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + var cssDiff = exports. cssDiff = new _base2['default']() ; + cssDiff.tokenize = function (value) { + return value.split(/([{}:;,]|\s+)/); + }; + + function diffCss(oldStr, newStr, callback) { + return cssDiff.diff(oldStr, newStr, callback); + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kaWZmL2Nzcy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O2dDQU9nQixPLEdBQUEsTzs7QUFQaEIsSSx5QkFBQSx5Qix3QkFBQTs7Ozs7Ozt1QkFFTyxJQUFNLFUseUJBQUEsUSx3QkFBQSxVQUFVLEkseUJBQUEsbUIsd0JBQWhCO0FBQ1AsUUFBUSxRQUFSLEdBQW1CLFVBQVMsS0FBVCxFQUFnQjtBQUNqQyxTQUFPLE1BQU0sS0FBTixDQUFZLGVBQVosQ0FBUDtBQUNELENBRkQ7O0FBSU8sU0FBUyxPQUFULENBQWlCLE1BQWpCLEVBQXlCLE1BQXpCLEVBQWlDLFFBQWpDLEVBQTJDO0FBQUUsU0FBTyxRQUFRLElBQVIsQ0FBYSxNQUFiLEVBQXFCLE1BQXJCLEVBQTZCLFFBQTdCLENBQVA7QUFBZ0QiLCJmaWxlIjoiY3NzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IERpZmYgZnJvbSAnLi9iYXNlJztcblxuZXhwb3J0IGNvbnN0IGNzc0RpZmYgPSBuZXcgRGlmZigpO1xuY3NzRGlmZi50b2tlbml6ZSA9IGZ1bmN0aW9uKHZhbHVlKSB7XG4gIHJldHVybiB2YWx1ZS5zcGxpdCgvKFt7fTo7LF18XFxzKykvKTtcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBkaWZmQ3NzKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjaykgeyByZXR1cm4gY3NzRGlmZi5kaWZmKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjayk7IH1cbiJdfQ== + + +/***/ }, +/* 8 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + exports.jsonDiff = undefined; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; + + exports. diffJson = diffJson; + exports. canonicalize = canonicalize; + + var _base = __webpack_require__(1) ; + + + var _base2 = _interopRequireDefault(_base); + + + var _line = __webpack_require__(5) ; + + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + + + var objectPrototypeToString = Object.prototype.toString; + + var jsonDiff = exports. jsonDiff = new _base2['default']() ; + // Discriminate between two lines of pretty-printed, serialized JSON where one of them has a + // dangling comma and the other doesn't. Turns out including the dangling comma yields the nicest output: + jsonDiff.useLongestToken = true; + + jsonDiff.tokenize = _line.lineDiff. tokenize; + jsonDiff.castInput = function (value) { + var undefinedReplacement = this.options.undefinedReplacement; + + + return typeof value === 'string' ? value : JSON.stringify(canonicalize(value), function (k, v) { + if (typeof v === 'undefined') { + return undefinedReplacement; + } + + return v; + }, ' '); + }; + jsonDiff.equals = function (left, right) { + return (_base2['default']. prototype.equals(left.replace(/,([\r\n])/g, '$1'), right.replace(/,([\r\n])/g, '$1')) + ); + }; + + function diffJson(oldObj, newObj, options) { + return jsonDiff.diff(oldObj, newObj, options); + } + + // This function handles the presence of circular references by bailing out when encountering an + // object that is already on the "stack" of items being processed. + function canonicalize(obj, stack, replacementStack) { + stack = stack || []; + replacementStack = replacementStack || []; + + var i = void 0 ; + + for (i = 0; i < stack.length; i += 1) { + if (stack[i] === obj) { + return replacementStack[i]; + } + } + + var canonicalizedObj = void 0 ; + + if ('[object Array]' === objectPrototypeToString.call(obj)) { + stack.push(obj); + canonicalizedObj = new Array(obj.length); + replacementStack.push(canonicalizedObj); + for (i = 0; i < obj.length; i += 1) { + canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack); + } + stack.pop(); + replacementStack.pop(); + return canonicalizedObj; + } + + if (obj && obj.toJSON) { + obj = obj.toJSON(); + } + + if ( (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object' && obj !== null) { + stack.push(obj); + canonicalizedObj = {}; + replacementStack.push(canonicalizedObj); + var sortedKeys = [], + key = void 0 ; + for (key in obj) { + /* istanbul ignore else */ + if (obj.hasOwnProperty(key)) { + sortedKeys.push(key); + } + } + sortedKeys.sort(); + for (i = 0; i < sortedKeys.length; i += 1) { + key = sortedKeys[i]; + canonicalizedObj[key] = canonicalize(obj[key], stack, replacementStack); + } + stack.pop(); + replacementStack.pop(); + } else { + canonicalizedObj = obj; + } + return canonicalizedObj; + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kaWZmL2pzb24uanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7OztnQ0EyQmdCLFEsR0FBQSxRO3lEQUlBLFksR0FBQSxZOztBQS9CaEIsSSx5QkFBQSx5Qix3QkFBQTs7Ozs7O0FBQ0EsSSx5QkFBQSx5Qix3QkFBQTs7Ozs7OztBQUVBLElBQU0sMEJBQTBCLE9BQU8sU0FBUCxDQUFpQixRQUFqRDs7QUFHTyxJQUFNLFcseUJBQUEsUSx3QkFBQSxXQUFXLEkseUJBQUEsbUIsd0JBQWpCOzs7QUFHUCxTQUFTLGVBQVQsR0FBMkIsSUFBM0I7O0FBRUEsU0FBUyxRQUFULEcseUJBQW9CLGUsd0JBQVMsUUFBN0I7QUFDQSxTQUFTLFNBQVQsR0FBcUIsVUFBUyxLQUFULEVBQWdCOzJCQUFBLEksdUJBQzVCLG9CQUQ0QixHQUNKLEtBQUssT0FERCxDQUM1QixvQkFENEI7OztBQUduQyxTQUFPLE9BQU8sS0FBUCxLQUFpQixRQUFqQixHQUE0QixLQUE1QixHQUFvQyxLQUFLLFNBQUwsQ0FBZSxhQUFhLEtBQWIsQ0FBZixFQUFvQyxVQUFTLENBQVQsRUFBWSxDQUFaLEVBQWU7QUFDNUYsUUFBSSxPQUFPLENBQVAsS0FBYSxXQUFqQixFQUE4QjtBQUM1QixhQUFPLG9CQUFQO0FBQ0Q7O0FBRUQsV0FBTyxDQUFQO0FBQ0QsR0FOMEMsRUFNeEMsSUFOd0MsQ0FBM0M7QUFPRCxDQVZEO0FBV0EsU0FBUyxNQUFULEdBQWtCLFVBQVMsSUFBVCxFQUFlLEtBQWYsRUFBc0I7QUFDdEMsUywwQkFBTyxrQix3QkFBSyxTQUFMLENBQWUsTUFBZixDQUFzQixLQUFLLE9BQUwsQ0FBYSxZQUFiLEVBQTJCLElBQTNCLENBQXRCLEVBQXdELE1BQU0sT0FBTixDQUFjLFlBQWQsRUFBNEIsSUFBNUIsQ0FBeEQ7QUFBUDtBQUNELENBRkQ7O0FBSU8sU0FBUyxRQUFULENBQWtCLE1BQWxCLEVBQTBCLE1BQTFCLEVBQWtDLE9BQWxDLEVBQTJDO0FBQUUsU0FBTyxTQUFTLElBQVQsQ0FBYyxNQUFkLEVBQXNCLE1BQXRCLEVBQThCLE9BQTlCLENBQVA7QUFBZ0Q7Ozs7QUFJN0YsU0FBUyxZQUFULENBQXNCLEdBQXRCLEVBQTJCLEtBQTNCLEVBQWtDLGdCQUFsQyxFQUFvRDtBQUN6RCxVQUFRLFNBQVMsRUFBakI7QUFDQSxxQkFBbUIsb0JBQW9CLEVBQXZDOztBQUVBLE1BQUksSSx5QkFBQSxNLHdCQUFKOztBQUVBLE9BQUssSUFBSSxDQUFULEVBQVksSUFBSSxNQUFNLE1BQXRCLEVBQThCLEtBQUssQ0FBbkMsRUFBc0M7QUFDcEMsUUFBSSxNQUFNLENBQU4sTUFBYSxHQUFqQixFQUFzQjtBQUNwQixhQUFPLGlCQUFpQixDQUFqQixDQUFQO0FBQ0Q7QUFDRjs7QUFFRCxNQUFJLG1CLHlCQUFBLE0sd0JBQUo7O0FBRUEsTUFBSSxxQkFBcUIsd0JBQXdCLElBQXhCLENBQTZCLEdBQTdCLENBQXpCLEVBQTREO0FBQzFELFVBQU0sSUFBTixDQUFXLEdBQVg7QUFDQSx1QkFBbUIsSUFBSSxLQUFKLENBQVUsSUFBSSxNQUFkLENBQW5CO0FBQ0EscUJBQWlCLElBQWpCLENBQXNCLGdCQUF0QjtBQUNBLFNBQUssSUFBSSxDQUFULEVBQVksSUFBSSxJQUFJLE1BQXBCLEVBQTRCLEtBQUssQ0FBakMsRUFBb0M7QUFDbEMsdUJBQWlCLENBQWpCLElBQXNCLGFBQWEsSUFBSSxDQUFKLENBQWIsRUFBcUIsS0FBckIsRUFBNEIsZ0JBQTVCLENBQXRCO0FBQ0Q7QUFDRCxVQUFNLEdBQU47QUFDQSxxQkFBaUIsR0FBakI7QUFDQSxXQUFPLGdCQUFQO0FBQ0Q7O0FBRUQsTUFBSSxPQUFPLElBQUksTUFBZixFQUF1QjtBQUNyQixVQUFNLElBQUksTUFBSixFQUFOO0FBQ0Q7O0FBRUQsTSwwQkFBSSxRLHVCQUFPLEdBQVAseUNBQU8sR0FBUCxPQUFlLFFBQWYsSUFBMkIsUUFBUSxJQUF2QyxFQUE2QztBQUMzQyxVQUFNLElBQU4sQ0FBVyxHQUFYO0FBQ0EsdUJBQW1CLEVBQW5CO0FBQ0EscUJBQWlCLElBQWpCLENBQXNCLGdCQUF0QjtBQUNBLFFBQUksYUFBYSxFQUFqQjtBQUFBLFFBQ0ksTSx5QkFBQSxNLHdCQURKO0FBRUEsU0FBSyxHQUFMLElBQVksR0FBWixFQUFpQjs7QUFFZixVQUFJLElBQUksY0FBSixDQUFtQixHQUFuQixDQUFKLEVBQTZCO0FBQzNCLG1CQUFXLElBQVgsQ0FBZ0IsR0FBaEI7QUFDRDtBQUNGO0FBQ0QsZUFBVyxJQUFYO0FBQ0EsU0FBSyxJQUFJLENBQVQsRUFBWSxJQUFJLFdBQVcsTUFBM0IsRUFBbUMsS0FBSyxDQUF4QyxFQUEyQztBQUN6QyxZQUFNLFdBQVcsQ0FBWCxDQUFOO0FBQ0EsdUJBQWlCLEdBQWpCLElBQXdCLGFBQWEsSUFBSSxHQUFKLENBQWIsRUFBdUIsS0FBdkIsRUFBOEIsZ0JBQTlCLENBQXhCO0FBQ0Q7QUFDRCxVQUFNLEdBQU47QUFDQSxxQkFBaUIsR0FBakI7QUFDRCxHQW5CRCxNQW1CTztBQUNMLHVCQUFtQixHQUFuQjtBQUNEO0FBQ0QsU0FBTyxnQkFBUDtBQUNEIiwiZmlsZSI6Impzb24uanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgRGlmZiBmcm9tICcuL2Jhc2UnO1xuaW1wb3J0IHtsaW5lRGlmZn0gZnJvbSAnLi9saW5lJztcblxuY29uc3Qgb2JqZWN0UHJvdG90eXBlVG9TdHJpbmcgPSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nO1xuXG5cbmV4cG9ydCBjb25zdCBqc29uRGlmZiA9IG5ldyBEaWZmKCk7XG4vLyBEaXNjcmltaW5hdGUgYmV0d2VlbiB0d28gbGluZXMgb2YgcHJldHR5LXByaW50ZWQsIHNlcmlhbGl6ZWQgSlNPTiB3aGVyZSBvbmUgb2YgdGhlbSBoYXMgYVxuLy8gZGFuZ2xpbmcgY29tbWEgYW5kIHRoZSBvdGhlciBkb2Vzbid0LiBUdXJucyBvdXQgaW5jbHVkaW5nIHRoZSBkYW5nbGluZyBjb21tYSB5aWVsZHMgdGhlIG5pY2VzdCBvdXRwdXQ6XG5qc29uRGlmZi51c2VMb25nZXN0VG9rZW4gPSB0cnVlO1xuXG5qc29uRGlmZi50b2tlbml6ZSA9IGxpbmVEaWZmLnRva2VuaXplO1xuanNvbkRpZmYuY2FzdElucHV0ID0gZnVuY3Rpb24odmFsdWUpIHtcbiAgY29uc3Qge3VuZGVmaW5lZFJlcGxhY2VtZW50fSA9IHRoaXMub3B0aW9ucztcblxuICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/IHZhbHVlIDogSlNPTi5zdHJpbmdpZnkoY2Fub25pY2FsaXplKHZhbHVlKSwgZnVuY3Rpb24oaywgdikge1xuICAgIGlmICh0eXBlb2YgdiA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWRSZXBsYWNlbWVudDtcbiAgICB9XG5cbiAgICByZXR1cm4gdjtcbiAgfSwgJyAgJyk7XG59O1xuanNvbkRpZmYuZXF1YWxzID0gZnVuY3Rpb24obGVmdCwgcmlnaHQpIHtcbiAgcmV0dXJuIERpZmYucHJvdG90eXBlLmVxdWFscyhsZWZ0LnJlcGxhY2UoLywoW1xcclxcbl0pL2csICckMScpLCByaWdodC5yZXBsYWNlKC8sKFtcXHJcXG5dKS9nLCAnJDEnKSk7XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gZGlmZkpzb24ob2xkT2JqLCBuZXdPYmosIG9wdGlvbnMpIHsgcmV0dXJuIGpzb25EaWZmLmRpZmYob2xkT2JqLCBuZXdPYmosIG9wdGlvbnMpOyB9XG5cbi8vIFRoaXMgZnVuY3Rpb24gaGFuZGxlcyB0aGUgcHJlc2VuY2Ugb2YgY2lyY3VsYXIgcmVmZXJlbmNlcyBieSBiYWlsaW5nIG91dCB3aGVuIGVuY291bnRlcmluZyBhblxuLy8gb2JqZWN0IHRoYXQgaXMgYWxyZWFkeSBvbiB0aGUgXCJzdGFja1wiIG9mIGl0ZW1zIGJlaW5nIHByb2Nlc3NlZC5cbmV4cG9ydCBmdW5jdGlvbiBjYW5vbmljYWxpemUob2JqLCBzdGFjaywgcmVwbGFjZW1lbnRTdGFjaykge1xuICBzdGFjayA9IHN0YWNrIHx8IFtdO1xuICByZXBsYWNlbWVudFN0YWNrID0gcmVwbGFjZW1lbnRTdGFjayB8fCBbXTtcblxuICBsZXQgaTtcblxuICBmb3IgKGkgPSAwOyBpIDwgc3RhY2subGVuZ3RoOyBpICs9IDEpIHtcbiAgICBpZiAoc3RhY2tbaV0gPT09IG9iaikge1xuICAgICAgcmV0dXJuIHJlcGxhY2VtZW50U3RhY2tbaV07XG4gICAgfVxuICB9XG5cbiAgbGV0IGNhbm9uaWNhbGl6ZWRPYmo7XG5cbiAgaWYgKCdbb2JqZWN0IEFycmF5XScgPT09IG9iamVjdFByb3RvdHlwZVRvU3RyaW5nLmNhbGwob2JqKSkge1xuICAgIHN0YWNrLnB1c2gob2JqKTtcbiAgICBjYW5vbmljYWxpemVkT2JqID0gbmV3IEFycmF5KG9iai5sZW5ndGgpO1xuICAgIHJlcGxhY2VtZW50U3RhY2sucHVzaChjYW5vbmljYWxpemVkT2JqKTtcbiAgICBmb3IgKGkgPSAwOyBpIDwgb2JqLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICBjYW5vbmljYWxpemVkT2JqW2ldID0gY2Fub25pY2FsaXplKG9ialtpXSwgc3RhY2ssIHJlcGxhY2VtZW50U3RhY2spO1xuICAgIH1cbiAgICBzdGFjay5wb3AoKTtcbiAgICByZXBsYWNlbWVudFN0YWNrLnBvcCgpO1xuICAgIHJldHVybiBjYW5vbmljYWxpemVkT2JqO1xuICB9XG5cbiAgaWYgKG9iaiAmJiBvYmoudG9KU09OKSB7XG4gICAgb2JqID0gb2JqLnRvSlNPTigpO1xuICB9XG5cbiAgaWYgKHR5cGVvZiBvYmogPT09ICdvYmplY3QnICYmIG9iaiAhPT0gbnVsbCkge1xuICAgIHN0YWNrLnB1c2gob2JqKTtcbiAgICBjYW5vbmljYWxpemVkT2JqID0ge307XG4gICAgcmVwbGFjZW1lbnRTdGFjay5wdXNoKGNhbm9uaWNhbGl6ZWRPYmopO1xuICAgIGxldCBzb3J0ZWRLZXlzID0gW10sXG4gICAgICAgIGtleTtcbiAgICBmb3IgKGtleSBpbiBvYmopIHtcbiAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBlbHNlICovXG4gICAgICBpZiAob2JqLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgc29ydGVkS2V5cy5wdXNoKGtleSk7XG4gICAgICB9XG4gICAgfVxuICAgIHNvcnRlZEtleXMuc29ydCgpO1xuICAgIGZvciAoaSA9IDA7IGkgPCBzb3J0ZWRLZXlzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICBrZXkgPSBzb3J0ZWRLZXlzW2ldO1xuICAgICAgY2Fub25pY2FsaXplZE9ialtrZXldID0gY2Fub25pY2FsaXplKG9ialtrZXldLCBzdGFjaywgcmVwbGFjZW1lbnRTdGFjayk7XG4gICAgfVxuICAgIHN0YWNrLnBvcCgpO1xuICAgIHJlcGxhY2VtZW50U3RhY2sucG9wKCk7XG4gIH0gZWxzZSB7XG4gICAgY2Fub25pY2FsaXplZE9iaiA9IG9iajtcbiAgfVxuICByZXR1cm4gY2Fub25pY2FsaXplZE9iajtcbn1cbiJdfQ== + + +/***/ }, +/* 9 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + exports.arrayDiff = undefined; + exports. diffArrays = diffArrays; + + var _base = __webpack_require__(1) ; + + + var _base2 = _interopRequireDefault(_base); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + var arrayDiff = exports. arrayDiff = new _base2['default']() ; + arrayDiff.tokenize = arrayDiff.join = function (value) { + return value.slice(); + }; + + function diffArrays(oldArr, newArr, callback) { + return arrayDiff.diff(oldArr, newArr, callback); + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kaWZmL2FycmF5LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Z0NBT2dCLFUsR0FBQSxVOztBQVBoQixJLHlCQUFBLHlCLHdCQUFBOzs7Ozs7O3VCQUVPLElBQU0sWSx5QkFBQSxRLHdCQUFBLFlBQVksSSx5QkFBQSxtQix3QkFBbEI7QUFDUCxVQUFVLFFBQVYsR0FBcUIsVUFBVSxJQUFWLEdBQWlCLFVBQVMsS0FBVCxFQUFnQjtBQUNwRCxTQUFPLE1BQU0sS0FBTixFQUFQO0FBQ0QsQ0FGRDs7QUFJTyxTQUFTLFVBQVQsQ0FBb0IsTUFBcEIsRUFBNEIsTUFBNUIsRUFBb0MsUUFBcEMsRUFBOEM7QUFBRSxTQUFPLFVBQVUsSUFBVixDQUFlLE1BQWYsRUFBdUIsTUFBdkIsRUFBK0IsUUFBL0IsQ0FBUDtBQUFrRCIsImZpbGUiOiJhcnJheS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBEaWZmIGZyb20gJy4vYmFzZSc7XG5cbmV4cG9ydCBjb25zdCBhcnJheURpZmYgPSBuZXcgRGlmZigpO1xuYXJyYXlEaWZmLnRva2VuaXplID0gYXJyYXlEaWZmLmpvaW4gPSBmdW5jdGlvbih2YWx1ZSkge1xuICByZXR1cm4gdmFsdWUuc2xpY2UoKTtcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBkaWZmQXJyYXlzKG9sZEFyciwgbmV3QXJyLCBjYWxsYmFjaykgeyByZXR1cm4gYXJyYXlEaWZmLmRpZmYob2xkQXJyLCBuZXdBcnIsIGNhbGxiYWNrKTsgfVxuIl19 + + +/***/ }, +/* 10 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + exports. applyPatch = applyPatch; + exports. applyPatches = applyPatches; + + var _parse = __webpack_require__(11) ; + + var _distanceIterator = __webpack_require__(12) ; + + + var _distanceIterator2 = _interopRequireDefault(_distanceIterator); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + function applyPatch(source, uniDiff) { + var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; + + if (typeof uniDiff === 'string') { + uniDiff = (0, _parse.parsePatch) (uniDiff); + } + + if (Array.isArray(uniDiff)) { + if (uniDiff.length > 1) { + throw new Error('applyPatch only works with a single input.'); + } + + uniDiff = uniDiff[0]; + } + + // Apply the diff to the input + var lines = source.split(/\r\n|[\n\v\f\r\x85]/), + delimiters = source.match(/\r\n|[\n\v\f\r\x85]/g) || [], + hunks = uniDiff.hunks, + compareLine = options.compareLine || function (lineNumber, line, operation, patchContent) { + return (line === patchContent + ); + }, + errorCount = 0, + fuzzFactor = options.fuzzFactor || 0, + minLine = 0, + offset = 0, + removeEOFNL = void 0 , + addEOFNL = void 0 ; + + /** + * Checks if the hunk exactly fits on the provided location + */ + function hunkFits(hunk, toPos) { + for (var j = 0; j < hunk.lines.length; j++) { + var line = hunk.lines[j], + operation = line[0], + content = line.substr(1); + + if (operation === ' ' || operation === '-') { + // Context sanity check + if (!compareLine(toPos + 1, lines[toPos], operation, content)) { + errorCount++; + + if (errorCount > fuzzFactor) { + return false; + } + } + toPos++; + } + } + + return true; + } + + // Search best fit offsets for each hunk based on the previous ones + for (var i = 0; i < hunks.length; i++) { + var hunk = hunks[i], + maxLine = lines.length - hunk.oldLines, + localOffset = 0, + toPos = offset + hunk.oldStart - 1; + + var iterator = (0, _distanceIterator2['default']) (toPos, minLine, maxLine); + + for (; localOffset !== undefined; localOffset = iterator()) { + if (hunkFits(hunk, toPos + localOffset)) { + hunk.offset = offset += localOffset; + break; + } + } + + if (localOffset === undefined) { + return false; + } + + // Set lower text limit to end of the current hunk, so next ones don't try + // to fit over already patched text + minLine = hunk.offset + hunk.oldStart + hunk.oldLines; + } + + // Apply patch hunks + for (var _i = 0; _i < hunks.length; _i++) { + var _hunk = hunks[_i], + _toPos = _hunk.offset + _hunk.newStart - 1; + if (_hunk.newLines == 0) { + _toPos++; + } + + for (var j = 0; j < _hunk.lines.length; j++) { + var line = _hunk.lines[j], + operation = line[0], + content = line.substr(1), + delimiter = _hunk.linedelimiters[j]; + + if (operation === ' ') { + _toPos++; + } else if (operation === '-') { + lines.splice(_toPos, 1); + delimiters.splice(_toPos, 1); + /* istanbul ignore else */ + } else if (operation === '+') { + lines.splice(_toPos, 0, content); + delimiters.splice(_toPos, 0, delimiter); + _toPos++; + } else if (operation === '\\') { + var previousOperation = _hunk.lines[j - 1] ? _hunk.lines[j - 1][0] : null; + if (previousOperation === '+') { + removeEOFNL = true; + } else if (previousOperation === '-') { + addEOFNL = true; + } + } + } + } + + // Handle EOFNL insertion/removal + if (removeEOFNL) { + while (!lines[lines.length - 1]) { + lines.pop(); + delimiters.pop(); + } + } else if (addEOFNL) { + lines.push(''); + delimiters.push('\n'); + } + for (var _k = 0; _k < lines.length - 1; _k++) { + lines[_k] = lines[_k] + delimiters[_k]; + } + return lines.join(''); + } + + // Wrapper that supports multiple file patches via callbacks. + function applyPatches(uniDiff, options) { + if (typeof uniDiff === 'string') { + uniDiff = (0, _parse.parsePatch) (uniDiff); + } + + var currentIndex = 0; + function processIndex() { + var index = uniDiff[currentIndex++]; + if (!index) { + return options.complete(); + } + + options.loadFile(index, function (err, data) { + if (err) { + return options.complete(err); + } + + var updatedContent = applyPatch(data, index, options); + options.patched(index, updatedContent, function (err) { + if (err) { + return options.complete(err); + } + + processIndex(); + }); + }); + } + processIndex(); + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wYXRjaC9hcHBseS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Z0NBR2dCLFUsR0FBQSxVO3lEQStIQSxZLEdBQUEsWTs7QUFsSWhCLEkseUJBQUEsMkIsd0JBQUE7O0FBQ0EsSSx5QkFBQSx3RCx3QkFBQTs7Ozs7Ozt1QkFFTyxTQUFTLFVBQVQsQ0FBb0IsTUFBcEIsRUFBNEIsT0FBNUIsRUFBbUQ7MkJBQUEsSSx1QkFBZCxPQUFjLHlEQUFKLEVBQUk7O0FBQ3hELE1BQUksT0FBTyxPQUFQLEtBQW1CLFFBQXZCLEVBQWlDO0FBQy9CLGMseUJBQVUsc0Isd0JBQUEsQ0FBVyxPQUFYLENBQVY7QUFDRDs7QUFFRCxNQUFJLE1BQU0sT0FBTixDQUFjLE9BQWQsQ0FBSixFQUE0QjtBQUMxQixRQUFJLFFBQVEsTUFBUixHQUFpQixDQUFyQixFQUF3QjtBQUN0QixZQUFNLElBQUksS0FBSixDQUFVLDRDQUFWLENBQU47QUFDRDs7QUFFRCxjQUFVLFFBQVEsQ0FBUixDQUFWO0FBQ0Q7OztBQUdELE1BQUksUUFBUSxPQUFPLEtBQVAsQ0FBYSxxQkFBYixDQUFaO0FBQUEsTUFDSSxhQUFhLE9BQU8sS0FBUCxDQUFhLHNCQUFiLEtBQXdDLEVBRHpEO0FBQUEsTUFFSSxRQUFRLFFBQVEsS0FGcEI7QUFBQSxNQUlJLGNBQWMsUUFBUSxXQUFSLElBQXdCLFVBQUMsVUFBRCxFQUFhLElBQWIsRUFBbUIsU0FBbkIsRUFBOEIsWUFBOUIsRSx5QkFBQTtBQUFBLFcsd0JBQStDLFNBQVM7QUFBeEQ7QUFBQSxHQUoxQztBQUFBLE1BS0ksYUFBYSxDQUxqQjtBQUFBLE1BTUksYUFBYSxRQUFRLFVBQVIsSUFBc0IsQ0FOdkM7QUFBQSxNQU9JLFVBQVUsQ0FQZDtBQUFBLE1BUUksU0FBUyxDQVJiO0FBQUEsTUFVSSxjLHlCQUFBLE0sd0JBVko7QUFBQSxNQVdJLFcseUJBQUEsTSx3QkFYSjs7Ozs7QUFnQkEsV0FBUyxRQUFULENBQWtCLElBQWxCLEVBQXdCLEtBQXhCLEVBQStCO0FBQzdCLFNBQUssSUFBSSxJQUFJLENBQWIsRUFBZ0IsSUFBSSxLQUFLLEtBQUwsQ0FBVyxNQUEvQixFQUF1QyxHQUF2QyxFQUE0QztBQUMxQyxVQUFJLE9BQU8sS0FBSyxLQUFMLENBQVcsQ0FBWCxDQUFYO0FBQUEsVUFDSSxZQUFZLEtBQUssQ0FBTCxDQURoQjtBQUFBLFVBRUksVUFBVSxLQUFLLE1BQUwsQ0FBWSxDQUFaLENBRmQ7O0FBSUEsVUFBSSxjQUFjLEdBQWQsSUFBcUIsY0FBYyxHQUF2QyxFQUE0Qzs7QUFFMUMsWUFBSSxDQUFDLFlBQVksUUFBUSxDQUFwQixFQUF1QixNQUFNLEtBQU4sQ0FBdkIsRUFBcUMsU0FBckMsRUFBZ0QsT0FBaEQsQ0FBTCxFQUErRDtBQUM3RDs7QUFFQSxjQUFJLGFBQWEsVUFBakIsRUFBNkI7QUFDM0IsbUJBQU8sS0FBUDtBQUNEO0FBQ0Y7QUFDRDtBQUNEO0FBQ0Y7O0FBRUQsV0FBTyxJQUFQO0FBQ0Q7OztBQUdELE9BQUssSUFBSSxJQUFJLENBQWIsRUFBZ0IsSUFBSSxNQUFNLE1BQTFCLEVBQWtDLEdBQWxDLEVBQXVDO0FBQ3JDLFFBQUksT0FBTyxNQUFNLENBQU4sQ0FBWDtBQUFBLFFBQ0ksVUFBVSxNQUFNLE1BQU4sR0FBZSxLQUFLLFFBRGxDO0FBQUEsUUFFSSxjQUFjLENBRmxCO0FBQUEsUUFHSSxRQUFRLFNBQVMsS0FBSyxRQUFkLEdBQXlCLENBSHJDOztBQUtBLFFBQUksVyx5QkFBVyxrQyx3QkFBQSxDQUFpQixLQUFqQixFQUF3QixPQUF4QixFQUFpQyxPQUFqQyxDQUFmOztBQUVBLFdBQU8sZ0JBQWdCLFNBQXZCLEVBQWtDLGNBQWMsVUFBaEQsRUFBNEQ7QUFDMUQsVUFBSSxTQUFTLElBQVQsRUFBZSxRQUFRLFdBQXZCLENBQUosRUFBeUM7QUFDdkMsYUFBSyxNQUFMLEdBQWMsVUFBVSxXQUF4QjtBQUNBO0FBQ0Q7QUFDRjs7QUFFRCxRQUFJLGdCQUFnQixTQUFwQixFQUErQjtBQUM3QixhQUFPLEtBQVA7QUFDRDs7OztBQUlELGNBQVUsS0FBSyxNQUFMLEdBQWMsS0FBSyxRQUFuQixHQUE4QixLQUFLLFFBQTdDO0FBQ0Q7OztBQUdELE9BQUssSUFBSSxLQUFJLENBQWIsRUFBZ0IsS0FBSSxNQUFNLE1BQTFCLEVBQWtDLElBQWxDLEVBQXVDO0FBQ3JDLFFBQUksUUFBTyxNQUFNLEVBQU4sQ0FBWDtBQUFBLFFBQ0ksU0FBUSxNQUFLLE1BQUwsR0FBYyxNQUFLLFFBQW5CLEdBQThCLENBRDFDO0FBRUEsUUFBSSxNQUFLLFFBQUwsSUFBaUIsQ0FBckIsRUFBd0I7QUFBRTtBQUFVOztBQUVwQyxTQUFLLElBQUksSUFBSSxDQUFiLEVBQWdCLElBQUksTUFBSyxLQUFMLENBQVcsTUFBL0IsRUFBdUMsR0FBdkMsRUFBNEM7QUFDMUMsVUFBSSxPQUFPLE1BQUssS0FBTCxDQUFXLENBQVgsQ0FBWDtBQUFBLFVBQ0ksWUFBWSxLQUFLLENBQUwsQ0FEaEI7QUFBQSxVQUVJLFVBQVUsS0FBSyxNQUFMLENBQVksQ0FBWixDQUZkO0FBQUEsVUFHSSxZQUFZLE1BQUssY0FBTCxDQUFvQixDQUFwQixDQUhoQjs7QUFLQSxVQUFJLGNBQWMsR0FBbEIsRUFBdUI7QUFDckI7QUFDRCxPQUZELE1BRU8sSUFBSSxjQUFjLEdBQWxCLEVBQXVCO0FBQzVCLGNBQU0sTUFBTixDQUFhLE1BQWIsRUFBb0IsQ0FBcEI7QUFDQSxtQkFBVyxNQUFYLENBQWtCLE1BQWxCLEVBQXlCLENBQXpCOztBQUVELE9BSk0sTUFJQSxJQUFJLGNBQWMsR0FBbEIsRUFBdUI7QUFDNUIsZ0JBQU0sTUFBTixDQUFhLE1BQWIsRUFBb0IsQ0FBcEIsRUFBdUIsT0FBdkI7QUFDQSxxQkFBVyxNQUFYLENBQWtCLE1BQWxCLEVBQXlCLENBQXpCLEVBQTRCLFNBQTVCO0FBQ0E7QUFDRCxTQUpNLE1BSUEsSUFBSSxjQUFjLElBQWxCLEVBQXdCO0FBQzdCLGNBQUksb0JBQW9CLE1BQUssS0FBTCxDQUFXLElBQUksQ0FBZixJQUFvQixNQUFLLEtBQUwsQ0FBVyxJQUFJLENBQWYsRUFBa0IsQ0FBbEIsQ0FBcEIsR0FBMkMsSUFBbkU7QUFDQSxjQUFJLHNCQUFzQixHQUExQixFQUErQjtBQUM3QiwwQkFBYyxJQUFkO0FBQ0QsV0FGRCxNQUVPLElBQUksc0JBQXNCLEdBQTFCLEVBQStCO0FBQ3BDLHVCQUFXLElBQVg7QUFDRDtBQUNGO0FBQ0Y7QUFDRjs7O0FBR0QsTUFBSSxXQUFKLEVBQWlCO0FBQ2YsV0FBTyxDQUFDLE1BQU0sTUFBTSxNQUFOLEdBQWUsQ0FBckIsQ0FBUixFQUFpQztBQUMvQixZQUFNLEdBQU47QUFDQSxpQkFBVyxHQUFYO0FBQ0Q7QUFDRixHQUxELE1BS08sSUFBSSxRQUFKLEVBQWM7QUFDbkIsVUFBTSxJQUFOLENBQVcsRUFBWDtBQUNBLGVBQVcsSUFBWCxDQUFnQixJQUFoQjtBQUNEO0FBQ0QsT0FBSyxJQUFJLEtBQUssQ0FBZCxFQUFpQixLQUFLLE1BQU0sTUFBTixHQUFlLENBQXJDLEVBQXdDLElBQXhDLEVBQThDO0FBQzVDLFVBQU0sRUFBTixJQUFZLE1BQU0sRUFBTixJQUFZLFdBQVcsRUFBWCxDQUF4QjtBQUNEO0FBQ0QsU0FBTyxNQUFNLElBQU4sQ0FBVyxFQUFYLENBQVA7QUFDRDs7O0FBR00sU0FBUyxZQUFULENBQXNCLE9BQXRCLEVBQStCLE9BQS9CLEVBQXdDO0FBQzdDLE1BQUksT0FBTyxPQUFQLEtBQW1CLFFBQXZCLEVBQWlDO0FBQy9CLGMseUJBQVUsc0Isd0JBQUEsQ0FBVyxPQUFYLENBQVY7QUFDRDs7QUFFRCxNQUFJLGVBQWUsQ0FBbkI7QUFDQSxXQUFTLFlBQVQsR0FBd0I7QUFDdEIsUUFBSSxRQUFRLFFBQVEsY0FBUixDQUFaO0FBQ0EsUUFBSSxDQUFDLEtBQUwsRUFBWTtBQUNWLGFBQU8sUUFBUSxRQUFSLEVBQVA7QUFDRDs7QUFFRCxZQUFRLFFBQVIsQ0FBaUIsS0FBakIsRUFBd0IsVUFBUyxHQUFULEVBQWMsSUFBZCxFQUFvQjtBQUMxQyxVQUFJLEdBQUosRUFBUztBQUNQLGVBQU8sUUFBUSxRQUFSLENBQWlCLEdBQWpCLENBQVA7QUFDRDs7QUFFRCxVQUFJLGlCQUFpQixXQUFXLElBQVgsRUFBaUIsS0FBakIsRUFBd0IsT0FBeEIsQ0FBckI7QUFDQSxjQUFRLE9BQVIsQ0FBZ0IsS0FBaEIsRUFBdUIsY0FBdkIsRUFBdUMsVUFBUyxHQUFULEVBQWM7QUFDbkQsWUFBSSxHQUFKLEVBQVM7QUFDUCxpQkFBTyxRQUFRLFFBQVIsQ0FBaUIsR0FBakIsQ0FBUDtBQUNEOztBQUVEO0FBQ0QsT0FORDtBQU9ELEtBYkQ7QUFjRDtBQUNEO0FBQ0QiLCJmaWxlIjoiYXBwbHkuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge3BhcnNlUGF0Y2h9IGZyb20gJy4vcGFyc2UnO1xuaW1wb3J0IGRpc3RhbmNlSXRlcmF0b3IgZnJvbSAnLi4vdXRpbC9kaXN0YW5jZS1pdGVyYXRvcic7XG5cbmV4cG9ydCBmdW5jdGlvbiBhcHBseVBhdGNoKHNvdXJjZSwgdW5pRGlmZiwgb3B0aW9ucyA9IHt9KSB7XG4gIGlmICh0eXBlb2YgdW5pRGlmZiA9PT0gJ3N0cmluZycpIHtcbiAgICB1bmlEaWZmID0gcGFyc2VQYXRjaCh1bmlEaWZmKTtcbiAgfVxuXG4gIGlmIChBcnJheS5pc0FycmF5KHVuaURpZmYpKSB7XG4gICAgaWYgKHVuaURpZmYubGVuZ3RoID4gMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdhcHBseVBhdGNoIG9ubHkgd29ya3Mgd2l0aCBhIHNpbmdsZSBpbnB1dC4nKTtcbiAgICB9XG5cbiAgICB1bmlEaWZmID0gdW5pRGlmZlswXTtcbiAgfVxuXG4gIC8vIEFwcGx5IHRoZSBkaWZmIHRvIHRoZSBpbnB1dFxuICBsZXQgbGluZXMgPSBzb3VyY2Uuc3BsaXQoL1xcclxcbnxbXFxuXFx2XFxmXFxyXFx4ODVdLyksXG4gICAgICBkZWxpbWl0ZXJzID0gc291cmNlLm1hdGNoKC9cXHJcXG58W1xcblxcdlxcZlxcclxceDg1XS9nKSB8fCBbXSxcbiAgICAgIGh1bmtzID0gdW5pRGlmZi5odW5rcyxcblxuICAgICAgY29tcGFyZUxpbmUgPSBvcHRpb25zLmNvbXBhcmVMaW5lIHx8ICgobGluZU51bWJlciwgbGluZSwgb3BlcmF0aW9uLCBwYXRjaENvbnRlbnQpID0+IGxpbmUgPT09IHBhdGNoQ29udGVudCksXG4gICAgICBlcnJvckNvdW50ID0gMCxcbiAgICAgIGZ1enpGYWN0b3IgPSBvcHRpb25zLmZ1enpGYWN0b3IgfHwgMCxcbiAgICAgIG1pbkxpbmUgPSAwLFxuICAgICAgb2Zmc2V0ID0gMCxcblxuICAgICAgcmVtb3ZlRU9GTkwsXG4gICAgICBhZGRFT0ZOTDtcblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBodW5rIGV4YWN0bHkgZml0cyBvbiB0aGUgcHJvdmlkZWQgbG9jYXRpb25cbiAgICovXG4gIGZ1bmN0aW9uIGh1bmtGaXRzKGh1bmssIHRvUG9zKSB7XG4gICAgZm9yIChsZXQgaiA9IDA7IGogPCBodW5rLmxpbmVzLmxlbmd0aDsgaisrKSB7XG4gICAgICBsZXQgbGluZSA9IGh1bmsubGluZXNbal0sXG4gICAgICAgICAgb3BlcmF0aW9uID0gbGluZVswXSxcbiAgICAgICAgICBjb250ZW50ID0gbGluZS5zdWJzdHIoMSk7XG5cbiAgICAgIGlmIChvcGVyYXRpb24gPT09ICcgJyB8fCBvcGVyYXRpb24gPT09ICctJykge1xuICAgICAgICAvLyBDb250ZXh0IHNhbml0eSBjaGVja1xuICAgICAgICBpZiAoIWNvbXBhcmVMaW5lKHRvUG9zICsgMSwgbGluZXNbdG9Qb3NdLCBvcGVyYXRpb24sIGNvbnRlbnQpKSB7XG4gICAgICAgICAgZXJyb3JDb3VudCsrO1xuXG4gICAgICAgICAgaWYgKGVycm9yQ291bnQgPiBmdXp6RmFjdG9yKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRvUG9zKys7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvLyBTZWFyY2ggYmVzdCBmaXQgb2Zmc2V0cyBmb3IgZWFjaCBodW5rIGJhc2VkIG9uIHRoZSBwcmV2aW91cyBvbmVzXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgaHVua3MubGVuZ3RoOyBpKyspIHtcbiAgICBsZXQgaHVuayA9IGh1bmtzW2ldLFxuICAgICAgICBtYXhMaW5lID0gbGluZXMubGVuZ3RoIC0gaHVuay5vbGRMaW5lcyxcbiAgICAgICAgbG9jYWxPZmZzZXQgPSAwLFxuICAgICAgICB0b1BvcyA9IG9mZnNldCArIGh1bmsub2xkU3RhcnQgLSAxO1xuXG4gICAgbGV0IGl0ZXJhdG9yID0gZGlzdGFuY2VJdGVyYXRvcih0b1BvcywgbWluTGluZSwgbWF4TGluZSk7XG5cbiAgICBmb3IgKDsgbG9jYWxPZmZzZXQgIT09IHVuZGVmaW5lZDsgbG9jYWxPZmZzZXQgPSBpdGVyYXRvcigpKSB7XG4gICAgICBpZiAoaHVua0ZpdHMoaHVuaywgdG9Qb3MgKyBsb2NhbE9mZnNldCkpIHtcbiAgICAgICAgaHVuay5vZmZzZXQgPSBvZmZzZXQgKz0gbG9jYWxPZmZzZXQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChsb2NhbE9mZnNldCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gU2V0IGxvd2VyIHRleHQgbGltaXQgdG8gZW5kIG9mIHRoZSBjdXJyZW50IGh1bmssIHNvIG5leHQgb25lcyBkb24ndCB0cnlcbiAgICAvLyB0byBmaXQgb3ZlciBhbHJlYWR5IHBhdGNoZWQgdGV4dFxuICAgIG1pbkxpbmUgPSBodW5rLm9mZnNldCArIGh1bmsub2xkU3RhcnQgKyBodW5rLm9sZExpbmVzO1xuICB9XG5cbiAgLy8gQXBwbHkgcGF0Y2ggaHVua3NcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBodW5rcy5sZW5ndGg7IGkrKykge1xuICAgIGxldCBodW5rID0gaHVua3NbaV0sXG4gICAgICAgIHRvUG9zID0gaHVuay5vZmZzZXQgKyBodW5rLm5ld1N0YXJ0IC0gMTtcbiAgICBpZiAoaHVuay5uZXdMaW5lcyA9PSAwKSB7IHRvUG9zKys7IH1cblxuICAgIGZvciAobGV0IGogPSAwOyBqIDwgaHVuay5saW5lcy5sZW5ndGg7IGorKykge1xuICAgICAgbGV0IGxpbmUgPSBodW5rLmxpbmVzW2pdLFxuICAgICAgICAgIG9wZXJhdGlvbiA9IGxpbmVbMF0sXG4gICAgICAgICAgY29udGVudCA9IGxpbmUuc3Vic3RyKDEpLFxuICAgICAgICAgIGRlbGltaXRlciA9IGh1bmsubGluZWRlbGltaXRlcnNbal07XG5cbiAgICAgIGlmIChvcGVyYXRpb24gPT09ICcgJykge1xuICAgICAgICB0b1BvcysrO1xuICAgICAgfSBlbHNlIGlmIChvcGVyYXRpb24gPT09ICctJykge1xuICAgICAgICBsaW5lcy5zcGxpY2UodG9Qb3MsIDEpO1xuICAgICAgICBkZWxpbWl0ZXJzLnNwbGljZSh0b1BvcywgMSk7XG4gICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgZWxzZSAqL1xuICAgICAgfSBlbHNlIGlmIChvcGVyYXRpb24gPT09ICcrJykge1xuICAgICAgICBsaW5lcy5zcGxpY2UodG9Qb3MsIDAsIGNvbnRlbnQpO1xuICAgICAgICBkZWxpbWl0ZXJzLnNwbGljZSh0b1BvcywgMCwgZGVsaW1pdGVyKTtcbiAgICAgICAgdG9Qb3MrKztcbiAgICAgIH0gZWxzZSBpZiAob3BlcmF0aW9uID09PSAnXFxcXCcpIHtcbiAgICAgICAgbGV0IHByZXZpb3VzT3BlcmF0aW9uID0gaHVuay5saW5lc1tqIC0gMV0gPyBodW5rLmxpbmVzW2ogLSAxXVswXSA6IG51bGw7XG4gICAgICAgIGlmIChwcmV2aW91c09wZXJhdGlvbiA9PT0gJysnKSB7XG4gICAgICAgICAgcmVtb3ZlRU9GTkwgPSB0cnVlO1xuICAgICAgICB9IGVsc2UgaWYgKHByZXZpb3VzT3BlcmF0aW9uID09PSAnLScpIHtcbiAgICAgICAgICBhZGRFT0ZOTCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBIYW5kbGUgRU9GTkwgaW5zZXJ0aW9uL3JlbW92YWxcbiAgaWYgKHJlbW92ZUVPRk5MKSB7XG4gICAgd2hpbGUgKCFsaW5lc1tsaW5lcy5sZW5ndGggLSAxXSkge1xuICAgICAgbGluZXMucG9wKCk7XG4gICAgICBkZWxpbWl0ZXJzLnBvcCgpO1xuICAgIH1cbiAgfSBlbHNlIGlmIChhZGRFT0ZOTCkge1xuICAgIGxpbmVzLnB1c2goJycpO1xuICAgIGRlbGltaXRlcnMucHVzaCgnXFxuJyk7XG4gIH1cbiAgZm9yIChsZXQgX2sgPSAwOyBfayA8IGxpbmVzLmxlbmd0aCAtIDE7IF9rKyspIHtcbiAgICBsaW5lc1tfa10gPSBsaW5lc1tfa10gKyBkZWxpbWl0ZXJzW19rXTtcbiAgfVxuICByZXR1cm4gbGluZXMuam9pbignJyk7XG59XG5cbi8vIFdyYXBwZXIgdGhhdCBzdXBwb3J0cyBtdWx0aXBsZSBmaWxlIHBhdGNoZXMgdmlhIGNhbGxiYWNrcy5cbmV4cG9ydCBmdW5jdGlvbiBhcHBseVBhdGNoZXModW5pRGlmZiwgb3B0aW9ucykge1xuICBpZiAodHlwZW9mIHVuaURpZmYgPT09ICdzdHJpbmcnKSB7XG4gICAgdW5pRGlmZiA9IHBhcnNlUGF0Y2godW5pRGlmZik7XG4gIH1cblxuICBsZXQgY3VycmVudEluZGV4ID0gMDtcbiAgZnVuY3Rpb24gcHJvY2Vzc0luZGV4KCkge1xuICAgIGxldCBpbmRleCA9IHVuaURpZmZbY3VycmVudEluZGV4KytdO1xuICAgIGlmICghaW5kZXgpIHtcbiAgICAgIHJldHVybiBvcHRpb25zLmNvbXBsZXRlKCk7XG4gICAgfVxuXG4gICAgb3B0aW9ucy5sb2FkRmlsZShpbmRleCwgZnVuY3Rpb24oZXJyLCBkYXRhKSB7XG4gICAgICBpZiAoZXJyKSB7XG4gICAgICAgIHJldHVybiBvcHRpb25zLmNvbXBsZXRlKGVycik7XG4gICAgICB9XG5cbiAgICAgIGxldCB1cGRhdGVkQ29udGVudCA9IGFwcGx5UGF0Y2goZGF0YSwgaW5kZXgsIG9wdGlvbnMpO1xuICAgICAgb3B0aW9ucy5wYXRjaGVkKGluZGV4LCB1cGRhdGVkQ29udGVudCwgZnVuY3Rpb24oZXJyKSB7XG4gICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICByZXR1cm4gb3B0aW9ucy5jb21wbGV0ZShlcnIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcHJvY2Vzc0luZGV4KCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBwcm9jZXNzSW5kZXgoKTtcbn1cbiJdfQ== + + +/***/ }, +/* 11 */ +/***/ function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + exports. parsePatch = parsePatch; + function parsePatch(uniDiff) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + var diffstr = uniDiff.split(/\r\n|[\n\v\f\r\x85]/), + delimiters = uniDiff.match(/\r\n|[\n\v\f\r\x85]/g) || [], + list = [], + i = 0; + + function parseIndex() { + var index = {}; + list.push(index); + + // Parse diff metadata + while (i < diffstr.length) { + var line = diffstr[i]; + + // File header found, end parsing diff metadata + if (/^(\-\-\-|\+\+\+|@@)\s/.test(line)) { + break; + } + + // Diff index + var header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line); + if (header) { + index.index = header[1]; + } + + i++; + } + + // Parse file headers if they are defined. Unified diff requires them, but + // there's no technical issues to have an isolated hunk without file header + parseFileHeader(index); + parseFileHeader(index); + + // Parse hunks + index.hunks = []; + + while (i < diffstr.length) { + var _line = diffstr[i]; + + if (/^(Index:|diff|\-\-\-|\+\+\+)\s/.test(_line)) { + break; + } else if (/^@@/.test(_line)) { + index.hunks.push(parseHunk()); + } else if (_line && options.strict) { + // Ignore unexpected content unless in strict mode + throw new Error('Unknown line ' + (i + 1) + ' ' + JSON.stringify(_line)); + } else { + i++; + } + } + } + + // Parses the --- and +++ headers, if none are found, no lines + // are consumed. + function parseFileHeader(index) { + var headerPattern = /^(---|\+\+\+)\s+([\S ]*)(?:\t(.*?)\s*)?$/; + var fileHeader = headerPattern.exec(diffstr[i]); + if (fileHeader) { + var keyPrefix = fileHeader[1] === '---' ? 'old' : 'new'; + index[keyPrefix + 'FileName'] = fileHeader[2]; + index[keyPrefix + 'Header'] = fileHeader[3]; + + i++; + } + } + + // Parses a hunk + // This assumes that we are at the start of a hunk. + function parseHunk() { + var chunkHeaderIndex = i, + chunkHeaderLine = diffstr[i++], + chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/); + + var hunk = { + oldStart: +chunkHeader[1], + oldLines: +chunkHeader[2] || 1, + newStart: +chunkHeader[3], + newLines: +chunkHeader[4] || 1, + lines: [], + linedelimiters: [] + }; + + var addCount = 0, + removeCount = 0; + for (; i < diffstr.length; i++) { + // Lines starting with '---' could be mistaken for the "remove line" operation + // But they could be the header for the next file. Therefore prune such cases out. + if (diffstr[i].indexOf('--- ') === 0 && i + 2 < diffstr.length && diffstr[i + 1].indexOf('+++ ') === 0 && diffstr[i + 2].indexOf('@@') === 0) { + break; + } + var operation = diffstr[i][0]; + + if (operation === '+' || operation === '-' || operation === ' ' || operation === '\\') { + hunk.lines.push(diffstr[i]); + hunk.linedelimiters.push(delimiters[i] || '\n'); + + if (operation === '+') { + addCount++; + } else if (operation === '-') { + removeCount++; + } else if (operation === ' ') { + addCount++; + removeCount++; + } + } else { + break; + } + } + + // Handle the empty block count case + if (!addCount && hunk.newLines === 1) { + hunk.newLines = 0; + } + if (!removeCount && hunk.oldLines === 1) { + hunk.oldLines = 0; + } + + // Perform optional sanity checking + if (options.strict) { + if (addCount !== hunk.newLines) { + throw new Error('Added line count did not match for hunk at line ' + (chunkHeaderIndex + 1)); + } + if (removeCount !== hunk.oldLines) { + throw new Error('Removed line count did not match for hunk at line ' + (chunkHeaderIndex + 1)); + } + } + + return hunk; + } + + while (i < diffstr.length) { + parseIndex(); + } + + return list; + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wYXRjaC9wYXJzZS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Z0NBQWdCLFUsR0FBQSxVO0FBQVQsU0FBUyxVQUFULENBQW9CLE9BQXBCLEVBQTJDOzJCQUFBLEksdUJBQWQsT0FBYyx5REFBSixFQUFJOztBQUNoRCxNQUFJLFVBQVUsUUFBUSxLQUFSLENBQWMscUJBQWQsQ0FBZDtBQUFBLE1BQ0ksYUFBYSxRQUFRLEtBQVIsQ0FBYyxzQkFBZCxLQUF5QyxFQUQxRDtBQUFBLE1BRUksT0FBTyxFQUZYO0FBQUEsTUFHSSxJQUFJLENBSFI7O0FBS0EsV0FBUyxVQUFULEdBQXNCO0FBQ3BCLFFBQUksUUFBUSxFQUFaO0FBQ0EsU0FBSyxJQUFMLENBQVUsS0FBVjs7O0FBR0EsV0FBTyxJQUFJLFFBQVEsTUFBbkIsRUFBMkI7QUFDekIsVUFBSSxPQUFPLFFBQVEsQ0FBUixDQUFYOzs7QUFHQSxVQUFJLHdCQUF3QixJQUF4QixDQUE2QixJQUE3QixDQUFKLEVBQXdDO0FBQ3RDO0FBQ0Q7OztBQUdELFVBQUksU0FBVSwwQ0FBRCxDQUE2QyxJQUE3QyxDQUFrRCxJQUFsRCxDQUFiO0FBQ0EsVUFBSSxNQUFKLEVBQVk7QUFDVixjQUFNLEtBQU4sR0FBYyxPQUFPLENBQVAsQ0FBZDtBQUNEOztBQUVEO0FBQ0Q7Ozs7QUFJRCxvQkFBZ0IsS0FBaEI7QUFDQSxvQkFBZ0IsS0FBaEI7OztBQUdBLFVBQU0sS0FBTixHQUFjLEVBQWQ7O0FBRUEsV0FBTyxJQUFJLFFBQVEsTUFBbkIsRUFBMkI7QUFDekIsVUFBSSxRQUFPLFFBQVEsQ0FBUixDQUFYOztBQUVBLFVBQUksaUNBQWlDLElBQWpDLENBQXNDLEtBQXRDLENBQUosRUFBaUQ7QUFDL0M7QUFDRCxPQUZELE1BRU8sSUFBSSxNQUFNLElBQU4sQ0FBVyxLQUFYLENBQUosRUFBc0I7QUFDM0IsY0FBTSxLQUFOLENBQVksSUFBWixDQUFpQixXQUFqQjtBQUNELE9BRk0sTUFFQSxJQUFJLFNBQVEsUUFBUSxNQUFwQixFQUE0Qjs7QUFFakMsY0FBTSxJQUFJLEtBQUosQ0FBVSxtQkFBbUIsSUFBSSxDQUF2QixJQUE0QixHQUE1QixHQUFrQyxLQUFLLFNBQUwsQ0FBZSxLQUFmLENBQTVDLENBQU47QUFDRCxPQUhNLE1BR0E7QUFDTDtBQUNEO0FBQ0Y7QUFDRjs7OztBQUlELFdBQVMsZUFBVCxDQUF5QixLQUF6QixFQUFnQztBQUM5QixRQUFNLGdCQUFnQiwwQ0FBdEI7QUFDQSxRQUFNLGFBQWEsY0FBYyxJQUFkLENBQW1CLFFBQVEsQ0FBUixDQUFuQixDQUFuQjtBQUNBLFFBQUksVUFBSixFQUFnQjtBQUNkLFVBQUksWUFBWSxXQUFXLENBQVgsTUFBa0IsS0FBbEIsR0FBMEIsS0FBMUIsR0FBa0MsS0FBbEQ7QUFDQSxZQUFNLFlBQVksVUFBbEIsSUFBZ0MsV0FBVyxDQUFYLENBQWhDO0FBQ0EsWUFBTSxZQUFZLFFBQWxCLElBQThCLFdBQVcsQ0FBWCxDQUE5Qjs7QUFFQTtBQUNEO0FBQ0Y7Ozs7QUFJRCxXQUFTLFNBQVQsR0FBcUI7QUFDbkIsUUFBSSxtQkFBbUIsQ0FBdkI7QUFBQSxRQUNJLGtCQUFrQixRQUFRLEdBQVIsQ0FEdEI7QUFBQSxRQUVJLGNBQWMsZ0JBQWdCLEtBQWhCLENBQXNCLDRDQUF0QixDQUZsQjs7QUFJQSxRQUFJLE9BQU87QUFDVCxnQkFBVSxDQUFDLFlBQVksQ0FBWixDQURGO0FBRVQsZ0JBQVUsQ0FBQyxZQUFZLENBQVosQ0FBRCxJQUFtQixDQUZwQjtBQUdULGdCQUFVLENBQUMsWUFBWSxDQUFaLENBSEY7QUFJVCxnQkFBVSxDQUFDLFlBQVksQ0FBWixDQUFELElBQW1CLENBSnBCO0FBS1QsYUFBTyxFQUxFO0FBTVQsc0JBQWdCO0FBTlAsS0FBWDs7QUFTQSxRQUFJLFdBQVcsQ0FBZjtBQUFBLFFBQ0ksY0FBYyxDQURsQjtBQUVBLFdBQU8sSUFBSSxRQUFRLE1BQW5CLEVBQTJCLEdBQTNCLEVBQWdDOzs7QUFHOUIsVUFBSSxRQUFRLENBQVIsRUFBVyxPQUFYLENBQW1CLE1BQW5CLE1BQStCLENBQS9CLElBQ00sSUFBSSxDQUFKLEdBQVEsUUFBUSxNQUR0QixJQUVLLFFBQVEsSUFBSSxDQUFaLEVBQWUsT0FBZixDQUF1QixNQUF2QixNQUFtQyxDQUZ4QyxJQUdLLFFBQVEsSUFBSSxDQUFaLEVBQWUsT0FBZixDQUF1QixJQUF2QixNQUFpQyxDQUgxQyxFQUc2QztBQUN6QztBQUNIO0FBQ0QsVUFBSSxZQUFZLFFBQVEsQ0FBUixFQUFXLENBQVgsQ0FBaEI7O0FBRUEsVUFBSSxjQUFjLEdBQWQsSUFBcUIsY0FBYyxHQUFuQyxJQUEwQyxjQUFjLEdBQXhELElBQStELGNBQWMsSUFBakYsRUFBdUY7QUFDckYsYUFBSyxLQUFMLENBQVcsSUFBWCxDQUFnQixRQUFRLENBQVIsQ0FBaEI7QUFDQSxhQUFLLGNBQUwsQ0FBb0IsSUFBcEIsQ0FBeUIsV0FBVyxDQUFYLEtBQWlCLElBQTFDOztBQUVBLFlBQUksY0FBYyxHQUFsQixFQUF1QjtBQUNyQjtBQUNELFNBRkQsTUFFTyxJQUFJLGNBQWMsR0FBbEIsRUFBdUI7QUFDNUI7QUFDRCxTQUZNLE1BRUEsSUFBSSxjQUFjLEdBQWxCLEVBQXVCO0FBQzVCO0FBQ0E7QUFDRDtBQUNGLE9BWkQsTUFZTztBQUNMO0FBQ0Q7QUFDRjs7O0FBR0QsUUFBSSxDQUFDLFFBQUQsSUFBYSxLQUFLLFFBQUwsS0FBa0IsQ0FBbkMsRUFBc0M7QUFDcEMsV0FBSyxRQUFMLEdBQWdCLENBQWhCO0FBQ0Q7QUFDRCxRQUFJLENBQUMsV0FBRCxJQUFnQixLQUFLLFFBQUwsS0FBa0IsQ0FBdEMsRUFBeUM7QUFDdkMsV0FBSyxRQUFMLEdBQWdCLENBQWhCO0FBQ0Q7OztBQUdELFFBQUksUUFBUSxNQUFaLEVBQW9CO0FBQ2xCLFVBQUksYUFBYSxLQUFLLFFBQXRCLEVBQWdDO0FBQzlCLGNBQU0sSUFBSSxLQUFKLENBQVUsc0RBQXNELG1CQUFtQixDQUF6RSxDQUFWLENBQU47QUFDRDtBQUNELFVBQUksZ0JBQWdCLEtBQUssUUFBekIsRUFBbUM7QUFDakMsY0FBTSxJQUFJLEtBQUosQ0FBVSx3REFBd0QsbUJBQW1CLENBQTNFLENBQVYsQ0FBTjtBQUNEO0FBQ0Y7O0FBRUQsV0FBTyxJQUFQO0FBQ0Q7O0FBRUQsU0FBTyxJQUFJLFFBQVEsTUFBbkIsRUFBMkI7QUFDekI7QUFDRDs7QUFFRCxTQUFPLElBQVA7QUFDRCIsImZpbGUiOiJwYXJzZS5qcyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBmdW5jdGlvbiBwYXJzZVBhdGNoKHVuaURpZmYsIG9wdGlvbnMgPSB7fSkge1xuICBsZXQgZGlmZnN0ciA9IHVuaURpZmYuc3BsaXQoL1xcclxcbnxbXFxuXFx2XFxmXFxyXFx4ODVdLyksXG4gICAgICBkZWxpbWl0ZXJzID0gdW5pRGlmZi5tYXRjaCgvXFxyXFxufFtcXG5cXHZcXGZcXHJcXHg4NV0vZykgfHwgW10sXG4gICAgICBsaXN0ID0gW10sXG4gICAgICBpID0gMDtcblxuICBmdW5jdGlvbiBwYXJzZUluZGV4KCkge1xuICAgIGxldCBpbmRleCA9IHt9O1xuICAgIGxpc3QucHVzaChpbmRleCk7XG5cbiAgICAvLyBQYXJzZSBkaWZmIG1ldGFkYXRhXG4gICAgd2hpbGUgKGkgPCBkaWZmc3RyLmxlbmd0aCkge1xuICAgICAgbGV0IGxpbmUgPSBkaWZmc3RyW2ldO1xuXG4gICAgICAvLyBGaWxlIGhlYWRlciBmb3VuZCwgZW5kIHBhcnNpbmcgZGlmZiBtZXRhZGF0YVxuICAgICAgaWYgKC9eKFxcLVxcLVxcLXxcXCtcXCtcXCt8QEApXFxzLy50ZXN0KGxpbmUpKSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICAvLyBEaWZmIGluZGV4XG4gICAgICBsZXQgaGVhZGVyID0gKC9eKD86SW5kZXg6fGRpZmYoPzogLXIgXFx3KykrKVxccysoLis/KVxccyokLykuZXhlYyhsaW5lKTtcbiAgICAgIGlmIChoZWFkZXIpIHtcbiAgICAgICAgaW5kZXguaW5kZXggPSBoZWFkZXJbMV07XG4gICAgICB9XG5cbiAgICAgIGkrKztcbiAgICB9XG5cbiAgICAvLyBQYXJzZSBmaWxlIGhlYWRlcnMgaWYgdGhleSBhcmUgZGVmaW5lZC4gVW5pZmllZCBkaWZmIHJlcXVpcmVzIHRoZW0sIGJ1dFxuICAgIC8vIHRoZXJlJ3Mgbm8gdGVjaG5pY2FsIGlzc3VlcyB0byBoYXZlIGFuIGlzb2xhdGVkIGh1bmsgd2l0aG91dCBmaWxlIGhlYWRlclxuICAgIHBhcnNlRmlsZUhlYWRlcihpbmRleCk7XG4gICAgcGFyc2VGaWxlSGVhZGVyKGluZGV4KTtcblxuICAgIC8vIFBhcnNlIGh1bmtzXG4gICAgaW5kZXguaHVua3MgPSBbXTtcblxuICAgIHdoaWxlIChpIDwgZGlmZnN0ci5sZW5ndGgpIHtcbiAgICAgIGxldCBsaW5lID0gZGlmZnN0cltpXTtcblxuICAgICAgaWYgKC9eKEluZGV4OnxkaWZmfFxcLVxcLVxcLXxcXCtcXCtcXCspXFxzLy50ZXN0KGxpbmUpKSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfSBlbHNlIGlmICgvXkBALy50ZXN0KGxpbmUpKSB7XG4gICAgICAgIGluZGV4Lmh1bmtzLnB1c2gocGFyc2VIdW5rKCkpO1xuICAgICAgfSBlbHNlIGlmIChsaW5lICYmIG9wdGlvbnMuc3RyaWN0KSB7XG4gICAgICAgIC8vIElnbm9yZSB1bmV4cGVjdGVkIGNvbnRlbnQgdW5sZXNzIGluIHN0cmljdCBtb2RlXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVW5rbm93biBsaW5lICcgKyAoaSArIDEpICsgJyAnICsgSlNPTi5zdHJpbmdpZnkobGluZSkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaSsrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIFBhcnNlcyB0aGUgLS0tIGFuZCArKysgaGVhZGVycywgaWYgbm9uZSBhcmUgZm91bmQsIG5vIGxpbmVzXG4gIC8vIGFyZSBjb25zdW1lZC5cbiAgZnVuY3Rpb24gcGFyc2VGaWxlSGVhZGVyKGluZGV4KSB7XG4gICAgY29uc3QgaGVhZGVyUGF0dGVybiA9IC9eKC0tLXxcXCtcXCtcXCspXFxzKyhbXFxTIF0qKSg/OlxcdCguKj8pXFxzKik/JC87XG4gICAgY29uc3QgZmlsZUhlYWRlciA9IGhlYWRlclBhdHRlcm4uZXhlYyhkaWZmc3RyW2ldKTtcbiAgICBpZiAoZmlsZUhlYWRlcikge1xuICAgICAgbGV0IGtleVByZWZpeCA9IGZpbGVIZWFkZXJbMV0gPT09ICctLS0nID8gJ29sZCcgOiAnbmV3JztcbiAgICAgIGluZGV4W2tleVByZWZpeCArICdGaWxlTmFtZSddID0gZmlsZUhlYWRlclsyXTtcbiAgICAgIGluZGV4W2tleVByZWZpeCArICdIZWFkZXInXSA9IGZpbGVIZWFkZXJbM107XG5cbiAgICAgIGkrKztcbiAgICB9XG4gIH1cblxuICAvLyBQYXJzZXMgYSBodW5rXG4gIC8vIFRoaXMgYXNzdW1lcyB0aGF0IHdlIGFyZSBhdCB0aGUgc3RhcnQgb2YgYSBodW5rLlxuICBmdW5jdGlvbiBwYXJzZUh1bmsoKSB7XG4gICAgbGV0IGNodW5rSGVhZGVySW5kZXggPSBpLFxuICAgICAgICBjaHVua0hlYWRlckxpbmUgPSBkaWZmc3RyW2krK10sXG4gICAgICAgIGNodW5rSGVhZGVyID0gY2h1bmtIZWFkZXJMaW5lLnNwbGl0KC9AQCAtKFxcZCspKD86LChcXGQrKSk/IFxcKyhcXGQrKSg/OiwoXFxkKykpPyBAQC8pO1xuXG4gICAgbGV0IGh1bmsgPSB7XG4gICAgICBvbGRTdGFydDogK2NodW5rSGVhZGVyWzFdLFxuICAgICAgb2xkTGluZXM6ICtjaHVua0hlYWRlclsyXSB8fCAxLFxuICAgICAgbmV3U3RhcnQ6ICtjaHVua0hlYWRlclszXSxcbiAgICAgIG5ld0xpbmVzOiArY2h1bmtIZWFkZXJbNF0gfHwgMSxcbiAgICAgIGxpbmVzOiBbXSxcbiAgICAgIGxpbmVkZWxpbWl0ZXJzOiBbXVxuICAgIH07XG5cbiAgICBsZXQgYWRkQ291bnQgPSAwLFxuICAgICAgICByZW1vdmVDb3VudCA9IDA7XG4gICAgZm9yICg7IGkgPCBkaWZmc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAvLyBMaW5lcyBzdGFydGluZyB3aXRoICctLS0nIGNvdWxkIGJlIG1pc3Rha2VuIGZvciB0aGUgXCJyZW1vdmUgbGluZVwiIG9wZXJhdGlvblxuICAgICAgLy8gQnV0IHRoZXkgY291bGQgYmUgdGhlIGhlYWRlciBmb3IgdGhlIG5leHQgZmlsZS4gVGhlcmVmb3JlIHBydW5lIHN1Y2ggY2FzZXMgb3V0LlxuICAgICAgaWYgKGRpZmZzdHJbaV0uaW5kZXhPZignLS0tICcpID09PSAwXG4gICAgICAgICAgICAmJiAoaSArIDIgPCBkaWZmc3RyLmxlbmd0aClcbiAgICAgICAgICAgICYmIGRpZmZzdHJbaSArIDFdLmluZGV4T2YoJysrKyAnKSA9PT0gMFxuICAgICAgICAgICAgJiYgZGlmZnN0cltpICsgMl0uaW5kZXhPZignQEAnKSA9PT0gMCkge1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgbGV0IG9wZXJhdGlvbiA9IGRpZmZzdHJbaV1bMF07XG5cbiAgICAgIGlmIChvcGVyYXRpb24gPT09ICcrJyB8fCBvcGVyYXRpb24gPT09ICctJyB8fCBvcGVyYXRpb24gPT09ICcgJyB8fCBvcGVyYXRpb24gPT09ICdcXFxcJykge1xuICAgICAgICBodW5rLmxpbmVzLnB1c2goZGlmZnN0cltpXSk7XG4gICAgICAgIGh1bmsubGluZWRlbGltaXRlcnMucHVzaChkZWxpbWl0ZXJzW2ldIHx8ICdcXG4nKTtcblxuICAgICAgICBpZiAob3BlcmF0aW9uID09PSAnKycpIHtcbiAgICAgICAgICBhZGRDb3VudCsrO1xuICAgICAgICB9IGVsc2UgaWYgKG9wZXJhdGlvbiA9PT0gJy0nKSB7XG4gICAgICAgICAgcmVtb3ZlQ291bnQrKztcbiAgICAgICAgfSBlbHNlIGlmIChvcGVyYXRpb24gPT09ICcgJykge1xuICAgICAgICAgIGFkZENvdW50Kys7XG4gICAgICAgICAgcmVtb3ZlQ291bnQrKztcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gSGFuZGxlIHRoZSBlbXB0eSBibG9jayBjb3VudCBjYXNlXG4gICAgaWYgKCFhZGRDb3VudCAmJiBodW5rLm5ld0xpbmVzID09PSAxKSB7XG4gICAgICBodW5rLm5ld0xpbmVzID0gMDtcbiAgICB9XG4gICAgaWYgKCFyZW1vdmVDb3VudCAmJiBodW5rLm9sZExpbmVzID09PSAxKSB7XG4gICAgICBodW5rLm9sZExpbmVzID0gMDtcbiAgICB9XG5cbiAgICAvLyBQZXJmb3JtIG9wdGlvbmFsIHNhbml0eSBjaGVja2luZ1xuICAgIGlmIChvcHRpb25zLnN0cmljdCkge1xuICAgICAgaWYgKGFkZENvdW50ICE9PSBodW5rLm5ld0xpbmVzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQWRkZWQgbGluZSBjb3VudCBkaWQgbm90IG1hdGNoIGZvciBodW5rIGF0IGxpbmUgJyArIChjaHVua0hlYWRlckluZGV4ICsgMSkpO1xuICAgICAgfVxuICAgICAgaWYgKHJlbW92ZUNvdW50ICE9PSBodW5rLm9sZExpbmVzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignUmVtb3ZlZCBsaW5lIGNvdW50IGRpZCBub3QgbWF0Y2ggZm9yIGh1bmsgYXQgbGluZSAnICsgKGNodW5rSGVhZGVySW5kZXggKyAxKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGh1bms7XG4gIH1cblxuICB3aGlsZSAoaSA8IGRpZmZzdHIubGVuZ3RoKSB7XG4gICAgcGFyc2VJbmRleCgpO1xuICB9XG5cbiAgcmV0dXJuIGxpc3Q7XG59XG4iXX0= + + +/***/ }, +/* 12 */ +/***/ function(module, exports) { + + "use strict"; + + exports.__esModule = true; + + exports["default"] = function (start, minLine, maxLine) { + var wantForward = true, + backwardExhausted = false, + forwardExhausted = false, + localOffset = 1; + + return function iterator() { + if (wantForward && !forwardExhausted) { + if (backwardExhausted) { + localOffset++; + } else { + wantForward = false; + } + + // Check if trying to fit beyond text length, and if not, check it fits + // after offset location (or desired location on first iteration) + if (start + localOffset <= maxLine) { + return localOffset; + } + + forwardExhausted = true; + } + + if (!backwardExhausted) { + if (!forwardExhausted) { + wantForward = true; + } + + // Check if trying to fit before text beginning, and if not, check it fits + // before offset location + if (minLine <= start - localOffset) { + return -localOffset++; + } + + backwardExhausted = true; + return iterator(); + } + + // We tried to fit hunk before text beginning and beyond text lenght, then + // hunk can't fit on the text. Return undefined + }; + }; + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlsL2Rpc3RhbmNlLWl0ZXJhdG9yLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7NENBR2UsVUFBUyxLQUFULEVBQWdCLE9BQWhCLEVBQXlCLE9BQXpCLEVBQWtDO0FBQy9DLE1BQUksY0FBYyxJQUFsQjtBQUFBLE1BQ0ksb0JBQW9CLEtBRHhCO0FBQUEsTUFFSSxtQkFBbUIsS0FGdkI7QUFBQSxNQUdJLGNBQWMsQ0FIbEI7O0FBS0EsU0FBTyxTQUFTLFFBQVQsR0FBb0I7QUFDekIsUUFBSSxlQUFlLENBQUMsZ0JBQXBCLEVBQXNDO0FBQ3BDLFVBQUksaUJBQUosRUFBdUI7QUFDckI7QUFDRCxPQUZELE1BRU87QUFDTCxzQkFBYyxLQUFkO0FBQ0Q7Ozs7QUFJRCxVQUFJLFFBQVEsV0FBUixJQUF1QixPQUEzQixFQUFvQztBQUNsQyxlQUFPLFdBQVA7QUFDRDs7QUFFRCx5QkFBbUIsSUFBbkI7QUFDRDs7QUFFRCxRQUFJLENBQUMsaUJBQUwsRUFBd0I7QUFDdEIsVUFBSSxDQUFDLGdCQUFMLEVBQXVCO0FBQ3JCLHNCQUFjLElBQWQ7QUFDRDs7OztBQUlELFVBQUksV0FBVyxRQUFRLFdBQXZCLEVBQW9DO0FBQ2xDLGVBQU8sQ0FBQyxhQUFSO0FBQ0Q7O0FBRUQsMEJBQW9CLElBQXBCO0FBQ0EsYUFBTyxVQUFQO0FBQ0Q7Ozs7QUFJRixHQWxDRDtBQW1DRCxDIiwiZmlsZSI6ImRpc3RhbmNlLWl0ZXJhdG9yLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLy8gSXRlcmF0b3IgdGhhdCB0cmF2ZXJzZXMgaW4gdGhlIHJhbmdlIG9mIFttaW4sIG1heF0sIHN0ZXBwaW5nXG4vLyBieSBkaXN0YW5jZSBmcm9tIGEgZ2l2ZW4gc3RhcnQgcG9zaXRpb24uIEkuZS4gZm9yIFswLCA0XSwgd2l0aFxuLy8gc3RhcnQgb2YgMiwgdGhpcyB3aWxsIGl0ZXJhdGUgMiwgMywgMSwgNCwgMC5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uKHN0YXJ0LCBtaW5MaW5lLCBtYXhMaW5lKSB7XG4gIGxldCB3YW50Rm9yd2FyZCA9IHRydWUsXG4gICAgICBiYWNrd2FyZEV4aGF1c3RlZCA9IGZhbHNlLFxuICAgICAgZm9yd2FyZEV4aGF1c3RlZCA9IGZhbHNlLFxuICAgICAgbG9jYWxPZmZzZXQgPSAxO1xuXG4gIHJldHVybiBmdW5jdGlvbiBpdGVyYXRvcigpIHtcbiAgICBpZiAod2FudEZvcndhcmQgJiYgIWZvcndhcmRFeGhhdXN0ZWQpIHtcbiAgICAgIGlmIChiYWNrd2FyZEV4aGF1c3RlZCkge1xuICAgICAgICBsb2NhbE9mZnNldCsrO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgd2FudEZvcndhcmQgPSBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgLy8gQ2hlY2sgaWYgdHJ5aW5nIHRvIGZpdCBiZXlvbmQgdGV4dCBsZW5ndGgsIGFuZCBpZiBub3QsIGNoZWNrIGl0IGZpdHNcbiAgICAgIC8vIGFmdGVyIG9mZnNldCBsb2NhdGlvbiAob3IgZGVzaXJlZCBsb2NhdGlvbiBvbiBmaXJzdCBpdGVyYXRpb24pXG4gICAgICBpZiAoc3RhcnQgKyBsb2NhbE9mZnNldCA8PSBtYXhMaW5lKSB7XG4gICAgICAgIHJldHVybiBsb2NhbE9mZnNldDtcbiAgICAgIH1cblxuICAgICAgZm9yd2FyZEV4aGF1c3RlZCA9IHRydWU7XG4gICAgfVxuXG4gICAgaWYgKCFiYWNrd2FyZEV4aGF1c3RlZCkge1xuICAgICAgaWYgKCFmb3J3YXJkRXhoYXVzdGVkKSB7XG4gICAgICAgIHdhbnRGb3J3YXJkID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgLy8gQ2hlY2sgaWYgdHJ5aW5nIHRvIGZpdCBiZWZvcmUgdGV4dCBiZWdpbm5pbmcsIGFuZCBpZiBub3QsIGNoZWNrIGl0IGZpdHNcbiAgICAgIC8vIGJlZm9yZSBvZmZzZXQgbG9jYXRpb25cbiAgICAgIGlmIChtaW5MaW5lIDw9IHN0YXJ0IC0gbG9jYWxPZmZzZXQpIHtcbiAgICAgICAgcmV0dXJuIC1sb2NhbE9mZnNldCsrO1xuICAgICAgfVxuXG4gICAgICBiYWNrd2FyZEV4aGF1c3RlZCA9IHRydWU7XG4gICAgICByZXR1cm4gaXRlcmF0b3IoKTtcbiAgICB9XG5cbiAgICAvLyBXZSB0cmllZCB0byBmaXQgaHVuayBiZWZvcmUgdGV4dCBiZWdpbm5pbmcgYW5kIGJleW9uZCB0ZXh0IGxlbmdodCwgdGhlblxuICAgIC8vIGh1bmsgY2FuJ3QgZml0IG9uIHRoZSB0ZXh0LiBSZXR1cm4gdW5kZWZpbmVkXG4gIH07XG59XG4iXX0= + + +/***/ }, +/* 13 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + exports. structuredPatch = structuredPatch; + exports. createTwoFilesPatch = createTwoFilesPatch; + exports. createPatch = createPatch; + + var _line = __webpack_require__(5) ; + + + function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + + function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) { + if (!options) { + options = {}; + } + if (typeof options.context === 'undefined') { + options.context = 4; + } + + var diff = (0, _line.diffLines) (oldStr, newStr, options); + diff.push({ value: '', lines: [] }); // Append an empty value to make cleanup easier + + function contextLines(lines) { + return lines.map(function (entry) { + return ' ' + entry; + }); + } + + var hunks = []; + var oldRangeStart = 0, + newRangeStart = 0, + curRange = [], + oldLine = 1, + newLine = 1; + + var _loop = function _loop( i) { + var current = diff[i], + lines = current.lines || current.value.replace(/\n$/, '').split('\n'); + current.lines = lines; + + if (current.added || current.removed) { + + var _curRange; + + + // If we have previous context, start with that + if (!oldRangeStart) { + var prev = diff[i - 1]; + oldRangeStart = oldLine; + newRangeStart = newLine; + + if (prev) { + curRange = options.context > 0 ? contextLines(prev.lines.slice(-options.context)) : []; + oldRangeStart -= curRange.length; + newRangeStart -= curRange.length; + } + } + + // Output our changes + (_curRange = curRange).push. apply ( _curRange , _toConsumableArray( lines.map(function (entry) { + return (current.added ? '+' : '-') + entry; + }))); + + // Track the updated file position + if (current.added) { + newLine += lines.length; + } else { + oldLine += lines.length; + } + } else { + // Identical context lines. Track line changes + if (oldRangeStart) { + // Close out any changes that have been output (or join overlapping) + if (lines.length <= options.context * 2 && i < diff.length - 2) { + + var _curRange2; + + + // Overlapping + (_curRange2 = curRange).push. apply ( _curRange2 , _toConsumableArray( contextLines(lines))); + } else { + + var _curRange3; + + + // end the range and output + var contextSize = Math.min(lines.length, options.context); + (_curRange3 = curRange).push. apply ( _curRange3 , _toConsumableArray( contextLines(lines.slice(0, contextSize)))); + + var hunk = { + oldStart: oldRangeStart, + oldLines: oldLine - oldRangeStart + contextSize, + newStart: newRangeStart, + newLines: newLine - newRangeStart + contextSize, + lines: curRange + }; + if (i >= diff.length - 2 && lines.length <= options.context) { + // EOF is inside this hunk + var oldEOFNewline = /\n$/.test(oldStr); + var newEOFNewline = /\n$/.test(newStr); + if (lines.length == 0 && !oldEOFNewline) { + // special case: old has no eol and no trailing context; no-nl can end up before adds + curRange.splice(hunk.oldLines, 0, '\\ No newline at end of file'); + } else if (!oldEOFNewline || !newEOFNewline) { + curRange.push('\\ No newline at end of file'); + } + } + hunks.push(hunk); + + oldRangeStart = 0; + newRangeStart = 0; + curRange = []; + } + } + oldLine += lines.length; + newLine += lines.length; + } + }; + + for (var i = 0; i < diff.length; i++) { + + _loop( i); + } + + return { + oldFileName: oldFileName, newFileName: newFileName, + oldHeader: oldHeader, newHeader: newHeader, + hunks: hunks + }; + } + + function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) { + var diff = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options); + + var ret = []; + if (oldFileName == newFileName) { + ret.push('Index: ' + oldFileName); + } + ret.push('==================================================================='); + ret.push('--- ' + diff.oldFileName + (typeof diff.oldHeader === 'undefined' ? '' : '\t' + diff.oldHeader)); + ret.push('+++ ' + diff.newFileName + (typeof diff.newHeader === 'undefined' ? '' : '\t' + diff.newHeader)); + + for (var i = 0; i < diff.hunks.length; i++) { + var hunk = diff.hunks[i]; + ret.push('@@ -' + hunk.oldStart + ',' + hunk.oldLines + ' +' + hunk.newStart + ',' + hunk.newLines + ' @@'); + ret.push.apply(ret, hunk.lines); + } + + return ret.join('\n') + '\n'; + } + + function createPatch(fileName, oldStr, newStr, oldHeader, newHeader, options) { + return createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader, options); + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wYXRjaC9jcmVhdGUuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O2dDQUVnQixlLEdBQUEsZTt5REFpR0EsbUIsR0FBQSxtQjt5REF3QkEsVyxHQUFBLFc7O0FBM0hoQixJLHlCQUFBLCtCLHdCQUFBOzs7Ozt1QkFFTyxTQUFTLGVBQVQsQ0FBeUIsV0FBekIsRUFBc0MsV0FBdEMsRUFBbUQsTUFBbkQsRUFBMkQsTUFBM0QsRUFBbUUsU0FBbkUsRUFBOEUsU0FBOUUsRUFBeUYsT0FBekYsRUFBa0c7QUFDdkcsTUFBSSxDQUFDLE9BQUwsRUFBYztBQUNaLGNBQVUsRUFBVjtBQUNEO0FBQ0QsTUFBSSxPQUFPLFFBQVEsT0FBZixLQUEyQixXQUEvQixFQUE0QztBQUMxQyxZQUFRLE9BQVIsR0FBa0IsQ0FBbEI7QUFDRDs7QUFFRCxNQUFNLE8seUJBQU8sb0Isd0JBQUEsQ0FBVSxNQUFWLEVBQWtCLE1BQWxCLEVBQTBCLE9BQTFCLENBQWI7QUFDQSxPQUFLLElBQUwsQ0FBVSxFQUFDLE9BQU8sRUFBUixFQUFZLE9BQU8sRUFBbkIsRUFBVixFOztBQUVBLFdBQVMsWUFBVCxDQUFzQixLQUF0QixFQUE2QjtBQUMzQixXQUFPLE1BQU0sR0FBTixDQUFVLFVBQVMsS0FBVCxFQUFnQjtBQUFFLGFBQU8sTUFBTSxLQUFiO0FBQXFCLEtBQWpELENBQVA7QUFDRDs7QUFFRCxNQUFJLFFBQVEsRUFBWjtBQUNBLE1BQUksZ0JBQWdCLENBQXBCO0FBQUEsTUFBdUIsZ0JBQWdCLENBQXZDO0FBQUEsTUFBMEMsV0FBVyxFQUFyRDtBQUFBLE1BQ0ksVUFBVSxDQURkO0FBQUEsTUFDaUIsVUFBVSxDQUQzQjs7QUFoQnVHLDZCLHdCQWtCOUYsQ0FsQjhGO0FBbUJyRyxRQUFNLFVBQVUsS0FBSyxDQUFMLENBQWhCO0FBQUEsUUFDTSxRQUFRLFFBQVEsS0FBUixJQUFpQixRQUFRLEtBQVIsQ0FBYyxPQUFkLENBQXNCLEtBQXRCLEVBQTZCLEVBQTdCLEVBQWlDLEtBQWpDLENBQXVDLElBQXZDLENBRC9CO0FBRUEsWUFBUSxLQUFSLEdBQWdCLEtBQWhCOztBQUVBLFFBQUksUUFBUSxLQUFSLElBQWlCLFFBQVEsT0FBN0IsRUFBc0M7O0FBQUE7Ozs7QUFFcEMsVUFBSSxDQUFDLGFBQUwsRUFBb0I7QUFDbEIsWUFBTSxPQUFPLEtBQUssSUFBSSxDQUFULENBQWI7QUFDQSx3QkFBZ0IsT0FBaEI7QUFDQSx3QkFBZ0IsT0FBaEI7O0FBRUEsWUFBSSxJQUFKLEVBQVU7QUFDUixxQkFBVyxRQUFRLE9BQVIsR0FBa0IsQ0FBbEIsR0FBc0IsYUFBYSxLQUFLLEtBQUwsQ0FBVyxLQUFYLENBQWlCLENBQUMsUUFBUSxPQUExQixDQUFiLENBQXRCLEdBQXlFLEVBQXBGO0FBQ0EsMkJBQWlCLFNBQVMsTUFBMUI7QUFDQSwyQkFBaUIsU0FBUyxNQUExQjtBQUNEO0FBQ0Y7OzsrQkFHRCxhLHVCQUFBLFVBQVMsSUFBVCxDLDBCQUFBLEssd0JBQUEsQywwQkFBQSxTLHdCQUFBLEUseUJBQUEsbUIsd0JBQWtCLE1BQU0sR0FBTixDQUFVLFVBQVMsS0FBVCxFQUFnQjtBQUMxQyxlQUFPLENBQUMsUUFBUSxLQUFSLEdBQWdCLEdBQWhCLEdBQXNCLEdBQXZCLElBQThCLEtBQXJDO0FBQ0QsT0FGaUIsQ0FBbEI7OztBQUtBLFVBQUksUUFBUSxLQUFaLEVBQW1CO0FBQ2pCLG1CQUFXLE1BQU0sTUFBakI7QUFDRCxPQUZELE1BRU87QUFDTCxtQkFBVyxNQUFNLE1BQWpCO0FBQ0Q7QUFDRixLQXpCRCxNQXlCTzs7QUFFTCxVQUFJLGFBQUosRUFBbUI7O0FBRWpCLFlBQUksTUFBTSxNQUFOLElBQWdCLFFBQVEsT0FBUixHQUFrQixDQUFsQyxJQUF1QyxJQUFJLEtBQUssTUFBTCxHQUFjLENBQTdELEVBQWdFOztBQUFBOzs7O21DQUU5RCxjLHVCQUFBLFVBQVMsSUFBVCxDLDBCQUFBLEssd0JBQUEsQywwQkFBQSxVLHdCQUFBLEUseUJBQUEsbUIsd0JBQWtCLGFBQWEsS0FBYixDQUFsQjtBQUNELFNBSEQsTUFHTzs7QUFBQTs7OztBQUVMLGNBQUksY0FBYyxLQUFLLEdBQUwsQ0FBUyxNQUFNLE1BQWYsRUFBdUIsUUFBUSxPQUEvQixDQUFsQjttQ0FDQSxjLHVCQUFBLFVBQVMsSUFBVCxDLDBCQUFBLEssd0JBQUEsQywwQkFBQSxVLHdCQUFBLEUseUJBQUEsbUIsd0JBQWtCLGFBQWEsTUFBTSxLQUFOLENBQVksQ0FBWixFQUFlLFdBQWYsQ0FBYixDQUFsQjs7QUFFQSxjQUFJLE9BQU87QUFDVCxzQkFBVSxhQUREO0FBRVQsc0JBQVcsVUFBVSxhQUFWLEdBQTBCLFdBRjVCO0FBR1Qsc0JBQVUsYUFIRDtBQUlULHNCQUFXLFVBQVUsYUFBVixHQUEwQixXQUo1QjtBQUtULG1CQUFPO0FBTEUsV0FBWDtBQU9BLGNBQUksS0FBSyxLQUFLLE1BQUwsR0FBYyxDQUFuQixJQUF3QixNQUFNLE1BQU4sSUFBZ0IsUUFBUSxPQUFwRCxFQUE2RDs7QUFFM0QsZ0JBQUksZ0JBQWlCLE1BQU0sSUFBTixDQUFXLE1BQVgsQ0FBckI7QUFDQSxnQkFBSSxnQkFBaUIsTUFBTSxJQUFOLENBQVcsTUFBWCxDQUFyQjtBQUNBLGdCQUFJLE1BQU0sTUFBTixJQUFnQixDQUFoQixJQUFxQixDQUFDLGFBQTFCLEVBQXlDOztBQUV2Qyx1QkFBUyxNQUFULENBQWdCLEtBQUssUUFBckIsRUFBK0IsQ0FBL0IsRUFBa0MsOEJBQWxDO0FBQ0QsYUFIRCxNQUdPLElBQUksQ0FBQyxhQUFELElBQWtCLENBQUMsYUFBdkIsRUFBc0M7QUFDM0MsdUJBQVMsSUFBVCxDQUFjLDhCQUFkO0FBQ0Q7QUFDRjtBQUNELGdCQUFNLElBQU4sQ0FBVyxJQUFYOztBQUVBLDBCQUFnQixDQUFoQjtBQUNBLDBCQUFnQixDQUFoQjtBQUNBLHFCQUFXLEVBQVg7QUFDRDtBQUNGO0FBQ0QsaUJBQVcsTUFBTSxNQUFqQjtBQUNBLGlCQUFXLE1BQU0sTUFBakI7QUFDRDtBQXZGb0c7O0FBa0J2RyxPQUFLLElBQUksSUFBSSxDQUFiLEVBQWdCLElBQUksS0FBSyxNQUF6QixFQUFpQyxHQUFqQyxFQUFzQzs7QUFBQSxVLHdCQUE3QixDQUE2QjtBQXNFckM7O0FBRUQsU0FBTztBQUNMLGlCQUFhLFdBRFIsRUFDcUIsYUFBYSxXQURsQztBQUVMLGVBQVcsU0FGTixFQUVpQixXQUFXLFNBRjVCO0FBR0wsV0FBTztBQUhGLEdBQVA7QUFLRDs7QUFFTSxTQUFTLG1CQUFULENBQTZCLFdBQTdCLEVBQTBDLFdBQTFDLEVBQXVELE1BQXZELEVBQStELE1BQS9ELEVBQXVFLFNBQXZFLEVBQWtGLFNBQWxGLEVBQTZGLE9BQTdGLEVBQXNHO0FBQzNHLE1BQU0sT0FBTyxnQkFBZ0IsV0FBaEIsRUFBNkIsV0FBN0IsRUFBMEMsTUFBMUMsRUFBa0QsTUFBbEQsRUFBMEQsU0FBMUQsRUFBcUUsU0FBckUsRUFBZ0YsT0FBaEYsQ0FBYjs7QUFFQSxNQUFNLE1BQU0sRUFBWjtBQUNBLE1BQUksZUFBZSxXQUFuQixFQUFnQztBQUM5QixRQUFJLElBQUosQ0FBUyxZQUFZLFdBQXJCO0FBQ0Q7QUFDRCxNQUFJLElBQUosQ0FBUyxxRUFBVDtBQUNBLE1BQUksSUFBSixDQUFTLFNBQVMsS0FBSyxXQUFkLElBQTZCLE9BQU8sS0FBSyxTQUFaLEtBQTBCLFdBQTFCLEdBQXdDLEVBQXhDLEdBQTZDLE9BQU8sS0FBSyxTQUF0RixDQUFUO0FBQ0EsTUFBSSxJQUFKLENBQVMsU0FBUyxLQUFLLFdBQWQsSUFBNkIsT0FBTyxLQUFLLFNBQVosS0FBMEIsV0FBMUIsR0FBd0MsRUFBeEMsR0FBNkMsT0FBTyxLQUFLLFNBQXRGLENBQVQ7O0FBRUEsT0FBSyxJQUFJLElBQUksQ0FBYixFQUFnQixJQUFJLEtBQUssS0FBTCxDQUFXLE1BQS9CLEVBQXVDLEdBQXZDLEVBQTRDO0FBQzFDLFFBQU0sT0FBTyxLQUFLLEtBQUwsQ0FBVyxDQUFYLENBQWI7QUFDQSxRQUFJLElBQUosQ0FDRSxTQUFTLEtBQUssUUFBZCxHQUF5QixHQUF6QixHQUErQixLQUFLLFFBQXBDLEdBQ0UsSUFERixHQUNTLEtBQUssUUFEZCxHQUN5QixHQUR6QixHQUMrQixLQUFLLFFBRHBDLEdBRUUsS0FISjtBQUtBLFFBQUksSUFBSixDQUFTLEtBQVQsQ0FBZSxHQUFmLEVBQW9CLEtBQUssS0FBekI7QUFDRDs7QUFFRCxTQUFPLElBQUksSUFBSixDQUFTLElBQVQsSUFBaUIsSUFBeEI7QUFDRDs7QUFFTSxTQUFTLFdBQVQsQ0FBcUIsUUFBckIsRUFBK0IsTUFBL0IsRUFBdUMsTUFBdkMsRUFBK0MsU0FBL0MsRUFBMEQsU0FBMUQsRUFBcUUsT0FBckUsRUFBOEU7QUFDbkYsU0FBTyxvQkFBb0IsUUFBcEIsRUFBOEIsUUFBOUIsRUFBd0MsTUFBeEMsRUFBZ0QsTUFBaEQsRUFBd0QsU0FBeEQsRUFBbUUsU0FBbkUsRUFBOEUsT0FBOUUsQ0FBUDtBQUNEIiwiZmlsZSI6ImNyZWF0ZS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7ZGlmZkxpbmVzfSBmcm9tICcuLi9kaWZmL2xpbmUnO1xuXG5leHBvcnQgZnVuY3Rpb24gc3RydWN0dXJlZFBhdGNoKG9sZEZpbGVOYW1lLCBuZXdGaWxlTmFtZSwgb2xkU3RyLCBuZXdTdHIsIG9sZEhlYWRlciwgbmV3SGVhZGVyLCBvcHRpb25zKSB7XG4gIGlmICghb3B0aW9ucykge1xuICAgIG9wdGlvbnMgPSB7fTtcbiAgfVxuICBpZiAodHlwZW9mIG9wdGlvbnMuY29udGV4dCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBvcHRpb25zLmNvbnRleHQgPSA0O1xuICB9XG5cbiAgY29uc3QgZGlmZiA9IGRpZmZMaW5lcyhvbGRTdHIsIG5ld1N0ciwgb3B0aW9ucyk7XG4gIGRpZmYucHVzaCh7dmFsdWU6ICcnLCBsaW5lczogW119KTsgICAvLyBBcHBlbmQgYW4gZW1wdHkgdmFsdWUgdG8gbWFrZSBjbGVhbnVwIGVhc2llclxuXG4gIGZ1bmN0aW9uIGNvbnRleHRMaW5lcyhsaW5lcykge1xuICAgIHJldHVybiBsaW5lcy5tYXAoZnVuY3Rpb24oZW50cnkpIHsgcmV0dXJuICcgJyArIGVudHJ5OyB9KTtcbiAgfVxuXG4gIGxldCBodW5rcyA9IFtdO1xuICBsZXQgb2xkUmFuZ2VTdGFydCA9IDAsIG5ld1JhbmdlU3RhcnQgPSAwLCBjdXJSYW5nZSA9IFtdLFxuICAgICAgb2xkTGluZSA9IDEsIG5ld0xpbmUgPSAxO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGRpZmYubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBjdXJyZW50ID0gZGlmZltpXSxcbiAgICAgICAgICBsaW5lcyA9IGN1cnJlbnQubGluZXMgfHwgY3VycmVudC52YWx1ZS5yZXBsYWNlKC9cXG4kLywgJycpLnNwbGl0KCdcXG4nKTtcbiAgICBjdXJyZW50LmxpbmVzID0gbGluZXM7XG5cbiAgICBpZiAoY3VycmVudC5hZGRlZCB8fCBjdXJyZW50LnJlbW92ZWQpIHtcbiAgICAgIC8vIElmIHdlIGhhdmUgcHJldmlvdXMgY29udGV4dCwgc3RhcnQgd2l0aCB0aGF0XG4gICAgICBpZiAoIW9sZFJhbmdlU3RhcnQpIHtcbiAgICAgICAgY29uc3QgcHJldiA9IGRpZmZbaSAtIDFdO1xuICAgICAgICBvbGRSYW5nZVN0YXJ0ID0gb2xkTGluZTtcbiAgICAgICAgbmV3UmFuZ2VTdGFydCA9IG5ld0xpbmU7XG5cbiAgICAgICAgaWYgKHByZXYpIHtcbiAgICAgICAgICBjdXJSYW5nZSA9IG9wdGlvbnMuY29udGV4dCA+IDAgPyBjb250ZXh0TGluZXMocHJldi5saW5lcy5zbGljZSgtb3B0aW9ucy5jb250ZXh0KSkgOiBbXTtcbiAgICAgICAgICBvbGRSYW5nZVN0YXJ0IC09IGN1clJhbmdlLmxlbmd0aDtcbiAgICAgICAgICBuZXdSYW5nZVN0YXJ0IC09IGN1clJhbmdlLmxlbmd0aDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBPdXRwdXQgb3VyIGNoYW5nZXNcbiAgICAgIGN1clJhbmdlLnB1c2goLi4uIGxpbmVzLm1hcChmdW5jdGlvbihlbnRyeSkge1xuICAgICAgICByZXR1cm4gKGN1cnJlbnQuYWRkZWQgPyAnKycgOiAnLScpICsgZW50cnk7XG4gICAgICB9KSk7XG5cbiAgICAgIC8vIFRyYWNrIHRoZSB1cGRhdGVkIGZpbGUgcG9zaXRpb25cbiAgICAgIGlmIChjdXJyZW50LmFkZGVkKSB7XG4gICAgICAgIG5ld0xpbmUgKz0gbGluZXMubGVuZ3RoO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgb2xkTGluZSArPSBsaW5lcy5sZW5ndGg7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIElkZW50aWNhbCBjb250ZXh0IGxpbmVzLiBUcmFjayBsaW5lIGNoYW5nZXNcbiAgICAgIGlmIChvbGRSYW5nZVN0YXJ0KSB7XG4gICAgICAgIC8vIENsb3NlIG91dCBhbnkgY2hhbmdlcyB0aGF0IGhhdmUgYmVlbiBvdXRwdXQgKG9yIGpvaW4gb3ZlcmxhcHBpbmcpXG4gICAgICAgIGlmIChsaW5lcy5sZW5ndGggPD0gb3B0aW9ucy5jb250ZXh0ICogMiAmJiBpIDwgZGlmZi5sZW5ndGggLSAyKSB7XG4gICAgICAgICAgLy8gT3ZlcmxhcHBpbmdcbiAgICAgICAgICBjdXJSYW5nZS5wdXNoKC4uLiBjb250ZXh0TGluZXMobGluZXMpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBlbmQgdGhlIHJhbmdlIGFuZCBvdXRwdXRcbiAgICAgICAgICBsZXQgY29udGV4dFNpemUgPSBNYXRoLm1pbihsaW5lcy5sZW5ndGgsIG9wdGlvbnMuY29udGV4dCk7XG4gICAgICAgICAgY3VyUmFuZ2UucHVzaCguLi4gY29udGV4dExpbmVzKGxpbmVzLnNsaWNlKDAsIGNvbnRleHRTaXplKSkpO1xuXG4gICAgICAgICAgbGV0IGh1bmsgPSB7XG4gICAgICAgICAgICBvbGRTdGFydDogb2xkUmFuZ2VTdGFydCxcbiAgICAgICAgICAgIG9sZExpbmVzOiAob2xkTGluZSAtIG9sZFJhbmdlU3RhcnQgKyBjb250ZXh0U2l6ZSksXG4gICAgICAgICAgICBuZXdTdGFydDogbmV3UmFuZ2VTdGFydCxcbiAgICAgICAgICAgIG5ld0xpbmVzOiAobmV3TGluZSAtIG5ld1JhbmdlU3RhcnQgKyBjb250ZXh0U2l6ZSksXG4gICAgICAgICAgICBsaW5lczogY3VyUmFuZ2VcbiAgICAgICAgICB9O1xuICAgICAgICAgIGlmIChpID49IGRpZmYubGVuZ3RoIC0gMiAmJiBsaW5lcy5sZW5ndGggPD0gb3B0aW9ucy5jb250ZXh0KSB7XG4gICAgICAgICAgICAvLyBFT0YgaXMgaW5zaWRlIHRoaXMgaHVua1xuICAgICAgICAgICAgbGV0IG9sZEVPRk5ld2xpbmUgPSAoL1xcbiQvLnRlc3Qob2xkU3RyKSk7XG4gICAgICAgICAgICBsZXQgbmV3RU9GTmV3bGluZSA9ICgvXFxuJC8udGVzdChuZXdTdHIpKTtcbiAgICAgICAgICAgIGlmIChsaW5lcy5sZW5ndGggPT0gMCAmJiAhb2xkRU9GTmV3bGluZSkge1xuICAgICAgICAgICAgICAvLyBzcGVjaWFsIGNhc2U6IG9sZCBoYXMgbm8gZW9sIGFuZCBubyB0cmFpbGluZyBjb250ZXh0OyBuby1ubCBjYW4gZW5kIHVwIGJlZm9yZSBhZGRzXG4gICAgICAgICAgICAgIGN1clJhbmdlLnNwbGljZShodW5rLm9sZExpbmVzLCAwLCAnXFxcXCBObyBuZXdsaW5lIGF0IGVuZCBvZiBmaWxlJyk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCFvbGRFT0ZOZXdsaW5lIHx8ICFuZXdFT0ZOZXdsaW5lKSB7XG4gICAgICAgICAgICAgIGN1clJhbmdlLnB1c2goJ1xcXFwgTm8gbmV3bGluZSBhdCBlbmQgb2YgZmlsZScpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBodW5rcy5wdXNoKGh1bmspO1xuXG4gICAgICAgICAgb2xkUmFuZ2VTdGFydCA9IDA7XG4gICAgICAgICAgbmV3UmFuZ2VTdGFydCA9IDA7XG4gICAgICAgICAgY3VyUmFuZ2UgPSBbXTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgb2xkTGluZSArPSBsaW5lcy5sZW5ndGg7XG4gICAgICBuZXdMaW5lICs9IGxpbmVzLmxlbmd0aDtcbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG9sZEZpbGVOYW1lOiBvbGRGaWxlTmFtZSwgbmV3RmlsZU5hbWU6IG5ld0ZpbGVOYW1lLFxuICAgIG9sZEhlYWRlcjogb2xkSGVhZGVyLCBuZXdIZWFkZXI6IG5ld0hlYWRlcixcbiAgICBodW5rczogaHVua3NcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVR3b0ZpbGVzUGF0Y2gob2xkRmlsZU5hbWUsIG5ld0ZpbGVOYW1lLCBvbGRTdHIsIG5ld1N0ciwgb2xkSGVhZGVyLCBuZXdIZWFkZXIsIG9wdGlvbnMpIHtcbiAgY29uc3QgZGlmZiA9IHN0cnVjdHVyZWRQYXRjaChvbGRGaWxlTmFtZSwgbmV3RmlsZU5hbWUsIG9sZFN0ciwgbmV3U3RyLCBvbGRIZWFkZXIsIG5ld0hlYWRlciwgb3B0aW9ucyk7XG5cbiAgY29uc3QgcmV0ID0gW107XG4gIGlmIChvbGRGaWxlTmFtZSA9PSBuZXdGaWxlTmFtZSkge1xuICAgIHJldC5wdXNoKCdJbmRleDogJyArIG9sZEZpbGVOYW1lKTtcbiAgfVxuICByZXQucHVzaCgnPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PScpO1xuICByZXQucHVzaCgnLS0tICcgKyBkaWZmLm9sZEZpbGVOYW1lICsgKHR5cGVvZiBkaWZmLm9sZEhlYWRlciA9PT0gJ3VuZGVmaW5lZCcgPyAnJyA6ICdcXHQnICsgZGlmZi5vbGRIZWFkZXIpKTtcbiAgcmV0LnB1c2goJysrKyAnICsgZGlmZi5uZXdGaWxlTmFtZSArICh0eXBlb2YgZGlmZi5uZXdIZWFkZXIgPT09ICd1bmRlZmluZWQnID8gJycgOiAnXFx0JyArIGRpZmYubmV3SGVhZGVyKSk7XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBkaWZmLmh1bmtzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgaHVuayA9IGRpZmYuaHVua3NbaV07XG4gICAgcmV0LnB1c2goXG4gICAgICAnQEAgLScgKyBodW5rLm9sZFN0YXJ0ICsgJywnICsgaHVuay5vbGRMaW5lc1xuICAgICAgKyAnICsnICsgaHVuay5uZXdTdGFydCArICcsJyArIGh1bmsubmV3TGluZXNcbiAgICAgICsgJyBAQCdcbiAgICApO1xuICAgIHJldC5wdXNoLmFwcGx5KHJldCwgaHVuay5saW5lcyk7XG4gIH1cblxuICByZXR1cm4gcmV0LmpvaW4oJ1xcbicpICsgJ1xcbic7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQYXRjaChmaWxlTmFtZSwgb2xkU3RyLCBuZXdTdHIsIG9sZEhlYWRlciwgbmV3SGVhZGVyLCBvcHRpb25zKSB7XG4gIHJldHVybiBjcmVhdGVUd29GaWxlc1BhdGNoKGZpbGVOYW1lLCBmaWxlTmFtZSwgb2xkU3RyLCBuZXdTdHIsIG9sZEhlYWRlciwgbmV3SGVhZGVyLCBvcHRpb25zKTtcbn1cbiJdfQ== + + +/***/ }, +/* 14 */ +/***/ function(module, exports) { + + "use strict"; + + exports.__esModule = true; + exports. convertChangesToDMP = convertChangesToDMP; + // See: http://code.google.com/p/google-diff-match-patch/wiki/API + function convertChangesToDMP(changes) { + var ret = [], + change = void 0 , + operation = void 0 ; + for (var i = 0; i < changes.length; i++) { + change = changes[i]; + if (change.added) { + operation = 1; + } else if (change.removed) { + operation = -1; + } else { + operation = 0; + } + + ret.push([operation, change.value]); + } + return ret; + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb252ZXJ0L2RtcC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Z0NBQ2dCLG1CLEdBQUEsbUI7O0FBQVQsU0FBUyxtQkFBVCxDQUE2QixPQUE3QixFQUFzQztBQUMzQyxNQUFJLE1BQU0sRUFBVjtBQUFBLE1BQ0ksUyx5QkFBQSxNLHdCQURKO0FBQUEsTUFFSSxZLHlCQUFBLE0sd0JBRko7QUFHQSxPQUFLLElBQUksSUFBSSxDQUFiLEVBQWdCLElBQUksUUFBUSxNQUE1QixFQUFvQyxHQUFwQyxFQUF5QztBQUN2QyxhQUFTLFFBQVEsQ0FBUixDQUFUO0FBQ0EsUUFBSSxPQUFPLEtBQVgsRUFBa0I7QUFDaEIsa0JBQVksQ0FBWjtBQUNELEtBRkQsTUFFTyxJQUFJLE9BQU8sT0FBWCxFQUFvQjtBQUN6QixrQkFBWSxDQUFDLENBQWI7QUFDRCxLQUZNLE1BRUE7QUFDTCxrQkFBWSxDQUFaO0FBQ0Q7O0FBRUQsUUFBSSxJQUFKLENBQVMsQ0FBQyxTQUFELEVBQVksT0FBTyxLQUFuQixDQUFUO0FBQ0Q7QUFDRCxTQUFPLEdBQVA7QUFDRCIsImZpbGUiOiJkbXAuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBTZWU6IGh0dHA6Ly9jb2RlLmdvb2dsZS5jb20vcC9nb29nbGUtZGlmZi1tYXRjaC1wYXRjaC93aWtpL0FQSVxuZXhwb3J0IGZ1bmN0aW9uIGNvbnZlcnRDaGFuZ2VzVG9ETVAoY2hhbmdlcykge1xuICBsZXQgcmV0ID0gW10sXG4gICAgICBjaGFuZ2UsXG4gICAgICBvcGVyYXRpb247XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgY2hhbmdlcy5sZW5ndGg7IGkrKykge1xuICAgIGNoYW5nZSA9IGNoYW5nZXNbaV07XG4gICAgaWYgKGNoYW5nZS5hZGRlZCkge1xuICAgICAgb3BlcmF0aW9uID0gMTtcbiAgICB9IGVsc2UgaWYgKGNoYW5nZS5yZW1vdmVkKSB7XG4gICAgICBvcGVyYXRpb24gPSAtMTtcbiAgICB9IGVsc2Uge1xuICAgICAgb3BlcmF0aW9uID0gMDtcbiAgICB9XG5cbiAgICByZXQucHVzaChbb3BlcmF0aW9uLCBjaGFuZ2UudmFsdWVdKTtcbiAgfVxuICByZXR1cm4gcmV0O1xufVxuIl19 + + +/***/ }, +/* 15 */ +/***/ function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + exports. convertChangesToXML = convertChangesToXML; + function convertChangesToXML(changes) { + var ret = []; + for (var i = 0; i < changes.length; i++) { + var change = changes[i]; + if (change.added) { + ret.push(''); + } else if (change.removed) { + ret.push(''); + } + + ret.push(escapeHTML(change.value)); + + if (change.added) { + ret.push(''); + } else if (change.removed) { + ret.push(''); + } + } + return ret.join(''); + } + + function escapeHTML(s) { + var n = s; + n = n.replace(/&/g, '&'); + n = n.replace(//g, '>'); + n = n.replace(/"/g, '"'); + + return n; + } + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb252ZXJ0L3htbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Z0NBQWdCLG1CLEdBQUEsbUI7QUFBVCxTQUFTLG1CQUFULENBQTZCLE9BQTdCLEVBQXNDO0FBQzNDLE1BQUksTUFBTSxFQUFWO0FBQ0EsT0FBSyxJQUFJLElBQUksQ0FBYixFQUFnQixJQUFJLFFBQVEsTUFBNUIsRUFBb0MsR0FBcEMsRUFBeUM7QUFDdkMsUUFBSSxTQUFTLFFBQVEsQ0FBUixDQUFiO0FBQ0EsUUFBSSxPQUFPLEtBQVgsRUFBa0I7QUFDaEIsVUFBSSxJQUFKLENBQVMsT0FBVDtBQUNELEtBRkQsTUFFTyxJQUFJLE9BQU8sT0FBWCxFQUFvQjtBQUN6QixVQUFJLElBQUosQ0FBUyxPQUFUO0FBQ0Q7O0FBRUQsUUFBSSxJQUFKLENBQVMsV0FBVyxPQUFPLEtBQWxCLENBQVQ7O0FBRUEsUUFBSSxPQUFPLEtBQVgsRUFBa0I7QUFDaEIsVUFBSSxJQUFKLENBQVMsUUFBVDtBQUNELEtBRkQsTUFFTyxJQUFJLE9BQU8sT0FBWCxFQUFvQjtBQUN6QixVQUFJLElBQUosQ0FBUyxRQUFUO0FBQ0Q7QUFDRjtBQUNELFNBQU8sSUFBSSxJQUFKLENBQVMsRUFBVCxDQUFQO0FBQ0Q7O0FBRUQsU0FBUyxVQUFULENBQW9CLENBQXBCLEVBQXVCO0FBQ3JCLE1BQUksSUFBSSxDQUFSO0FBQ0EsTUFBSSxFQUFFLE9BQUYsQ0FBVSxJQUFWLEVBQWdCLE9BQWhCLENBQUo7QUFDQSxNQUFJLEVBQUUsT0FBRixDQUFVLElBQVYsRUFBZ0IsTUFBaEIsQ0FBSjtBQUNBLE1BQUksRUFBRSxPQUFGLENBQVUsSUFBVixFQUFnQixNQUFoQixDQUFKO0FBQ0EsTUFBSSxFQUFFLE9BQUYsQ0FBVSxJQUFWLEVBQWdCLFFBQWhCLENBQUo7O0FBRUEsU0FBTyxDQUFQO0FBQ0QiLCJmaWxlIjoieG1sLmpzIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGZ1bmN0aW9uIGNvbnZlcnRDaGFuZ2VzVG9YTUwoY2hhbmdlcykge1xuICBsZXQgcmV0ID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgY2hhbmdlcy5sZW5ndGg7IGkrKykge1xuICAgIGxldCBjaGFuZ2UgPSBjaGFuZ2VzW2ldO1xuICAgIGlmIChjaGFuZ2UuYWRkZWQpIHtcbiAgICAgIHJldC5wdXNoKCc8aW5zPicpO1xuICAgIH0gZWxzZSBpZiAoY2hhbmdlLnJlbW92ZWQpIHtcbiAgICAgIHJldC5wdXNoKCc8ZGVsPicpO1xuICAgIH1cblxuICAgIHJldC5wdXNoKGVzY2FwZUhUTUwoY2hhbmdlLnZhbHVlKSk7XG5cbiAgICBpZiAoY2hhbmdlLmFkZGVkKSB7XG4gICAgICByZXQucHVzaCgnPC9pbnM+Jyk7XG4gICAgfSBlbHNlIGlmIChjaGFuZ2UucmVtb3ZlZCkge1xuICAgICAgcmV0LnB1c2goJzwvZGVsPicpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmV0LmpvaW4oJycpO1xufVxuXG5mdW5jdGlvbiBlc2NhcGVIVE1MKHMpIHtcbiAgbGV0IG4gPSBzO1xuICBuID0gbi5yZXBsYWNlKC8mL2csICcmYW1wOycpO1xuICBuID0gbi5yZXBsYWNlKC88L2csICcmbHQ7Jyk7XG4gIG4gPSBuLnJlcGxhY2UoLz4vZywgJyZndDsnKTtcbiAgbiA9IG4ucmVwbGFjZSgvXCIvZywgJyZxdW90OycpO1xuXG4gIHJldHVybiBuO1xufVxuIl19 + + +/***/ } +]) +}); diff --git a/modules/cms/classes/Asset.php b/modules/cms/classes/Asset.php new file mode 100644 index 0000000..9a83504 --- /dev/null +++ b/modules/cms/classes/Asset.php @@ -0,0 +1,316 @@ +theme = $theme; + + $this->allowedExtensions = self::getEditableExtensions(); + + parent::__construct(); + } + + /** + * Loads the object from a file. + * This method is used in the CMS back-end. It doesn't use any caching. + * @param \Cms\Classes\Theme $theme Specifies the theme the object belongs to. + * @param string $fileName Specifies the file name, with the extension. + * The file name can contain only alphanumeric symbols, dashes and dots. + * @return mixed Returns a CMS object instance or null if the object wasn't found. + */ + public static function load($theme, $fileName) + { + return (new static($theme))->find($fileName); + } + + /** + * Prepares the theme datasource for the model. + * @param \Cms\Classes\Theme|string $theme Specifies a parent theme. + * @return $this + */ + public static function inTheme($theme) + { + if (is_string($theme)) { + $theme = Theme::load($theme); + } + + return new static($theme); + } + + /** + * Find a single template by its file name. + * + * @param string $fileName + * @return mixed|static + */ + public function find($fileName) + { + $filePath = $this->getFilePath($fileName); + + if (!File::isFile($filePath)) { + return null; + } + + if (($content = @File::get($filePath)) === false) { + return null; + } + + $this->fileName = $fileName; + $this->originalFileName = $fileName; + $this->mtime = File::lastModified($filePath); + $this->content = $content; + $this->exists = true; + return $this; + } + + /** + * Sets the object attributes. + * @param array $attributes A list of attributes to set. + */ + public function fill(array $attributes) + { + foreach ($attributes as $key => $value) { + if (!in_array($key, $this->fillable)) { + throw new ApplicationException(Lang::get( + 'cms::lang.cms_object.invalid_property', + ['name' => $key] + )); + } + + $this->$key = $value; + } + } + + /** + * Saves the object to the disk. + */ + public function save() + { + $this->validateFileName(); + + $fullPath = $this->getFilePath(); + + if (File::isFile($fullPath) && $this->originalFileName !== $this->fileName) { + throw new ApplicationException(Lang::get( + 'cms::lang.cms_object.file_already_exists', + ['name'=>$this->fileName] + )); + } + + $dirPath = $this->theme->getPath().'/'.$this->dirName; + if (!file_exists($dirPath) || !is_dir($dirPath)) { + if (!File::makeDirectory($dirPath, 0777, true, true)) { + throw new ApplicationException(Lang::get( + 'cms::lang.cms_object.error_creating_directory', + ['name'=>$dirPath] + )); + } + } + + if (($pos = strpos($this->fileName, '/')) !== false) { + $dirPath = dirname($fullPath); + + if (!is_dir($dirPath) && !File::makeDirectory($dirPath, 0777, true, true)) { + throw new ApplicationException(Lang::get( + 'cms::lang.cms_object.error_creating_directory', + ['name'=>$dirPath] + )); + } + } + + $newFullPath = $fullPath; + if (@File::put($fullPath, $this->content) === false) { + throw new ApplicationException(Lang::get( + 'cms::lang.cms_object.error_saving', + ['name'=>$this->fileName] + )); + } + + if (strlen($this->originalFileName) && $this->originalFileName !== $this->fileName) { + $fullPath = $this->getFilePath($this->originalFileName); + + if (File::isFile($fullPath)) { + @unlink($fullPath); + } + } + + clearstatcache(); + + $this->mtime = @File::lastModified($newFullPath); + $this->originalFileName = $this->fileName; + $this->exists = true; + } + + public function delete() + { + $fileName = Request::input('fileName'); + $fullPath = $this->getFilePath($fileName); + + $this->validateFileName($fileName); + + if (File::exists($fullPath)) { + if (!@File::delete($fullPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_deleting_file', + ['name' => $fileName] + )); + } + } + } + + /** + * Validate the supplied filename, extension and path. + * @param string $fileName + */ + protected function validateFileName($fileName = null) + { + if ($fileName === null) { + $fileName = $this->fileName; + } + + $fileName = trim($fileName); + + if (!strlen($fileName)) { + throw new ValidationException(['fileName' => + Lang::get('cms::lang.cms_object.file_name_required', [ + 'allowed' => implode(', ', $this->allowedExtensions), + 'invalid' => pathinfo($fileName, PATHINFO_EXTENSION) + ]) + ]); + } + + if (!FileHelper::validateExtension($fileName, $this->allowedExtensions, false)) { + throw new ValidationException(['fileName' => + Lang::get('cms::lang.cms_object.invalid_file_extension', [ + 'allowed' => implode(', ', $this->allowedExtensions), + 'invalid' => pathinfo($fileName, PATHINFO_EXTENSION) + ]) + ]); + } + + if (!FileHelper::validatePath($fileName, null)) { + throw new ValidationException(['fileName' => + Lang::get('cms::lang.cms_object.invalid_file', [ + 'name' => $fileName + ]) + ]); + } + } + + /** + * Returns the file name. + * @return string + */ + public function getFileName() + { + return $this->fileName; + } + + /** + * Returns the absolute file path. + * @param string $fileName Specifies the file name to return the path to. + * @return string + */ + public function getFilePath($fileName = null) + { + if ($fileName === null) { + $fileName = $this->fileName; + } + + $directory = $this->theme->getPath() . '/' . $this->dirName . '/'; + $filePath = $directory . $fileName; + + // Limit paths to those under the theme's assets directory + if (!PathResolver::within($filePath, $directory)) { + return false; + } + + return PathResolver::resolve($filePath); + } + + /** + * Returns a list of editable asset extensions. + * The list can be overridden with the cms.editableAssetTypes configuration option. + * @return array + */ + public static function getEditableExtensions() + { + $defaultTypes = ['css', 'js', 'less', 'sass', 'scss']; + + $configTypes = Config::get('cms.editableAssetTypes'); + if (!$configTypes) { + return $defaultTypes; + } + + return $configTypes; + } +} diff --git a/modules/cms/classes/AutoDatasource.php b/modules/cms/classes/AutoDatasource.php new file mode 100644 index 0000000..1266511 --- /dev/null +++ b/modules/cms/classes/AutoDatasource.php @@ -0,0 +1,569 @@ + $datasource] + * @return void + */ + public function __construct(array $datasources) + { + $this->datasources = $datasources; + + $this->activeDatasourceKey = array_keys($datasources)[0]; + + $this->populateCache(); + + $this->postProcessor = new Processor; + } + + /** + * Populate the local cache of paths available in each datasource + * + * @param boolean $refresh Default false, set to true to force the cache to be rebuilt + * @return void + */ + protected function populateCache($refresh = false) + { + $pathCache = []; + foreach ($this->datasources as $datasource) { + // Remove any existing cache data + if ($refresh && $this->allowCacheRefreshes) { + Cache::forget($datasource->getPathsCacheKey()); + } + + // Load the cache + $pathCache[] = Cache::rememberForever($datasource->getPathsCacheKey(), function () use ($datasource) { + return $datasource->getAvailablePaths(); + }); + } + $this->pathCache = $pathCache; + } + + /** + * Check to see if the specified datasource has the provided Halcyon Model + * + * @param string $source The string key of the datasource to check + * @param Model $model The Halcyon Model to check for + * @return boolean + */ + public function sourceHasModel(string $source, Model $model) + { + if (!$model->exists) { + return false; + } + + $result = false; + + $sourcePaths = $this->getSourcePaths($source); + + if (!empty($sourcePaths)) { + // Generate the path + list($name, $extension) = $model->getFileNameParts(); + $path = $this->makeFilePath($model->getObjectTypeDirName(), $name, $extension); + + // Deleted paths are included as being handled by a datasource + // The functionality built on this will need to make sure they + // include deleted records when actually performing syncing actions + if (isset($sourcePaths[$path])) { + $result = true; + } + } + + return $result; + } + + /** + * Get the available paths for the specified datasource key + * + * @param string $source The string key of the datasource to check + * @return void + */ + public function getSourcePaths(string $source) + { + $result = []; + + $keys = array_keys($this->datasources); + if (in_array($source, $keys)) { + // Get the datasource's cache index key + $cacheIndex = array_search($source, $keys); + + // Return the available paths + $result = $this->pathCache[$cacheIndex]; + } + + return $result; + } + + /** + * Forces all operations in a provided closure to run within a selected datasource. + * + * @param string $source + * @param \Closure $closure + * @return mixed + */ + public function usingSource(string $source, \Closure $closure) + { + if (!array_key_exists($source, $this->datasources)) { + throw new ApplicationException('Invalid datasource specified.'); + } + + // Setup the datasource for single source mode + $previousSource = $this->activeDatasourceKey; + $this->activeDatasourceKey = $source; + $this->singleDatasourceMode = true; + + // Execute the callback + $return = $closure->call($this); + + // Restore the datasource to auto mode + $this->singleDatasourceMode = false; + $this->activeDatasourceKey = $previousSource; + + return $return; + } + + /** + * Push the provided model to the specified datasource + * + * @param Model $model The Halcyon Model to push + * @param string $source The string key of the datasource to use + * @return void + */ + public function pushToSource(Model $model, string $source) + { + $this->usingSource($source, function () use ($model) { + $datasource = $this->getActiveDatasource(); + + // Get the path parts + $dirName = $model->getObjectTypeDirName(); + list($fileName, $extension) = $model->getFileNameParts(); + + // Get the file content + $content = $datasource->getPostProcessor()->processUpdate($model->newQuery(), []); + + // Perform an update on the selected datasource (will insert if it doesn't exist) + $this->update($dirName, $fileName, $extension, $content); + }); + } + + /** + * Remove the provided model from the specified datasource + * + * @param Model $model The Halcyon model to remove + * @param string $source The string key of the datasource to use + * @return void + */ + public function removeFromSource(Model $model, string $source) + { + $this->usingSource($source, function () use ($model) { + $datasource = $this->getActiveDatasource(); + + // Get the path parts + $dirName = $model->getObjectTypeDirName(); + list($fileName, $extension) = $model->getFileNameParts(); + + // Perform a forced delete on the selected datasource to ensure it's removed + $this->forceDelete($dirName, $fileName, $extension); + }); + } + + /** + * Get the appropriate datasource for the provided path + * + * @param string $path + * @return Datasource + */ + protected function getDatasourceForPath(string $path) + { + // Always return the active datasource when singleDatasourceMode is enabled + if ($this->singleDatasourceMode) { + return $this->getActiveDatasource(); + } + + // Default to the last datasource provided + $datasourceIndex = count($this->datasources) - 1; + + $isDeleted = false; + + foreach ($this->pathCache as $i => $paths) { + if (isset($paths[$path])) { + $datasourceIndex = $i; + + // Set isDeleted to the inverse of the the path's existance flag + $isDeleted = !$paths[$path]; + + // Break on first datasource that can handle the path + break; + } + } + + if ($isDeleted) { + throw new Exception("$path is deleted"); + } + + $datasourceIndex = array_keys($this->datasources)[$datasourceIndex]; + + return $this->datasources[$datasourceIndex]; + } + + /** + * Get all valid paths for the provided directory, removing any paths marked as deleted + * + * @param string $dirName + * @param array $options Array of options, [ + * 'extensions' => ['htm', 'md', 'twig'], // Extensions to search for + * 'fileMatch' => '*gr[ae]y', // Shell matching pattern to match the filename against using the fnmatch function + * ]; + * @return array $paths ["$dirName/path/1.md", "$dirName/path/2.md"] + */ + protected function getValidPaths(string $dirName, array $options = []) + { + // Initialize result set + $paths = []; + + // Reverse the order of the sources so that earlier + // sources are prioritized over later sources + $pathsCache = array_reverse($this->pathCache); + + // Get paths available in the provided dirName, allowing proper prioritization of earlier datasources + foreach ($pathsCache as $datasourceKey => $sourcePaths) { + // Only look at the active datasource if singleDatasourceMode is enabled + if ($this->singleDatasourceMode && $datasourceKey !== $this->activeDatasourceKey) { + continue; + } + + $paths = array_merge($paths, array_filter($sourcePaths, function ($path) use ($dirName, $options) { + $basePath = $dirName . '/'; + + $inPath = starts_with($path, $basePath); + + // Check the fileMatch if provided as an option + $fnMatch = !empty($options['fileMatch']) ? fnmatch($options['fileMatch'], str_after($path, $basePath)) : true; + + // Check the extension if provided as an option + $validExt = !empty($options['extensions']) && is_array($options['extensions']) ? in_array(pathinfo($path, PATHINFO_EXTENSION), $options['extensions']) : true; + + return $inPath && $fnMatch && $validExt; + }, ARRAY_FILTER_USE_KEY)); + } + + // Filter out 'deleted' paths: + $paths = array_filter($paths, function ($value) { + return (bool) $value; + }); + + // Return just an array of paths + return array_keys($paths); + } + + /** + * Helper to make file path. + * + * @param string $dirName + * @param string $fileName + * @param string $extension + * @return string + */ + protected function makeFilePath(string $dirName, string $fileName, string $extension) + { + return $dirName . '/' . $fileName . '.' . $extension; + } + + /** + * Get the datasource for use with CRUD operations + * + * @return DatasourceInterface + */ + protected function getActiveDatasource() + { + return $this->datasources[$this->activeDatasourceKey]; + } + + /** + * Returns a single template. + * + * @param string $dirName + * @param string $fileName + * @param string $extension + * @return mixed + */ + public function selectOne(string $dirName, string $fileName, string $extension) + { + try { + $path = $this->makeFilePath($dirName, $fileName, $extension); + $result = $this->getDatasourceForPath($path)->selectOne($dirName, $fileName, $extension); + + // if result = null, this means that + // - a: The requested record doesn't exist + // - b: The requested record exists, but is marked deleted + // - c: The requested record is reported to exist in a datasource that it doesn't actually exist in + if (is_null($result)) { + foreach ($this->pathCache as $paths) { + // If the path is reported to exist here (and isn't marked deleted) even though the previous attempt + // returned nothing, then the paths cache needs to be rebuilt and we should try again + if (@$paths[$path]) { + $this->populateCache(true); + $result = $this->getDatasourceForPath($path)->selectOne($dirName, $fileName, $extension); + break; + } + } + } + } catch (Exception $ex) { + $result = null; + } + + return $result; + } + + /** + * Returns all templates. + * + * @param string $dirName + * @param array $options Array of options, [ + * 'columns' => ['fileName', 'mtime', 'content'], // Only return specific columns + * 'extensions' => ['htm', 'md', 'twig'], // Extensions to search for + * 'fileMatch' => '*gr[ae]y', // Shell matching pattern to match the filename against using the fnmatch function + * 'orders' => false // Not implemented + * 'limit' => false // Not implemented + * 'offset' => false // Not implemented + * ]; + * @return array + */ + public function select(string $dirName, array $options = []) + { + // Handle fileName listings through just the cache + if (@$options['columns'] === ['fileName']) { + // Return just filenames of the valid paths for this directory + $results = array_values(array_map(function ($path) use ($dirName) { + return ['fileName' => str_after($path, $dirName . '/')]; + }, $this->getValidPaths($dirName, $options))); + + // Retrieve full listings from datasources directly + } else { + // Initialize result set + $sourceResults = []; + + // Reverse the order of the sources so that earlier + // sources are prioritized over later sources + $datasources = array_reverse($this->datasources); + + foreach ($datasources as $datasource) { + $sourceResults = array_merge($sourceResults, $datasource->select($dirName, $options)); + } + + // Remove duplicate results prioritizing results from earlier datasources + $sourceResults = collect($sourceResults)->keyBy('fileName'); + + // Get a list of valid filenames from the list of valid paths for this directory + $validFiles = array_map(function ($path) use ($dirName) { + return str_after($path, $dirName . '/'); + }, $this->getValidPaths($dirName, $options)); + + // Filter out deleted paths + $results = array_values($sourceResults->filter(function ($value, $key) use ($validFiles) { + return in_array($key, $validFiles); + })->all()); + } + + return $results; + } + + /** + * Creates a new template, only inserts to the active datasource + * + * @param string $dirName + * @param string $fileName + * @param string $extension + * @param string $content + * @return bool + */ + public function insert(string $dirName, string $fileName, string $extension, string $content) + { + // Insert only on the active datasource + $result = $this->getActiveDatasource()->insert($dirName, $fileName, $extension, $content); + + // Refresh the cache + $this->populateCache(true); + + return $result; + } + + /** + * Updates an existing template. + * + * @param string $dirName + * @param string $fileName + * @param string $extension + * @param string $content + * @param string $oldFileName Defaults to null + * @param string $oldExtension Defaults to null + * @return int + */ + public function update(string $dirName, string $fileName, string $extension, string $content, $oldFileName = null, $oldExtension = null) + { + $searchFileName = $oldFileName ?: $fileName; + $searchExt = $oldExtension ?: $extension; + + // Ensure that files that are being renamed have their old names marked as deleted prior to inserting the renamed file + // Also ensure that the cache only gets updated at the end of this operation instead of twice, once here and again at the end + if ($searchFileName !== $fileName || $searchExt !== $extension) { + $this->allowCacheRefreshes = false; + $this->delete($dirName, $searchFileName, $searchExt); + $this->allowCacheRefreshes = true; + } + + $datasource = $this->getActiveDatasource(); + + if (!empty($datasource->selectOne($dirName, $searchFileName, $searchExt))) { + $result = $datasource->update($dirName, $fileName, $extension, $content, $oldFileName, $oldExtension); + } else { + $result = $datasource->insert($dirName, $fileName, $extension, $content); + } + + // Refresh the cache + $this->populateCache(true); + + return $result; + } + + /** + * Run a delete statement against the datasource, only runs delete on active datasource + * + * @param string $dirName + * @param string $fileName + * @param string $extension + * @return int + */ + public function delete(string $dirName, string $fileName, string $extension) + { + try { + // Delete from only the active datasource + if ($this->forceDeleting) { + $this->getActiveDatasource()->forceDelete($dirName, $fileName, $extension); + } else { + $this->getActiveDatasource()->delete($dirName, $fileName, $extension); + } + } + catch (Exception $ex) { + // Only attempt to do an insert-delete when not force deleting the record + if (!$this->forceDeleting) { + // Check to see if this is a valid path to delete + $path = $this->makeFilePath($dirName, $fileName, $extension); + + if (in_array($path, $this->getValidPaths($dirName))) { + // Retrieve the current record + $record = $this->selectOne($dirName, $fileName, $extension); + + // Insert the current record into the active datasource so we can mark it as deleted + $this->insert($dirName, $fileName, $extension, $record['content']); + + // Perform the deletion on the newly inserted record + $this->delete($dirName, $fileName, $extension); + } else { + throw (new DeleteFileException)->setInvalidPath($path); + } + } + } + + // Refresh the cache + $this->populateCache(true); + } + + /** + * Return the last modified date of an object + * + * @param string $dirName + * @param string $fileName + * @param string $extension + * @return int + */ + public function lastModified(string $dirName, string $fileName, string $extension) + { + return $this->getDatasourceForPath($this->makeFilePath($dirName, $fileName, $extension))->lastModified($dirName, $fileName, $extension); + } + + /** + * Generate a cache key unique to this datasource. + * + * @param string $name + * @return string + */ + public function makeCacheKey($name = '') + { + $key = ''; + foreach ($this->datasources as $datasource) { + $key .= $datasource->makeCacheKey($name) . '-'; + } + $key .= $name; + + return crc32($key); + } + + /** + * Generate a paths cache key unique to this datasource + * + * @return string + */ + public function getPathsCacheKey() + { + return 'halcyon-datastore-auto'; + } + + /** + * Get all available paths within this datastore + * + * @return array $paths ['path/to/file1.md' => true (path can be handled and exists), 'path/to/file2.md' => false (path can be handled but doesn't exist)] + */ + public function getAvailablePaths() + { + $paths = []; + $datasources = array_reverse($this->datasources); + foreach ($datasources as $datasource) { + $paths = array_merge($paths, $datasource->getAvailablePaths()); + } + return $paths; + } +} diff --git a/modules/cms/classes/CmsCompoundObject.php b/modules/cms/classes/CmsCompoundObject.php new file mode 100644 index 0000000..254cf1e --- /dev/null +++ b/modules/cms/classes/CmsCompoundObject.php @@ -0,0 +1,498 @@ + [] + ]; + + /** + * @var array Contains the view bag properties. + * This property is used by the page editor internally. + */ + public $viewBag = []; + + /** + * @var array The attributes that are mass assignable. + */ + protected $fillable = [ + 'markup', + 'settings', + 'code' + ]; + + /** + * The methods that should be returned from the collection of all objects. + * + * @var array + */ + protected $passthru = [ + 'lists', + 'where', + 'sortBy', + 'whereComponent', + 'withComponent' + ]; + + /** + * @var bool Model supports code and settings sections. + */ + protected $isCompoundObject = true; + + /** + * @var array|null Cache for component properties. + */ + protected static $objectComponentPropertyMap; + + /** + * @var mixed Cache store for the getViewBag method. + */ + protected $viewBagCache = false; + + /** + * Triggered after the object is loaded. + * @return void + */ + public function afterFetch() + { + $this->parseComponentSettings(); + $this->validateSettings(); + $this->parseSettings(); + } + + /** + * Triggered when the model is saved. + * @return void + */ + public function beforeSave() + { + // Ignore line-ending only changes to the code property to avoid triggering safe mode + // when no changes actually occurred, it was just the browser reformatting line endings + if ($this->isDirty('code')) { + $oldCode = str_replace("\n", "\r\n", str_replace("\r", '', $this->getOriginal('code'))); + $newCode = str_replace("\n", "\r\n", str_replace("\r", '', $this->code)); + if ($oldCode === $newCode) { + $this->code = $this->getOriginal('code'); + } + } + + $this->checkSafeMode(); + } + + /** + * Create a new Collection instance. + * + * @param array $models + * @return \October\Rain\Halcyon\Collection + */ + public function newCollection(array $models = []) + { + return new CmsObjectCollection($models); + } + + /** + * If the model is loaded with an invalid INI section, the invalid content will be + * passed as a special attribute. Look for it, then locate the failure reason. + * @return void + */ + protected function validateSettings() + { + if (isset($this->attributes[SectionParser::ERROR_INI])) { + CmsException::mask($this, 200); + Ini::parse($this->attributes[SectionParser::ERROR_INI]); + CmsException::unmask(); + } + } + + /** + * Parses the settings array. + * Child classes can override this method in order to update the content + * of the $settings property after the object is loaded from a file. + * @return void + */ + protected function parseSettings() + { + $this->fillViewBagArray(); + } + + /** + * This method checks if safe mode is enabled by config, and the code + * attribute is modified and populated. If so an exception is thrown. + * @return void + */ + protected function checkSafeMode() + { + if (CmsHelpers::safeModeEnabled() && $this->isDirty('code') && strlen(trim($this->code))) { + throw new ApplicationException(Lang::get('cms::lang.cms_object.safe_mode_enabled')); + } + } + + // + // Components + // + + /** + * Runs components defined in the settings + * Process halts if a component returns a value + * @return void + */ + public function runComponents() + { + foreach ($this->components as $component) { + if ($event = $component->fireEvent('component.beforeRun', [], true)) { + return $event; + } + + if ($result = $component->onRun()) { + return $result; + } + + if ($event = $component->fireEvent('component.run', [], true)) { + return $event; + } + } + } + + /** + * Parse component sections. + * Replace the multiple component sections with a single "components" + * element in the $settings property. + * @return void + */ + protected function parseComponentSettings() + { + $this->settings = $this->getSettingsAttribute(); + + $manager = ComponentManager::instance(); + $components = []; + foreach ($this->settings as $setting => $value) { + if (!is_array($value)) { + continue; + } + + $settingParts = explode(' ', $setting); + $settingName = $settingParts[0]; + + $components[$setting] = $value; + unset($this->settings[$setting]); + } + + $this->settings['components'] = $components; + } + + /** + * Returns a component by its name. + * This method is used only in the back-end and for internal system needs when + * the standard way to access components is not an option. + * @param string $componentName Specifies the component name. + * @return \Cms\Classes\ComponentBase Returns the component instance or null. + */ + public function getComponent($componentName) + { + if (!($componentSection = $this->hasComponent($componentName))) { + return null; + } + + return ComponentManager::instance()->makeComponent( + $componentName, + null, + $this->settings['components'][$componentSection] + ); + } + + /** + * Checks if the object has a component with the specified name. + * @param string $componentName Specifies the component name. + * @return mixed Return false or the full component name used on the page (it could include the alias). + */ + public function hasComponent($componentName) + { + $componentManager = ComponentManager::instance(); + $componentName = $componentManager->resolve($componentName); + + foreach ($this->settings['components'] as $sectionName => $values) { + $result = $sectionName; + + if ($sectionName == $componentName) { + return $result; + } + + $parts = explode(' ', $sectionName); + if (count($parts) > 1) { + $sectionName = trim($parts[0]); + + if ($sectionName == $componentName) { + return $result; + } + } + + $sectionName = $componentManager->resolve($sectionName); + if ($sectionName == $componentName) { + return $result; + } + } + + return false; + } + + /** + * Returns component property names and values. + * This method implements caching and can be used in the run-time on the front-end. + * @param string $componentName Specifies the component name. + * @return array Returns an associative array with property names in the keys and property values in the values. + */ + public function getComponentProperties($componentName) + { + $key = md5($this->theme->getPath()).'component-properties'; + + if (self::$objectComponentPropertyMap !== null) { + $objectComponentMap = self::$objectComponentPropertyMap; + } + else { + $cached = Cache::get($key, false); + $unserialized = $cached ? @unserialize(@base64_decode($cached)) : false; + $objectComponentMap = $unserialized ?: []; + if ($objectComponentMap) { + self::$objectComponentPropertyMap = $objectComponentMap; + } + } + + $objectCode = $this->getBaseFileName(); + + if (array_key_exists($objectCode, $objectComponentMap)) { + if (array_key_exists($componentName, $objectComponentMap[$objectCode])) { + return $objectComponentMap[$objectCode][$componentName]; + } + + return []; + } + + if (!isset($this->settings['components'])) { + $objectComponentMap[$objectCode] = []; + } + else { + foreach ($this->settings['components'] as $name => $settings) { + $nameParts = explode(' ', $name); + if (count($nameParts) > 1) { + $name = trim($nameParts[0]); + } + + $component = $this->getComponent($name); + if (!$component) { + continue; + } + + $componentProperties = []; + $propertyDefinitions = $component->defineProperties(); + foreach ($propertyDefinitions as $propertyName => $propertyInfo) { + $componentProperties[$propertyName] = $component->property($propertyName); + } + + $objectComponentMap[$objectCode][$name] = $componentProperties; + } + } + + self::$objectComponentPropertyMap = $objectComponentMap; + + $expiresAt = now()->addMinutes(Config::get('cms.parsedPageCacheTTL', 10)); + Cache::put($key, base64_encode(serialize($objectComponentMap)), $expiresAt); + + if (array_key_exists($componentName, $objectComponentMap[$objectCode])) { + return $objectComponentMap[$objectCode][$componentName]; + } + + return []; + } + + /** + * Clears the object cache. + * @param \Cms\Classes\Theme $theme Specifies a parent theme. + * @return void + */ + public static function clearCache($theme) + { + $key = md5($theme->getPath()).'component-properties'; + Cache::forget($key); + } + + // + // View Bag + // + + /** + * Returns the configured view bag component. + * This method is used only in the back-end and for internal system needs when + * the standard way to access components is not an option. + * @return \Cms\Components\ViewBag Returns the view bag component instance. + */ + public function getViewBag() + { + if ($this->viewBagCache !== false) { + return $this->viewBagCache; + } + + $componentName = 'viewBag'; + + if (!isset($this->settings['components'][$componentName])) { + $viewBag = new ViewBag(null, []); + $viewBag->name = $componentName; + + return $this->viewBagCache = $viewBag; + } + + return $this->viewBagCache = $this->getComponent($componentName); + } + + /** + * Copies view bag properties to the view bag array. + * This is required for the back-end editors. + * @return void + */ + protected function fillViewBagArray() + { + $viewBag = $this->getViewBag(); + foreach ($viewBag->getProperties() as $name => $value) { + $this->viewBag[$name] = $value; + } + + $this->fireEvent('cmsObject.fillViewBagArray'); + } + + // + // Twig + // + + /** + * Returns the Twig content string + * @return string + */ + public function getTwigContent() + { + return $this->markup; + } + + /** + * Returns Twig node tree generated from the object's markup. + * This method is used by the system internally and shouldn't + * participate in the front-end request processing. + * @link http://twig.sensiolabs.org/doc/internals.html Twig internals + * @param mixed $markup Specifies the markup content. + * Use FALSE to load the content from the markup section. + * @return Twig\Node\ModuleNode A node tree + */ + public function getTwigNodeTree($markup = false) + { + $loader = new TwigLoader(); + $twig = new TwigEnvironment($loader, []); + $twig->addExtension(new CmsTwigExtension()); + $twig->addExtension(new SystemTwigExtension); + + $stream = $twig->tokenize(new TwigSource($markup === false ? $this->markup : $markup, 'getTwigNodeTree')); + return $twig->parse($stream); + } + + // + // Magic + // + + /** + * Implements getter functionality for visible properties defined in + * the settings section or view bag array. + */ + public function __get($name) + { + if (is_array($this->settings) && array_key_exists($name, $this->settings)) { + return $this->settings[$name]; + } + + if (is_array($this->viewBag) && array_key_exists($name, $this->viewBag)) { + return $this->viewBag[$name]; + } + + return parent::__get($name); + } + + /** + * Dynamically set attributes on the model. + * + * @param string $key + * @param mixed $value + * @return void + */ + public function __set($key, $value) + { + parent::__set($key, $value); + + if (array_key_exists($key, $this->settings)) { + $this->settings[$key] = $this->attributes[$key]; + } + } + + /** + * Determine if an attribute exists on the object. + * + * @param string $key + * @return bool + */ + public function __isset($key) + { + if (parent::__isset($key) === true) { + return true; + } + + if (isset($this->viewBag[$key]) === true) { + return true; + } + + return isset($this->settings[$key]); + } + + /** + * Dynamically handle calls into the query instance. + * + * @param string $method + * @param array $parameters + * @return mixed + */ + public function __call($method, $parameters) + { + if (in_array($method, $this->passthru)) { + $collection = $this->get(); + return call_user_func_array([$collection, $method], $parameters); + } + + return parent::__call($method, $parameters); + } +} diff --git a/modules/cms/classes/CmsController.php b/modules/cms/classes/CmsController.php new file mode 100644 index 0000000..6f9e1fb --- /dev/null +++ b/modules/cms/classes/CmsController.php @@ -0,0 +1,52 @@ +extendableConstruct(); + } + + /** + * Extend this object properties upon construction. + * @param Closure $callback + */ + public static function extend(Closure $callback) + { + self::extendableExtendCallback($callback); + } + + /** + * Finds and serves the request using the primary controller. + * @param string $url Specifies the requested page URL. + * If the parameter is omitted, the current URL used. + * @return string Returns the processed page content. + */ + public function run($url = '/') + { + return App::make(Controller::class)->run($url); + } +} diff --git a/modules/cms/classes/CmsException.php b/modules/cms/classes/CmsException.php new file mode 100644 index 0000000..602a990 --- /dev/null +++ b/modules/cms/classes/CmsException.php @@ -0,0 +1,236 @@ + 'General', + 200 => 'INI Settings', + 300 => 'PHP Content', + 400 => 'Twig Template' + ]; + + /** + * Creates the CMS exception object. + * @param mixed $message The message to display as a string, or a CmsCompoundObject that is used + * for using this exception as a mask for another exception type. + * @param int $code Error code to specify the exception type: + * Error 100: A general exception. + * Error 200: Mask the exception as INI content. + * Error 300: Mask the exception as PHP content. + * Error 400: Mask the exception as Twig content. + * @param \Exception $previous Previous exception. + */ + public function __construct($message = null, $code = 100, Exception $previous = null) + { + if ($message instanceof CmsCompoundObject || $message instanceof ComponentPartial) { + $this->compoundObject = $message; + $message = ''; + } + + if (isset(static::$errorCodes[$code])) { + $this->errorType = static::$errorCodes[$code]; + } + + parent::__construct($message, $code, $previous); + } + + /** + * Checks some conditions to confirm error has actually occurred + * due to the CMS template code, not some external code. If the error + * has occurred in external code, the function will return false. Otherwise return + * true and modify the exception by overriding it's content, line and message values + * to be accurate against a CMS object properties. + * @param \Exception $exception The exception to modify. + * @return bool + */ + public function processCompoundObject(Exception $exception) + { + switch ($this->code) { + case 200: + $result = $this->processIni($exception); + break; + + case 300: + $result = $this->processPhp($exception); + break; + + case 400: + $result = $this->processTwig($exception); + break; + } + if ($result !== false) { + $this->file = $this->compoundObject->getFilePath(); + + if (File::isFile($this->file) && is_readable($this->file)) { + $this->fileContent = @file($this->file); + } + } + + return $result; + } + + /** + * Override properties of an exception specific to the INI section + * of a CMS object. + * @param \Exception $exception The exception to modify. + * @return bool + */ + protected function processIni(Exception $exception) + { + $message = $exception->getMessage(); + + /* + * Expecting: syntax error, unexpected '!' in Unknown on line 4 + */ + if (!starts_with($message, 'syntax error')) { + return false; + } + if (strpos($message, 'Unknown') === false) { + return false; + } + if (strpos($exception->getFile(), 'Ini.php') === false) { + return false; + } + + /* + * Line number from parse_ini_string() error. + * The last word should contain the line number. + */ + $parts = explode(' ', $message); + $line = array_pop($parts); + $this->line = (int)$line; + + // Find where the ini settings section begins + $offsetArray = SectionParser::parseOffset($this->compoundObject->getContent()); + $this->line += $offsetArray['settings']; + + $this->message = $message; + + // Account for line 0 + $this->line--; + + return true; + } + + /** + * Override properties of an exception specific to the PHP section + * of a CMS object. + * @param \Exception $exception The exception to modify. + * @return bool + */ + protected function processPhp(Exception $exception) + { + /* + * Fatal Error + */ + if ($exception instanceof \Symfony\Component\Debug\Exception\FatalErrorException) { + $check = false; + + // Expected: */modules/cms/classes/CodeParser.php(165) : eval()'d code line 7 + if (strpos($exception->getFile(), 'CodeParser.php')) { + $check = true; + } + + // Expected: */storage/cms/cache/39/05/home.htm.php + if (strpos($exception->getFile(), $this->compoundObject->getFileName() . '.php')) { + $check = true; + } + + if (!$check) { + return false; + } + /* + * Errors occurring the PHP code base class (Cms\Classes\CodeBase) + */ + } + else { + $trace = $exception->getTrace(); + if (isset($trace[1]['class'])) { + $class = $trace[1]['class']; + if (!is_subclass_of($class, CodeBase::class)) { + return false; + } + } + } + + $this->message = $exception->getMessage(); + + // Offset the php, namespace and bracket tags from the generated class. + $this->line = $exception->getLine() - 3; + + // Find where the php code section begins + $offsetArray = SectionParser::parseOffset($this->compoundObject->getContent()); + $this->line += $offsetArray['code']; + + // Account for line 0 + $this->line--; + + return true; + } + + /** + * Override properties of an exception specific to the Twig section + * of a CMS object. + * @param \Exception $exception The exception to modify. + * @return bool + */ + protected function processTwig(Exception $exception) + { + // Must be a Twig related exception + if (!$exception instanceof TwigError) { + return false; + } + + $this->message = $exception->getRawMessage(); + $this->line = $exception->getTemplateLine(); + + // Find where the twig markup section begins + $offsetArray = SectionParser::parseOffset($this->compoundObject->getContent()); + $this->line += $offsetArray['markup']; + + // Account for line 0 + $this->line--; + + return true; + } + + /** + * Masks this exception with the details of the supplied. The error code for + * this exception object will determine how the supplied exception is used. + * Error 100: A general exception. Inherits \System\Classes\ExceptionBase::applyMask() + * Error 200: Mask the exception as INI content. + * Error 300: Mask the exception as PHP content. + * Error 400: Mask the exception as Twig content. + * @param \Exception $exception The exception to modify. + * @return void + */ + public function applyMask(Exception $exception) + { + if ($this->code == 100 || $this->processCompoundObject($exception) === false) { + parent::applyMask($exception); + return; + } + } +} diff --git a/modules/cms/classes/CmsObject.php b/modules/cms/classes/CmsObject.php new file mode 100644 index 0000000..eb4e73e --- /dev/null +++ b/modules/cms/classes/CmsObject.php @@ -0,0 +1,362 @@ +getDefaultDatasource()) { + return; + } + + $defaultTheme = App::runningInBackend() + ? Theme::getEditThemeCode() + : Theme::getActiveThemeCode(); + + Theme::load($defaultTheme); + + $resolver->setDefaultDatasource($defaultTheme); + } + + /** + * Loads the object from a file. + * This method is used in the CMS back-end. It doesn't use any caching. + * @param mixed $theme Specifies the theme the object belongs to. + * @param string $fileName Specifies the file name, with the extension. + * The file name can contain only alphanumeric symbols, dashes and dots. + * @return mixed Returns a CMS object instance or null if the object wasn't found. + */ + public static function load($theme, $fileName) + { + return static::inTheme($theme)->find($fileName); + } + + /** + * Loads the object from a cache. + * This method is used by the CMS in the runtime. If the cache is not found, it is created. + * @param \Cms\Classes\Theme $theme Specifies the theme the object belongs to. + * @param string $fileName Specifies the file name, with the extension. + * @return mixed Returns a CMS object instance or null if the object wasn't found. + */ + public static function loadCached($theme, $fileName) + { + return static::inTheme($theme) + ->remember(Config::get('cms.parsedPageCacheTTL', 1440)) + ->find($fileName) + ; + } + + /** + * Returns the list of objects in the specified theme. + * This method is used internally by the system. + * @param \Cms\Classes\Theme $theme Specifies a parent theme. + * @param boolean $skipCache Indicates if objects should be reloaded from the disk bypassing the cache. + * @return Collection Returns a collection of CMS objects. + */ + public static function listInTheme($theme, $skipCache = false) + { + $result = []; + $instance = static::inTheme($theme); + + if ($skipCache) { + $result = $instance->get(); + } else { + $items = $instance->newQuery()->lists('fileName'); + + $loadedItems = []; + foreach ($items as $item) { + $loadedItems[] = static::loadCached($theme, $item); + } + + $result = $instance->newCollection($loadedItems); + } + + /** + * @event cms.object.listInTheme + * Provides opportunity to filter the items returned by a call to CmsObject::listInTheme() + * + * Parameters provided are `$cmsObject` (the object being listed) and `$objectList` (a collection of the CmsObjects being returned). + * > Note: The `$objectList` provided is an object reference to a CmsObjectCollection, to make changes you must use object modifying methods. + * + * Example usage (filters all pages except for the 404 page on the CMS Maintenance mode settings page): + * + * // Extend only the Settings Controller + * \System\Controllers\Settings::extend(function ($controller) { + * // Listen for the cms.object.listInTheme event + * \Event::listen('cms.object.listInTheme', function ($cmsObject, $objectList) { + * // Get the current context of the Settings Manager to ensure we only affect what we need to affect + * $context = \System\Classes\SettingsManager::instance()->getContext(); + * if ($context->owner === 'october.cms' && $context->itemCode === 'maintenance_settings') { + * // Double check that this is a Page List that we're modifying + * if ($cmsObject instanceof \Cms\Classes\Page) { + * // Perform filtering with an original-object modifying method as $objectList is passed by reference (being that it's an object) + * foreach ($objectList as $index => $page) { + * if ($page->url !== '/404') { + * $objectList->forget($index); + * } + * } + * } + * } + * }); + * }); + */ + Event::fire('cms.object.listInTheme', [$instance, $result]); + + return $result; + } + + /** + * Prepares the theme datasource for the model. + * @param \Cms\Classes\Theme $theme Specifies a parent theme. + * @return $this + */ + public static function inTheme($theme) + { + if (is_string($theme)) { + $theme = Theme::load($theme); + } + + return static::on($theme->getDirName()); + } + + /** + * Save the object to the theme. + * + * @param array $options + * @return bool + */ + public function save(array $options = null) + { + try { + parent::save($options); + } + catch (Exception $ex) { + $this->throwHalcyonSaveException($ex); + } + } + + /** + * Returns the CMS theme this object belongs to. + * @return \Cms\Classes\Theme + */ + public function getThemeAttribute() + { + if ($this->themeCache !== null) { + return $this->themeCache; + } + + $themeName = $this->getDatasourceName() + ?: static::getDatasourceResolver()->getDefaultDatasource(); + + return $this->themeCache = Theme::load($themeName); + } + + /** + * Returns the full path to the template file corresponding to this object. + * @param string $fileName + * @return string + */ + public function getFilePath($fileName = null) + { + if ($fileName === null) { + $fileName = $this->fileName; + } + + $directory = $this->theme->getPath() . '/' . $this->getObjectTypeDirName() . '/'; + $filePath = $directory . $fileName; + + // Limit paths to those under the corresponding theme directory + if (!PathResolver::within($filePath, $directory)) { + return false; + } + + return PathResolver::resolve($filePath); + } + + /** + * Returns the file name. + * @return string + */ + public function getFileName() + { + return $this->fileName; + } + + /** + * Returns the file name without the extension. + * @return string + */ + public function getBaseFileName() + { + $pos = strrpos($this->fileName, '.'); + if ($pos === false) { + return $this->fileName; + } + + return substr($this->fileName, 0, $pos); + } + + /** + * Helper for {{ page.id }} or {{ layout.id }} twig vars + * Returns a unique string for this object. + * @return string + */ + public function getId() + { + return str_replace('/', '-', $this->getBaseFileName()); + } + + /** + * Returns the file content. + * @return string + */ + public function getContent() + { + return $this->content; + } + + /** + * Returns the Twig content string. + * @return string + */ + public function getTwigContent() + { + return $this->content; + } + + /** + * Returns the key used by the Twig cache. + * @return string + */ + public function getTwigCacheKey() + { + $key = $this->getFilePath(); + + if ($event = $this->fireEvent('cmsObject.getTwigCacheKey', compact('key'), true)) { + $key = $event; + } + + return $key; + } + + // + // Internals + // + + /** + * Converts an exception type thrown by Halcyon to a native CMS exception. + * @param Exception $ex + */ + protected function throwHalcyonSaveException(Exception $ex) + { + if ($ex instanceof \October\Rain\Halcyon\Exception\MissingFileNameException) { + throw new ValidationException([ + 'fileName' => Lang::get('cms::lang.cms_object.file_name_required') + ]); + } + elseif ($ex instanceof \October\Rain\Halcyon\Exception\InvalidExtensionException) { + throw new ValidationException(['fileName' => + Lang::get('cms::lang.cms_object.invalid_file_extension', [ + 'allowed' => implode(', ', $ex->getAllowedExtensions()), + 'invalid' => $ex->getInvalidExtension() + ]) + ]); + } + elseif ($ex instanceof \October\Rain\Halcyon\Exception\InvalidFileNameException) { + throw new ValidationException([ + 'fileName' => Lang::get('cms::lang.cms_object.invalid_file', ['name'=>$ex->getInvalidFileName()]) + ]); + } + elseif ($ex instanceof \October\Rain\Halcyon\Exception\FileExistsException) { + throw new ApplicationException( + Lang::get('cms::lang.cms_object.file_already_exists', ['name' => $ex->getInvalidPath()]) + ); + } + elseif ($ex instanceof \October\Rain\Halcyon\Exception\CreateDirectoryException) { + throw new ApplicationException( + Lang::get('cms::lang.cms_object.error_creating_directory', ['name' => $ex->getInvalidPath()]) + ); + } + elseif ($ex instanceof \October\Rain\Halcyon\Exception\CreateFileException) { + throw new ApplicationException( + Lang::get('cms::lang.cms_object.error_saving', ['name' => $ex->getInvalidPath()]) + ); + } + else { + throw $ex; + } + } +} diff --git a/modules/cms/classes/CmsObjectCollection.php b/modules/cms/classes/CmsObjectCollection.php new file mode 100644 index 0000000..2105789 --- /dev/null +++ b/modules/cms/classes/CmsObjectCollection.php @@ -0,0 +1,119 @@ +filter(function ($object) use ($components, $callback) { + $hasComponent = false; + + foreach ((array) $components as $componentName) { + if (!$callback && $object->hasComponent($componentName)) { + $hasComponent = true; + } + + if ($callback && ($component = $object->getComponent($componentName))) { + $hasComponent = call_user_func($callback, $component) ?: $hasComponent; + } + } + + return $hasComponent; + }); + } + + /** + * Returns objects whose properties match the supplied value. + * + * Note that this deviates from Laravel 6's Illuminate\Support\Traits\EnumeratesValues::where() method signature, + * which uses ($key, $operator = null, $value = null) as parameters and that this class extends. + * + * To ensure backwards compatibility with our current Halcyon functionality, this method retains the original + * parameters and functions the same way as before, with handling for the $value and $strict parameters to ensure + * they match the previously expected formats. This means that you cannot use operators for "where" queries on + * CMS object collections. + * + * @param string $property + * @param string $value + * @param bool $strict + * @return static + */ + public function where($property, $value = null, $strict = null) + { + if (empty($value) || !is_string($value)) { + throw new ApplicationException('You must provide a string value to compare with when executing a "where" ' + . 'query for CMS object collections.'); + } + + if (!isset($strict) || !is_bool($strict)) { + $strict = true; + } + + return $this->filter(function ($object) use ($property, $value, $strict) { + if (!array_key_exists($property, $object->settings)) { + return false; + } + + return $strict + ? $object->settings[$property] === $value + : $object->settings[$property] == $value; + }); + } + + /** + * Returns objects whose component properties match the supplied value. + * @param mixed $components + * @param string $property + * @param string $value + * @param bool $strict + * @return static + */ + public function whereComponent($components, $property, $value, $strict = false) + { + return $this->filter(function ($object) use ($components, $property, $value, $strict) { + + $hasComponent = false; + + foreach ((array) $components as $componentName) { + if (!$componentAlias = $object->hasComponent($componentName)) { + continue; + } + + $componentSettings = array_get($object->settings, 'components', []); + + if (!array_key_exists($componentAlias, $componentSettings)) { + continue; + } + + $settings = $componentSettings[$componentAlias]; + + if (!array_key_exists($property, $settings)) { + continue; + } + + if ( + ($strict && $settings[$property] === $value) || + (!$strict && $settings[$property] == $value) + ) { + $hasComponent = true; + } + } + + return $hasComponent; + }); + } +} diff --git a/modules/cms/classes/CodeBase.php b/modules/cms/classes/CodeBase.php new file mode 100644 index 0000000..777f7ff --- /dev/null +++ b/modules/cms/classes/CodeBase.php @@ -0,0 +1,168 @@ +page = $page; + $this->layout = $layout; + $this->controller = $controller; + + parent::__construct(); + } + + /** + * This event is triggered when all components are initialized and before AJAX is handled. + * The layout's onInit method triggers before the page's onInit method. + */ + public function onInit() + { + } + + /** + * This event is triggered in the beginning of the execution cycle. + * The layout's onStart method triggers before the page's onStart method. + */ + public function onStart() + { + } + + /** + * This event is triggered in the end of the execution cycle, but before the page is displayed. + * The layout's onEnd method triggers after the page's onEnd method. + */ + public function onEnd() + { + } + + /** + * ArrayAccess implementation + */ + public function offsetSet($offset, $value) + { + $this->controller->vars[$offset] = $value; + } + + /** + * ArrayAccess implementation + */ + public function offsetExists($offset) + { + return isset($this->controller->vars[$offset]); + } + + /** + * ArrayAccess implementation + */ + public function offsetUnset($offset) + { + unset($this->controller->vars[$offset]); + } + + /** + * ArrayAccess implementation + */ + public function offsetGet($offset) + { + return $this->controller->vars[$offset] ?? null; + } + + /** + * Dynamically handle calls into the controller instance. + * @param string $method + * @param array $parameters + * @return mixed + */ + public function __call($method, $parameters) + { + if ($this->methodExists($method)) { + return call_user_func_array([$this, $method], $parameters); + } + + return call_user_func_array([$this->controller, $method], $parameters); + } + + /** + * This object is referenced as $this->page in Cms\Classes\ComponentBase, + * so to avoid $this->page->page this method will proxy there. This is also + * used as a helper for accessing controller variables/components easier + * in the page code, eg. $this->foo instead of $this['foo'] + * @param string $name + * @return void + */ + public function __get($name) + { + if (isset($this->page->components[$name]) || isset($this->layout->components[$name])) { + return $this[$name]; + } + + if (($value = $this->page->{$name}) !== null) { + return $value; + } + + if (array_key_exists($name, $this->controller->vars)) { + return $this[$name]; + } + + return null; + } + + /** + * This will set a property on the CMS Page object. + * @param string $name + * @param mixed $value + * @return void + */ + public function __set($name, $value) + { + return $this->page->{$name} = $value; + } + + /** + * This will check if a property is set on the CMS Page object. + * @param string $name + * @return bool + */ + public function __isset($name) + { + if (isset($this->page->components[$name]) || isset($this->layout->components[$name])) { + return true; + } + + if (isset($this->page->{$name})) { + return true; + } + + return array_key_exists($name, $this->controller->vars); + } +} diff --git a/modules/cms/classes/CodeParser.php b/modules/cms/classes/CodeParser.php new file mode 100644 index 0000000..f0cdb13 --- /dev/null +++ b/modules/cms/classes/CodeParser.php @@ -0,0 +1,382 @@ +object = $object; + $this->filePath = $object->getFilePath(); + $this->dataCacheKey = Config::get('cache.codeParserDataCacheKey', 'cms-php-file-data'); + } + + /** + * Parses the CMS object's PHP code section and returns an array with the following keys: + * - className + * - filePath (path to the parsed PHP file) + * - offset (PHP section offset in the template file) + * - source ('parser', 'request-cache', or 'cache') + * @return array + */ + public function parse() + { + /* + * If the object has already been parsed in this request return the cached data. + */ + if (array_key_exists($this->filePath, self::$cache)) { + self::$cache[$this->filePath]['source'] = 'request-cache'; + return self::$cache[$this->filePath]; + } + + /* + * Try to load the parsed data from the cache + */ + $path = $this->getCacheFilePath(); + + $result = [ + 'filePath' => $path, + 'className' => null, + 'source' => null, + 'offset' => 0 + ]; + + /* + * There are two types of possible caching scenarios, either stored + * in the cache itself, or stored as a cache file. In both cases, + * make sure the cache is not stale and use it. + */ + if (is_file($path)) { + $cachedInfo = $this->getCachedFileInfo(); + $hasCache = $cachedInfo !== null; + + /* + * Valid cache, return result + */ + if ($hasCache && $cachedInfo['mtime'] == $this->object->mtime) { + $result['className'] = $cachedInfo['className']; + $result['source'] = 'cache'; + + return self::$cache[$this->filePath] = $result; + } + + /* + * Cache expired, cache file not stale, refresh cache and return result + */ + if (!$hasCache && filemtime($path) >= $this->object->mtime) { + $className = $this->extractClassFromFile($path); + if ($className) { + $result['className'] = $className; + $result['source'] = 'file-cache'; + + $this->storeCachedInfo($result); + return $result; + } + } + } + + $result['className'] = $this->rebuild($path); + $result['source'] = 'parser'; + + $this->storeCachedInfo($result); + return $result; + } + + /** + * Rebuilds the current file cache. + * @param string The path in which the cached file should be stored + */ + protected function rebuild($path) + { + $uniqueName = str_replace('.', '', uniqid('', true)).'_'.md5(mt_rand()); + $className = 'Cms'.$uniqueName.'Class'; + + $body = $this->object->code; + $body = preg_replace('/^\s*function/m', 'public function', $body); + + $namespaces = []; + $pattern = '/(use\s+[a-z0-9_\\\\]+(\s+as\s+[a-z0-9_]+)?;(\r\n|\n)?)/mi'; + preg_match_all($pattern, $body, $namespaces); + $body = preg_replace($pattern, '', $body); + + $parentClass = $this->object->getCodeClassParent(); + if ($parentClass !== null) { + $parentClass = ' extends '.$parentClass; + } + + $fileContents = 'validate($fileContents); + + $this->makeDirectorySafe(dirname($path)); + + $this->writeContentSafe($path, $fileContents); + + return $className; + } + + /** + * Runs the object's PHP file and returns the corresponding object. + * @param \Cms\Classes\Page $page Specifies the CMS page. + * @param \Cms\Classes\Layout $layout Specifies the CMS layout. + * @param \Cms\Classes\Controller $controller Specifies the CMS controller. + * @return mixed + */ + public function source($page, $layout, $controller) + { + $data = $this->parse(); + $className = $data['className']; + + if (!class_exists($className)) { + require_once $data['filePath']; + } + + if (!class_exists($className) && ($data = $this->handleCorruptCache($data))) { + $className = $data['className']; + } + + return new $className($page, $layout, $controller); + } + + /** + * In some rare cases the cache file will not contain the class + * name we expect. When this happens, destroy the corrupt file, + * flush the request cache, and repeat the cycle. + * @return void + */ + protected function handleCorruptCache($data) + { + $path = array_get($data, 'filePath', $this->getCacheFilePath()); + + if (is_file($path)) { + if (($className = $this->extractClassFromFile($path)) && class_exists($className)) { + $data['className'] = $className; + return $data; + } + + @unlink($path); + } + + unset(self::$cache[$this->filePath]); + + return $this->parse(); + } + + // + // Cache + // + + /** + * Stores result data inside cache. + * @param array $result + * @return void + */ + protected function storeCachedInfo($result) + { + $cacheItem = $result; + $cacheItem['mtime'] = $this->object->mtime; + + $cached = $this->getCachedInfo() ?: []; + $cached[$this->filePath] = $cacheItem; + + $expiresAt = now()->addMinutes(1440); + Cache::put($this->dataCacheKey, base64_encode(serialize($cached)), $expiresAt); + + self::$cache[$this->filePath] = $result; + } + + /** + * Returns path to the cached parsed file + * @return string + */ + protected function getCacheFilePath() + { + $hash = md5($this->filePath); + $result = storage_path().'/cms/cache/'; + $result .= substr($hash, 0, 2).'/'; + $result .= substr($hash, 2, 2).'/'; + $result .= basename($this->filePath); + $result .= '.php'; + + return $result; + } + + /** + * Returns information about all cached files. + * @return mixed Returns an array representing the cached data or NULL. + */ + protected function getCachedInfo() + { + $cached = Cache::get($this->dataCacheKey, false); + + if ( + $cached !== false && + ($cached = @unserialize(@base64_decode($cached))) !== false + ) { + return $cached; + } + + return null; + } + + /** + * Returns information about a cached file + * @return integer + */ + protected function getCachedFileInfo() + { + $cached = $this->getCachedInfo(); + + if ($cached !== null && array_key_exists($this->filePath, $cached)) { + return $cached[$this->filePath]; + } + + return null; + } + + // + // Helpers + // + + /** + * Evaluates PHP content in order to detect syntax errors. + * The method handles PHP errors and throws exceptions. + */ + protected function validate($php) + { + eval('?>'.$php); + } + + /** + * Extracts the class name from a cache file + * @return string + */ + protected function extractClassFromFile($path) + { + $fileContent = file_get_contents($path); + $matches = []; + $pattern = '/Cms\S+_\S+Class/'; + preg_match($pattern, $fileContent, $matches); + + if (!empty($matches[0])) { + return $matches[0]; + } + + return null; + } + + /** + * Writes content with concurrency support and cache busting + * This work is based on the Twig\Cache\FilesystemCache class + */ + protected function writeContentSafe($path, $content) + { + $count = 0; + $tmpFile = tempnam(dirname($path), basename($path)); + + if (@file_put_contents($tmpFile, $content) === false) { + throw new SystemException(Lang::get('system::lang.file.create_fail', ['name'=>$tmpFile])); + } + + while (!@rename($tmpFile, $path)) { + usleep(rand(50000, 200000)); + + if ($count++ > 10) { + throw new SystemException(Lang::get('system::lang.file.create_fail', ['name'=>$path])); + } + } + + File::chmod($path); + + /* + * Compile cached file into bytecode cache + */ + if (Config::get('cms.forceBytecodeInvalidation', false)) { + $opcache_enabled = ini_get('opcache.enable'); + $opcache_path = trim(ini_get('opcache.restrict_api')); + + if (!empty($opcache_path) && !starts_with(__FILE__, $opcache_path)) { + $opcache_enabled = false; + } + + if (function_exists('opcache_invalidate') && $opcache_enabled) { + opcache_invalidate($path, true); + } + elseif (function_exists('apc_compile_file')) { + apc_compile_file($path); + } + } + } + + /** + * Make directory with concurrency support + */ + protected function makeDirectorySafe($dir) + { + $count = 0; + + if (is_dir($dir)) { + if (!is_writable($dir)) { + throw new SystemException(Lang::get('system::lang.directory.create_fail', ['name'=>$dir])); + } + + return; + } + + while (!is_dir($dir) && !@mkdir($dir, 0777, true)) { + usleep(rand(50000, 200000)); + + if ($count++ > 10) { + throw new SystemException(Lang::get('system::lang.directory.create_fail', ['name'=>$dir])); + } + } + + File::chmodRecursive($dir); + } +} diff --git a/modules/cms/classes/ComponentBase.php b/modules/cms/classes/ComponentBase.php new file mode 100644 index 0000000..230a32c --- /dev/null +++ b/modules/cms/classes/ComponentBase.php @@ -0,0 +1,329 @@ +page = $cmsObject; + $this->controller = $cmsObject->controller; + } + + $this->properties = $this->validateProperties($properties); + + $className = Str::normalizeClassName(get_called_class()); + $this->dirName = strtolower(str_replace('\\', '/', $className)); + $this->assetPath = Config::get('cms.pluginsPath', '/plugins').dirname(dirname($this->dirName)); + + parent::__construct(); + } + + /** + * Returns information about this component, including name and description. + */ + abstract public function componentDetails(); + + /** + * Returns the absolute component path. + */ + public function getPath() + { + return plugins_path() . $this->dirName; + } + + /** + * Executed when this component is first initialized, before AJAX requests. + */ + public function init() + { + } + + /** + * Executed when this component is bound to a page or layout, part of + * the page life cycle. + */ + public function onRun() + { + } + + /** + * Executed when this component is rendered on a page or layout. + */ + public function onRender() + { + } + + /** + * Renders a requested partial in context of this component, + * see Cms\Classes\Controller@renderPartial for usage. + */ + public function renderPartial() + { + $this->controller->setComponentContext($this); + $result = call_user_func_array([$this->controller, 'renderPartial'], func_get_args()); + $this->controller->setComponentContext(null); + return $result; + } + + /** + * Executes the event cycle when running an AJAX handler. + * @return boolean Returns true if the handler was found. Returns false otherwise. + */ + public function runAjaxHandler($handler) + { + /** + * @event cms.component.beforeRunAjaxHandler + * Provides an opportunity to modify an AJAX request to a component before it is processed by the component + * + * The parameter provided is `$handler` (the requested AJAX handler to be run) + * + * Example usage (forwards AJAX handlers to a backend widget): + * + * Event::listen('cms.component.beforeRunAjaxHandler', function ((\Cms\Classes\ComponentBase) $component, (string) $handler) { + * if (strpos($handler, '::')) { + * list($componentAlias, $handlerName) = explode('::', $handler); + * if ($componentAlias === $this->getBackendWidgetAlias()) { + * return $this->backendControllerProxy->runAjaxHandler($handler); + * } + * } + * }); + * + * Or + * + * $this->controller->bindEvent('component.beforeRunAjaxHandler', function ((string) $handler) { + * if (strpos($handler, '::')) { + * list($componentAlias, $handlerName) = explode('::', $handler); + * if ($componentAlias === $this->getBackendWidgetAlias()) { + * return $this->backendControllerProxy->runAjaxHandler($handler); + * } + * } + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.component.beforeRunAjaxHandler', [$handler])) { + return $event; + } + + $result = $this->$handler(); + + /** + * @event cms.component.runAjaxHandler + * Provides an opportunity to modify an AJAX request to a component after it is processed by the component + * + * The parameters provided are `$handler` (the requested AJAX handler to be run) and `$result` (the result of the component processing the request) + * + * Example usage (Logs requests and their response): + * + * Event::listen('cms.component.beforeRunHandler', function ((\Cms\Classes\ComponentBase) $component, (string) $handler, (mixed) $result) { + * if (in_array($handler, $interceptHandlers)) { + * return 'request has been intercepted, original response: ' . json_encode($result); + * } + * }); + * + * Or + * + * $this->controller->bindEvent('componenet.beforeRunAjaxHandler', function ((string) $handler, (mixed) $result) { + * if (in_array($handler, $interceptHandlers)) { + * return 'request has been intercepted, original response: ' . json_encode($result); + * } + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.component.runAjaxHandler', [$handler, $result])) { + return $event; + } + + return $result; + } + + // + // External properties + // + + /* + * Description on how to access external property names. + * + * # When + * pageNumber = "7" + * $this->propertyName('pageNumber'); // Returns NULL + * $this->paramName('pageNumber'); // Returns NULL + * + * # When + * pageNumber = "{{ :page }}" + * + * $this->propertyName('pageNumber'); // Returns ":page" + * $this->paramName('pageNumber'); // Returns "page" + * + * # When + * pageNumber = "{{ page }}" + * + * $this->propertyName('pageNumber'); // Returns "page" + * $this->paramName('pageNumber'); // Returns NULL + */ + + /** + * Sets names used by external properties. + * @param array $names The key should be the property name, + * the value should be the external property name. + * @return void + */ + public function setExternalPropertyNames(array $names) + { + $this->externalPropertyNames = $names; + } + + /** + * Sets an external property name. + * @param string $name Property name + * @param string $extName External property name + * @return string + */ + public function setExternalPropertyName($name, $extName) + { + return $this->externalPropertyNames[$name] = $extName; + } + + /** + * Returns the external property name when the property value is an external property reference. + * Otherwise the default value specified is returned. + * @param string $name The property name + * @param mixed $default + * @return string + */ + public function propertyName($name, $default = null) + { + return array_get($this->externalPropertyNames, $name, $default); + } + + /** + * Returns the external property name when the property value is a routing parameter reference. + * Otherwise the default value specified is returned. + * @param string $name The property name + * @param mixed $default + * @return string + */ + public function paramName($name, $default = null) + { + if (($extName = $this->propertyName($name)) && substr($extName, 0, 1) == ':') { + return substr($extName, 1); + } + + return $default; + } + + // + // Magic methods + // + + /** + * Dynamically handle calls into the controller instance. + * @param string $method + * @param array $parameters + * @return mixed + */ + public function __call($method, $parameters) + { + try { + return parent::__call($method, $parameters); + } + catch (BadMethodCallException $ex) { + } + + if (method_exists($this->controller, $method)) { + return call_user_func_array([$this->controller, $method], $parameters); + } + + throw new BadMethodCallException(Lang::get('cms::lang.component.method_not_found', [ + 'name' => get_class($this), + 'method' => $method + ])); + } + + /** + * Returns the component's alias, used by __SELF__ + */ + public function __toString() + { + return $this->alias; + } +} diff --git a/modules/cms/classes/ComponentHelpers.php b/modules/cms/classes/ComponentHelpers.php new file mode 100644 index 0000000..04660d7 --- /dev/null +++ b/modules/cms/classes/ComponentHelpers.php @@ -0,0 +1,129 @@ + 'oc.alias', + 'title' => Lang::get('cms::lang.component.alias'), + 'description' => Lang::get('cms::lang.component.alias_description'), + 'type' => 'string', + 'validationPattern' => '^(@)?[a-zA-Z]+[0-9a-z\_]*$', + 'validationMessage' => Lang::get('cms::lang.component.validation_message'), + 'required' => true, + 'showExternalParam' => false + ]; + $result[] = $property; + } + + $properties = $component->defineProperties(); + if (is_array($properties)) { + foreach ($properties as $name => $params) { + $property = [ + 'property' => $name, + 'title' => array_get($params, 'title', $name), + 'type' => array_get($params, 'type', 'string'), + 'showExternalParam' => array_get($params, 'showExternalParam', true) + ]; + + foreach ($params as $name => $value) { + if (isset($property[$name])) { + continue; + } + $property[$name] = $value; + } + + /* + * Translate human values + */ + $translate = ['title', 'description', 'options', 'group', 'validationMessage']; + foreach ($property as $name => $value) { + if (!in_array($name, $translate)) { + continue; + } + + if (is_array($value)) { + array_walk($property[$name], function (&$_value, $key) { + $_value = Lang::get($_value); + }); + } + else { + $property[$name] = Lang::get($value); + } + } + + $result[] = $property; + } + } + + if ($returnArray) { + return $result; + } + + return json_encode($result); + } + + /** + * Returns a component property values. + * @param mixed $component The component object + * @return mixed + */ + public static function getComponentPropertyValues($component) + { + $result = []; + + $result['oc.alias'] = $component->alias; + + $properties = $component->defineProperties(); + foreach ($properties as $name => $params) { + $result[$name] = $component->property($name); + } + + return json_encode($result); + } + + /** + * Returns a component name. + * @param mixed $component The component object + * @return string + */ + public static function getComponentName($component) + { + $details = $component->componentDetails(); + $name = $details['name'] ?? 'cms::lang.component.unnamed'; + + return Lang::get($name); + } + + /** + * Returns a component description. + * @param mixed $component The component object + * @return string + */ + public static function getComponentDescription($component) + { + $details = $component->componentDetails(); + $name = $details['description'] ?? 'cms::lang.component.no_description'; + + return Lang::get($name); + } +} diff --git a/modules/cms/classes/ComponentManager.php b/modules/cms/classes/ComponentManager.php new file mode 100644 index 0000000..47d3d00 --- /dev/null +++ b/modules/cms/classes/ComponentManager.php @@ -0,0 +1,239 @@ +callbacks as $callback) { + $callback($this); + } + + /* + * Load plugin components + */ + $pluginManager = PluginManager::instance(); + $plugins = $pluginManager->getPlugins(); + + foreach ($plugins as $plugin) { + $components = $plugin->registerComponents(); + if (!is_array($components)) { + continue; + } + + foreach ($components as $className => $code) { + $this->registerComponent($className, $code, $plugin); + } + } + } + + /** + * Manually registers a component for consideration. Usage: + * + * ComponentManager::registerComponents(function ($manager) { + * $manager->registerComponent('October\Demo\Components\Test', 'testComponent'); + * }); + * + * @param callable $definitions + * @return array Array values are class names. + */ + public function registerComponents(callable $definitions) + { + $this->callbacks[] = $definitions; + } + + /** + * Registers a single component. + */ + public function registerComponent($className, $code = null, $plugin = null) + { + if (!$this->classMap) { + $this->classMap = []; + } + + if (!$this->codeMap) { + $this->codeMap = []; + } + + if (!$code) { + $code = Str::getClassId($className); + } + + if ($code == 'viewBag' && $className != 'Cms\Components\ViewBag') { + throw new SystemException(sprintf( + 'The component code viewBag is reserved. Please use another code for the component class %s.', + $className + )); + } + + $className = Str::normalizeClassName($className); + $this->codeMap[$code] = $className; + $this->classMap[$className] = $code; + if ($plugin !== null) { + $this->pluginMap[$className] = $plugin; + } + } + + /** + * Returns a list of registered components. + * @return array Array keys are codes, values are class names. + */ + public function listComponents() + { + if ($this->codeMap === null) { + $this->loadComponents(); + } + + return $this->codeMap; + } + + /** + * Returns an array of all component detail definitions. + * @return array Array keys are component codes, values are the details defined in the component. + */ + public function listComponentDetails() + { + if ($this->detailsCache !== null) { + return $this->detailsCache; + } + + $details = []; + foreach ($this->listComponents() as $componentAlias => $componentClass) { + $details[$componentAlias] = $this->makeComponent($componentClass)->componentDetails(); + } + + return $this->detailsCache = $details; + } + + /** + * Returns a class name from a component code + * Normalizes a class name or converts an code to it's class name. + * @return string The class name resolved, or null. + */ + public function resolve($name) + { + $codes = $this->listComponents(); + + if (isset($codes[$name])) { + return $codes[$name]; + } + + $name = Str::normalizeClassName($name); + if (isset($this->classMap[$name])) { + return $name; + } + + return null; + } + + /** + * Checks to see if a component has been registered. + * @param string $name A component class name or code. + * @return bool Returns true if the component is registered, otherwise false. + */ + public function hasComponent($name) + { + $className = $this->resolve($name); + if (!$className) { + return false; + } + + return isset($this->classMap[$className]); + } + + /** + * Makes a component object with properties set. + * + * @param string $name A component class name or code. + * @param CmsObject $cmsObject The Cms object that spawned this component. + * @param array $properties The properties set by the Page or Layout. + * @param bool $isSoftComponent Defines if this is a soft component. + * + * @return ComponentBase The component object. + * @throws SystemException If the (hard) component cannot be found or is not registered. + */ + public function makeComponent($name, $cmsObject = null, $properties = [], $isSoftComponent = false) + { + $className = $this->resolve(ltrim($name, '@')); + + if (!$className && !$isSoftComponent) { + throw new SystemException(sprintf( + 'Class name is not registered for the component "%s". Check the component plugin.', + $name + )); + } + + if (!class_exists($className) && !$isSoftComponent) { + throw new SystemException(sprintf( + 'Component class not found "%s". Check the component plugin.', + $className + )); + } + + if (class_exists($className)) { + $component = App::make($className, [$cmsObject, $properties]); + $component->name = $name; + + return $component; + } + } + + /** + * Returns a parent plugin for a specific component object. + * @param mixed $component A component to find the plugin for. + * @return mixed Returns the plugin object or null. + */ + public function findComponentPlugin($component) + { + $className = Str::normalizeClassName(get_class($component)); + if (isset($this->pluginMap[$className])) { + return $this->pluginMap[$className]; + } + + return null; + } +} diff --git a/modules/cms/classes/ComponentPartial.php b/modules/cms/classes/ComponentPartial.php new file mode 100644 index 0000000..68a444b --- /dev/null +++ b/modules/cms/classes/ComponentPartial.php @@ -0,0 +1,262 @@ +component = $component; + + parent::__construct(); + } + + /** + * Loads the object from a file. + * This method is used in the CMS back-end. It doesn't use any caching. + * @param \Cms\Classes\ComponentBase $component Specifies the component the object belongs to. + * @param string $fileName Specifies the file name, with the extension. + * The file name can contain only alphanumeric symbols, dashes and dots. + * @return mixed Returns a CMS object instance or null if the object wasn't found. + */ + public static function load($component, $fileName) + { + return (new static($component))->find($fileName); + } + + /** + * There is not much point caching a component partial, so this behavior + * reverts to a regular load call. + * @param \Cms\Classes\ComponentBase $component + * @param string $fileName + * @return mixed + */ + public static function loadCached($component, $fileName) + { + return static::load($component, $fileName); + } + + /** + * Checks if a partial override exists in the supplied theme and returns it. + * Since the beginning of time, October inconsistently checked for overrides + * using the component alias exactly, resulting in a folder with uppercase + * characters, subsequently this method checks for both variants. + * + * @param \Cms\Classes\Theme $theme + * @param \Cms\Classes\ComponentBase $component + * @param string $fileName + * @return mixed + */ + public static function loadOverrideCached($theme, $component, $fileName) + { + $partial = Partial::loadCached($theme, strtolower($component->alias) . '/' . $fileName); + + if ($partial === null) { + $partial = Partial::loadCached($theme, $component->alias . '/' . $fileName); + } + + return $partial; + } + + /** + * Find a single template by its file name. + * + * @param string $fileName + * @return mixed|static + */ + public function find($fileName) + { + $fileName = $this->validateFileName($fileName); + + $filePath = $this->getFilePath($fileName); + + if (!File::isFile($filePath)) { + return null; + } + + if (($content = @File::get($filePath)) === false) { + return null; + } + + $this->fileName = $fileName; + $this->mtime = File::lastModified($filePath); + $this->content = $content; + return $this; + } + + /** + * Returns true if the specific component contains a matching partial. + * @param \Cms\Classes\ComponentBase $component Specifies a component the file belongs to. + * @param string $fileName Specifies the file name to check. + * @return bool + */ + public static function check(ComponentBase $component, $fileName) + { + $partial = new static($component); + $filePath = $partial->getFilePath($fileName); + if (!strlen(File::extension($filePath))) { + $filePath .= '.'.$partial->getDefaultExtension(); + } + + return File::isFile($filePath); + } + + /** + * Checks the supplied file name for validity. + * @param string $fileName + * @return string + */ + protected function validateFileName($fileName) + { + if (!FileHelper::validatePath($fileName, $this->maxNesting)) { + throw new ApplicationException(Lang::get('cms::lang.cms_object.invalid_file', [ + 'name' => $fileName + ])); + } + + if (!strlen(File::extension($fileName))) { + $fileName .= '.'.$this->defaultExtension; + } + + return $fileName; + } + + /** + * Returns the file content. + * @return string + */ + public function getContent() + { + return $this->content; + } + + /** + * Returns the Twig content string. + * @return string + */ + public function getTwigContent() + { + return $this->content; + } + + /** + * Returns the key used by the Twig cache. + * @return string + */ + public function getTwigCacheKey() + { + return $this->getFilePath(); + } + + /** + * Returns the file name. + * @return string + */ + public function getFileName() + { + return $this->fileName; + } + + /** + * Returns the default extension used by this template. + * @return string + */ + public function getDefaultExtension() + { + return $this->defaultExtension; + } + + /** + * Returns the file name without the extension. + * @return string + */ + public function getBaseFileName() + { + $pos = strrpos($this->fileName, '.'); + if ($pos === false) { + return $this->fileName; + } + + return substr($this->fileName, 0, $pos); + } + + /** + * Returns the absolute file path. + * @param string $fileName Specifies the file name to return the path to. + * @return string + */ + public function getFilePath($fileName = null) + { + if ($fileName === null) { + $fileName = $this->fileName; + } + + $component = $this->component; + $path = $component->getPath().'/'.$fileName; + + /* + * Check the shared "/partials" directory for the partial + */ + if (!File::isFile($path)) { + $sharedDir = dirname($component->getPath()).'/partials'; + $sharedPath = $sharedDir.'/'.$fileName; + if (File::isFile($sharedPath)) { + return $sharedPath; + } + } + + return $path; + } +} diff --git a/modules/cms/classes/Content.php b/modules/cms/classes/Content.php new file mode 100644 index 0000000..a2ba639 --- /dev/null +++ b/modules/cms/classes/Content.php @@ -0,0 +1,73 @@ +parseMarkup(); + } + + /** + * Returns a default value for parsedMarkup attribute. + * @return string + */ + public function getParsedMarkupAttribute() + { + if (array_key_exists('parsedMarkup', $this->attributes)) { + return $this->attributes['parsedMarkup']; + } + + return $this->attributes['parsedMarkup'] = $this->parseMarkup(); + } + + /** + * Parses the content markup according to the file type. + * @return string + */ + public function parseMarkup() + { + $extension = strtolower(File::extension($this->fileName)); + + switch ($extension) { + case 'txt': + $result = htmlspecialchars($this->markup); + break; + case 'md': + $result = Markdown::parse($this->markup); + break; + default: + $result = $this->markup; + } + + return $result; + } +} diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php new file mode 100644 index 0000000..df0b5f4 --- /dev/null +++ b/modules/cms/classes/Controller.php @@ -0,0 +1,1594 @@ +theme = $theme ?: Theme::getActiveTheme(); + if (!$this->theme) { + throw new CmsException(Lang::get('cms::lang.theme.active.not_found')); + } + + $this->assetPath = Config::get('cms.themesPath', '/themes') . '/' . $this->theme->getDirName(); + $this->router = new Router($this->theme); + $this->partialStack = new PartialStack; + $this->initTwigEnvironment(); + + self::$instance = $this; + } + + /** + * Finds and serves the requested page. + * If the page cannot be found, returns the page with the URL /404. + * If the /404 page doesn't exist, returns the system 404 page. + * If the parameter is null, the current URL used. If it is not + * provided then '/' is used + * + * @param string|null $url Specifies the requested page URL. + * @return BaseResponse Returns the response to the provided URL + */ + public function run($url = '/') + { + if ($url === null) { + $url = Request::path(); + } + + if (trim($url) === '') { + $url = '/'; + } + + /* + * Hidden page + */ + $page = $this->router->findByUrl($url); + if ($page && $page->is_hidden && !BackendAuth::getUser()) { + $page = null; + } + + /* + * Maintenance mode + */ + if ( + MaintenanceSetting::isConfigured() && + MaintenanceSetting::get('is_enabled', false) && + !BackendAuth::getUser() + ) { + if (!Request::ajax()) { + $this->setStatusCode(503); + } + + $page = Page::loadCached($this->theme, MaintenanceSetting::get('cms_page')); + } + + /** + * @event cms.page.beforeDisplay + * Provides an opportunity to swap the page that gets displayed immediately after loading the page assigned to the URL. + * + * Example usage: + * + * Event::listen('cms.page.beforeDisplay', function ((\Cms\Classes\Controller) $controller, (string) $url, (\Cms\Classes\Page) $page) { + * if ($url === '/tricked-you') { + * return \Cms\Classes\Page::loadCached('trick-theme-code', 'page-file-name'); + * } + * }); + * + * Or + * + * $CmsController->bindEvent('page.beforeDisplay', function ((string) $url, (\Cms\Classes\Page) $page) { + * if ($url === '/tricked-you') { + * return \Cms\Classes\Page::loadCached('trick-theme-code', 'page-file-name'); + * } + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.page.beforeDisplay', [$url, $page])) { + if ($event instanceof Page) { + $page = $event; + } else { + return $event; + } + } + + /* + * If the page was not found, render the 404 page - either provided by the theme or the built-in one. + */ + if (!$page || $url === '404' || ($url === 'error' && !Config::get('app.debug', false))) { + if (!Request::ajax()) { + $this->setStatusCode(404); + } + + // Log the 404 request + if (!App::runningUnitTests()) { + RequestLog::add(); + } + + if (!$page = $this->router->findByUrl('/404')) { + return Response::make(View::make('cms::404'), $this->statusCode); + } + } + + /* + * Run the page + */ + $result = $this->runPage($page); + + /* + * Post-processing + */ + $result = $this->postProcessResult($page, $url, $result); + + /** + * @event cms.page.display + * Provides an opportunity to modify the response after the page for the URL has been processed. `$result` could be a string representing the HTML to be returned or it could be a Response instance. + * + * Example usage: + * + * Event::listen('cms.page.display', function ((\Cms\Classes\Controller) $controller, (string) $url, (\Cms\Classes\Page) $page, (mixed) $result) { + * if ($url === '/tricked-you') { + * return Response::make('Boo!', 200); + * } + * }); + * + * Or + * + * $CmsController->bindEvent('page.display', function ((string) $url, (\Cms\Classes\Page) $page, (mixed) $result) { + * if ($url === '/tricked-you') { + * return Response::make('Boo!', 200); + * } + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.page.display', [$url, $page, $result])) { + $result = $event; + } + + /* + * Prepare and return response + * @see \System\Traits\ResponseMaker + */ + return $this->makeResponse($result); + } + + /** + * Renders a page in its entirety, including component initialization. + * AJAX will be disabled for this process. + * @param string $pageFile Specifies the CMS page file name to run. + * @param array $parameters Routing parameters. + * @param \Cms\Classes\Theme $theme Theme object + */ + public static function render($pageFile, $parameters = [], $theme = null) + { + if (!$theme && (!$theme = Theme::getActiveTheme())) { + throw new CmsException(Lang::get('cms::lang.theme.active.not_found')); + } + + $controller = new static($theme); + $controller->getRouter()->setParameters($parameters); + + if (($page = Page::load($theme, $pageFile)) === null) { + throw new CmsException(Lang::get('cms::lang.page.not_found_name', ['name'=>$pageFile])); + } + + return $controller->runPage($page, false); + } + + /** + * Runs a page directly from its object and supplied parameters. + * @param \Cms\Classes\Page $page Specifies the CMS page to run. + * @return string + */ + public function runPage($page, $useAjax = true) + { + $this->page = $page; + + /* + * If the page doesn't refer any layout, create the fallback layout. + * Otherwise load the layout specified in the page. + */ + if (!$page->layout) { + $layout = Layout::initFallback($this->theme); + } + elseif (($layout = Layout::loadCached($this->theme, $page->layout)) === null) { + throw new CmsException(Lang::get('cms::lang.layout.not_found_name', ['name'=>$page->layout])); + } + + $this->layout = $layout; + + /* + * The 'this' variable is reserved for default variables. + */ + $this->vars['this'] = [ + 'page' => $this->page, + 'layout' => $this->layout, + 'theme' => $this->theme, + 'param' => $this->router->getParameters(), + 'controller' => $this, + 'environment' => App::environment(), + 'session' => App::make('session'), + ]; + + /* + * Check for the presence of validation errors in the session. + */ + $this->vars['errors'] = (Config::get('session.driver') && Session::has('errors')) + ? Session::get('errors') + : new \Illuminate\Support\ViewErrorBag; + + /* + * Handle AJAX requests and execute the life cycle functions + */ + $this->initCustomObjects(); + + $this->initComponents(); + + /* + * Give the layout and page an opportunity to participate + * after components are initialized and before AJAX is handled. + */ + if ($this->layoutObj) { + CmsException::mask($this->layout, 300); + $this->layoutObj->onInit(); + CmsException::unmask(); + } + + CmsException::mask($this->page, 300); + $this->pageObj->onInit(); + CmsException::unmask(); + + /** + * @event cms.page.init + * Provides an opportunity to return a custom response from Controller->runPage() before AJAX handlers are executed + * + * Example usage: + * + * Event::listen('cms.page.init', function ((\Cms\Classes\Controller) $controller, (\Cms\Classes\Page) $page) { + * return \Cms\Classes\Page::loadCached('trick-theme-code', 'page-file-name'); + * }); + * + * Or + * + * $CmsController->bindEvent('page.init', function ((\Cms\Classes\Page) $page) { + * return \Cms\Classes\Page::loadCached('trick-theme-code', 'page-file-name'); + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.page.init', [$page])) { + return $event; + } + + /* + * Execute AJAX event + */ + if ($useAjax && $ajaxResponse = $this->execAjaxHandlers()) { + return $ajaxResponse; + } + + /* + * Execute postback handler + */ + if ( + $useAjax && + ($handler = post('_handler')) && + $this->verifyCsrfToken() && + ($handlerResponse = $this->runAjaxHandler($handler)) && + $handlerResponse !== true + ) { + return $handlerResponse; + } + + /* + * Execute page lifecycle + */ + if ($cycleResponse = $this->execPageCycle()) { + return $cycleResponse; + } + + /** + * @event cms.page.beforeRenderPage + * Fires after AJAX handlers are dealt with and provides an opportunity to modify the page contents + * + * Example usage: + * + * Event::listen('cms.page.beforeRenderPage', function ((\Cms\Classes\Controller) $controller, (\Cms\Classes\Page) $page) { + * return 'Custom page contents'; + * }); + * + * Or + * + * $CmsController->bindEvent('page.beforeRenderPage', function ((\Cms\Classes\Page) $page) { + * return 'Custom page contents'; + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.page.beforeRenderPage', [$page])) { + $this->pageContents = $event; + } + else { + /* + * Render the page + */ + CmsException::mask($this->page, 400); + $this->loader->setObject($this->page); + $template = $this->twig->loadTemplate($this->page->getFilePath()); + $this->pageContents = $template->render($this->vars); + CmsException::unmask(); + } + + /* + * Render the layout + */ + CmsException::mask($this->layout, 400); + $this->loader->setObject($this->layout); + $template = $this->twig->loadTemplate($this->layout->getFilePath()); + $result = $template->render($this->vars); + CmsException::unmask(); + + return $result; + } + + /** + * Invokes the current page cycle without rendering the page, + * used by AJAX handler that may rely on the logic inside the action. + */ + public function pageCycle() + { + return $this->execPageCycle(); + } + + /** + * Executes the page life cycle. + * Creates an object from the PHP sections of the page and + * it's layout, then executes their life cycle functions. + */ + protected function execPageCycle() + { + /** + * @event cms.page.start + * Fires before all of the page & layout lifecycle handlers are run + * + * Example usage: + * + * Event::listen('cms.page.start', function ((\Cms\Classes\Controller) $controller) { + * return Response::make('Taking over the lifecycle!', 200); + * }); + * + * Or + * + * $CmsController->bindEvent('page.start', function () { + * return Response::make('Taking over the lifecycle!', 200); + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.page.start')) { + return $event; + } + + /* + * Run layout functions + */ + if ($this->layoutObj) { + CmsException::mask($this->layout, 300); + $response = ( + ($result = $this->layoutObj->onStart()) || + ($result = $this->layout->runComponents()) || + ($result = $this->layoutObj->onBeforePageStart()) + ) ? $result : null; + CmsException::unmask(); + + if ($response) { + return $response; + } + } + + /* + * Run page functions + */ + CmsException::mask($this->page, 300); + $response = ( + ($result = $this->pageObj->onStart()) || + ($result = $this->page->runComponents()) || + ($result = $this->pageObj->onEnd()) + ) ? $result : null; + CmsException::unmask(); + + if ($response) { + return $response; + } + + /* + * Run remaining layout functions + */ + if ($this->layoutObj) { + CmsException::mask($this->layout, 300); + $response = ($result = $this->layoutObj->onEnd()) ? $result : null; + CmsException::unmask(); + } + + /** + * @event cms.page.end + * Fires after all of the page & layout lifecycle handlers are run + * + * Example usage: + * + * Event::listen('cms.page.end', function ((\Cms\Classes\Controller) $controller) { + * return Response::make('Taking over the lifecycle!', 200); + * }); + * + * Or + * + * $CmsController->bindEvent('page.end', function () { + * return Response::make('Taking over the lifecycle!', 200); + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.page.end')) { + return $event; + } + + return $response; + } + + /** + * Post-processes page HTML code before it's sent to the client. + * Note for pre-processing see cms.template.processTwigContent event. + * @param \Cms\Classes\Page $page Specifies the current CMS page. + * @param string $url Specifies the current URL. + * @param string $content The page markup to post-process. + * @return string Returns the updated result string. + */ + protected function postProcessResult($page, $url, $content) + { + $content = MediaViewHelper::instance()->processHtml($content); + + /** + * @event cms.page.postprocess + * Provides opportunity to hook into the post-processing of page HTML code before being sent to the client. `$dataHolder` = {content: $htmlContent} + * + * Example usage: + * + * Event::listen('cms.page.postprocess', function ((\Cms\Classes\Controller) $controller, (string) $url, (\Cms\Classes\Page) $page, (object) $dataHolder) { + * return 'My custom content'; + * }); + * + * Or + * + * $CmsController->bindEvent('page.postprocess', function ((string) $url, (\Cms\Classes\Page) $page, (object) $dataHolder) { + * return 'My custom content'; + * }); + * + */ + $dataHolder = (object) ['content' => $content]; + $this->fireSystemEvent('cms.page.postprocess', [$url, $page, $dataHolder]); + + return $dataHolder->content; + } + + // + // Initialization + // + + /** + * Initializes the Twig environment and loader. + * Registers the \Cms\Twig\Extension object with Twig. + * @return void + */ + protected function initTwigEnvironment() + { + $this->loader = new TwigLoader; + + $useCache = !Config::get('cms.twigNoCache'); + $isDebugMode = Config::get('app.debug', false); + $strictVariables = Config::get('cms.enableTwigStrictVariables', false); + $strictVariables = $strictVariables ?? $isDebugMode; + $forceBytecode = Config::get('cms.forceBytecodeInvalidation', false); + + $options = [ + 'auto_reload' => true, + 'debug' => $isDebugMode, + 'strict_variables' => $strictVariables, + ]; + + if ($useCache) { + $options['cache'] = new TwigCacheFilesystem( + storage_path().'/cms/twig', + $forceBytecode ? TwigCacheFilesystem::FORCE_BYTECODE_INVALIDATION : 0 + ); + } + + $this->twig = new TwigEnvironment($this->loader, $options); + $this->twig->addExtension(new CmsTwigExtension($this)); + $this->twig->addExtension(new SystemTwigExtension); + $this->twig->addExtension(new SandboxExtension(new SecurityPolicy, true)); + + if ($isDebugMode) { + $this->twig->addExtension(new DebugExtension($this)); + } + } + + /** + * Initializes the custom layout and page objects. + * @return void + */ + protected function initCustomObjects() + { + $this->layoutObj = null; + + if (!$this->layout->isFallBack()) { + CmsException::mask($this->layout, 300); + $parser = new CodeParser($this->layout); + $this->layoutObj = $parser->source($this->page, $this->layout, $this); + CmsException::unmask(); + } + + CmsException::mask($this->page, 300); + $parser = new CodeParser($this->page); + $this->pageObj = $parser->source($this->page, $this->layout, $this); + CmsException::unmask(); + } + + /** + * Initializes the components for the layout and page. + * @return void + */ + protected function initComponents() + { + if (!$this->layout->isFallBack()) { + foreach ($this->layout->settings['components'] as $component => $properties) { + list($name, $alias) = strpos($component, ' ') + ? explode(' ', $component) + : [$component, $component]; + + $this->addComponent($name, $alias, $properties, true); + } + } + + foreach ($this->page->settings['components'] as $component => $properties) { + list($name, $alias) = strpos($component, ' ') + ? explode(' ', $component) + : [$component, $component]; + + $this->addComponent($name, $alias, $properties); + } + + /** + * @event cms.page.initComponents + * Fires after the components for the given page have been initialized + * + * Example usage: + * + * Event::listen('cms.page.initComponents', function ((\Cms\Classes\Controller) $controller, (\Cms\Classes\Page) $page, (\Cms\Classes\Layout) $layout) { + * \Log::info($page->title . ' components have been initialized'); + * }); + * + * Or + * + * $CmsController->bindEvent('page.initComponents', function ((\Cms\Classes\Page) $page, (\Cms\Classes\Layout) $layout) { + * \Log::info($page->title . ' components have been initialized'); + * }); + * + */ + $this->fireSystemEvent('cms.page.initComponents', [$this->page, $this->layout]); + } + + // + // AJAX + // + + /** + * Returns the AJAX handler for the current request, if available. + * @return string + */ + public function getAjaxHandler() + { + if (!Request::ajax() || Request::method() != 'POST') { + return null; + } + + if ($handler = Request::header('X_OCTOBER_REQUEST_HANDLER')) { + return trim($handler); + } + + return null; + } + + /** + * Executes the page, layout, component and plugin AJAX handlers. + * @return mixed Returns the AJAX Response object or null. + */ + protected function execAjaxHandlers() + { + if ($handler = $this->getAjaxHandler()) { + try { + /* + * Validate the handler name + */ + if (!preg_match('/^(?:\w+\:{2})?on[A-Z]{1}[\w+]*$/', $handler)) { + throw new CmsException(Lang::get('cms::lang.ajax_handler.invalid_name', ['name'=>$handler])); + } + + /* + * Validate the handler partial list + */ + if ($partialList = trim(Request::header('X_OCTOBER_REQUEST_PARTIALS'))) { + $partialList = explode('&', $partialList); + + foreach ($partialList as $partial) { + if (!preg_match('/^(?:\w+\:{2}|@)?[a-z0-9\_\-\.\/]+$/i', $partial)) { + throw new CmsException(Lang::get('cms::lang.partial.invalid_name', ['name'=>$partial])); + } + } + } + else { + $partialList = []; + } + + $responseContents = []; + + /* + * Execute the handler + */ + if (!$result = $this->runAjaxHandler($handler)) { + throw new CmsException(Lang::get('cms::lang.ajax_handler.not_found', ['name'=>$handler])); + } + + /* + * Render partials and return the response as array that will be converted to JSON automatically. + */ + foreach ($partialList as $partial) { + $responseContents[$partial] = $this->renderPartial($partial); + } + + /* + * If the handler returned a redirect, process the URL and dispose of it so + * framework.js knows to redirect the browser and not the request! + */ + if ($result instanceof RedirectResponse) { + $responseContents['X_OCTOBER_REDIRECT'] = $result->getTargetUrl(); + $result = null; + } + /* + * No redirect is used, look for any flash messages + */ + elseif (Request::header('X_OCTOBER_REQUEST_FLASH') && Flash::check()) { + $responseContents['X_OCTOBER_FLASH_MESSAGES'] = Flash::all(); + } + + /* + * If the handler returned an array, we should add it to output for rendering. + * If it is a string, add it to the array with the key "result". + * If an object, pass it to Laravel as a response object. + */ + if (is_array($result)) { + $responseContents = array_merge($responseContents, $result); + } + elseif (is_string($result)) { + $responseContents['result'] = $result; + } + elseif (is_object($result)) { + return $result; + } + + return Response::make($responseContents, $this->statusCode); + } + catch (ValidationException $ex) { + /* + * Handle validation errors + */ + $responseContents['X_OCTOBER_ERROR_FIELDS'] = $ex->getFields(); + $responseContents['X_OCTOBER_ERROR_MESSAGE'] = $ex->getMessage(); + throw new AjaxException($responseContents); + } + catch (Exception $ex) { + throw $ex; + } + } + + return null; + } + + /** + * Tries to find and run an AJAX handler in the page, layout, components and plugins. + * The method stops as soon as the handler is found. + * @param string $handler name of the ajax handler + * @return boolean Returns true if the handler was found. Returns false otherwise. + */ + protected function runAjaxHandler($handler) + { + /** + * @event cms.ajax.beforeRunHandler + * Provides an opportunity to modify an AJAX request + * + * The parameter provided is `$handler` (the requested AJAX handler to be run) + * + * Example usage (forwards AJAX handlers to a backend widget): + * + * Event::listen('cms.ajax.beforeRunHandler', function ((\Cms\Classes\Controller) $controller, (string) $handler) { + * if (strpos($handler, '::')) { + * list($componentAlias, $handlerName) = explode('::', $handler); + * if ($componentAlias === $this->getBackendWidgetAlias()) { + * return $this->backendControllerProxy->runAjaxHandler($handler); + * } + * } + * }); + * + * Or + * + * $this->controller->bindEvent('ajax.beforeRunHandler', function ((string) $handler) { + * if (strpos($handler, '::')) { + * list($componentAlias, $handlerName) = explode('::', $handler); + * if ($componentAlias === $this->getBackendWidgetAlias()) { + * return $this->backendControllerProxy->runAjaxHandler($handler); + * } + * } + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.ajax.beforeRunHandler', [$handler])) { + return $event; + } + + /* + * Process Component handler + */ + if (strpos($handler, '::')) { + list($componentName, $handlerName) = explode('::', $handler); + $componentObj = $this->findComponentByName($componentName); + + if ($componentObj && $componentObj->methodExists($handlerName)) { + $this->componentContext = $componentObj; + $result = $componentObj->runAjaxHandler($handlerName); + return $result ?: true; + } + } + /* + * Process code section handler + */ + else { + if (method_exists($this->pageObj, $handler)) { + $result = $this->pageObj->$handler(); + return $result ?: true; + } + + if (!$this->layout->isFallBack() && method_exists($this->layoutObj, $handler)) { + $result = $this->layoutObj->$handler(); + return $result ?: true; + } + + /* + * Cycle each component to locate a usable handler + */ + if (($componentObj = $this->findComponentByHandler($handler)) !== null) { + $this->componentContext = $componentObj; + $result = $componentObj->runAjaxHandler($handler); + return $result ?: true; + } + } + + /* + * Generic handler that does nothing + */ + if ($handler == 'onAjax') { + return true; + } + + return false; + } + + // + // Rendering + // + + /** + * Renders a requested page. + * The framework uses this method internally. + */ + public function renderPage() + { + $contents = $this->pageContents; + + /** + * @event cms.page.render + * Provides an opportunity to manipulate the page's rendered contents + * + * Example usage: + * + * Event::listen('cms.page.render', function ((\Cms\Classes\Controller) $controller, (string) $pageContents) { + * return 'My custom contents'; + * }); + * + * Or + * + * $CmsController->bindEvent('page.render', function ((string) $pageContents) { + * return 'My custom contents'; + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.page.render', [$contents])) { + return $event; + } + + return $contents; + } + + /** + * Renders a requested partial. + * The framework uses this method internally. + * @param string $name The view to load. + * @param array $parameters Parameter variables to pass to the view. + * @param bool $throwException Throw an exception if the partial is not found. + * @return mixed Partial contents or false if not throwing an exception. + */ + public function renderPartial($name, $parameters = [], $throwException = true) + { + $vars = $this->vars; + $this->vars = array_merge($this->vars, $parameters); + + /* + * Alias @ symbol for :: + */ + if (substr($name, 0, 1) == '@') { + $name = '::' . substr($name, 1); + } + + /** + * @event cms.page.beforeRenderPartial + * Provides an opportunity to manipulate the name of the partial being rendered before it renders + * + * Example usage: + * + * Event::listen('cms.page.beforeRenderPartial', function ((\Cms\Classes\Controller) $controller, (string) $partialName) { + * return Cms\Classes\Partial::loadCached($theme, 'custom-partial-name'); + * }); + * + * Or + * + * $CmsController->bindEvent('page.beforeRenderPartial', function ((string) $partialName) { + * return Cms\Classes\Partial::loadCached($theme, 'custom-partial-name'); + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.page.beforeRenderPartial', [$name])) { + $partial = $event; + } + /* + * Process Component partial + */ + elseif (strpos($name, '::') !== false) { + list($componentAlias, $partialName) = explode('::', $name); + + /* + * Component alias not supplied + */ + if (!strlen($componentAlias)) { + if ($this->componentContext !== null) { + $componentObj = $this->componentContext; + } + elseif (($componentObj = $this->findComponentByPartial($partialName)) === null) { + if ($throwException) { + throw new CmsException(Lang::get('cms::lang.partial.not_found_name', ['name'=>$partialName])); + } + + return false; + } + } + /* + * Component alias is supplied + */ + elseif (($componentObj = $this->findComponentByName($componentAlias)) === null) { + if ($throwException) { + throw new CmsException(Lang::get('cms::lang.component.not_found', ['name'=>$componentAlias])); + } + + return false; + } + + $partial = null; + $this->componentContext = $componentObj; + + /* + * Check if the theme has an override + */ + $partial = ComponentPartial::loadOverrideCached($this->theme, $componentObj, $partialName); + + /* + * Check the component partial + */ + if ($partial === null) { + $partial = ComponentPartial::loadCached($componentObj, $partialName); + } + + if ($partial === null) { + if ($throwException) { + throw new CmsException(Lang::get('cms::lang.partial.not_found_name', ['name'=>$name])); + } + + return false; + } + + /* + * Set context for self access + */ + $this->vars['__SELF__'] = $componentObj; + } + /* + * Process theme partial + */ + elseif (($partial = Partial::loadCached($this->theme, $name)) === null) { + if ($throwException) { + throw new CmsException(Lang::get('cms::lang.partial.not_found_name', ['name'=>$name])); + } + + return false; + } + + /* + * Run functions for CMS partials only (Cms\Classes\Partial) + */ + if ($partial instanceof Partial) { + $this->partialStack->stackPartial(); + + $manager = ComponentManager::instance(); + + foreach ($partial->settings['components'] as $component => $properties) { + // Do not inject the viewBag component to the environment. + // Not sure if they're needed there by the requirements, + // but there were problems with array-typed properties used by Static Pages + // snippets and setComponentPropertiesFromParams(). --ab + if ($component == 'viewBag') { + continue; + } + + list($name, $alias) = strpos($component, ' ') + ? explode(' ', $component) + : [$component, $component]; + + if (!$componentObj = $manager->makeComponent($name, $this->pageObj, $properties)) { + throw new CmsException(Lang::get('cms::lang.component.not_found', ['name'=>$name])); + } + + $componentObj->alias = $alias; + $parameters[$alias] = $partial->components[$alias] = $componentObj; + + $this->partialStack->addComponent($alias, $componentObj); + + $this->setComponentPropertiesFromParams($componentObj, $parameters); + $componentObj->init(); + } + + CmsException::mask($this->page, 300); + $parser = new CodeParser($partial); + $partialObj = $parser->source($this->page, $this->layout, $this); + CmsException::unmask(); + + CmsException::mask($partial, 300); + $partialObj->onStart(); + $partial->runComponents(); + $partialObj->onEnd(); + CmsException::unmask(); + } + + /* + * Render the partial + */ + CmsException::mask($partial, 400); + $this->loader->setObject($partial); + $template = $this->twig->loadTemplate($partial->getFilePath()); + $partialContent = $template->render(array_merge($this->vars, $parameters)); + CmsException::unmask(); + + if ($partial instanceof Partial) { + $this->partialStack->unstackPartial(); + } + + $this->vars = $vars; + + /** + * @event cms.page.renderPartial + * Provides an opportunity to manipulate the output of a partial after being rendered + * + * Example usage: + * + * Event::listen('cms.page.renderPartial', function ((\Cms\Classes\Controller) $controller, (string) $partialName, (string) &$partialContent) { + * return "Overriding content"; + * }); + * + * Or + * + * $CmsController->bindEvent('page.renderPartial', function ((string) $partialName, (string) &$partialContent) { + * return "Overriding content"; + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.page.renderPartial', [$name, &$partialContent])) { + return $event; + } + + return $partialContent; + } + + /** + * Renders a requested content file. + * The framework uses this method internally. + * @param string $name The content view to load. + * @param array $parameters Parameter variables to pass to the view. + * @return string + */ + public function renderContent($name, $parameters = []) + { + /** + * @event cms.page.beforeRenderContent + * Provides an opportunity to manipulate the name of the content file being rendered before it renders + * + * Example usage: + * + * Event::listen('cms.page.beforeRenderContent', function ((\Cms\Classes\Controller) $controller, (string) $contentName) { + * return Cms\Classes\Content::loadCached($theme, 'custom-content-name'); + * }); + * + * Or + * + * $CmsController->bindEvent('page.beforeRenderContent', function ((string) $contentName) { + * return Cms\Classes\Content::loadCached($theme, 'custom-content-name'); + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.page.beforeRenderContent', [$name])) { + $content = $event; + } + /* + * Load content from theme + */ + elseif (($content = Content::loadCached($this->theme, $name)) === null) { + throw new CmsException(Lang::get('cms::lang.content.not_found_name', ['name'=>$name])); + } + + $fileContent = $content->parsedMarkup; + + /* + * Inject global view variables + */ + $globalVars = ViewHelper::getGlobalVars(); + if (!empty($globalVars)) { + $parameters = (array) $parameters + $globalVars; + } + + /* + * Parse basic template variables + */ + if (!empty($parameters)) { + $fileContent = TextParser::parse($fileContent, $parameters); + } + + /** + * @event cms.page.renderContent + * Provides an opportunity to manipulate the output of a content file after being rendered + * + * Example usage: + * + * Event::listen('cms.page.renderContent', function ((\Cms\Classes\Controller) $controller, (string) $contentName, (string) &$fileContent) { + * return "Overriding content"; + * }); + * + * Or + * + * $CmsController->bindEvent('page.renderContent', function ((string) $contentName, (string) &$fileContent) { + * return "Overriding content"; + * }); + * + */ + if ($event = $this->fireSystemEvent('cms.page.renderContent', [$name, &$fileContent])) { + return $event; + } + + return $fileContent; + } + + /** + * Renders a component's default content, preserves the previous component context. + * @param $name + * @param array $parameters + * @return string Returns the component default contents. + */ + public function renderComponent($name, $parameters = []) + { + $result = null; + $previousContext = $this->componentContext; + + if ($componentObj = $this->findComponentByName($name)) { + $componentObj->id = uniqid($name); + $componentObj->setProperties(array_merge($componentObj->getProperties(), $parameters)); + $this->componentContext = $componentObj; + $result = $componentObj->onRender(); + } + + if (!$result) { + $result = $this->renderPartial($name.'::default', [], false); + } + + $this->componentContext = $previousContext; + return $result; + } + + // + // Getters + // + + /** + * Returns an existing instance of the controller. + * If the controller doesn't exists, returns null. + * @return mixed Returns the controller object or null. + */ + public static function getController() + { + return self::$instance; + } + + /** + * Returns the current CMS theme. + * @return \Cms\Classes\Theme + */ + public function getTheme() + { + return $this->theme; + } + + /** + * Returns the Twig environment. + * @return TwigEnvironment + */ + public function getTwig() + { + return $this->twig; + } + + /** + * Returns the Twig loader. + * @return \Cms\Twig\Loader + */ + public function getLoader() + { + return $this->loader; + } + + /** + * Returns the routing object. + * @return \Cms\Classes\Router + */ + public function getRouter() + { + return $this->router; + } + + /** + * Intended to be called from the layout, returns the page code base object. + * @return \Cms\Classes\CodeBase + */ + public function getPageObject() + { + return $this->pageObj; + } + + /** + * Returns the CMS page object being processed by the controller. + * The object is not available on the early stages of the controller + * initialization. + * @return \Cms\Classes\Page Returns the Page object or null. + */ + public function getPage() + { + return $this->page; + } + + /** + * Intended to be called from the page, returns the layout code base object. + * @return \Cms\Classes\CodeBase + */ + public function getLayoutObject() + { + return $this->layoutObj; + } + + /** + * Returns the CMS layout object being processed by the controller. + * The object is not available on the early stages of the controller + * initialization. + * @return \Cms\Classes\Layout Returns the Layout object or null. + */ + public function getLayout() + { + return $this->layout; + } + + // + // Page helpers + // + + /** + * Looks up the URL for a supplied page and returns it relative to the website root. + * + * @param mixed $name Specifies the Cms Page file name. + * @param array $parameters Route parameters to consider in the URL. + * @param bool $routePersistence By default the existing routing parameters will be included + * @return string + */ + public function pageUrl($name, $parameters = [], $routePersistence = true) + { + if (!$name) { + return $this->currentPageUrl($parameters, $routePersistence); + } + + /* + * Second parameter can act as third + */ + if (is_bool($parameters)) { + $routePersistence = $parameters; + } + + if (!is_array($parameters)) { + $parameters = []; + } + + if ($routePersistence) { + $parameters = array_merge($this->router->getParameters(), $parameters); + } + + if (!$url = $this->router->findByFile($name, $parameters)) { + return null; + } + + return Cms::url($url); + } + + /** + * Looks up the current page URL with supplied parameters and route persistence. + * @param array $parameters + * @param bool $routePersistence + * @return null|string + */ + public function currentPageUrl($parameters = [], $routePersistence = true) + { + if (!$currentFile = $this->page->getFileName()) { + return null; + } + + return $this->pageUrl($currentFile, $parameters, $routePersistence); + } + + /** + * Converts supplied URL to a theme URL relative to the website root. If the URL provided is an + * array then the files will be combined. + * @param mixed $url Specifies the theme-relative URL. If null, the theme path is returned. + * @return string + */ + public function themeUrl($url = null) + { + $themeDir = $this->getTheme()->getDirName(); + + if (is_array($url)) { + $_url = Url::to(CombineAssets::combine($url, themes_path().'/'.$themeDir)); + } + else { + $_url = Config::get('cms.themesPath', '/themes').'/'.$themeDir; + if ($url !== null) { + $_url .= '/'.$url; + } + $_url = Url::asset($_url); + } + + return $_url; + } + + /** + * Returns a routing parameter. + * @param string $name Routing parameter name. + * @param string $default Default to use if none is found. + * @return string + */ + public function param($name, $default = null) + { + return $this->router->getParameter($name, $default); + } + + // + // Component helpers + // + + /** + * Adds a component to the page object. + * + * @param mixed $name Component class name or short name + * @param string $alias Alias to give the component + * @param array $properties Component properties + * @param bool $addToLayout Add to layout, instead of page + * + * @return ComponentBase|null Component object. Will return `null` if a soft component is used but not found. + * @throws CmsException if the (hard) component is not found. + * @throws SystemException if the (hard) component class is not found or is not registered. + */ + public function addComponent($name, $alias, $properties, $addToLayout = false) + { + $manager = ComponentManager::instance(); + $isSoftComponent = $this->isSoftComponent($name); + + if ($isSoftComponent) { + $name = $this->parseComponentLabel($name); + $alias = $this->parseComponentLabel($alias); + } + + $componentObj = $manager->makeComponent( + $name, + ($addToLayout) ? $this->layoutObj : $this->pageObj, + $properties, + $isSoftComponent + ); + + if (is_null($componentObj)) { + if (!$isSoftComponent) { + throw new CmsException(Lang::get('cms::lang.component.not_found', ['name' => $name])); + } + + // A missing soft component will return null. + return null; + } + + $componentObj->alias = $alias; + $this->vars[$alias] = $componentObj; + + if ($addToLayout) { + $this->layout->components[$alias] = $componentObj; + } else { + $this->page->components[$alias] = $componentObj; + } + + $this->setComponentPropertiesFromParams($componentObj); + $componentObj->init(); + + return $componentObj; + } + + /** + * Searches the layout and page components by an alias + * @param $name + * @return ComponentBase The component object, if found + */ + public function findComponentByName($name) + { + if (isset($this->page->components[$name])) { + return $this->page->components[$name]; + } + + if (isset($this->layout->components[$name])) { + return $this->layout->components[$name]; + } + + $partialComponent = $this->partialStack->getComponent($name); + if ($partialComponent !== null) { + return $partialComponent; + } + + return null; + } + + /** + * Searches the layout and page components by an AJAX handler + * @param string $handler + * @return ComponentBase The component object, if found + */ + public function findComponentByHandler($handler) + { + foreach ($this->page->components as $component) { + if ($component->methodExists($handler)) { + return $component; + } + } + + foreach ($this->layout->components as $component) { + if ($component->methodExists($handler)) { + return $component; + } + } + + return null; + } + + /** + * Searches the layout and page components by a partial file + * @param string $partial + * @return ComponentBase The component object, if found + */ + public function findComponentByPartial($partial) + { + foreach ($this->page->components as $component) { + if (ComponentPartial::check($component, $partial)) { + return $component; + } + } + + foreach ($this->layout->components as $component) { + if (ComponentPartial::check($component, $partial)) { + return $component; + } + } + + return null; + } + + /** + * Set the component context manually, used by Components when calling renderPartial. + * @param ComponentBase $component + * @return void + */ + public function setComponentContext(ComponentBase $component = null) + { + $this->componentContext = $component; + } + + /** + * Sets component property values from partial parameters. + * The property values should be defined as {{ param }}. + * @param ComponentBase $component The component object. + * @param array $parameters Specifies the partial parameters. + */ + protected function setComponentPropertiesFromParams($component, $parameters = []) + { + $properties = $component->getProperties(); + $routerParameters = $this->router->getParameters(); + + foreach ($properties as $propertyName => $propertyValue) { + if (is_array($propertyValue)) { + continue; + } + + $matches = []; + if (preg_match('/^\{\{([^\}]+)\}\}$/', $propertyValue, $matches)) { + $paramName = trim($matches[1]); + + if (substr($paramName, 0, 1) == ':') { + $routeParamName = substr($paramName, 1); + $newPropertyValue = $routerParameters[$routeParamName] ?? null; + } + else { + $newPropertyValue = array_get($parameters, $paramName, null); + } + + $component->setProperty($propertyName, $newPropertyValue); + $component->setExternalPropertyName($propertyName, $paramName); + } + } + } + + /** + * Removes prefixed '@' from soft component name + * @param string $label + * @return string + */ + protected function parseComponentLabel($label) + { + if ($this->isSoftComponent($label)) { + return ltrim($label, '@'); + } + return $label; + } + + /** + * Checks if component name has @. + * @param string $label + * @return bool + */ + protected function isSoftComponent($label) + { + return starts_with($label, '@'); + } +} diff --git a/modules/cms/classes/Layout.php b/modules/cms/classes/Layout.php new file mode 100644 index 0000000..8ef4b59 --- /dev/null +++ b/modules/cms/classes/Layout.php @@ -0,0 +1,51 @@ +markup = '{% page %}'; + $obj->fileName = self::FALLBACK_FILE_NAME; + return $obj; + } + + /** + * Returns true if the layout is a fallback layout + * @return boolean + */ + public function isFallBack() + { + return $this->fileName === self::FALLBACK_FILE_NAME; + } + + /** + * Returns name of a PHP class to us a parent for the PHP class created for the object's PHP section. + * @return mixed Returns the class name or null. + */ + public function getCodeClassParent() + { + return LayoutCode::class; + } +} diff --git a/modules/cms/classes/LayoutCode.php b/modules/cms/classes/LayoutCode.php new file mode 100644 index 0000000..c6a4d4b --- /dev/null +++ b/modules/cms/classes/LayoutCode.php @@ -0,0 +1,18 @@ += 2020. + */ +class MediaLibrary extends SystemMediaLibrary +{ + /** + * Initialize this singleton. + */ + protected function init() + { + traceLog('Class ' . __CLASS__ . ' has been deprecated, use ' . SystemMediaLibrary::class . ' instead.'); + parent::init(); + } +} diff --git a/modules/cms/classes/MediaLibraryItem.php b/modules/cms/classes/MediaLibraryItem.php new file mode 100644 index 0000000..e6e37d9 --- /dev/null +++ b/modules/cms/classes/MediaLibraryItem.php @@ -0,0 +1,19 @@ += 2020. + */ +class MediaLibraryItem extends SystemMediaLibraryItem +{ + public function __construct() + { + traceLog('Class Cms\Classes\MediaLibraryItem has been deprecated, use ' . SystemMediaLibraryItem::class . ' instead.'); + parent::__construct(...func_get_args()); + } +} diff --git a/modules/cms/classes/MediaViewHelper.php b/modules/cms/classes/MediaViewHelper.php new file mode 100644 index 0000000..2d743db --- /dev/null +++ b/modules/cms/classes/MediaViewHelper.php @@ -0,0 +1,105 @@ +extractMediaTags($html); + foreach ($mediaTags as $tagInfo) { + $pattern = preg_quote($tagInfo['declaration']); + $generatedMarkup = $this->generateMediaTagMarkup($tagInfo['type'], $tagInfo['src']); + $html = mb_ereg_replace($pattern, $generatedMarkup, $html); + } + + return $html; + } + + protected function extractMediaTags($html) + { + $result = []; + $matches = []; + + $tagDefinitions = [ + 'audio' => '/data\-audio\s*=\s*"([^"]+)"/', + 'video' => '/data\-video\s*=\s*"([^"]+)"/' + ]; + + if (preg_match_all('/\]+\>[^\<]*\<\/figure\>/i', $html, $matches)) { + foreach ($matches[0] as $mediaDeclaration) { + foreach ($tagDefinitions as $type => $pattern) { + $nameMatch = []; + if (preg_match($pattern, $mediaDeclaration, $nameMatch)) { + $result[] = [ + 'declaration' => $mediaDeclaration, + 'type' => $type, + 'src' => $nameMatch[1] + ]; + } + } + } + } + + return $result; + } + + protected function generateMediaTagMarkup($type, $src) + { + $partialName = $type == 'audio' ? 'oc-audio-player' : 'oc-video-player'; + + if ($this->playerPartialExists($partialName)) { + return Controller::getController()->renderPartial($partialName, ['src' => $src]); + } + + return $this->getDefaultPlayerMarkup($type, $src); + } + + protected function playerPartialExists($name) + { + if (array_key_exists($name, $this->playerPartialFlags)) { + return $this->playerPartialFlags[$name]; + } + + $controller = Controller::getController(); + if (!$controller) { + throw new ApplicationException('Media tags can only be processed for front-end requests.'); + } + + $partial = Partial::loadCached($controller->getTheme(), $name); + + return $this->playerPartialFlags[$name] = !!$partial; + } + + protected function getDefaultPlayerMarkup($type, $src) + { + switch ($type) { + case 'video': + return ''; + break; + + case 'audio': + return ''; + break; + } + } +} diff --git a/modules/cms/classes/Meta.php b/modules/cms/classes/Meta.php new file mode 100644 index 0000000..b74872e --- /dev/null +++ b/modules/cms/classes/Meta.php @@ -0,0 +1,85 @@ +bindEvent('model.beforeSave', function () { + $this->content = $this->renderContent(); + }); + $this->bindEvent('model.afterFetch', function () { + $this->attributes = array_merge($this->attributes, $this->parseContent()); + }); + } + + /** + * Processes the content attribute to an array of menu data. + * @return array|null + */ + protected function parseContent() + { + if ($this->contentDataCache !== null) { + return $this->contentDataCache; + } + + $parsedData = Yaml::parse($this->content); + + if (!is_array($parsedData)) { + return null; + } + + return $this->contentDataCache = $parsedData; + } + + /** + * Renders the meta data as a content string in YAML format. + * @return string + */ + protected function renderContent() + { + return Yaml::render($this->settings); + } + + /** + * Compile the content for this CMS object, used by the theme logger. + * @return string + */ + public function toCompiled() + { + return $this->renderContent(); + } +} diff --git a/modules/cms/classes/ObjectMemoryCache.php b/modules/cms/classes/ObjectMemoryCache.php new file mode 100644 index 0000000..341fd66 --- /dev/null +++ b/modules/cms/classes/ObjectMemoryCache.php @@ -0,0 +1,12 @@ + 'required', + 'url' => 'required' + ]; + + /** + * Returns name of a PHP class to us a parent for the PHP class created for the object's PHP section. + * @return mixed Returns the class name or null. + */ + public function getCodeClassParent() + { + return PageCode::class; + } + + /** + * Returns a list of layouts available in the theme. + * This method is used by the form widget. + * @return array Returns an array of strings. + */ + public function getLayoutOptions() + { + if (!($theme = Theme::getEditTheme())) { + throw new ApplicationException(Lang::get('cms::lang.theme.edit.not_found')); + } + + $layouts = Layout::listInTheme($theme, true); + $result = []; + $result[null] = Lang::get('cms::lang.page.no_layout'); + + foreach ($layouts as $layout) { + $baseName = $layout->getBaseFileName(); + + if (FileDefinitions::isPathIgnored($baseName)) { + continue; + } + + $result[$baseName] = strlen($layout->name) ? $layout->name : $baseName; + } + + return $result; + } + + /** + * Helper that returns a nicer list of pages for use in dropdowns. + * @return array + */ + public static function getNameList() + { + $result = []; + $pages = self::sortBy('baseFileName')->all(); + foreach ($pages as $page) { + $result[$page->baseFileName] = $page->title . ' (' . $page->baseFileName . ')'; + } + + return $result; + } + + /** + * Helper that makes a URL for a page in the active theme. + * @param mixed $page Specifies the Cms Page file name. + * @param array $params Route parameters to consider in the URL. + * @return string + */ + public static function url($page, array $params = []) + { + /* + * Reuse existing controller or create a new one, + * assuming that the method is called not during the front-end + * request processing. + */ + $controller = Controller::getController() ?: new Controller; + + return $controller->pageUrl($page, $params, true); + } + + /** + * Handler for the pages.menuitem.getTypeInfo event. + * Returns a menu item type information. The type information is returned as array + * with the following elements: + * - references - a list of the item type reference options. The options are returned in the + * ["key"] => "title" format for options that don't have sub-options, and in the format + * ["key"] => ["title"=>"Option title", "items"=>[...]] for options that have sub-options. Optional, + * required only if the menu item type requires references. + * - nesting - Boolean value indicating whether the item type supports nested items. Optional, + * false if omitted. + * - dynamicItems - Boolean value indicating whether the item type could generate new menu items. + * Optional, false if omitted. + * - cmsPages - a list of CMS pages (objects of the Cms\Classes\Page class), if the item type requires + * a CMS page reference to resolve the item URL. + * @param string $type Specifies the menu item type + * @return array Returns an array + */ + public static function getMenuTypeInfo(string $type) + { + $result = []; + + if ($type === 'cms-page') { + $theme = Theme::getActiveTheme(); + $pages = self::listInTheme($theme, true); + $references = []; + + foreach ($pages as $page) { + $references[$page->getBaseFileName()] = $page->title . ' [' . $page->getBaseFileName() . ']'; + } + + $result = [ + 'references' => $references, + 'nesting' => false, + 'dynamicItems' => false + ]; + } + + return $result; + } + + /** + * Handler for the pages.menuitem.resolveItem event. + * Returns information about a menu item. The result is an array + * with the following keys: + * - url - the menu item URL. Not required for menu item types that return all available records. + * The URL should be returned relative to the website root and include the subdirectory, if any. + * Use the Url::to() helper to generate the URLs. + * - isActive - determines whether the menu item is active. Not required for menu item types that + * return all available records. + * - items - an array of arrays with the same keys (url, isActive, items) + the title key. + * The items array should be added only if the $item's $nesting property value is TRUE. + * @param \RainLab\Pages\Classes\MenuItem $item Specifies the menu item. + * @param string $url Specifies the current page URL, normalized, in lower case + * @param \Cms\Classes\Theme $theme Specifies the current theme. + * The URL is specified relative to the website root, it includes the subdirectory name, if any. + * @return mixed Returns an array. Returns null if the item cannot be resolved. + */ + public static function resolveMenuItem($item, string $url, Theme $theme) + { + $result = null; + + if ($item->type === 'cms-page') { + if (!$item->reference) { + return; + } + + $page = self::loadCached($theme, $item->reference); + + // Remove hidden CMS pages from menus when backend user is logged out + if ($page && $page->is_hidden && !BackendAuth::getUser()) { + return; + } + + $controller = Controller::getController() ?: new Controller; + $pageUrl = $controller->pageUrl($item->reference, [], false); + + $result = []; + $result['url'] = $pageUrl; + $result['isActive'] = $pageUrl == $url; + $result['mtime'] = $page ? $page->mtime : null; + } + + return $result; + } + + /** + * Handler for the backend.richeditor.getTypeInfo event. + * Returns a menu item type information. The type information is returned as array + * @param string $type Specifies the page link type + * @return array + */ + public static function getRichEditorTypeInfo(string $type) + { + $result = []; + + if ($type === 'cms-page') { + $theme = Theme::getActiveTheme(); + $pages = self::listInTheme($theme, true); + + foreach ($pages as $page) { + $url = self::url($page->getBaseFileName()); + $result[$url] = $page->title; + } + } + + return $result; + } +} diff --git a/modules/cms/classes/PageCode.php b/modules/cms/classes/PageCode.php new file mode 100644 index 0000000..36b614a --- /dev/null +++ b/modules/cms/classes/PageCode.php @@ -0,0 +1,11 @@ +activePartial !== null) { + array_unshift($this->partialStack, $this->activePartial); + } + + $this->activePartial = [ + 'components' => [] + ]; + } + + /** + * Partial exit point, removes the active partial from the stack. + */ + public function unstackPartial() + { + $this->activePartial = array_shift($this->partialStack); + } + + /** + * Adds a component to the active partial stack. + */ + public function addComponent($alias, $componentObj) + { + array_push($this->activePartial['components'], [ + 'name' => $alias, + 'obj' => $componentObj + ]); + } + + /** + * Returns a component by its alias from the partial stack. + */ + public function getComponent($name) + { + if (!$this->activePartial) { + return null; + } + + $component = $this->findComponentFromStack($name, $this->activePartial); + if ($component !== null) { + return $component; + } + + foreach ($this->partialStack as $stack) { + $component = $this->findComponentFromStack($name, $stack); + if ($component !== null) { + return $component; + } + } + + return null; + } + + /** + * Locates a component by its alias from the supplied stack. + */ + protected function findComponentFromStack($name, $stack) + { + foreach ($stack['components'] as $componentInfo) { + if ($componentInfo['name'] == $name) { + return $componentInfo['obj']; + } + } + + return null; + } +} diff --git a/modules/cms/classes/Router.php b/modules/cms/classes/Router.php new file mode 100644 index 0000000..a0c4340 --- /dev/null +++ b/modules/cms/classes/Router.php @@ -0,0 +1,358 @@ +/blog/post/:post_id + * Name of parameters should be compatible with PHP variable names. To make a parameter optional + * add the question mark after its name: + *
    /blog/post/:post_id?
    + * By default parameters in the middle of the URL are required, for example: + *
    /blog/:post_id?/comments - although the :post_id parameter is marked as optional,
    + * it will be processed as required.
    + * Optional parameters can have default values which are used as fallback values in case if the real + * parameter value is not presented in the URL. Default values cannot contain the pipe symbols and question marks. + * Specify the default value after the question mark: + *
    /blog/category/:category_id?10 - The category_id parameter would be 10 for this URL: /blog/category
    + * You can also add regular expression validation to parameters. To add a validation expression + * add the pipe symbol after the parameter name (or the question mark) and specify the expression. + * The forward slash symbol is not allowed in the expressions. Examples: + *
    /blog/:post_id|^[0-9]+$/comments - this will match /blog/post/10/comments
    + * /blog/:post_id|^[0-9]+$ - this will match /blog/post/3
    + * /blog/:post_name?|^[a-z0-9\-]+$ - this will match /blog/my-blog-post
    + * + * @package october\cms + * @author Alexey Bobkov, Samuel Georges + */ +class Router +{ + /** + * @var \Cms\Classes\Theme A reference to the CMS theme containing the object. + */ + protected $theme; + + /** + * @var string The last URL to be looked up using findByUrl(). + */ + protected $url; + + /** + * @var array A list of parameters names and values extracted from the URL pattern and URL string. + */ + protected $parameters = []; + + /** + * @var array Contains the URL map - the list of page file names and corresponding URL patterns. + */ + protected $urlMap = []; + + /** + * October\Rain\Router\Router Router object with routes preloaded. + */ + protected $routerObj; + + /** + * Creates the router instance. + * @param \Cms\Classes\Theme $theme Specifies the theme being processed. + */ + public function __construct(Theme $theme) + { + $this->theme = $theme; + } + + /** + * Finds a page by its URL. Returns the page object and sets the $parameters property. + * @param string $url The requested URL string. + * @return \Cms\Classes\Page Returns \Cms\Classes\Page object or null if the page cannot be found. + */ + public function findByUrl($url) + { + $this->url = $url; + $url = RouterHelper::normalizeUrl($url); + + /** + * @event cms.router.beforeRoute + * Fires before the CMS Router handles a route + * + * Example usage: + * + * Event::listen('cms.router.beforeRoute', function ((string) $url, (\Cms\Classes\Router) $thisRouterInstance) { + * return \Cms\Classes\Page::loadCached('trick-theme-code', 'page-file-name'); + * }); + * + */ + $apiResult = Event::fire('cms.router.beforeRoute', [$url, $this], true); + if ($apiResult !== null) { + return $apiResult; + } + + for ($pass = 1; $pass <= 2; $pass++) { + $fileName = null; + $urlList = []; + + $cacheable = Config::get('cms.enableRoutesCache'); + if ($cacheable) { + $fileName = $this->getCachedUrlFileName($url, $urlList); + if (is_array($fileName)) { + list($fileName, $this->parameters) = $fileName; + } + } + + /* + * Find the page by URL and cache the route + */ + if (!$fileName) { + $router = $this->getRouterObject(); + if ($router->match($url)) { + $this->parameters = $router->getParameters(); + + $fileName = $router->matchedRoute(); + + if ($cacheable) { + if (!$urlList || !is_array($urlList)) { + $urlList = []; + } + + $urlList[$url] = !empty($this->parameters) + ? [$fileName, $this->parameters] + : $fileName; + + $key = $this->getUrlListCacheKey(); + $expiresAt = now()->addMinutes(Config::get('cms.urlCacheTtl', 1)); + Cache::put( + $key, + base64_encode(serialize($urlList)), + $expiresAt + ); + } + } + } + + /* + * Return the page + */ + if ($fileName) { + if (($page = Page::loadCached($this->theme, $fileName)) === null) { + /* + * If the page was not found on the disk, clear the URL cache + * and repeat the routing process. + */ + if ($pass == 1) { + $this->clearCache(); + continue; + } + + return null; + } + + return $page; + } + + return null; + } + } + + /** + * Finds a URL by it's page. Returns the URL route for linking to the page and uses the supplied + * parameters in it's address. + * @param string $fileName Page file name. + * @param array $parameters Route parameters to consider in the URL. + * @return string A built URL matching the page route. + */ + public function findByFile($fileName, $parameters = []) + { + if (!strlen(File::extension($fileName))) { + $fileName .= '.htm'; + } + + $router = $this->getRouterObject(); + return $router->url($fileName, $parameters); + } + + /** + * Autoloads the URL map only allowing a single execution. + * @return array Returns the URL map. + */ + protected function getRouterObject() + { + if ($this->routerObj !== null) { + return $this->routerObj; + } + + /* + * Load up each route rule + */ + $router = new RainRouter(); + foreach ($this->getUrlMap() as $pageInfo) { + $router->route($pageInfo['file'], $pageInfo['pattern']); + } + + /* + * Sort all the rules + */ + $router->sortRules(); + + return $this->routerObj = $router; + } + + /** + * Autoloads the URL map only allowing a single execution. + * @return array Returns the URL map. + */ + protected function getUrlMap() + { + if (!count($this->urlMap)) { + $this->loadUrlMap(); + } + + return $this->urlMap; + } + + /** + * Loads the URL map - a list of page file names and corresponding URL patterns. + * The URL map can is cached. The clearUrlMap() method resets the cache. By default + * the map is updated every time when a page is saved in the back-end, or + * when the interval defined with the cms.urlCacheTtl expires. + * @return boolean Returns true if the URL map was loaded from the cache. Otherwise returns false. + */ + protected function loadUrlMap() + { + $key = $this->getCacheKey('page-url-map'); + + $cacheable = Config::get('cms.enableRoutesCache'); + if ($cacheable) { + $cached = Cache::get($key, false); + } + else { + $cached = false; + } + + if (!$cached || ($unserialized = @unserialize(@base64_decode($cached))) === false) { + /* + * The item doesn't exist in the cache, create the map + */ + $pages = $this->theme->listPages(); + $map = []; + foreach ($pages as $page) { + if (!$page->url) { + continue; + } + + $map[] = ['file' => $page->getFileName(), 'pattern' => $page->url]; + } + + $this->urlMap = $map; + if ($cacheable) { + $expiresAt = now()->addMinutes(Config::get('cms.urlCacheTtl', 1)); + Cache::put($key, base64_encode(serialize($map)), $expiresAt); + } + + return false; + } + + $this->urlMap = $unserialized; + return true; + } + + /** + * Clears the router cache. + */ + public function clearCache() + { + Cache::forget($this->getCacheKey('page-url-map')); + Cache::forget($this->getCacheKey('cms-url-list')); + } + + /** + * Sets the current routing parameters. + * @param array $parameters + * @return array + */ + public function setParameters(array $parameters) + { + $this->parameters = $parameters; + } + + /** + * Returns the current routing parameters. + * @return array + */ + public function getParameters() + { + return $this->parameters; + } + + /** + * Returns the last URL to be looked up. + * @return string + */ + public function getUrl() + { + return $this->url; + } + + /** + * Returns a routing parameter. + * @param string $name + * @param string|null $default + * @return string|null + */ + public function getParameter($name, $default = null) + { + if (isset($this->parameters[$name]) && ($this->parameters[$name] === '0' || !empty($this->parameters[$name]))) { + return $this->parameters[$name]; + } + + return $default; + } + + /** + * Returns the caching URL key depending on the theme. + * @param string $keyName Specifies the base key name. + * @return string Returns the theme-specific key name. + */ + protected function getCacheKey($keyName) + { + return md5($this->theme->getPath()).$keyName.Lang::getLocale(); + } + + /** + * Returns the cache key name for the URL list. + * @return string + */ + protected function getUrlListCacheKey() + { + return $this->getCacheKey('cms-url-list'); + } + + /** + * Tries to load a page file name corresponding to a specified URL from the cache. + * @param string $url Specifies the requested URL. + * @param array &$urlList The URL list loaded from the cache + * @return mixed Returns the page file name if the URL exists in the cache. Otherwise returns null. + */ + protected function getCachedUrlFileName($url, &$urlList) + { + $key = $this->getUrlListCacheKey(); + $urlList = Cache::get($key, false); + + if ($urlList + && ($urlList = @unserialize(@base64_decode($urlList))) + && is_array($urlList) + && array_key_exists($url, $urlList) + ) { + return $urlList[$url]; + } + + return null; + } +} diff --git a/modules/cms/classes/Theme.php b/modules/cms/classes/Theme.php new file mode 100644 index 0000000..6ce06a1 --- /dev/null +++ b/modules/cms/classes/Theme.php @@ -0,0 +1,607 @@ +setDirName($dirName); + $theme->registerHalcyonDatasource(); + + return $theme; + } + + /** + * Returns the absolute theme path. + * @param string $dirName Optional theme directory. Defaults to $this->getDirName() + * @return string + */ + public function getPath($dirName = null) + { + if (!$dirName) { + $dirName = $this->getDirName(); + } + + return themes_path().'/'.$dirName; + } + + /** + * Sets the theme directory name. + * @return void + */ + public function setDirName($dirName) + { + $this->dirName = $dirName; + } + + /** + * Returns the theme directory name. + * @return string + */ + public function getDirName() + { + return $this->dirName; + } + + /** + * Helper for {{ theme.id }} twig vars + * Returns a unique string for this theme. + * @return string + */ + public function getId() + { + return snake_case(str_replace('/', '-', $this->getDirName())); + } + + /** + * Determines if a theme with given directory name exists + * @param string $dirName The theme directory + * @return bool + */ + public static function exists($dirName) + { + $theme = static::load($dirName); + $path = $theme->getPath(); + + return File::isDirectory($path); + } + + /** + * Returns a list of pages in the theme. + * This method is used internally in the routing process and in the back-end UI. + * @param boolean $skipCache Indicates if the pages should be reloaded from the disk bypassing the cache. + * @return array Returns an array of \Cms\Classes\Page objects. + */ + public function listPages($skipCache = false) + { + return Page::listInTheme($this, $skipCache); + } + + /** + * Returns true if this theme is the chosen active theme. + */ + public function isActiveTheme() + { + $activeTheme = self::getActiveTheme(); + + return $activeTheme && $activeTheme->getDirName() == $this->getDirName(); + } + + /** + * Returns the active theme code. + * By default the active theme is loaded from the cms.activeTheme parameter, + * but this behavior can be overridden by the cms.theme.getActiveTheme event listener. + * @return string + * If the theme doesn't exist, returns null. + */ + public static function getActiveThemeCode() + { + $activeTheme = Config::get('cms.activeTheme'); + $themes = static::all(); + $havingMoreThemes = count($themes) > 1; + $themeHasChanged = !empty($themes[0]) && $themes[0]->dirName !== $activeTheme; + $checkDatabase = $havingMoreThemes || $themeHasChanged; + + if ($checkDatabase && App::hasDatabase()) { + try { + try { + $expiresAt = now()->addMinutes(1440); + $dbResult = Cache::remember(self::ACTIVE_KEY, $expiresAt, function () { + return Parameter::applyKey(self::ACTIVE_KEY)->value('value'); + }); + } + catch (Exception $ex) { + // Cache failed + $dbResult = Parameter::applyKey(self::ACTIVE_KEY)->value('value'); + } + } + catch (Exception $ex) { + // Database failed + $dbResult = null; + } + + if ($dbResult !== null && static::exists($dbResult)) { + $activeTheme = $dbResult; + } + } + + /** + * @event cms.theme.getActiveTheme + * Overrides the active theme code. + * + * If a value is returned from this halting event, it will be used as the active + * theme code. Example usage: + * + * Event::listen('cms.theme.getActiveTheme', function () { + * return 'mytheme'; + * }); + * + */ + $apiResult = Event::fire('cms.theme.getActiveTheme', [], true); + if ($apiResult !== null) { + $activeTheme = $apiResult; + } + + if (!strlen($activeTheme)) { + throw new SystemException(Lang::get('cms::lang.theme.active.not_set')); + } + + return $activeTheme; + } + + + /** + * Returns the active theme object. + * @return \Cms\Classes\Theme Returns the loaded theme object. + * If the theme doesn't exist, returns null. + */ + public static function getActiveTheme() + { + if (self::$activeThemeCache !== false) { + return self::$activeThemeCache; + } + + $theme = static::load(static::getActiveThemeCode()); + + if (!File::isDirectory($theme->getPath())) { + return self::$activeThemeCache = null; + } + + return self::$activeThemeCache = $theme; + } + + /** + * Sets the active theme. + * The active theme code is stored in the database and overrides the configuration cms.activeTheme parameter. + * @param string $code Specifies the active theme code. + */ + public static function setActiveTheme($code) + { + self::resetCache(); + + Parameter::set(self::ACTIVE_KEY, $code); + + /** + * @event cms.theme.setActiveTheme + * Fires when the active theme has been changed. + * + * If a value is returned from this halting event, it will be used as the active + * theme code. Example usage: + * + * Event::listen('cms.theme.setActiveTheme', function ($code) { + * \Log::info("Theme has been changed to $code"); + * }); + * + */ + Event::fire('cms.theme.setActiveTheme', compact('code')); + } + + /** + * Returns the edit theme code. + * By default the edit theme is loaded from the cms.editTheme parameter, + * but this behavior can be overridden by the cms.theme.getEditTheme event listeners. + * If the edit theme is not defined in the configuration file, the active theme + * is returned. + * @return string + */ + public static function getEditThemeCode() + { + $editTheme = Config::get('cms.editTheme'); + if (!$editTheme) { + $editTheme = static::getActiveThemeCode(); + } + + /** + * @event cms.theme.getEditTheme + * Overrides the edit theme code. + * + * If a value is returned from this halting event, it will be used as the edit + * theme code. Example usage: + * + * Event::listen('cms.theme.getEditTheme', function () { + * return "the-edit-theme-code"; + * }); + * + */ + $apiResult = Event::fire('cms.theme.getEditTheme', [], true); + if ($apiResult !== null) { + $editTheme = $apiResult; + } + + if (!strlen($editTheme)) { + throw new SystemException(Lang::get('cms::lang.theme.edit.not_set')); + } + + return $editTheme; + } + + /** + * Returns the edit theme. + * @return \Cms\Classes\Theme Returns the loaded theme object. + */ + public static function getEditTheme() + { + if (self::$editThemeCache !== false) { + return self::$editThemeCache; + } + + $theme = static::load(static::getEditThemeCode()); + + if (!File::isDirectory($theme->getPath())) { + return self::$editThemeCache = null; + } + + return self::$editThemeCache = $theme; + } + + /** + * Returns a list of all themes. + * @return array Returns an array of the Theme objects. + */ + public static function all() + { + $it = new DirectoryIterator(themes_path()); + $it->rewind(); + + $result = []; + foreach ($it as $fileinfo) { + if (!$fileinfo->isDir() || $fileinfo->isDot()) { + continue; + } + + $theme = static::load($fileinfo->getFilename()); + + $result[] = $theme; + } + + return $result; + } + + /** + * Reads the theme.yaml file and returns the theme configuration values. + * @return array Returns the parsed configuration file values. + */ + public function getConfig() + { + if ($this->configCache !== null) { + return $this->configCache; + } + + $path = $this->getPath().'/theme.yaml'; + if (!File::exists($path)) { + return $this->configCache = []; + } + + $config = Yaml::parseFile($path); + + /** + * @event cms.theme.extendConfig + * Extend basic theme configuration supplied by the theme by returning an array. + * + * Note if planning on extending form fields, use the `cms.theme.extendFormConfig` + * event instead. + * + * Example usage: + * + * Event::listen('cms.theme.extendConfig', function ($themeCode, &$config) { + * $config['name'] = 'October Theme'; + * $config['description'] = 'Another great theme from October CMS'; + * }); + * + */ + Event::fire('cms.theme.extendConfig', [$this->getDirName(), &$config]); + + return $this->configCache = $config; + } + + /** + * Themes have a dedicated `form` option that provide form fields + * for customization, this is an immutable accessor for that and + * also an solid anchor point for extension. + * @return array + */ + public function getFormConfig() + { + $config = $this->getConfigArray('form'); + + /** + * @event cms.theme.extendFormConfig + * Extend form field configuration supplied by the theme by returning an array. + * + * Note if you are planning on using `assetVar` to inject CSS variables from a + * plugin registration file, make sure the plugin has elevated permissions. + * + * Example usage: + * + * Event::listen('cms.theme.extendFormConfig', function ($themeCode, &$config) { + * array_set($config, 'tabs.fields.header_color', [ + * 'label' => 'Header Colour', + * 'type' => 'colorpicker', + * 'availableColors' => [#34495e, #708598, #3498db], + * 'assetVar' => 'header-bg', + * 'tab' => 'Global' + * ]); + * }); + * + */ + Event::fire('cms.theme.extendFormConfig', [$this->getDirName(), &$config]); + + return $config; + } + + /** + * Returns a value from the theme configuration file by its name. + * @param string $name Specifies the configuration parameter name. + * @param mixed $default Specifies the default value to return in case if the parameter + * doesn't exist in the configuration file. + * @return mixed Returns the parameter value or a default value + */ + public function getConfigValue($name, $default = null) + { + return array_get($this->getConfig(), $name, $default); + } + + /** + * Returns an array value from the theme configuration file by its name. + * If the value is a string, it is treated as a YAML file and loaded. + * @param string $name Specifies the configuration parameter name. + * @return array + */ + public function getConfigArray($name) + { + $result = array_get($this->getConfig(), $name, []); + + if (is_string($result)) { + $fileName = File::symbolizePath($result); + + if (File::isLocalPath($fileName)) { + $path = $fileName; + } + else { + $path = $this->getPath().'/'.$result; + } + + if (!File::exists($path)) { + throw new ApplicationException('Path does not exist: '.$path); + } + + $result = Yaml::parseFile($path); + } + + return (array) $result; + } + + /** + * Writes to the theme.yaml file with the supplied array values. + * @param array $values Data to write + * @param array $overwrite If true, undefined values are removed. + * @return void + */ + public function writeConfig($values = [], $overwrite = false) + { + if (!$overwrite) { + $values = $values + (array) $this->getConfig(); + } + + $path = $this->getPath().'/theme.yaml'; + if (!File::exists($path)) { + throw new ApplicationException('Path does not exist: '.$path); + } + + $contents = Yaml::render($values); + File::put($path, $contents); + $this->configCache = $values; + + self::resetCache(); + } + + /** + * Returns the theme preview image URL. + * If the image file doesn't exist returns the placeholder image URL. + * @return string Returns the image URL. + */ + public function getPreviewImageUrl() + { + $previewPath = $this->getConfigValue('previewImage', 'assets/images/theme-preview.png'); + + if (File::exists($this->getPath().'/'.$previewPath)) { + return Url::asset('themes/'.$this->getDirName().'/'.$previewPath); + } + + return Url::asset('modules/cms/assets/images/default-theme-preview.png'); + } + + /** + * Resets any memory or cache involved with the active or edit theme. + * @return void + */ + public static function resetCache() + { + self::$activeThemeCache = false; + self::$editThemeCache = false; + + Cache::forget(self::ACTIVE_KEY); + Cache::forget(self::EDIT_KEY); + } + + /** + * Returns true if this theme has form fields that supply customization data. + * @return bool + */ + public function hasCustomData() + { + return $this->getConfigValue('form', false); + } + + /** + * Returns data specific to this theme + * @return Cms\Models\ThemeData + */ + public function getCustomData() + { + return ThemeData::forTheme($this); + } + + /** + * Remove data specific to this theme + * @return bool + */ + public function removeCustomData() + { + if ($this->hasCustomData()) { + return $this->getCustomData()->delete(); + } + + return true; + } + + /** + * Checks to see if the database layer has been enabled + * + * @return boolean + */ + public static function databaseLayerEnabled() + { + $enableDbLayer = Config::get('cms.databaseTemplates', false); + if (is_null($enableDbLayer)) { + $enableDbLayer = !Config::get('app.debug', false); + } + + return $enableDbLayer && App::hasDatabase(); + } + + /** + * Ensures this theme is registered as a Halcyon datasource. + * @return void + */ + public function registerHalcyonDatasource() + { + $resolver = App::make('halcyon'); + + if (!$resolver->hasDatasource($this->dirName)) { + if (static::databaseLayerEnabled()) { + $datasource = new AutoDatasource([ + 'database' => new DbDatasource($this->dirName, 'cms_theme_templates'), + 'filesystem' => new FileDatasource($this->getPath(), App::make('files')), + ]); + } else { + $datasource = new FileDatasource($this->getPath(), App::make('files')); + } + + $resolver->addDatasource($this->dirName, $datasource); + } + } + + /** + * Get the theme's datasource + * + * @return DatasourceInterface + */ + public function getDatasource() + { + $resolver = App::make('halcyon'); + return $resolver->datasource($this->getDirName()); + } + + /** + * Implements the getter functionality. + * @param string $name + * @return void + */ + public function __get($name) + { + if ($this->hasCustomData()) { + return $this->getCustomData()->{$name}; + } + + return null; + } + + /** + * Determine if an attribute exists on the object. + * @param string $key + * @return void + */ + public function __isset($key) + { + if ($this->hasCustomData()) { + $theme = $this->getCustomData(); + return $theme->offsetExists($key); + } + + return false; + } +} diff --git a/modules/cms/classes/ThemeManager.php b/modules/cms/classes/ThemeManager.php new file mode 100644 index 0000000..20de61a --- /dev/null +++ b/modules/cms/classes/ThemeManager.php @@ -0,0 +1,127 @@ +getInstalled(); + foreach ($installed as $code => $name) { + if ($dirName == $name) { + return $code; + } + } + + return null; + } + + // + // Management + // + + /** + * Completely delete a theme from the system. + * @param string $theme Theme code/namespace + * @return void + */ + public function deleteTheme($theme) + { + if (!$theme) { + return false; + } + + if (is_string($theme)) { + $theme = CmsTheme::load($theme); + } + + if ($theme->isActiveTheme()) { + throw new ApplicationException(trans('cms::lang.theme.delete_active_theme_failed')); + } + + $theme->removeCustomData(); + + /* + * Delete from file system + */ + $themePath = $theme->getPath(); + if (File::isDirectory($themePath)) { + File::deleteDirectory($themePath); + } + + /* + * Set uninstalled + */ + if ($themeCode = $this->findByDirName($theme->getDirName())) { + $this->setUninstalled($themeCode); + } + } +} diff --git a/modules/cms/classes/asset/fields.yaml b/modules/cms/classes/asset/fields.yaml new file mode 100644 index 0000000..7935713 --- /dev/null +++ b/modules/cms/classes/asset/fields.yaml @@ -0,0 +1,26 @@ +# =================================== +# Form Field Definitions +# =================================== + +fields: + fileName: + label: cms::lang.editor.filename + attributes: + default-focus: 1 + + toolbar: + type: partial + path: content_toolbar + cssClass: collapse-visible + +tabs: + cssClass: master-area + +secondaryTabs: + stretch: true + fields: + content: + tab: cms::lang.editor.content + stretch: true + type: codeeditor + language: css \ No newline at end of file diff --git a/modules/cms/classes/content/fields.yaml b/modules/cms/classes/content/fields.yaml new file mode 100644 index 0000000..ed13c79 --- /dev/null +++ b/modules/cms/classes/content/fields.yaml @@ -0,0 +1,28 @@ +# =================================== +# Form Field Definitions +# =================================== + +fields: + fileName: + label: cms::lang.editor.filename + attributes: + default-focus: 1 + + toolbar: + type: partial + path: content_toolbar + cssClass: collapse-visible + + components: Cms\FormWidgets\Components + +tabs: + cssClass: master-area + +secondaryTabs: + stretch: true + fields: + markup: + tab: cms::lang.editor.content + stretch: true + type: codeeditor + language: html \ No newline at end of file diff --git a/modules/cms/classes/layout/fields.yaml b/modules/cms/classes/layout/fields.yaml new file mode 100644 index 0000000..62c2921 --- /dev/null +++ b/modules/cms/classes/layout/fields.yaml @@ -0,0 +1,45 @@ +# =================================== +# Form Field Definitions +# =================================== + +fields: + fileName: + label: cms::lang.editor.filename + span: left + attributes: + default-focus: 1 + + settings[description]: + label: cms::lang.editor.description + span: right + + toolbar: + type: partial + path: layout_toolbar + cssClass: collapse-visible + + components: Cms\FormWidgets\Components + +tabs: + cssClass: master-area + +secondaryTabs: + stretch: true + fields: + markup: + tab: cms::lang.editor.markup + stretch: true + type: codeeditor + language: twig + + safemode_notice: + tab: cms::lang.editor.code + type: partial + hidden: true + cssClass: p-b-0 + + code: + tab: cms::lang.editor.code + stretch: true + type: codeeditor + language: php diff --git a/modules/cms/classes/page/fields.yaml b/modules/cms/classes/page/fields.yaml new file mode 100644 index 0000000..ac754d3 --- /dev/null +++ b/modules/cms/classes/page/fields.yaml @@ -0,0 +1,87 @@ +# =================================== +# Form Field Definitions +# =================================== + +fields: + settings[title]: + span: left + label: cms::lang.editor.title + placeholder: cms::lang.editor.new_title + attributes: + default-focus: 1 + + settings[url]: + span: right + placeholder: / + label: cms::lang.editor.url + preset: + field: settings[title] + type: url + + toolbar: + type: partial + path: page_toolbar + cssClass: collapse-visible + + components: Cms\FormWidgets\Components + +tabs: + cssClass: master-area + fields: + fileName: + tab: cms::lang.editor.settings + span: left + label: cms::lang.editor.filename + preset: + field: settings[title] + type: file + + settings[layout]: + tab: cms::lang.editor.settings + span: right + label: cms::lang.editor.layout + type: dropdown + options: getLayoutOptions + + settings[description]: + tab: cms::lang.editor.settings + label: cms::lang.editor.description + type: textarea + size: tiny + + settings[meta_title]: + tab: cms::lang.editor.meta + label: cms::lang.editor.meta_title + + settings[meta_description]: + tab: cms::lang.editor.meta + label: cms::lang.editor.meta_description + type: textarea + size: tiny + + settings[is_hidden]: + tab: cms::lang.editor.settings + label: cms::lang.editor.hidden + type: checkbox + comment: cms::lang.editor.hidden_comment + +secondaryTabs: + stretch: true + fields: + markup: + tab: cms::lang.editor.markup + stretch: true + type: codeeditor + language: twig + + safemode_notice: + tab: cms::lang.editor.code + type: partial + hidden: true + cssClass: p-b-0 + + code: + tab: cms::lang.editor.code + stretch: true + type: codeeditor + language: php diff --git a/modules/cms/classes/partial/fields.yaml b/modules/cms/classes/partial/fields.yaml new file mode 100644 index 0000000..9e5f0a8 --- /dev/null +++ b/modules/cms/classes/partial/fields.yaml @@ -0,0 +1,45 @@ +# =================================== +# Form Field Definitions +# =================================== + +fields: + fileName: + span: left + label: cms::lang.editor.filename + attributes: + default-focus: 1 + + settings[description]: + span: right + label: cms::lang.editor.description + + toolbar: + type: partial + path: partial_toolbar + cssClass: collapse-visible + + components: Cms\FormWidgets\Components + +tabs: + cssClass: master-area + +secondaryTabs: + stretch: true + fields: + markup: + tab: cms::lang.editor.markup + stretch: true + type: codeeditor + language: twig + + safemode_notice: + tab: cms::lang.editor.code + type: partial + hidden: true + cssClass: p-b-0 + + code: + tab: cms::lang.editor.code + stretch: true + type: codeeditor + language: php diff --git a/modules/cms/classes/theme/fields.yaml b/modules/cms/classes/theme/fields.yaml new file mode 100644 index 0000000..7b1a128 --- /dev/null +++ b/modules/cms/classes/theme/fields.yaml @@ -0,0 +1,47 @@ +# =================================== +# Form Field Definitions +# =================================== + +tabs: + defaultTab: cms::lang.theme.default_tab + fields: + + name: + label: cms::lang.theme.name_label + placeholder: cms::lang.theme.name_create_placeholder + span: auto + required: true + attributes: + default-focus: 1 + + dir_name@create: + label: cms::lang.theme.dir_name_label + placeholder: cms::lang.theme.dir_name_create_label + span: auto + preset: name + required: true + + dir_name@update: + label: cms::lang.theme.dir_name_label + disabled: true + span: auto + + description: + label: cms::lang.theme.description_label + placeholder: cms::lang.theme.description_placeholder + type: textarea + size: tiny + + author: + label: cms::lang.theme.author_label + placeholder: cms::lang.theme.author_placeholder + span: auto + + homepage: + label: cms::lang.theme.homepage_label + placeholder: cms::lang.theme.homepage_placeholder + span: auto + + code: + label: cms::lang.theme.code_label + placeholder: cms::lang.theme.code_placeholder diff --git a/modules/cms/components/Resources.php b/modules/cms/components/Resources.php new file mode 100644 index 0000000..d5be4bb --- /dev/null +++ b/modules/cms/components/Resources.php @@ -0,0 +1,190 @@ + 'Resources', + 'description' => 'Easily reference theme assets for inclusion on a page.', + ]; + } + + /** + * @return array + */ + public function defineProperties() + { + return [ + 'js' => [ + 'title' => 'JavaScript', + 'description' => 'JavaScript file(s) in the assets/js folder', + 'type' => 'stringList', + 'showExternalParam' => false + ], + 'less' => [ + 'title' => 'LESS', + 'description' => 'LESS file(s) in the assets/less folder', + 'type' => 'stringList', + 'showExternalParam' => false + ], + 'sass' => [ + 'title' => 'SASS', + 'description' => 'SASS file(s) in the assets/sass folder', + 'type' => 'stringList', + 'showExternalParam' => false + ], + 'css' => [ + 'title' => 'CSS', + 'description' => 'Stylesheet file(s) in the assets/css folder', + 'type' => 'stringList', + 'showExternalParam' => false + ], + 'vars' => [ + 'title' => 'Variables', + 'description' => 'Page variables name(s) and value(s)', + 'type' => 'dictionary', + 'showExternalParam' => false + ] + ]; + } + + public function init() + { + $this->assetPath = $this->guessAssetPath(); + $this->jsDir = $this->guessAssetDirectory(['js', 'javascript'], $this->jsDir); + $this->sassDir = $this->guessAssetDirectory(['sass', 'scss'], $this->sassDir); + } + + public function onRun() + { + /* + * JavaScript + */ + $js = []; + if ($assets = $this->property('js')) { + $js += array_map([$this, 'prefixJs'], (array) $assets); + } + + /* + * LESS + */ + $less = []; + if ($assets = $this->property('less')) { + $less += array_map([$this, 'prefixLess'], (array) $assets); + } + + /* + * SASS + */ + $sass = []; + if ($assets = $this->property('sass')) { + $sass += array_map([$this, 'prefixSass'], (array) $assets); + } + + /* + * CSS + */ + $css = []; + if ($assets = $this->property('css')) { + $css += array_map([$this, 'prefixCss'], (array) $assets); + } + + if (count($js)) { + $this->addJs(CombineAssets::combine($js, $this->assetPath)); + } + + if (count($less)) { + $this->addCss(CombineAssets::combine($less, $this->assetPath)); + } + + if (count($sass)) { + $this->addCss(CombineAssets::combine($sass, $this->assetPath)); + } + + if (count($css)) { + $this->addCss(CombineAssets::combine($css, $this->assetPath)); + } + + /* + * Variables + */ + if ($vars = $this->property('vars')) { + foreach ((array) $vars as $key => $value) { + $this->page[$key] = $value; + } + } + } + + protected function prefixJs($value) + { + return $this->jsDir.'/'.trim($value); + } + + protected function prefixCss($value) + { + return $this->cssDir.'/'.trim($value); + } + + protected function prefixLess($value) + { + return $this->lessDir.'/'.trim($value); + } + + protected function prefixSass($value) + { + return $this->sassDir.'/'.trim($value); + } + + protected function guessAssetDirectory(array $possible, $default = null) + { + foreach ($possible as $option) { + if (File::isDirectory($this->assetPath.'/'.$option)) { + return $option; + } + } + + return $default; + } + + protected function guessAssetPath() + { + $baseTheme = themes_path().'/'.$this->getTheme()->getDirName(); + + if (File::isDirectory($baseTheme.'/assets')) { + return $baseTheme.'/assets'; + } + + return $baseTheme.'/resources'; + } +} diff --git a/modules/cms/components/SoftComponent.php b/modules/cms/components/SoftComponent.php new file mode 100644 index 0000000..bcbb37d --- /dev/null +++ b/modules/cms/components/SoftComponent.php @@ -0,0 +1,33 @@ +componentCssClass = 'warning-component'; + $this->inspectorEnabled = false; + + parent::__construct(null, $properties); + } + + /** + * @return array + */ + public function componentDetails() + { + return [ + 'name' => 'cms::lang.component.soft_component', + 'description' => 'cms::lang.component.soft_component_description' + ]; + } +} diff --git a/modules/cms/components/UnknownComponent.php b/modules/cms/components/UnknownComponent.php new file mode 100644 index 0000000..9282216 --- /dev/null +++ b/modules/cms/components/UnknownComponent.php @@ -0,0 +1,34 @@ +errorMessage = $errorMessage; + $this->componentCssClass = 'error-component'; + $this->inspectorEnabled = false; + + parent::__construct($cmsObject, $properties); + } + + /** + * @return array + */ + public function componentDetails() + { + return [ + 'name' => 'Unknown component', + 'description' => $this->errorMessage + ]; + } +} diff --git a/modules/cms/components/ViewBag.php b/modules/cms/components/ViewBag.php new file mode 100644 index 0000000..076e55e --- /dev/null +++ b/modules/cms/components/ViewBag.php @@ -0,0 +1,83 @@ + 'viewBag', + 'description' => 'Stores custom template properties.' + ]; + } + + /** + * @param array $properties + * @return array + */ + public function validateProperties(array $properties) + { + return $properties; + } + + /** + * Implements the getter functionality. + * @param string $name + * @return void + */ + public function __get($name) + { + if (array_key_exists($name, $this->properties)) { + return $this->properties[$name]; + } + + return null; + } + + /** + * Determine if an attribute exists on the object. + * @param string $key + * @return bool + */ + public function __isset($key) + { + if (array_key_exists($key, $this->properties)) { + return true; + } + + return false; + } + + /** + * @return array + */ + public function defineProperties() + { + $result = []; + + foreach ($this->properties as $name => $value) { + $result[$name] = [ + 'title' => $name, + 'type' => 'string' + ]; + } + + return $result; + } +} diff --git a/modules/cms/composer.json b/modules/cms/composer.json new file mode 100644 index 0000000..0738322 --- /dev/null +++ b/modules/cms/composer.json @@ -0,0 +1,35 @@ +{ + "name": "october/cms", + "type": "october-module", + "description": "CMS module for October CMS", + "homepage": "https://octobercms.com", + "keywords": ["october cms", "october", "cms"], + "license": "MIT", + "authors": [ + { + "name": "Alexey Bobkov", + "email": "aleksey.bobkov@gmail.com", + "role": "Co-founder" + }, + { + "name": "Samuel Georges", + "email": "daftspunky@gmail.com", + "role": "Co-founder" + } + ], + "require": { + "php": ">=7.2", + "composer/installers": "~1.0" + }, + "autoload": { + "psr-4": { + "Cms\\": "" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "minimum-stability": "dev" +} diff --git a/modules/cms/contracts/CmsObject.php b/modules/cms/contracts/CmsObject.php new file mode 100644 index 0000000..c6b9b67 --- /dev/null +++ b/modules/cms/contracts/CmsObject.php @@ -0,0 +1,61 @@ +getController() instanceof Index) { + return; + } + if (!$widget->model instanceof CmsCompoundObject) { + return; + } + + if (empty($widget->secondaryTabs['fields'])) { + return; + } + + if (array_key_exists('code', $widget->secondaryTabs['fields']) && CmsHelpers::safeModeEnabled()) { + $widget->secondaryTabs['fields']['safemode_notice']['hidden'] = false; + $widget->secondaryTabs['fields']['code']['readOnly'] = true; + }; + }); + + BackendMenu::setContext('October.Cms', 'cms', true); + + try { + if (!($theme = Theme::getEditTheme())) { + throw new ApplicationException(Lang::get('cms::lang.theme.edit.not_found')); + } + + $this->theme = $theme; + + new TemplateList($this, 'pageList', function () use ($theme) { + return Page::listInTheme($theme, true); + }); + + new TemplateList($this, 'partialList', function () use ($theme) { + return Partial::listInTheme($theme, true); + }); + + new TemplateList($this, 'layoutList', function () use ($theme) { + return Layout::listInTheme($theme, true); + }); + + new TemplateList($this, 'contentList', function () use ($theme) { + return Content::listInTheme($theme, true); + }); + + new ComponentList($this, 'componentList'); + + new AssetList($this, 'assetList'); + } + catch (Exception $ex) { + $this->handleError($ex); + } + } + + // + // Pages + // + + /** + * Index page action + * @return void + */ + public function index() + { + $this->addJs('/modules/cms/assets/js/october.cmspage.js', 'core'); + $this->addJs('/modules/cms/assets/js/october.dragcomponents.js', 'core'); + $this->addJs('/modules/cms/assets/js/october.tokenexpander.js', 'core'); + $this->addCss('/modules/cms/assets/css/october.components.css', 'core'); + + // Preload the code editor class as it could be needed + // before it loads dynamically. + $this->addJs('/modules/backend/formwidgets/codeeditor/assets/js/build-min.js', 'core'); + + $this->bodyClass = 'compact-container'; + $this->pageTitle = 'cms::lang.cms.menu_label'; + $this->pageTitleTemplate = '%s '.Lang::get($this->pageTitle); + + if (Request::ajax() && Request::input('formWidgetAlias')) { + $this->bindFormWidgetToController(); + } + } + + /** + * Opens an existing template from the index page + * @return array + */ + public function index_onOpenTemplate() + { + $this->validateRequestTheme(); + + $type = Request::input('type'); + $template = $this->loadTemplate($type, Request::input('path')); + $widget = $this->makeTemplateFormWidget($type, $template); + + $this->vars['templatePath'] = Request::input('path'); + $this->vars['lastModified'] = DateTime::makeCarbon($template->mtime); + $this->vars['canCommit'] = $this->canCommitTemplate($template); + $this->vars['canReset'] = $this->canResetTemplate($template); + + if ($type === 'page') { + $router = new RainRouter; + $this->vars['pageUrl'] = $router->urlFromPattern($template->url); + } + + return [ + 'tabTitle' => $this->getTabTitle($type, $template), + 'tab' => $this->makePartial('form_page', [ + 'form' => $widget, + 'templateType' => $type, + 'templateTheme' => $this->theme->getDirName(), + 'templateMtime' => $template->mtime + ]) + ]; + } + + /** + * Saves the template currently open + * @return array + */ + public function onSave() + { + $this->validateRequestTheme(); + $type = Request::input('templateType'); + $templatePath = trim(Request::input('templatePath')); + $template = $templatePath ? $this->loadTemplate($type, $templatePath) : $this->createTemplate($type); + $formWidget = $this->makeTemplateFormWidget($type, $template); + + $saveData = $formWidget->getSaveData(); + $postData = post(); + $templateData = []; + + $settings = array_get($saveData, 'settings', []) + Request::input('settings', []); + $settings = $this->upgradeSettings($settings, $template->settings); + + if ($settings) { + $templateData['settings'] = $settings; + } + + $fields = ['markup', 'code', 'fileName', 'content']; + + foreach ($fields as $field) { + if (array_key_exists($field, $saveData)) { + $templateData[$field] = $saveData[$field]; + } + elseif (array_key_exists($field, $postData)) { + $templateData[$field] = $postData[$field]; + } + } + + if (!empty($templateData['markup']) && Config::get('cms.convertLineEndings', false) === true) { + $templateData['markup'] = $this->convertLineEndings($templateData['markup']); + } + + if (!empty($templateData['code']) && Config::get('cms.convertLineEndings', false) === true) { + $templateData['code'] = $this->convertLineEndings($templateData['code']); + } + + if ( + !Request::input('templateForceSave') && $template->mtime + && Request::input('templateMtime') != $template->mtime + ) { + throw new ApplicationException('mtime-mismatch'); + } + + $template->attributes = []; + $template->fill($templateData); + $template->save(); + + /** + * @event cms.template.save + * Fires after a CMS template (page|partial|layout|content|asset) has been saved. + * + * Example usage: + * + * Event::listen('cms.template.save', function ((\Cms\Controllers\Index) $controller, (mixed) $templateObject, (string) $type) { + * \Log::info("A $type has been saved"); + * }); + * + * Or + * + * $CmsIndexController->bindEvent('template.save', function ((mixed) $templateObject, (string) $type) { + * \Log::info("A $type has been saved"); + * }); + * + */ + $this->fireSystemEvent('cms.template.save', [$template, $type]); + + Flash::success(Lang::get('cms::lang.template.saved')); + + return $this->getUpdateResponse($template, $type); + } + + /** + * Displays a form that suggests the template has been edited elsewhere + * @return string + */ + public function onOpenConcurrencyResolveForm() + { + return $this->makePartial('concurrency_resolve_form'); + } + + /** + * Create a new template + * @return array + */ + public function onCreateTemplate() + { + $type = Request::input('type'); + $template = $this->createTemplate($type); + + if ($type === 'asset') { + $template->fileName = $this->widget->assetList->getCurrentRelativePath(); + } + + $widget = $this->makeTemplateFormWidget($type, $template); + + $this->vars['templatePath'] = ''; + $this->vars['canCommit'] = $this->canCommitTemplate($template); + $this->vars['canReset'] = $this->canResetTemplate($template); + + return [ + 'tabTitle' => $this->getTabTitle($type, $template), + 'tab' => $this->makePartial('form_page', [ + 'form' => $widget, + 'templateType' => $type, + 'templateTheme' => $this->theme->getDirName(), + 'templateMtime' => null + ]) + ]; + } + + /** + * Deletes multiple templates at the same time + * @return array + */ + public function onDeleteTemplates() + { + $this->validateRequestTheme(); + + $type = Request::input('type'); + $templates = Request::input('template'); + $error = null; + $deleted = []; + + try { + foreach ($templates as $path => $selected) { + if ($selected) { + $this->loadTemplate($type, $path)->delete(); + $deleted[] = $path; + } + } + } + catch (Exception $ex) { + $error = $ex->getMessage(); + } + + /** + * @event cms.template.delete + * Fires after a CMS template (page|partial|layout|content|asset) has been deleted. + * + * Example usage: + * + * Event::listen('cms.template.delete', function ((\Cms\Controllers\Index) $controller, (string) $type) { + * \Log::info("A $type has been deleted"); + * }); + * + * Or + * + * $CmsIndexController->bindEvent('template.delete', function ((string) $type) { + * \Log::info("A $type has been deleted"); + * }); + * + */ + $this->fireSystemEvent('cms.template.delete', [$type]); + + return [ + 'deleted' => $deleted, + 'error' => $error, + 'theme' => Request::input('theme') + ]; + } + + /** + * Deletes a template + * @return void + */ + public function onDelete() + { + $this->validateRequestTheme(); + + $type = Request::input('templateType'); + + $this->loadTemplate($type, trim(Request::input('templatePath')))->delete(); + + /* + * Extensibility - documented above + */ + $this->fireSystemEvent('cms.template.delete', [$type]); + } + + /** + * Returns list of available templates + * @return array + */ + public function onGetTemplateList() + { + $this->validateRequestTheme(); + + $page = Page::inTheme($this->theme); + return [ + 'layouts' => $page->getLayoutOptions() + ]; + } + + /** + * Remembers an open or closed state for a supplied token, for example, component folders. + * @return array + */ + public function onExpandMarkupToken() + { + if (!$alias = post('tokenName')) { + throw new ApplicationException(Lang::get('cms::lang.component.no_records')); + } + + // Can only expand components at this stage + if ((!$type = post('tokenType')) && $type !== 'component') { + return; + } + + if (!($names = (array) post('component_names')) || !($aliases = (array) post('component_aliases'))) { + throw new ApplicationException(Lang::get('cms::lang.component.not_found', ['name' => $alias])); + } + + if (($index = array_get(array_flip($aliases), $alias, false)) === false) { + throw new ApplicationException(Lang::get('cms::lang.component.not_found', ['name' => $alias])); + } + + if (!$componentName = array_get($names, $index)) { + throw new ApplicationException(Lang::get('cms::lang.component.not_found', ['name' => $alias])); + } + + $manager = ComponentManager::instance(); + $componentObj = $manager->makeComponent($componentName); + $partial = ComponentPartial::load($componentObj, 'default'); + + if (!$partial) { + throw new ApplicationException(Lang::get('cms::lang.component.no_default_partial')); + } + + $content = $partial->getContent(); + $content = str_replace('__SELF__', $alias, $content); + + return $content; + } + + /** + * Commits the DB changes of a template to the filesystem + * + * @return array $response + */ + public function onCommit() + { + $this->validateRequestTheme(); + $type = Request::input('templateType'); + $template = $this->loadTemplate($type, trim(Request::input('templatePath'))); + + if ($this->canCommitTemplate($template)) { + // Populate the filesystem with the template and then remove it from the db + $datasource = $this->getThemeDatasource(); + $datasource->pushToSource($template, 'filesystem'); + $datasource->removeFromSource($template, 'database'); + + Flash::success(Lang::get('cms::lang.editor.commit_success', ['type' => $type])); + } + + return array_merge($this->getUpdateResponse($template, $type), ['forceReload' => true]); + } + + /** + * Resets a template to the version on the filesystem + * + * @return array $response + */ + public function onReset() + { + $this->validateRequestTheme(); + $type = Request::input('templateType'); + $template = $this->loadTemplate($type, trim(Request::input('templatePath'))); + + if ($this->canResetTemplate($template)) { + // Remove the template from the DB + $datasource = $this->getThemeDatasource(); + $datasource->removeFromSource($template, 'database'); + + Flash::success(Lang::get('cms::lang.editor.reset_success', ['type' => $type])); + } + + return array_merge($this->getUpdateResponse($template, $type), ['forceReload' => true]); + } + + // + // Methods for internal use + // + + /** + * Get the response to return in an AJAX request that updates a template + * + * @param object $template The template that has been affected + * @param string $type The type of template being affected + * @return array $result; + */ + protected function getUpdateResponse($template, string $type) + { + $result = [ + 'templatePath' => $template->fileName, + 'templateMtime' => $template->mtime, + 'tabTitle' => $this->getTabTitle($type, $template) + ]; + + if ($type === 'page') { + $result['pageUrl'] = Url::to($template->url); + $router = new Router($this->theme); + $router->clearCache(); + CmsCompoundObject::clearCache($this->theme); + } + + $result['canCommit'] = $this->canCommitTemplate($template); + $result['canReset'] = $this->canResetTemplate($template); + + return $result; + } + + /** + * Get the active theme's datasource + * + * @return \October\Rain\Halcyon\Datasource\DatasourceInterface + */ + protected function getThemeDatasource() + { + return $this->theme->getDatasource(); + } + + /** + * Check to see if the provided template can be committed + * Only available in debug mode, the DB layer must be enabled, and the template must exist in the database + * + * @param CmsObject $template + * @return boolean + */ + protected function canCommitTemplate($template) + { + if ($template instanceof Cms\Contracts\CmsObject === false) { + return false; + } + + $result = false; + + if (Config::get('app.debug', false) && + Theme::databaseLayerEnabled() && + $this->getThemeDatasource()->sourceHasModel('database', $template) + ) { + $result = true; + } + + return $result; + } + + /** + * Check to see if the provided template can be reset + * Only available when the DB layer is enabled and the template exists in both the DB & Filesystem + * + * @param CmsObject $template + * @return boolean + */ + protected function canResetTemplate($template) + { + if ($template instanceof Cms\Contracts\CmsObject === false) { + return false; + } + + $result = false; + + if (Theme::databaseLayerEnabled()) { + $datasource = $this->getThemeDatasource(); + $result = $datasource->sourceHasModel('database', $template) && $datasource->sourceHasModel('filesystem', $template); + } + + return $result; + } + + /** + * Validate that the current request is within the active theme + * @return void + */ + protected function validateRequestTheme() + { + if ($this->theme->getDirName() != Request::input('theme')) { + throw new ApplicationException(Lang::get('cms::lang.theme.edit.not_match')); + } + } + + /** + * Resolves a template type to its class name + * @param string $type + * @return string + */ + protected function resolveTypeClassName($type) + { + $types = [ + 'page' => Page::class, + 'partial' => Partial::class, + 'layout' => Layout::class, + 'content' => Content::class, + 'asset' => Asset::class + ]; + + if (!array_key_exists($type, $types)) { + throw new ApplicationException(Lang::get('cms::lang.template.invalid_type')); + } + + return $types[$type]; + } + + /** + * Returns an existing template of a given type + * @param string $type + * @param string $path + * @return mixed + */ + protected function loadTemplate($type, $path) + { + $class = $this->resolveTypeClassName($type); + + if (!($template = call_user_func([$class, 'load'], $this->theme, $path))) { + throw new ApplicationException(Lang::get('cms::lang.template.not_found')); + } + + /** + * @event cms.template.processSettingsAfterLoad + * Fires immediately after a CMS template (page|partial|layout|content|asset) has been loaded and provides an opportunity to interact with it. + * + * Example usage: + * + * Event::listen('cms.template.processSettingsAfterLoad', function ((\Cms\Controllers\Index) $controller, (mixed) $templateObject) { + * // Make some modifications to the $template object + * }); + * + * Or + * + * $CmsIndexController->bindEvent('template.processSettingsAfterLoad', function ((mixed) $templateObject) { + * // Make some modifications to the $template object + * }); + * + */ + $this->fireSystemEvent('cms.template.processSettingsAfterLoad', [$template]); + + return $template; + } + + /** + * Creates a new template of a given type + * @param string $type + * @return mixed + */ + protected function createTemplate($type) + { + $class = $this->resolveTypeClassName($type); + + if (!($template = $class::inTheme($this->theme))) { + throw new ApplicationException(Lang::get('cms::lang.template.not_found')); + } + + return $template; + } + + /** + * Returns the text for a template tab + * @param string $type + * @param string $template + * @return string + */ + protected function getTabTitle($type, $template) + { + if ($type === 'page') { + $result = $template->title ?: $template->getFileName(); + if (!$result) { + $result = Lang::get('cms::lang.page.new'); + } + + return $result; + } + + if ($type === 'partial' || $type === 'layout' || $type === 'content' || $type === 'asset') { + $result = in_array($type, ['asset', 'content']) ? $template->getFileName() : $template->getBaseFileName(); + if (!$result) { + $result = Lang::get('cms::lang.'.$type.'.new'); + } + + return $result; + } + + return $template->getFileName(); + } + + /** + * Returns a form widget for a specified template type. + * @param string $type + * @param string $template + * @param string $alias + * @return Backend\Widgets\Form + */ + protected function makeTemplateFormWidget($type, $template, $alias = null) + { + $formConfigs = [ + 'page' => '~/modules/cms/classes/page/fields.yaml', + 'partial' => '~/modules/cms/classes/partial/fields.yaml', + 'layout' => '~/modules/cms/classes/layout/fields.yaml', + 'content' => '~/modules/cms/classes/content/fields.yaml', + 'asset' => '~/modules/cms/classes/asset/fields.yaml' + ]; + + if (!array_key_exists($type, $formConfigs)) { + throw new ApplicationException(Lang::get('cms::lang.template.not_found')); + } + + $widgetConfig = $this->makeConfig($formConfigs[$type]); + $widgetConfig->model = $template; + $widgetConfig->alias = $alias ?: 'form'.studly_case($type).md5($template->exists ? $template->getFileName() : uniqid()); + + return $this->makeWidget('Backend\Widgets\Form', $widgetConfig); + } + + /** + * Processes the component settings so they are ready to be saved. + * @param array $settings The new settings for this template. + * @param array $prevSettings The previous settings for this template. + * @return array + */ + protected function upgradeSettings($settings, $prevSettings) + { + /* + * Handle component usage + */ + $componentProperties = post('component_properties'); + $componentNames = post('component_names'); + $componentAliases = post('component_aliases'); + + if ($componentProperties !== null) { + if ($componentNames === null || $componentAliases === null) { + throw new ApplicationException(Lang::get('cms::lang.component.invalid_request')); + } + + $count = count($componentProperties); + if (count($componentNames) != $count || count($componentAliases) != $count) { + throw new ApplicationException(Lang::get('cms::lang.component.invalid_request')); + } + + for ($index = 0; $index < $count; $index++) { + $componentName = $componentNames[$index]; + $componentAlias = $componentAliases[$index]; + + $isSoftComponent = (substr($componentAlias, 0, 1) === '@'); + $componentName = ltrim($componentName, '@'); + $componentAlias = ltrim($componentAlias, '@'); + + if ($componentAlias !== $componentName) { + $section = $componentName . ' ' . $componentAlias; + } else { + $section = $componentName; + } + if ($isSoftComponent) { + $section = '@' . $section; + } + + $properties = json_decode($componentProperties[$index], true); + unset($properties['oc.alias'], $properties['inspectorProperty'], $properties['inspectorClassName']); + + if (!$properties) { + $oldComponentSettings = array_key_exists($section, $prevSettings['components']) + ? $prevSettings['components'][$section] + : null; + if ($isSoftComponent && $oldComponentSettings) { + $settings[$section] = $oldComponentSettings; + } else { + $settings[$section] = $properties; + } + } else { + $settings[$section] = $properties; + } + } + } + + /* + * Handle view bag + */ + $viewBag = post('viewBag'); + if ($viewBag !== null) { + $settings['viewBag'] = $viewBag; + } + + /** + * @event cms.template.processSettingsBeforeSave + * Fires before a CMS template (page|partial|layout|content|asset) is saved and provides an opportunity to interact with the settings data. `$dataHolder` = {settings: []} + * + * Example usage: + * + * Event::listen('cms.template.processSettingsBeforeSave', function ((\Cms\Controllers\Index) $controller, (object) $dataHolder) { + * // Make some modifications to the $dataHolder object + * }); + * + * Or + * + * $CmsIndexController->bindEvent('template.processSettingsBeforeSave', function ((object) $dataHolder) { + * // Make some modifications to the $dataHolder object + * }); + * + */ + $dataHolder = (object) ['settings' => $settings]; + $this->fireSystemEvent('cms.template.processSettingsBeforeSave', [$dataHolder]); + + return $dataHolder->settings; + } + + /** + * Finds a given component by its alias. + * + * If found, this will return the component's name, alias and properties. + * + * @param string $aliasQuery The alias to search for + * @param array $components The array of components to look within. + * @return array|null + */ + protected function findComponentByAlias(string $aliasQuery, array $components = []) + { + $found = null; + + foreach ($components as $name => $properties) { + list($name, $alias) = strpos($name, ' ') ? explode(' ', $name) : [$name, $name]; + + if (ltrim($alias, '@') === ltrim($aliasQuery, '@')) { + $found = [ + 'name' => ltrim($name, '@'), + 'alias' => $alias, + 'properties' => $properties + ]; + break; + } + } + + return $found; + } + + /** + * Binds the active form widget to the controller + * @return void + */ + protected function bindFormWidgetToController() + { + $alias = Request::input('formWidgetAlias'); + $type = Request::input('templateType'); + $object = $this->loadTemplate($type, Request::input('templatePath')); + $widget = $this->makeTemplateFormWidget($type, $object, $alias); + + $widget->bindToController(); + } + + /** + * Replaces Windows style (/r/n) line endings with unix style (/n) + * line endings. + * @param string $markup The markup to convert to unix style endings + * @return string + */ + protected function convertLineEndings($markup) + { + $markup = str_replace(["\r\n", "\r"], "\n", $markup); + + return $markup; + } +} diff --git a/modules/cms/controllers/Media.php b/modules/cms/controllers/Media.php new file mode 100644 index 0000000..d45ddd6 --- /dev/null +++ b/modules/cms/controllers/Media.php @@ -0,0 +1,22 @@ += 2020. + */ +class Media extends MediaController +{ + /** + * Constructor. + */ + public function __construct() + { + traceLog('Controller Cms\Controllers\Media has been deprecated, use ' . MediaController::class . ' instead.'); + parent::__construct(); + } +} diff --git a/modules/cms/controllers/ThemeLogs.php b/modules/cms/controllers/ThemeLogs.php new file mode 100644 index 0000000..a229aef --- /dev/null +++ b/modules/cms/controllers/ThemeLogs.php @@ -0,0 +1,91 @@ +listRefresh(); + } + + public function index_onEmptyLog() + { + ThemeLog::truncate(); + Flash::success(Lang::get('cms::lang.theme_log.empty_success')); + return $this->listRefresh(); + } + + public function index_onDelete() + { + if (($checkedIds = post('checked')) && is_array($checkedIds) && count($checkedIds)) { + foreach ($checkedIds as $recordId) { + if (!$record = ThemeLog::find($recordId)) { + continue; + } + $record->delete(); + } + + Flash::success(Lang::get('backend::lang.list.delete_selected_success')); + } + else { + Flash::error(Lang::get('backend::lang.list.delete_selected_empty')); + } + + return $this->listRefresh(); + } + + public function preview($id) + { + $this->addCss('/modules/cms/assets/css/themelogs/template-diff.css', 'core'); + $this->addJs('/modules/cms/assets/vendor/jsdiff/diff.js', 'core'); + $this->addJs('/modules/cms/assets/js/themelogs/template-diff.js', 'core'); + + return $this->asExtension('FormController')->preview($id); + } +} diff --git a/modules/cms/controllers/ThemeOptions.php b/modules/cms/controllers/ThemeOptions.php new file mode 100644 index 0000000..78068c8 --- /dev/null +++ b/modules/cms/controllers/ThemeOptions.php @@ -0,0 +1,149 @@ +pageTitle = 'cms::lang.theme.settings_menu'; + + BackendMenu::setContext('October.System', 'system', 'settings'); + SettingsManager::setContext('October.Cms', 'theme'); + } + + public function update($dirName = null) + { + $dirName = $this->getDirName($dirName); + + try { + $model = $this->getThemeData($dirName); + + $this->asExtension('FormController')->update($model->id); + + $this->vars['hasCustomData'] = $this->hasThemeData($dirName); + } + catch (Exception $ex) { + $this->handleError($ex); + } + } + + public function update_onSave($dirName = null) + { + $model = $this->getThemeData($this->getDirName($dirName)); + $result = $this->asExtension('FormController')->update_onSave($model->id); + + // Redirect close requests to the settings index when user doesn't have access + // to go back to the theme selection page + if (!$this->user->hasAccess('cms.manage_themes') && input('close')) { + $result = Backend::redirect('system/settings'); + } + + return $result; + } + + public function update_onResetDefault($dirName = null) + { + $model = $this->getThemeData($this->getDirName($dirName)); + $model->delete(); + + return Backend::redirect('cms/themeoptions/update/'.$dirName); + } + + /** + * Add form fields defined in theme.yaml + */ + public function formExtendFieldsBefore($form) + { + $model = $form->model; + $theme = $this->findThemeObject($model->theme); + $form->config = $this->mergeConfig($form->config, $theme->getFormConfig()); + $form->init(); + } + + // + // Helpers + // + + /** + * Default to the active theme if user doesn't have access to manage all themes + * + * @param string $dirName + * @return string + */ + protected function getDirName(string $dirName = null) + { + /* + * Only the active theme can be managed without this permission + */ + if ($dirName && !$this->user->hasAccess('cms.manage_themes')) { + $dirName = null; + } + + if ($dirName === null) { + $dirName = CmsTheme::getActiveThemeCode(); + } + + return $dirName; + } + + protected function hasThemeData($dirName) + { + return $this->findThemeObject($dirName)->hasCustomData(); + } + + protected function getThemeData($dirName) + { + $theme = $this->findThemeObject($dirName); + return ThemeData::forTheme($theme); + } + + protected function findThemeObject($name = null) + { + if ($name === null) { + $name = post('theme'); + } + + if (!$name || (!$theme = CmsTheme::load($name))) { + throw new ApplicationException(trans('cms::lang.theme.not_found_name', ['name' => $name])); + } + + return $theme; + } +} diff --git a/modules/cms/controllers/Themes.php b/modules/cms/controllers/Themes.php new file mode 100644 index 0000000..83febf3 --- /dev/null +++ b/modules/cms/controllers/Themes.php @@ -0,0 +1,322 @@ +addCss('/modules/cms/assets/css/october.theme-selector.css', 'core'); + + $this->pageTitle = 'cms::lang.theme.settings_menu'; + BackendMenu::setContext('October.System', 'system', 'settings'); + SettingsManager::setContext('October.Cms', 'theme'); + + /* + * Custom redirect for unauthorized request + */ + $this->bindEvent('page.beforeDisplay', function () { + if (!$this->user->hasAccess('cms.manage_themes')) { + return Backend::redirect('cms/themeoptions/update'); + } + }); + + /* + * Enable AJAX for Form widgets + */ + if (post('mode') === 'import') { + $this->makeImportFormWidget($this->findThemeObject())->bindToController(); + } + } + + public function index() + { + $this->bodyClass = 'compact-container'; + } + + public function index_onSetActiveTheme() + { + CmsTheme::setActiveTheme(post('theme')); + + return [ + '#theme-list' => $this->makePartial('theme_list') + ]; + } + + public function index_onDelete() + { + ThemeManager::instance()->deleteTheme(post('theme')); + + Flash::success(trans('cms::lang.theme.delete_theme_success')); + return Redirect::refresh(); + } + + // + // Theme properties + // + + public function index_onLoadFieldsForm() + { + $theme = $this->findThemeObject(); + $this->vars['widget'] = $this->makeFieldsFormWidget($theme); + $this->vars['themeDir'] = $theme->getDirName(); + + return $this->makePartial('theme_fields_form'); + } + + public function index_onSaveFields() + { + $theme = $this->findThemeObject(); + $widget = $this->makeFieldsFormWidget($theme); + $theme->writeConfig($widget->getSaveData()); + + return ['#themeListItem-'.$theme->getId() => $this->makePartial('theme_list_item', ['theme' => $theme])]; + } + + protected function makeFieldsFormWidget($theme) + { + $widgetConfig = $this->makeConfig('~/modules/cms/classes/theme/fields.yaml'); + $widgetConfig->alias = 'form'.studly_case($theme->getDirName()); + $widgetConfig->model = $theme; + $widgetConfig->data = $theme->getConfig(); + $widgetConfig->data['dir_name'] = $theme->getDirName(); + $widgetConfig->arrayName = 'Theme'; + $widgetConfig->context = 'update'; + + return $this->makeWidget(Form::class, $widgetConfig); + } + + // + // Create theme + // + + public function index_onLoadCreateForm() + { + $this->vars['widget'] = $this->makeCreateFormWidget(); + return $this->makePartial('theme_create_form'); + } + + public function index_onCreate() + { + $widget = $this->makeCreateFormWidget(); + $data = $widget->getSaveData(); + $newDirName = trim(array_get($data, 'dir_name')); + $destinationPath = themes_path().'/'.$newDirName; + + $data = array_except($data, 'dir_name'); + + if (!strlen(trim(array_get($data, 'name')))) { + throw new ValidationException(['name' => trans('cms::lang.theme.create_theme_required_name')]); + } + + if (!preg_match('/^[a-z0-9\_\-]+$/i', $newDirName)) { + throw new ValidationException(['dir_name' => trans('cms::lang.theme.dir_name_invalid')]); + } + + if (File::isDirectory($destinationPath)) { + throw new ValidationException(['dir_name' => trans('cms::lang.theme.dir_name_taken')]); + } + + File::makeDirectory($destinationPath); + File::makeDirectory($destinationPath.'/assets'); + File::makeDirectory($destinationPath.'/content'); + File::makeDirectory($destinationPath.'/layouts'); + File::makeDirectory($destinationPath.'/pages'); + File::makeDirectory($destinationPath.'/partials'); + File::put($destinationPath.'/theme.yaml', ''); + + $theme = CmsTheme::load($newDirName); + $theme->writeConfig($data); + + Flash::success(trans('cms::lang.theme.create_theme_success')); + return Redirect::refresh(); + } + + protected function makeCreateFormWidget() + { + $widgetConfig = $this->makeConfig('~/modules/cms/classes/theme/fields.yaml'); + $widgetConfig->alias = 'formCreateTheme'; + $widgetConfig->model = new CmsTheme; + $widgetConfig->arrayName = 'Theme'; + $widgetConfig->context = 'create'; + + return $this->makeWidget('Backend\Widgets\Form', $widgetConfig); + } + + // + // Duplicate + // + + public function index_onLoadDuplicateForm() + { + $theme = $this->findThemeObject(); + $this->vars['themeDir'] = $theme->getDirName(); + + return $this->makePartial('theme_duplicate_form'); + } + + public function index_onDuplicateTheme() + { + $theme = $this->findThemeObject(); + $newDirName = trim(post('new_dir_name')); + $sourcePath = $theme->getPath(); + $destinationPath = themes_path().'/'.$newDirName; + + if (!preg_match('/^[a-z0-9\_\-]+$/i', $newDirName)) { + throw new ValidationException(['new_dir_name' => trans('cms::lang.theme.dir_name_invalid')]); + } + + if (File::isDirectory($destinationPath)) { + throw new ValidationException(['new_dir_name' => trans('cms::lang.theme.dir_name_taken')]); + } + + File::copyDirectory($sourcePath, $destinationPath); + $newTheme = CmsTheme::load($newDirName); + $newName = $newTheme->getConfigValue('name') . ' - Copy'; + $newTheme->writeConfig(['name' => $newName]); + + Flash::success(trans('cms::lang.theme.duplicate_theme_success')); + return Redirect::refresh(); + } + + // + // Theme export + // + + public function index_onLoadExportForm() + { + $theme = $this->findThemeObject(); + $this->vars['widget'] = $this->makeExportFormWidget($theme); + $this->vars['themeDir'] = $theme->getDirName(); + + return $this->makePartial('theme_export_form'); + } + + public function index_onExport() + { + $theme = $this->findThemeObject(); + $widget = $this->makeExportFormWidget($theme); + + $model = new ThemeExport; + $file = $model->export($theme, $widget->getSaveData()); + + return Backend::redirect('cms/themes/download/'.$file.'/'.$theme->getDirName().'.zip'); + } + + public function download($name, $outputName = null) + { + try { + $this->pageTitle = 'Download theme export archive'; + return ThemeExport::download($name, $outputName); + } + catch (Exception $ex) { + $this->handleError($ex); + } + } + + protected function makeExportFormWidget($theme) + { + $widgetConfig = $this->makeConfig('~/modules/cms/models/themeexport/fields.yaml'); + $widgetConfig->alias = 'form'.studly_case($theme->getDirName()); + $widgetConfig->model = new ThemeExport; + $widgetConfig->model->theme = $theme; + $widgetConfig->arrayName = 'ThemeExport'; + + return $this->makeWidget('Backend\Widgets\Form', $widgetConfig); + } + + // + // Theme import + // + + public function index_onLoadImportForm() + { + if (\Cms\Helpers\Cms::safeModeEnabled()) { + throw new ApplicationException(trans('cms::lang.cms_object.safe_mode_enabled')); + } + + $theme = $this->findThemeObject(); + $this->vars['widget'] = $this->makeImportFormWidget($theme); + $this->vars['themeDir'] = $theme->getDirName(); + + return $this->makePartial('theme_import_form'); + } + + public function index_onImport() + { + if (\Cms\Helpers\Cms::safeModeEnabled()) { + throw new ApplicationException(trans('cms::lang.cms_object.safe_mode_enabled')); + } + + $theme = $this->findThemeObject(); + $widget = $this->makeImportFormWidget($theme); + + $model = new ThemeImport; + $model->import($theme, $widget->getSaveData(), $widget->getSessionKey()); + + Flash::success(trans('cms::lang.theme.import_theme_success')); + return Redirect::refresh(); + } + + protected function makeImportFormWidget($theme) + { + $widgetConfig = $this->makeConfig('~/modules/cms/models/themeimport/fields.yaml'); + $widgetConfig->alias = 'form'.studly_case($theme->getDirName()); + $widgetConfig->model = new ThemeImport; + $widgetConfig->model->theme = $theme; + $widgetConfig->arrayName = 'ThemeImport'; + + return $this->makeWidget('Backend\Widgets\Form', $widgetConfig); + } + + // + // Helpers + // + + protected function findThemeObject($name = null) + { + if ($name === null) { + $name = post('theme'); + } + + if (!$name || (!$theme = CmsTheme::load($name))) { + throw new ApplicationException(trans('cms::lang.theme.not_found_name', ['name' => $name])); + } + + return $theme; + } +} diff --git a/modules/cms/controllers/index/_button_commit.htm b/modules/cms/controllers/index/_button_commit.htm new file mode 100644 index 0000000..cf08583 --- /dev/null +++ b/modules/cms/controllers/index/_button_commit.htm @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/modules/cms/controllers/index/_button_lastmodified.htm b/modules/cms/controllers/index/_button_lastmodified.htm new file mode 100644 index 0000000..129378f --- /dev/null +++ b/modules/cms/controllers/index/_button_lastmodified.htm @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/modules/cms/controllers/index/_button_reset.htm b/modules/cms/controllers/index/_button_reset.htm new file mode 100644 index 0000000..eac4f53 --- /dev/null +++ b/modules/cms/controllers/index/_button_reset.htm @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/modules/cms/controllers/index/_common_toolbar_actions.htm b/modules/cms/controllers/index/_common_toolbar_actions.htm new file mode 100644 index 0000000..89cb87e --- /dev/null +++ b/modules/cms/controllers/index/_common_toolbar_actions.htm @@ -0,0 +1,14 @@ +makePartial('button_commit'); ?> + +makePartial('button_reset'); ?> + + + +makePartial('button_lastmodified'); ?> \ No newline at end of file diff --git a/modules/cms/controllers/index/_concurrency_resolve_form.htm b/modules/cms/controllers/index/_concurrency_resolve_form.htm new file mode 100644 index 0000000..03ec6ca --- /dev/null +++ b/modules/cms/controllers/index/_concurrency_resolve_form.htm @@ -0,0 +1,29 @@ +'return false']) ?> + + + + diff --git a/modules/cms/controllers/index/_content_toolbar.htm b/modules/cms/controllers/index/_content_toolbar.htm new file mode 100644 index 0000000..02476a7 --- /dev/null +++ b/modules/cms/controllers/index/_content_toolbar.htm @@ -0,0 +1,12 @@ +
    + + + + + makePartial('common_toolbar_actions', ['toolbarSource' => 'content']); ?> +
    diff --git a/modules/cms/controllers/index/_form_page.htm b/modules/cms/controllers/index/_form_page.htm new file mode 100644 index 0000000..74d1b2f --- /dev/null +++ b/modules/cms/controllers/index/_form_page.htm @@ -0,0 +1,16 @@ + 'layout', + 'data-change-monitor' => 'true', + 'data-window-close-confirm' => e(trans('backend::lang.form.confirm_tab_close')), + 'data-inspector-external-parameters' => true +]) ?> + render() ?> + + + + + + + + + \ No newline at end of file diff --git a/modules/cms/controllers/index/_layout_toolbar.htm b/modules/cms/controllers/index/_layout_toolbar.htm new file mode 100644 index 0000000..fe336a1 --- /dev/null +++ b/modules/cms/controllers/index/_layout_toolbar.htm @@ -0,0 +1,12 @@ +
    + + + + + makePartial('common_toolbar_actions', ['toolbarSource' => 'layout']); ?> +
    diff --git a/modules/cms/controllers/index/_page_toolbar.htm b/modules/cms/controllers/index/_page_toolbar.htm new file mode 100644 index 0000000..e72f76d --- /dev/null +++ b/modules/cms/controllers/index/_page_toolbar.htm @@ -0,0 +1,23 @@ +
    + + + + + + + + + + makePartial('common_toolbar_actions', ['toolbarSource' => 'page']); ?> +
    diff --git a/modules/cms/controllers/index/_partial_toolbar.htm b/modules/cms/controllers/index/_partial_toolbar.htm new file mode 100644 index 0000000..4f4df2c --- /dev/null +++ b/modules/cms/controllers/index/_partial_toolbar.htm @@ -0,0 +1,12 @@ +
    + + + + + makePartial('common_toolbar_actions', ['toolbarSource' => 'partial']); ?> +
    diff --git a/modules/cms/controllers/index/_safemode_notice.htm b/modules/cms/controllers/index/_safemode_notice.htm new file mode 100644 index 0000000..b9e320c --- /dev/null +++ b/modules/cms/controllers/index/_safemode_notice.htm @@ -0,0 +1,6 @@ +
    +
    + +

    +
    +
    diff --git a/modules/cms/controllers/index/_sidepanel.htm b/modules/cms/controllers/index/_sidepanel.htm new file mode 100644 index 0000000..e38e505 --- /dev/null +++ b/modules/cms/controllers/index/_sidepanel.htm @@ -0,0 +1,80 @@ + +
    +
    +
    + user->hasAccess('cms.manage_pages')): ?> + +
    + widget->pageList->render() ?> +
    + + user->hasAccess('cms.manage_partials')): ?> + +
    + widget->partialList->render() ?> +
    + + user->hasAccess('cms.manage_layouts')): ?> + +
    + widget->layoutList->render() ?> +
    + + user->hasAccess('cms.manage_content')): ?> + +
    + widget->contentList->render() ?> +
    + + user->hasAccess('cms.manage_assets')): ?> + +
    + widget->assetList->render() ?> +
    + + user->hasAccess(['cms.manage_pages', 'cms.manage_layouts', 'cms.manage_partials'])): ?> + +
    + widget->componentList->render() ?> +
    + +
    +
    +
    diff --git a/modules/cms/controllers/index/config_content_list.yaml b/modules/cms/controllers/index/config_content_list.yaml new file mode 100644 index 0000000..a41ff5e --- /dev/null +++ b/modules/cms/controllers/index/config_content_list.yaml @@ -0,0 +1,7 @@ +# =================================== +# Configures the layout list widget +# =================================== + +noRecordsMessage: 'cms::lang.content.no_list_records' +deleteConfirmation: 'cms::lang.content.delete_confirm_multiple' +itemType: content diff --git a/modules/cms/controllers/index/config_layout_list.yaml b/modules/cms/controllers/index/config_layout_list.yaml new file mode 100644 index 0000000..9d66a36 --- /dev/null +++ b/modules/cms/controllers/index/config_layout_list.yaml @@ -0,0 +1,8 @@ +# =================================== +# Configures the layout list widget +# =================================== + +descriptionProperty: description +noRecordsMessage: 'cms::lang.layout.no_list_records' +deleteConfirmation: 'cms::lang.layout.delete_confirm_multiple' +itemType: layout diff --git a/modules/cms/controllers/index/config_page_list.yaml b/modules/cms/controllers/index/config_page_list.yaml new file mode 100644 index 0000000..b250218 --- /dev/null +++ b/modules/cms/controllers/index/config_page_list.yaml @@ -0,0 +1,15 @@ +# =================================== +# Configures the page list widget +# =================================== + +titleProperty: 'title' +descriptionProperty: description +descriptionProperties: + url: URL +noRecordsMessage: 'cms::lang.page.no_list_records' +deleteConfirmation: 'cms::lang.page.delete_confirm_multiple' +itemType: page +sortingProperties: + url: 'cms::lang.page.url' + title: 'cms::lang.page.title' + fileName: 'cms::lang.page.file_name' diff --git a/modules/cms/controllers/index/config_partial_list.yaml b/modules/cms/controllers/index/config_partial_list.yaml new file mode 100644 index 0000000..fae9b1a --- /dev/null +++ b/modules/cms/controllers/index/config_partial_list.yaml @@ -0,0 +1,8 @@ +# =================================== +# Configures the partial list widget +# =================================== + +descriptionProperty: description +noRecordsMessage: 'cms::lang.partial.no_list_records' +deleteConfirmation: 'cms::lang.partial.delete_confirm_multiple' +itemType: partial diff --git a/modules/cms/controllers/index/index.htm b/modules/cms/controllers/index/index.htm new file mode 100644 index 0000000..98baa45 --- /dev/null +++ b/modules/cms/controllers/index/index.htm @@ -0,0 +1,31 @@ + + fatalError): ?> + makePartial('sidepanel') ?> + + + + + fatalError): ?> +
    + +
    +
    + +
    +
    +
    +
    + +
    + +

    fatalError)) ?>

    + + diff --git a/modules/cms/controllers/media/index.htm b/modules/cms/controllers/media/index.htm new file mode 100644 index 0000000..d6f5048 --- /dev/null +++ b/modules/cms/controllers/media/index.htm @@ -0,0 +1,7 @@ + + + + 'layout', 'onsubmit'=>'return false']) ?> + widget->manager->render() ?> + + \ No newline at end of file diff --git a/modules/cms/controllers/themelogs/_field_content.htm b/modules/cms/controllers/themelogs/_field_content.htm new file mode 100644 index 0000000..3154caa --- /dev/null +++ b/modules/cms/controllers/themelogs/_field_content.htm @@ -0,0 +1,3 @@ +
    +
    +
    diff --git a/modules/cms/controllers/themelogs/_field_diff_content.htm b/modules/cms/controllers/themelogs/_field_diff_content.htm new file mode 100644 index 0000000..0e7a78e --- /dev/null +++ b/modules/cms/controllers/themelogs/_field_diff_content.htm @@ -0,0 +1,7 @@ +
    +
    
    +
    diff --git a/modules/cms/controllers/themelogs/_field_diff_template.htm b/modules/cms/controllers/themelogs/_field_diff_template.htm new file mode 100644 index 0000000..47ca899 --- /dev/null +++ b/modules/cms/controllers/themelogs/_field_diff_template.htm @@ -0,0 +1,7 @@ +
    +
    diff --git a/modules/cms/controllers/themelogs/_field_template.htm b/modules/cms/controllers/themelogs/_field_template.htm new file mode 100644 index 0000000..75d1610 --- /dev/null +++ b/modules/cms/controllers/themelogs/_field_template.htm @@ -0,0 +1 @@ +
    diff --git a/modules/cms/controllers/themelogs/_hint.htm b/modules/cms/controllers/themelogs/_hint.htm new file mode 100644 index 0000000..78591ed --- /dev/null +++ b/modules/cms/controllers/themelogs/_hint.htm @@ -0,0 +1,4 @@ + +

    + +

    \ No newline at end of file diff --git a/modules/cms/controllers/themelogs/_hint_preview.htm b/modules/cms/controllers/themelogs/_hint_preview.htm new file mode 100644 index 0000000..298de0e --- /dev/null +++ b/modules/cms/controllers/themelogs/_hint_preview.htm @@ -0,0 +1,22 @@ +type == $formModel::TYPE_DELETE): ?> +
    +
    + +

    +
    +
    +type == $formModel::TYPE_CREATE): ?> +
    +
    + +

    +
    +
    + +
    +
    + +

    +
    +
    + diff --git a/modules/cms/controllers/themelogs/_list_toolbar.htm b/modules/cms/controllers/themelogs/_list_toolbar.htm new file mode 100644 index 0000000..cbcfde0 --- /dev/null +++ b/modules/cms/controllers/themelogs/_list_toolbar.htm @@ -0,0 +1,31 @@ +
    + + + + + + + +
    diff --git a/modules/cms/controllers/themelogs/_preview_scoreboard.htm b/modules/cms/controllers/themelogs/_preview_scoreboard.htm new file mode 100644 index 0000000..abcf44d --- /dev/null +++ b/modules/cms/controllers/themelogs/_preview_scoreboard.htm @@ -0,0 +1,18 @@ +
    +

    +

    #id) ?>

    +
    +user): ?> +
    +

    +

    user->full_name) ?>

    +
    + +
    +

    +

    created_at->toDayDateTimeString()) ?>

    +
    +
    +

    +

    theme_name) ?>

    +
    diff --git a/modules/cms/controllers/themelogs/config_filter.yaml b/modules/cms/controllers/themelogs/config_filter.yaml new file mode 100644 index 0000000..2e35941 --- /dev/null +++ b/modules/cms/controllers/themelogs/config_filter.yaml @@ -0,0 +1,16 @@ +# =================================== +# Filter Scope Definitions +# =================================== + +scopes: + + created_at: + label: backend::lang.access_log.created_at + type: daterange + conditions: created_at >= ':after' AND created_at <= ':before' + + user: + label: backend::lang.access_log.login + modelClass: Backend\Models\User + conditions: user_id in (:filtered) + nameFrom: login diff --git a/modules/cms/controllers/themelogs/config_form.yaml b/modules/cms/controllers/themelogs/config_form.yaml new file mode 100644 index 0000000..be54c6e --- /dev/null +++ b/modules/cms/controllers/themelogs/config_form.yaml @@ -0,0 +1,19 @@ +# =================================== +# Form Behavior Config +# =================================== + +# Record name +name: system::lang.event_log.menu_label + +# Model Form Field configuration +form: ~/modules/cms/models/themelog/fields.yaml + +# Model Class name +modelClass: Cms\Models\ThemeLog + +# Default redirect location +defaultRedirect: cms/themelogs + +# Preview page +preview: + title: cms::lang.theme_log.preview_title \ No newline at end of file diff --git a/modules/cms/controllers/themelogs/config_list.yaml b/modules/cms/controllers/themelogs/config_list.yaml new file mode 100644 index 0000000..f3b0197 --- /dev/null +++ b/modules/cms/controllers/themelogs/config_list.yaml @@ -0,0 +1,22 @@ +# =================================== +# List Behavior Config +# =================================== + +title: cms::lang.theme_log.menu_label +list: ~/modules/cms/models/themelog/columns.yaml +modelClass: Cms\Models\ThemeLog +recordUrl: cms/themelogs/preview/:id +noRecordsMessage: backend::lang.list.no_records +recordsPerPage: 30 +showSetup: true +showCheckboxes: true +defaultSort: + column: count + direction: desc + +toolbar: + buttons: list_toolbar + search: + prompt: backend::lang.list.search_prompt + +filter: config_filter.yaml diff --git a/modules/cms/controllers/themelogs/index.htm b/modules/cms/controllers/themelogs/index.htm new file mode 100644 index 0000000..d20ced2 --- /dev/null +++ b/modules/cms/controllers/themelogs/index.htm @@ -0,0 +1,5 @@ +
    + makeHintPartial('system_requestlogs_hint', 'hint') ?> +
    + +listRender() ?> \ No newline at end of file diff --git a/modules/cms/controllers/themelogs/preview.htm b/modules/cms/controllers/themelogs/preview.htm new file mode 100644 index 0000000..5c8aae8 --- /dev/null +++ b/modules/cms/controllers/themelogs/preview.htm @@ -0,0 +1,34 @@ + +
      +
    • +
    • pageTitle)) ?>
    • +
    + + +fatalError): ?> + +
    +
    + makePartial('preview_scoreboard') ?> +
    +
    + +
    + makePartial('hint_preview') ?> +
    + +
    + formRenderPreview() ?> +
    + + + +

    fatalError)) ?>

    + + + +

    + + + +

    diff --git a/modules/cms/controllers/themeoptions/config_form.yaml b/modules/cms/controllers/themeoptions/config_form.yaml new file mode 100644 index 0000000..a26cac1 --- /dev/null +++ b/modules/cms/controllers/themeoptions/config_form.yaml @@ -0,0 +1,21 @@ +# =================================== +# Form Behavior Config +# =================================== + +# Record name +name: cms::lang.theme.theme_label + +# Fields are defined by extension +form: [] + +# Model Class name +modelClass: Cms\Models\ThemeData + +# Default redirect location +defaultRedirect: cms/themes + +# Update page +update: + title: cms::lang.theme.customize_theme + redirect: cms/themes + redirectClose: cms/themes diff --git a/modules/cms/controllers/themeoptions/update.htm b/modules/cms/controllers/themeoptions/update.htm new file mode 100644 index 0000000..4bc7b58 --- /dev/null +++ b/modules/cms/controllers/themeoptions/update.htm @@ -0,0 +1,70 @@ + +
      +
    • +
    • pageTitle)) ?>
    • +
    + + +fatalError): ?> + + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + + + + + + +
    +
    + + + + +
    +
    +

    There are no theme options available to customize.

    +
    +
    + + + + +

    fatalError) ?>

    +

    + + diff --git a/modules/cms/controllers/themes/_theme_create_form.htm b/modules/cms/controllers/themes/_theme_create_form.htm new file mode 100644 index 0000000..5ec6184 --- /dev/null +++ b/modules/cms/controllers/themes/_theme_create_form.htm @@ -0,0 +1,54 @@ + 'themeCreateForm', + 'data-popup-load-indicator' => true +]) ?> + + + + fatalError): ?> + + + + + + + + + + + + + + diff --git a/modules/cms/controllers/themes/_theme_duplicate_form.htm b/modules/cms/controllers/themes/_theme_duplicate_form.htm new file mode 100644 index 0000000..bcaa751 --- /dev/null +++ b/modules/cms/controllers/themes/_theme_duplicate_form.htm @@ -0,0 +1,75 @@ + 'themeDuplicateForm', + 'data-popup-load-indicator' => true, +]) ?> + + + + + + fatalError): ?> + + + + + + + + + + + + + + diff --git a/modules/cms/controllers/themes/_theme_export_form.htm b/modules/cms/controllers/themes/_theme_export_form.htm new file mode 100644 index 0000000..8d3e778 --- /dev/null +++ b/modules/cms/controllers/themes/_theme_export_form.htm @@ -0,0 +1,63 @@ + 'themeExportForm', + 'data-popup-load-indicator' => true, + 'data-request-success' => 'closeExportThemePopup()' +]) ?> + + + + + + fatalError): ?> + + + + + + + + + + + + + + diff --git a/modules/cms/controllers/themes/_theme_fields_form.htm b/modules/cms/controllers/themes/_theme_fields_form.htm new file mode 100644 index 0000000..eb8ea1e --- /dev/null +++ b/modules/cms/controllers/themes/_theme_fields_form.htm @@ -0,0 +1,56 @@ + 'themeFieldsForm', + 'data-popup-load-indicator' => true +]) ?> + + + + + + fatalError): ?> + + + + + + + + + + + + + + diff --git a/modules/cms/controllers/themes/_theme_import_form.htm b/modules/cms/controllers/themes/_theme_import_form.htm new file mode 100644 index 0000000..4fe68f1 --- /dev/null +++ b/modules/cms/controllers/themes/_theme_import_form.htm @@ -0,0 +1,57 @@ + 'themeImportForm', + 'data-popup-load-indicator' => true, +]) ?> + + + + + + + fatalError): ?> + + + + + + + + + + + + + + diff --git a/modules/cms/controllers/themes/_theme_list.htm b/modules/cms/controllers/themes/_theme_list.htm new file mode 100644 index 0000000..f2a8872 --- /dev/null +++ b/modules/cms/controllers/themes/_theme_list.htm @@ -0,0 +1,31 @@ + + $theme): ?> + +
    + makePartial('theme_list_item', ['theme' => $theme]) ?> +
    + + + + \ No newline at end of file diff --git a/modules/cms/controllers/themes/_theme_list_item.htm b/modules/cms/controllers/themes/_theme_list_item.htm new file mode 100644 index 0000000..19da857 --- /dev/null +++ b/modules/cms/controllers/themes/_theme_list_item.htm @@ -0,0 +1,121 @@ +getConfigValue('author'); +?> + +
    +
    +
    +
    +

    getConfigValue('name', $theme->getDirName())) ?>

    + +

    ''.e($author).'']) ?>

    + +

    + getConfigValue('description', 'The theme description is not provided.')) ?> +

    +
    + + isActiveTheme()): ?> + + + + + hasCustomData()): ?> + + + + + + +
    +
    diff --git a/modules/cms/controllers/themes/download.htm b/modules/cms/controllers/themes/download.htm new file mode 100644 index 0000000..33d0163 --- /dev/null +++ b/modules/cms/controllers/themes/download.htm @@ -0,0 +1,13 @@ + +
      +
    • +
    • pageTitle)) ?>
    • +
    + + +fatalError): ?> + +

    fatalError) ?>

    +

    + + \ No newline at end of file diff --git a/modules/cms/controllers/themes/index.htm b/modules/cms/controllers/themes/index.htm new file mode 100644 index 0000000..5b7fe3e --- /dev/null +++ b/modules/cms/controllers/themes/index.htm @@ -0,0 +1,11 @@ + +
    +
    + 'return false']) ?> +
    + makePartial('theme_list') ?> +
    + +
    +
    + \ No newline at end of file diff --git a/modules/cms/database/migrations/2014_10_01_000001_Db_Cms_Theme_Data.php b/modules/cms/database/migrations/2014_10_01_000001_Db_Cms_Theme_Data.php new file mode 100644 index 0000000..4f7cccd --- /dev/null +++ b/modules/cms/database/migrations/2014_10_01_000001_Db_Cms_Theme_Data.php @@ -0,0 +1,23 @@ +engine = 'InnoDB'; + $table->increments('id'); + $table->string('theme')->nullable()->index(); + $table->mediumtext('data')->nullable(); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('cms_theme_data'); + } +} diff --git a/modules/cms/database/migrations/2016_10_01_000002_Db_Cms_Timestamp_Fix.php b/modules/cms/database/migrations/2016_10_01_000002_Db_Cms_Timestamp_Fix.php new file mode 100644 index 0000000..327640e --- /dev/null +++ b/modules/cms/database/migrations/2016_10_01_000002_Db_Cms_Timestamp_Fix.php @@ -0,0 +1,24 @@ +engine = 'InnoDB'; + $table->increments('id'); + $table->string('type', 20)->index(); + $table->string('theme')->nullable()->index(); + $table->string('template')->nullable(); + $table->string('old_template')->nullable(); + $table->longText('content')->nullable(); + $table->longText('old_content')->nullable(); + $table->integer('user_id')->index()->nullable(); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('cms_theme_logs'); + } +} diff --git a/modules/cms/database/migrations/2018_11_01_000001_Db_Cms_Theme_Templates.php b/modules/cms/database/migrations/2018_11_01_000001_Db_Cms_Theme_Templates.php new file mode 100644 index 0000000..f81a4ba --- /dev/null +++ b/modules/cms/database/migrations/2018_11_01_000001_Db_Cms_Theme_Templates.php @@ -0,0 +1,26 @@ +engine = 'InnoDB'; + $table->increments('id'); + $table->string('source')->index(); + $table->string('path')->index(); + $table->longText('content'); + $table->integer('file_size')->unsigned(); + $table->dateTime('updated_at')->nullable(); + $table->dateTime('deleted_at')->nullable(); + }); + } + + public function down() + { + Schema::dropIfExists('cms_theme_templates'); + } +} diff --git a/modules/cms/facades/Cms.php b/modules/cms/facades/Cms.php new file mode 100644 index 0000000..4657595 --- /dev/null +++ b/modules/cms/facades/Cms.php @@ -0,0 +1,21 @@ +listComponents(); + + return $this->makePartial('formcomponents', ['components' => $components]); + } + + protected function listComponents() + { + $result = []; + + if (!isset($this->model->settings['components'])) { + return $result; + } + + $manager = ComponentManager::instance(); + $manager->listComponents(); + + foreach ($this->model->settings['components'] as $name => $properties) { + list($name, $alias) = strpos($name, ' ') ? explode(' ', $name) : [$name, $name]; + + try { + $componentObj = $manager->makeComponent($name, null, $properties); + $componentObj->alias = ((starts_with($name, '@') && $alias !== $name) ? '@' : '') . $alias; + $componentObj->pluginIcon = 'icon-puzzle-piece'; + + /* + * Look up the plugin hosting this component + */ + $plugin = $manager->findComponentPlugin($componentObj); + if ($plugin) { + $pluginDetails = $plugin->pluginDetails(); + if (isset($pluginDetails['icon'])) { + $componentObj->pluginIcon = $pluginDetails['icon']; + } + } + } + catch (Exception $ex) { + if (starts_with($name, '@')) { + $componentObj = new SoftComponent($properties); + $componentObj->name = $name; + $componentObj->alias = (($alias !== $name) ? '@' : '') . $alias; + $componentObj->pluginIcon = 'icon-flag'; + } else { + $componentObj = new UnknownComponent(null, $properties, $ex->getMessage()); + $componentObj->alias = $alias; + $componentObj->pluginIcon = 'icon-bug'; + } + } + + $result[] = $componentObj; + } + + return $result; + } + + protected function getComponentName($component) + { + return ComponentHelpers::getComponentName($component); + } + + protected function getComponentDescription($component) + { + return ComponentHelpers::getComponentDescription($component); + } + + protected function getComponentsPropertyConfig($component) + { + return ComponentHelpers::getComponentsPropertyConfig($component); + } + + protected function getComponentPropertyValues($component) + { + return ComponentHelpers::getComponentPropertyValues($component); + } +} diff --git a/modules/cms/formwidgets/MediaFinder.php b/modules/cms/formwidgets/MediaFinder.php new file mode 100644 index 0000000..171ac54 --- /dev/null +++ b/modules/cms/formwidgets/MediaFinder.php @@ -0,0 +1,32 @@ += 2020. + */ +class MediaFinder extends BackendMediaFinder +{ + /** + * Constructor. + */ + public function __construct() + { + traceLog('FormWidget Cms\FormWidgets\MediaFinder has been deprecated, use ' . BackendMediaFinder::class . ' instead.'); + + $this->assetPath = '/modules/backend/formwidgets/mediafinder/assets'; + $this->viewPath = base_path('/modules/backend/formwidgets/mediafinder/partials'); + + parent::__construct(...func_get_args()); + } +} diff --git a/modules/cms/formwidgets/components/partials/_component.htm b/modules/cms/formwidgets/components/partials/_component.htm new file mode 100644 index 0000000..0707d8b --- /dev/null +++ b/modules/cms/formwidgets/components/partials/_component.htm @@ -0,0 +1,17 @@ +
    +
    inspectorEnabled): ?>data-inspectable + data-inspector-title="getComponentName($component)) ?>" + data-inspector-description="getComponentDescription($component)) ?>" + data-inspector-config="getComponentsPropertyConfig($component)) ?>" + data-inspector-class=""> + + + alias) ?> + + + + × +
    +
    \ No newline at end of file diff --git a/modules/cms/formwidgets/components/partials/_formcomponents.htm b/modules/cms/formwidgets/components/partials/_formcomponents.htm new file mode 100644 index 0000000..0f22cbb --- /dev/null +++ b/modules/cms/formwidgets/components/partials/_formcomponents.htm @@ -0,0 +1,17 @@ +
    + + isHidden): ?> + makePartial('component', ['component' => $component]) ?> + + + +
    +
    + + isHidden): ?> + makePartial('component', ['component' => $component]) ?> + + +
    +
    +
    diff --git a/modules/cms/helpers/Cms.php b/modules/cms/helpers/Cms.php new file mode 100644 index 0000000..34332c2 --- /dev/null +++ b/modules/cms/helpers/Cms.php @@ -0,0 +1,48 @@ +getByAction($routeAction) !== null; + } + + if (substr($path, 0, 1) == '/') { + $path = substr($path, 1); + } + + if (self::$actionExists) { + return Url::action($routeAction, ['slug' => $path]); + } + + return Url::to($path); + } + + public static function safeModeEnabled() + { + $safeMode = Config::get('cms.enableSafeMode', null); + if ($safeMode === null) { + $safeMode = !Config::get('app.debug', false); + } + return $safeMode; + } +} diff --git a/modules/cms/helpers/File.php b/modules/cms/helpers/File.php new file mode 100644 index 0000000..8849927 --- /dev/null +++ b/modules/cms/helpers/File.php @@ -0,0 +1,74 @@ + $maxNesting) { + return false; + } + + foreach ($segments as $segment) { + if (!self::validateName($segment)) { + return false; + } + } + + return true; + } +} diff --git a/modules/cms/lang/ar/lang.php b/modules/cms/lang/ar/lang.php new file mode 100644 index 0000000..aca0842 --- /dev/null +++ b/modules/cms/lang/ar/lang.php @@ -0,0 +1,40 @@ + [ + 'active_theme' => [ + 'widget_title_default' => 'الموقع', + 'online' => 'أونلاين', + 'maintenance' => 'تحت الصيانة', + 'manage_themes' => 'إدارة القوالب', + 'customize_theme' => 'تخصيص القالب' + ] + ], + 'page' => [ + 'menu_label' => 'الصفحات', + ], + 'layout' => [ + 'menu_label' => 'النماذج', + ], + 'partial' => [ + 'menu_label' => 'الجزئيات', + ], + 'content' => [ + 'menu_label' => 'المحتوى', + ], + 'cms' => [ + 'menu_label' => 'المحتوى' + ], + 'editor' => [ + 'settings' => 'الإعدادات', + ], + 'asset' => [ + 'menu_label' => 'الأصول', + ], + 'component' => [ + 'menu_label' => 'المكونات', + ], + 'permissions' => [ + 'name' => 'إدارة المحتوى', + ], +]; diff --git a/modules/cms/lang/be/lang.php b/modules/cms/lang/be/lang.php new file mode 100644 index 0000000..a88134d --- /dev/null +++ b/modules/cms/lang/be/lang.php @@ -0,0 +1,255 @@ + [ + 'invalid_file' => "Няправільнае імя файла: \":name\". Імёны файлаў могуць утрымліваць толькі літарна-лічбавыя знакі, знакі падкрэслення, працяжнік і кропкі. Некаторыя прыклады правільных імёнаў файлаў: page.htm, page, subdirectory/page", + 'invalid_property' => "Ўласцівасць \":name\" не можа быць ўстаноўлена", + 'file_already_exists' => "Файл \":name\" ужо існуе", + 'error_saving' => "Памылка падчас захавання файла \":name\". Калі ласка, праверце дазволы на запіс", + 'error_creating_directory' => "Памылка падчас стварэння каталогу \":name\". Калі ласка, праверце дазволы на запіс", + 'invalid_file_extension' => "Няправільнае пашырэнне файла: :invalid. Дазволеныя пашырэнні: :allowed", + 'error_deleting' => "Памылка падчас выдалення файла шаблону \":name\". Калі ласка, праверце дазволы на запіс", + 'delete_success' => "Выдалена шаблонаў: :count", + 'file_name_required' => "Патрабуецца імя файла", + 'safe_mode_enabled' => "Бяспечны рэжым ужо уключаны", + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => "Вэбсайт", + 'online' => "Анлайн", + 'maintenance' => "У абслугоўванні", + 'manage_themes' => "Кіраванне тэмамі", + ] + ], + 'theme' => [ + 'not_found_name' => "Тэма \":name\" не знойдзена", + 'active' => [ + 'not_set' => "Актыўная тэма не ўстаноўлена", + 'not_found' => "Актыўная тэма не знойдзена" + ], + 'edit' => [ + 'not_set' => "Тэма для рэдагавання не ўстаноўлена", + 'not_found' => "Тэма для рэдагавання не знойдзена", + 'not_match' => "Аб'ект, які Вы спрабуеце адкрыць, не належыць рэдагуемай тэме. Калі ласка, перазагрузіце старонку" + ], + 'settings_menu' => "Інтэрфейсная тэма", + 'settings_menu_description' => "Прагляд усталяваных тэм і выбар актыўнай тэмы", + 'default_tab' => "Уласцівасці", + 'name_label' => "Імя", + 'name_create_placeholder' => "Новае імя тэмы", + 'author_label' => "Аўтар", + 'author_placeholder' => "Імя чалавека або назва кампаніі", + 'description_label' => "Апісанне", + 'description_placeholder' => "Апісанне тэмы", + 'homepage_label' => "Хатняя старонка", + 'homepage_placeholder' => "Адрас вэбсайта", + 'code_label' => "Код", + 'code_placeholder' => "Унікальны код гэтай тэмы, які можа быць выкарыстаны для распаўсюджвання", + 'dir_name_label' => "Назва каталогу", + 'dir_name_create_label' => "Каталог прызначэння для тэмы", + 'theme_label' => "Тэма", + 'theme_title' => "Тэмы", + 'activate_button' => "Актываваць", + 'active_button' => "Актыўная", + 'customize_theme' => "Наладзіць тэму", + 'customize_button' => "Налады", + 'duplicate_button' => "Капіраваць", + 'duplicate_title' => "Скапіраваць тэму", + 'duplicate_theme_success' => "Тэма скапіравана!", + 'manage_button' => "Кіраванне", + 'manage_title' => "Кіраваць тэмай", + 'edit_properties_title' => "Тэма", + 'edit_properties_button' => "Рэдагаваць налады", + 'save_properties' => "Захаваць налады", + 'import_button' => "Імпарт", + 'import_title' => "Імпартаваць тэму", + 'import_theme_success' => "Тэма імпартавана!", + 'import_uploaded_file' => "Архіў тэмы", + 'import_overwrite_label' => "Перапісаць файлы, што існуюць", + 'import_overwrite_comment' => "Зніміце гэтую пазнаку, каб імпартаваць толькі новыя файлы", + 'import_folders_label' => "Каталогі", + 'import_folders_comment' => "Калі ласка, выберыце каталогі тэмы, якія Вы жадаеце імпартаваць", + 'export_button' => "Экспарт", + 'export_title' => "Экспартаваць тэму", + 'export_folders_label' => "Каталогі", + 'export_folders_comment' => "Калі ласка, выберыце каталогі тэмы, якія Вы жадаеце экспартаваць", + 'delete_button' => "Выдаліць", + 'delete_confirm' => "Вы ўпэўнены, што жадаеце выдаліць гэтую тэму? Гэта нельга адмяніць!", + 'delete_active_theme_failed' => "Немагчыма выдаліць актыўную тэму, паспрабуйце спачатку зрабіць іншую тэму актыўнай", + 'delete_theme_success' => "Тэма была выдалена!", + 'create_title' => "Стварыць тэму", + 'create_button' => "Стварыць", + 'create_new_blank_theme' => "Стварыць новую пустую тэму", + 'create_theme_success' => "Тэма была створана!", + 'create_theme_required_name' => "Калі ласка, укажыце імя тэмы", + 'new_directory_name_label' => "Каталог тэмы", + 'new_directory_name_comment' => "Вызначце новае імя каталога для скапіраванай тэмы", + 'dir_name_invalid' => "Імя можа складацца толькі з лічбаў, лацінскіх літараў і наступных сімвалаў: _-", + 'dir_name_taken' => "Пажаданае імя ўжо існуе", + 'find_more_themes' => "Знайсці больш тэм", + 'saving' => "Захаванне тэмы...", + 'return' => "Вярнуцца да спісу тэм", + ], + 'maintenance' => [ + 'settings_menu' => "Рэжым абслугоўвання", + 'settings_menu_description' => "Наладзіць старонку рэжыма абслугоўвання і пераключыць наладу", + 'is_enabled' => "Уключыць рэжым абслугоўвання", + 'is_enabled_comment' => "Выберыце старонку, якую неабходна паказваць, калі ўключаны рэжым абслугоўвання", + 'hint' => "Рэжым абслугоўвання будзе паказваць абраную старонку наведвальнікам, якія не ўвайшлі ў панэль кіравання", + ], + 'page' => [ + 'not_found_name' => "Старонка \":name\" не знойдзена", + 'not_found' => [ + 'label' => "Старонка не знойдзена", + 'help' => "Запрошаная старонка не можа быць знойдзена" + ], + 'custom_error' => [ + 'label' => "Памылка на старонцы", + 'help' => "Прабачце, але нешта здарылася і старонка не можа быць адлюстравана" + ], + 'menu_label' => "Старонкі", + 'unsaved_label' => "Незахаваныя старонкі", + 'no_list_records' => "Няма старонак", + 'new' => "Новая старонка", + 'invalid_url' => "Няправільны фармат URL. URL павінен пачынацца з \"\\/\" і складацца з лацінскіх літараў, лічбаў і наступных сімвалаў: ._-[]:?|/+*^$", + 'delete_confirm_multiple' => "Выдаліць абраныя старонкі?", + 'delete_confirm_single' => "Выдаліць гэтую старонку?", + 'no_layout' => "-- няма макету --", + 'cms_page' => "Старонка CMS" + ], + 'layout' => [ + 'not_found_name' => "Макет \":name\" не знойдзены", + 'menu_label' => "Макеты", + 'unsaved_label' => "Незахаваныя макеты", + 'no_list_records' => "Няма макетаў", + 'new' => "Новы макет", + 'delete_confirm_multiple' => "Выдаліць абраныя макеты?", + 'delete_confirm_single' => "Выдаліць гэты макет?" + ], + 'partial' => [ + 'not_found_name' => "Частковы шаблон \":name\" не знойдзены", + 'invalid_name' => "Няправільная назва частковага шаблона: \":name\"", + 'menu_label' => "Частковыя шаблоны", + 'unsaved_label' => "Незахаваныя частковыя шаблоны", + 'no_list_records' => "Няма частковых шаблонаў", + 'delete_confirm_multiple' => "Выдаліць абраныя шаблоны?", + 'delete_confirm_single' => "Выдаліць гэты частковы шаблон?", + 'new' => "Новы частковы шаблон" + ], + 'content' => [ + 'not_found_name' => "Зместавы файл \":name\" не знойдзены", + 'menu_label' => "Змест", + 'unsaved_label' => "Незахаваны змест", + 'no_list_records' => "Зместавыя файлы не знойдзены", + 'delete_confirm_multiple' => "Выдаліць абраныя зместавыя файлы альбо каталогі?", + 'delete_confirm_single' => "Выдаліць гэты зместавы файл?", + 'new' => "Новы зместавы файл" + ], + 'ajax_handler' => [ + 'invalid_name' => "Няправільнае імя апрацоўшчыка AJAX: \":name\"", + 'not_found' => "AJAX апрацоўшчык \":name\" не знойдзены" + ], + 'cms' => [ + 'menu_label' => "CMS" + ], + 'sidebar' => [ + 'add' => "Дадаць", + 'search' => "Знайсці..." + ], + 'editor' => [ + 'settings' => "Налады", + 'title' => "Назва", + 'new_title' => "Назва новай старонкі", + 'url' => "URL", + 'filename' => "Імя файла", + 'layout' => "Макет", + 'description' => "Апісанне", + 'preview' => "Папярэдні прагляд", + 'meta' => "Мета", + 'meta_title' => "Назва мета-дадзеных", + 'meta_description' => "Апісанне мета-дадзеных", + 'markup' => "Макет", + 'code' => "Код", + 'content' => "Змест", + 'hidden' => "Схаваная", + 'hidden_comment' => "Схаваная старонка бачная толькі для карыстальнікаў панэлі кіравання, якія ўвайшлі ў сістэму", + 'enter_fullscreen' => "Ўключыць паўнаэкранны рэжым", + 'exit_fullscreen' => "Выключыць паўнаэкранны рэжым", + 'open_searchbox' => "Адчыніць пошук", + 'close_searchbox' => "Зачыніць пошук", + 'open_replacebox' => "Адчыніць налады для замены", + 'close_replacebox' => "Зачыніць налады для замены" + ], + 'asset' => [ + 'menu_label' => "Рэсурсы", + 'unsaved_label' => "Незахаваныя рэсурсы", + 'drop_down_add_title' => "Дадаць...", + 'drop_down_operation_title' => "Дзеянне...", + 'upload_files' => "Загрузіць файлы", + 'create_file' => "Стварыць файл", + 'create_directory' => "Стварыць каталог", + 'directory_popup_title' => "Новы каталог", + 'directory_name' => "Назва каталогу", + 'rename' => "Пераіменаваць", + 'delete' => "Выдаліць", + 'move' => "Перамясціць", + 'select' => "Выбраць", + 'new' => "Новы файл", + 'rename_popup_title' => "Пераіменаваць", + 'rename_new_name' => "Новае імя", + 'invalid_path' => "Шлях можа ўтрымліваць толькі лічбы, лацінскія літары, прабелы і наступныя сімвалы: ._-/", + 'error_deleting_file' => "Памылка падчас выдалення файлу \":name\"", + 'error_deleting_dir_not_empty' => "Памылка падчас выдалення каталогу \":name\". Каталог не пусты", + 'error_deleting_dir' => "Памылка падчас выдалення каталогу \":name\"", + 'invalid_name' => "Імя можа ўтрымліваць толькі лічбы, лацінскія літары, прабелы і наступныя сімвалы: ._-", + 'original_not_found' => "Арыгінальныя файл альбо каталог не былі знойдзены", + 'already_exists' => "Файл альбо каталог з такім імем ужо існуе", + 'error_renaming' => "Памылка падчас пераіменавання файла ільбо каталога", + 'name_cant_be_empty' => "Імя не можа быць пустым", + 'too_large' => "Файл занадта вялікі. Найбольы дазволеы памер :max_size", + 'type_not_allowed' => "Дазволеныя толькі наступныя тыпы файлаў: :allowed_types", + 'file_not_valid' => "Файл няправільны", + 'error_uploading_file' => "Памылка падчас загрузкі файла \":name\": :error", + 'move_please_select' => "калі ласка, выберыце", + 'move_destination' => "Каталог прызначэння", + 'move_popup_title' => "Перамясціць рэсурсы", + 'move_button' => "Перамясціць", + 'selected_files_not_found' => "Абраныя файлы не былі знойдзеныя", + 'select_destination_dir' => "Калі ласка, вызначце каталог прызначэння", + 'destination_not_found' => "Каталог прызначэння не знойдзены", + 'error_moving_file' => "Памылка падчас перамяшчэння файла \":file\"", + 'error_moving_directory' => "Памылка падчас перамяшчэння каталогу \":dir\"", + 'error_deleting_directory' => "Памылка падчас выдалення зыходнага каталогу \":dir\"", + 'no_list_records' => "Файлы не знойдзены", + 'delete_confirm' => "Выдаліць абраныя файлы альбо каталогі?", + 'path' => "Шлях" + ], + 'component' => [ + 'menu_label' => "Кампаненты", + 'unnamed' => "Неназваны", + 'no_description' => "Няма апісання", + 'alias' => "Псеўданім", + 'alias_description' => "Унікальнае імя макету, каб ужываць яго на старонцы альбо ў макеце", + 'validation_message' => "Псеўданімы для кампанентаў з'яўляюцца неабходнымі і могуць складацца толькі з лацінскіх сімвалаў, лічбаў і знакаў падкрэслівання. Пачынацца павінны з лацінскага сімвала", + 'invalid_request' => "Шаблон не можа быць захаваны з-за няправільных дадзеных кампаненту", + 'no_records' => "Няма кампанентаў", + 'not_found' => "Кампанент \":name\" не знойдзены", + 'method_not_found' => "Кампанент \":name\" не мае метада \":method\"" + ], + 'template' => [ + 'invalid_type' => "Невядомы тып шаблону", + 'not_found' => "Шаблон не знойдзены", + 'saved' => "Шаблон захаваны", + 'no_list_records' => "Запісы не знойдзены", + 'delete_confirm' => "Выдаліць абраныя шаблоны?" + ], + 'permissions' => [ + 'name' => "CMS", + 'manage_content' => "Кіраванне зместавымі файламі сайту", + 'manage_assets' => "Кіраванне рэсурсамі сайту - малюнкамі, файламі JavaScript, CSS", + 'manage_pages' => "Стварэнне, змяненне і выдаленне старонак сайту", + 'manage_layouts' => "Стварэнне, змяненне і выдаленне CMS макетаў", + 'manage_partials' => "Стварэнне, змяненне і выдаленне частковых шаблонаў CMS", + 'manage_themes' => "Актывацыя, дэактывацыя і налады тэмаў CMS", + ] +]; diff --git a/modules/cms/lang/bg/lang.php b/modules/cms/lang/bg/lang.php new file mode 100644 index 0000000..c3909b9 --- /dev/null +++ b/modules/cms/lang/bg/lang.php @@ -0,0 +1,235 @@ + [ + 'invalid_file' => 'Невалидно име на файл: :name. Имената на файловете могат да съдържат само букви и символи, долни черти, тирета и точки. Някои примери за правилни имена на файлове: page.htm, страница, поддиректория / страница', + 'invalid_property' => "Свойство ': name' не може да се сложи.", + 'file_already_exists' => "Файл ':name' вече съществува.", + 'error_saving' => "Грешка при запазване на ':name'. Моля, проверете правата за записване.", + 'error_creating_directory' => 'Грешка при създаване на директория :name. Моля, проверете правата за записване.', + 'invalid_file_extension' => 'Невалидно разширение на файл: :invalid. Позволени разширения са: :allowed.', + 'error_deleting' => "Грешка при изтриване на шаблонен файл ':name'. Моля, проверете правата за записване.", + 'delete_success' => 'Шаблоните са успешно изтрити: :count.', + 'file_name_required' => 'Полето Име на Файл е задължително.' + ], + 'theme' => [ + 'not_found_name' => "Темата ':name' не е намерена.", + 'active' => [ + 'not_set' => 'Активната тема не е зададена.', + 'not_found' => 'Активната тема не е намерена.' + ], + 'edit' => [ + 'not_set' => 'Темата за редактиране не е зададена.', + 'not_found' => 'Темата за редактиране не е намерена.', + 'not_match' => 'Обектът, който се опитвате да достъпите, не принадлежи към темата да се редактира. Моля, презаредете страницата.' + ], + 'settings_menu' => 'Front-end Тема', + 'settings_menu_description' => 'Преглед на списъка с инсталирани теми и изберете активна тема.', + 'default_tab' => 'Свойства', + 'name_label' => 'Име', + 'name_create_placeholder' => 'Ново име на тема', + 'author_label' => 'Автор', + 'author_placeholder' => 'Лице или име на фирма', + 'description_label' => 'Описание', + 'description_placeholder' => 'Описание на Темата', + 'homepage_label' => 'Страница', + 'homepage_placeholder' => 'Сайт адрес', + 'code_label' => 'Код', + 'code_placeholder' => 'Уникален код на тази тема, използвана за разпространение', + 'dir_name_label' => 'Име на директория', + 'dir_name_create_label' => 'Директорията на дестинация за темата', + 'theme_label' => 'Тема', + 'theme_title' => 'Теми', + 'activate_button' => 'Активна', + 'active_button' => 'Активна', + 'customize_theme' => 'Персонализирайте Тема', + 'customize_button' => 'Персонализирайте', + 'duplicate_button' => 'Дубликиране', + 'duplicate_title' => 'Дубликиране на Тема', + 'duplicate_theme_success' => 'Темата е успешно дубликирана!', + 'manage_button' => 'Управление', + 'manage_title' => 'Управление Теми', + 'edit_properties_title' => 'Теми', + 'edit_properties_button' => 'Редактиране на свойства', + 'save_properties' => 'Запазване на свойства', + 'import_button' => 'Внасяне', + 'import_title' => 'Внасяне на Тема', + 'import_theme_success' => 'Успешно внесена Тема!', + 'import_uploaded_file' => 'Тема архивен файл', + 'import_overwrite_label' => 'Презаписване съществуващите файлове', + 'import_overwrite_comment' => 'Махнете отметката в това квадратче, за да импортирате само нови файлове', + 'import_folders_label' => 'Папки', + 'import_folders_comment' => 'Моля, изберете папката на темата, която бихте искали да внесете', + 'export_button' => 'Изнасяне', + 'export_title' => 'Изнасяне на Тема', + 'export_folders_label' => 'Папки', + 'export_folders_comment' => 'Моля, изберете папката на темата, която бихте искали да изнесете', + 'delete_button' => 'Изтриване', + 'delete_confirm' => 'Сигурни ли сте че искате да изтриете тази тема? Това не може да бъде отменено!', + 'delete_active_theme_failed' => 'Не може да се изтрие активна тема, опитайте да активирате друга тема първо.', + 'delete_theme_success' => 'Успешно изтрита тема!', + 'create_title' => 'Създай Тема', + 'create_button' => 'Създай', + 'create_new_blank_theme' => 'Създай нова празна тема', + 'create_theme_success' => 'Успешно създадена Тема!', + 'create_theme_required_name' => 'Моля, задайте име за темата.', + 'new_directory_name_label' => 'Тема директория', + 'new_directory_name_comment' => 'Представете ново име на директория за дубликата на темата.', + 'dir_name_invalid' => 'Името може да съдържа само цифри, латински букви и следните символи: _-', + 'dir_name_taken' => 'Желаната директория за тема вече съществува.', + 'find_more_themes' => 'Намери още теми', + 'saving' => 'Запазване на Тема...', + 'return' => 'Назад към списъка с теми', + ], + 'maintenance' => [ + 'settings_menu' => 'Режим на поддръжка', + 'settings_menu_description' => 'Конфигуриране на страницата в Режим на поддръжка и превключване на настройката.', + 'is_enabled' => 'Активиране на Режим на поддръжка', + 'is_enabled_comment' => 'Когато е активиран, посетителите на сайта ще виждат само страницата по-долу.' + ], + 'page' => [ + 'not_found_name' => "Страницата ':name' не намерена.", + 'not_found' => [ + 'label' => 'Страницата не е намерена.', + 'help' => 'Заявената страница не може да бъде намерена.' + ], + 'custom_error' => [ + 'label' => 'Грешка на страницата.', + 'help' => "Съжаляваме, но нещо се обърка и на страницата не може да бъде показана." + ], + 'menu_label' => 'Страници', + 'unsaved_label' => 'Незапазена страница(и)', + 'no_list_records' => 'Няма намерени страници.', + 'new' => 'Нова страница', + 'invalid_url' => 'Невалиден формат за URL. Той трябва да започне със символа за наклонена черта и може да съдържат цифри, латински букви и следните символи: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Наистина ли искате да изтриете избраните страници?', + 'delete_confirm_single' => 'Наистина ли искате да изтриете страницата?', + 'no_layout' => '-- няма оформление --' + ], + 'layout' => [ + 'not_found_name' => "Оформлението ':name' не намерено.", + 'menu_label' => 'Оформление', + 'unsaved_label' => 'Незапазено оформление(я)', + 'no_list_records' => 'Няма намерени оформления', + 'new' => 'Ново оформление', + 'delete_confirm_multiple' => 'Наистина ли искате да изтриете избраните оформления?', + 'delete_confirm_single' => 'Наистина ли искате да изтриете това оформление?' + ], + 'partial' => [ + 'not_found_name' => "Частична страница ':name' не е намерена.", + 'invalid_name' => 'Невалидно име за частична страница: :name.', + 'menu_label' => 'Частични страници', + 'unsaved_label' => 'Незапазени частична страница(и)', + 'no_list_records' => 'No partials found', + 'delete_confirm_multiple' => 'Наистина ли искате да изтриете избраните частични страници?', + 'delete_confirm_single' => 'Наистина ли искате да изтриете тази частична страница?', + 'new' => 'Нова частична страница' + ], + 'content' => [ + 'not_found_name' => "Файлът със съдържание ':name' не е намерен.", + 'menu_label' => 'Съдържание', + 'unsaved_label' => 'Незапазено съдържание', + 'no_list_records' => 'Няма намерени файлове със съдържание', + 'delete_confirm_multiple' => 'Наистина ли искате да изтриете избраните файлове със съдържание или директории?', + 'delete_confirm_single' => 'Наистина ли искате да изтриете този файл със съдържание?', + 'new' => 'Нов файл със съдържание' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Невалидно име на AJAX манипулатор: :name.', + 'not_found' => "AJAX манипулатор ':name' не е намерен." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Добави', + 'search' => 'Търсене...' + ], + 'editor' => [ + 'settings' => 'Настройки', + 'title' => 'Заглавие', + 'new_title' => 'Ново заглавие на страница', + 'url' => 'URL', + 'filename' => 'Име на файл', + 'layout' => 'Оформление', + 'description' => 'Описание', + 'preview' => 'Предварителен преглед', + 'meta' => 'Мета', + 'meta_title' => 'Мета Заглавие', + 'meta_description' => 'Мета Описание', + 'markup' => 'Markup', + 'code' => 'Код', + 'content' => 'Съдържание', + 'hidden' => 'Скрит', + 'hidden_comment' => 'Скрити страници са достъпни само от логнатите регистрирани потребители.', + 'enter_fullscreen' => 'Премини в режим на цял екран', + 'exit_fullscreen' => 'Изход от режим на цял екран' + ], + 'asset' => [ + 'menu_label' => 'Ресурси', + 'unsaved_label' => 'Незапазени ресурс(и)', + 'drop_down_add_title' => 'Добави...', + 'drop_down_operation_title' => 'Действие...', + 'upload_files' => 'Качване на файл(ове)', + 'create_file' => 'Създай файл', + 'create_directory' => 'Създай директория', + 'directory_popup_title' => 'Нова директория', + 'directory_name' => 'Име на директория', + 'rename' => 'Преименувай', + 'delete' => 'Изтрий', + 'move' => 'Премести', + 'select' => 'Избери', + 'new' => 'Нов файл', + 'rename_popup_title' => 'Преименувай', + 'rename_new_name' => 'Ново име', + 'invalid_path' => 'Пътят може да съдържа само цифри, латински букви, интервали и следните символи: ._-/', + 'error_deleting_file' => 'Грешка при изтриване на файл :name.', + 'error_deleting_dir_not_empty' => 'грешка при изтриване на директория :name. Директорията не е празна.', + 'error_deleting_dir' => 'Грешка при изтриване на файл :name.', + 'invalid_name' => 'Името може да съдържа само цифри, латински букви, интервали и следните символи: ._-', + 'original_not_found' => 'Оригиналния файл или директория не е намерен', + 'already_exists' => 'Файл или директория с това име вече съществува', + 'error_renaming' => 'Грешка при преименуване на файл или директория', + 'name_cant_be_empty' => 'Името не може да е празно', + 'too_large' => 'Каченият файл е твърде голям. Максимално допустимия размерът на файл е :max_size', + 'type_not_allowed' => 'Разрешени са само следните типове файлове: :allowed_types', + 'file_not_valid' => 'Файлът не е валиден', + 'error_uploading_file' => "Грешка при качването на файл ':name': :error", + 'move_please_select' => 'Моля изберете', + 'move_destination' => 'Дестинационна директория', + 'move_popup_title' => 'Преместете Ресурси', + 'move_button' => 'Премести', + 'selected_files_not_found' => 'Избрани файлове не са намерени', + 'select_destination_dir' => 'Моля изберете дестинационна директория', + 'destination_not_found' => 'Дестинационната директория не е намерена', + 'error_moving_file' => 'Грешка при преместването на файл :file', + 'error_moving_directory' => 'Грешка при преместването на директория :dir', + 'error_deleting_directory' => 'Грешка при изтриване на оригинална директория :dir', + 'path' => 'Път' + ], + 'component' => [ + 'menu_label' => 'Компоненти', + 'unnamed' => 'Без име', + 'no_description' => 'Няма дадено описание', + 'alias' => 'Псевдоним', + 'alias_description' => 'Уникално име е дадено на този компонент, когато се използва в кода на страница или оформление.', + 'validation_message' => 'Компонент псевдоними са задължителни и могат да съдържат само латински символи, цифри и долна черта. Псевдонимите трябва да започнат с латински символ', + 'invalid_request' => 'Шаблонът не може да бъде спасен, защото от невалиден данни на компонент.', + 'no_records' => 'Няма намерени компоненти', + 'not_found' => "Компонентът ':name' не е намерен.", + 'method_not_found' => "Компонентът ':name' не съдържа метод ':method'." + ], + 'template' => [ + 'invalid_type' => 'Неизвестен тип шаблон.', + 'not_found' => 'Заявения шаблон не е намерен.', + 'saved'=> 'Шаблонът е запазен успешно.' + ], + 'permissions' => [ + 'name' => 'Cms', + 'manage_content' => 'Управление на съдържанието', + 'manage_assets' => 'Управление на ресурси', + 'manage_pages' => 'Управление на страници', + 'manage_layouts' => 'Управление на оформления', + 'manage_partials' => 'Управление на частични страници', + 'manage_themes' => 'Управление на теми', + ] +]; diff --git a/modules/cms/lang/ca/lang.php b/modules/cms/lang/ca/lang.php new file mode 100644 index 0000000..e9b5247 --- /dev/null +++ b/modules/cms/lang/ca/lang.php @@ -0,0 +1,293 @@ + [ + 'invalid_file' => "Nom d'arxiu invàlid: :name. Els noms d'arxiu només poden contenir símbols alfanumèrics, subratllats, guions i punts. Exemples de noms d'arxiu correctes: pagina.htm, pagina, subdirectori/pagina", + 'invalid_property' => "No es pot establir a propietat ':name'", + 'file_already_exists' => "L'arxiu ':name' ja existeix.", + 'error_saving' => "Error guardant l'arxiu ':name'. Si us plau revisa els permisos d'escriptura.", + 'error_creating_directory' => "Error creant el directori ':name'. Si us plau revisa els permisos d'escriptura.", + 'invalid_file_extension' => "Extensió d'arxiu invàlida: :invalid. Extensions permeses: :allowed.", + 'error_deleting' => "Error eliminant l'arxiu de plantilla ':name'. Si us plau revisa els permisos d'escriptura.", + 'delete_success' => 'Plantilles eliminades: :count.', + 'file_name_required' => "El camp 'Nom d'arxiu' és obligatori.", + 'safe_mode_enabled' => 'El mode segur està activat.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Lloc web', + 'online' => 'Online', + 'maintenance' => 'En manteniment', + 'manage_themes' => 'Gestionar temes', + 'customize_theme' => 'Personalitzar tema' + ] + ], + 'theme' => [ + 'not_found_name' => "No s'ha trobat el tema ':name'.", + 'by_author' => 'Per :name', + 'active' => [ + 'not_set' => "No s'ha establit un tema actiu.", + 'not_found' => "No s'ha trobat el tema actiu." + ], + 'edit' => [ + 'not_set' => "No s'ha establit un tema d'edició.", + 'not_found' => "No s'ha trobat el tema d'edició.", + 'not_match' => "L'objecte al que estàs intentant accedir no pertany al tema que estàs editant. Si us plau recarrega la pàgina." + ], + 'settings_menu' => 'Tema de front-end', + 'settings_menu_description' => 'Gestionar el tema de front-end i les opcions de personalització.', + 'default_tab' => 'Propietats', + 'name_label' => 'Nom', + 'name_create_placeholder' => 'Nou nom del tema', + 'author_label' => 'Autor', + 'author_placeholder' => 'Persona o companyia', + 'description_label' => 'Descripció', + 'description_placeholder' => 'Descripció del tema', + 'homepage_label' => 'Lloc web', + 'homepage_placeholder' => 'URL del lloc web', + 'code_label' => 'Codi', + 'code_placeholder' => 'Un codi únic per aquest tema utilitzat per a la distribució', + 'preview_image_label' => 'Imatge de previsualització', + 'preview_image_placeholder' => 'La ruta de la imatge de previsualització.', + 'dir_name_label' => 'Nom del directori', + 'dir_name_create_label' => 'El directori de destí del tema', + 'theme_label' => 'Tema', + 'theme_title' => 'Temes', + 'activate_button' => 'Activar', + 'active_button' => 'Activar', + 'customize_theme' => 'Personalitzar tema', + 'customize_button' => 'Personalitzar', + 'duplicate_button' => 'Duplicar', + 'duplicate_title' => 'Duplicar tema', + 'duplicate_theme_success' => 'Tema duplicat!', + 'manage_button' => 'Gestionar', + 'manage_title' => 'Gestionar el tema', + 'edit_properties_title' => 'Tema', + 'edit_properties_button' => 'Editar propietats', + 'save_properties' => 'Guardar propietats', + 'import_button' => 'Importar', + 'import_title' => 'Importar tema', + 'import_theme_success' => 'Tema importat!', + 'import_uploaded_file' => 'Arxiu de tema', + 'import_overwrite_label' => 'Sobreescriure arxius existents', + 'import_overwrite_comment' => 'Desmarca aquesta casella per importar només arxius nous', + 'import_folders_label' => 'Carpetes', + 'import_folders_comment' => 'Si us plau selecciona les carpetes del tema que vols importar', + 'export_button' => 'Exportar', + 'export_title' => 'Exportar tema', + 'export_folders_label' => 'Carpetes', + 'export_folders_comment' => 'Si us plau selecciona les carpetes del tema que vols exportar', + 'delete_button' => 'Eliminar', + 'delete_confirm' => 'Eliminar aquest tema? No es pot desfer!', + 'delete_active_theme_failed' => 'No es pot eliminar el tema actiu, estableix un altre tema com a actiu primer.', + 'delete_theme_success' => 'Tema eliminat!', + 'create_title' => 'Crear tema', + 'create_button' => 'Crear', + 'create_new_blank_theme' => 'Crear un nou tema buit', + 'create_theme_success' => 'Tema creat!', + 'create_theme_required_name' => 'Si us plau indica un nom pel nou tema.', + 'new_directory_name_label' => 'Directori del tema', + 'new_directory_name_comment' => 'Indica un nou nom de directori per al tema duplicat.', + 'dir_name_invalid' => 'El nom només pot contenir números, lletres llatines i els següents símbols: _-', + 'dir_name_taken' => 'El nom de directori desitjat ja existeix.', + 'find_more_themes' => 'Trobar més temes', + 'saving' => 'Guardant tema...', + 'return' => 'Tornar a la llista de temes' + ], + 'maintenance' => [ + 'settings_menu' => 'Mode de manteniment', + 'settings_menu_description' => "Configura el mode de manteniment i canvia l'activació.", + 'is_enabled' => 'Activar el mode de manteniment', + 'is_enabled_comment' => 'Selecciona la pàgina per mostrar quan el mode de manteniment està activat.', + 'hint' => "El mode de manteniment mostrarà la pàgina de manteniment als visitants que no hagin accedit a l'àrea d'administració." + ], + 'page' => [ + 'not_found_name' => "La pàgina ':name' no s'ha trobat", + 'not_found' => [ + 'label' => 'Pàgina no trobada', + 'help' => 'La pàgina demanada no es pot trobar.' + ], + 'custom_error' => [ + 'label' => 'Error de pàgina', + 'help' => "Ens sap greu, però alguna cosa ha anat malament i la pàgina no es pot mostrar." + ], + 'menu_label' => 'Pàgines', + 'unsaved_label' => 'Pàgines no guardades', + 'no_list_records' => "No s'han trobat pàgines", + 'new' => 'Nova pàgina', + 'invalid_url' => 'Format d\'URL invàlid. La URL ha de començar amb el símbol / i pot contenir números, lletres llatines i els següents símbols: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Eliminar pàgines seleccionades?', + 'delete_confirm_single' => 'Eliminar aquesta pàgina?', + 'no_layout' => '-- sense plantilla --', + 'cms_page' => 'Pàgina de CMS', + 'title' => 'Títol de pàgina', + 'url' => 'URL de pàgina', + 'file_name' => "Nom de l'arxiu de pàgina" + ], + 'layout' => [ + 'not_found_name' => "La plantilla ':name' no s'ha trobat", + 'menu_label' => 'Plantilles', + 'unsaved_label' => 'Plantilles no guardades', + 'no_list_records' => "No s'han trobat plantilles", + 'new' => 'Nova plantilla', + 'delete_confirm_multiple' => 'Eliminar plantilles seleccionades?', + 'delete_confirm_single' => 'Eliminar aquesta plantilla?' + ], + 'partial' => [ + 'not_found_name' => "El parcial ':name' no s'ha trobat.", + 'invalid_name' => 'Nom de parcial invàlid: :name.', + 'menu_label' => 'Parcials', + 'unsaved_label' => 'Parcials no guardats', + 'no_list_records' => "No s'han trobat parcials", + 'delete_confirm_multiple' => 'Eliminar parcials seleccionats?', + 'delete_confirm_single' => 'Eliminar aquest parcial?', + 'new' => 'Nou parcial' + ], + 'content' => [ + 'not_found_name' => "L'arxiu de contingut ':name' no s'ha trobat.", + 'menu_label' => 'Contingut', + 'unsaved_label' => 'Contingut no guardat', + 'no_list_records' => "No s'han trobat arxius de contingut", + 'delete_confirm_multiple' => 'Eliminar arxius o directoris de contingut seleccionats?', + 'delete_confirm_single' => 'Eliminar aquest arxiu de contingut?', + 'new' => 'Nou arxiu de contingut' + ], + 'ajax_handler' => [ + 'invalid_name' => "Nom de manipulador d'AJAX invàlid: :name.", + 'not_found' => "El manipulador d'AJAX ':name' no s'ha trobat." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Afegir', + 'search' => 'Cercar...' + ], + 'editor' => [ + 'settings' => 'Opcions', + 'title' => 'Títol', + 'new_title' => 'Nou títol de pàgina', + 'url' => 'URL', + 'filename' => "Nom d'arxiu", + 'layout' => 'Plantilla', + 'description' => 'Descripció', + 'preview' => 'Previsualitzar', + 'meta' => 'Meta', + 'meta_title' => 'Meta títol', + 'meta_description' => 'Meta descripció', + 'markup' => 'Marcat', + 'code' => 'Codi', + 'content' => 'Contingut', + 'hidden' => 'Amagat', + 'hidden_comment' => "Les pàgines amagades només són accessibles pels usuaris connectats a l'àrea d'administració.", + 'enter_fullscreen' => 'Activar mode de pàgina completa', + 'exit_fullscreen' => 'Sortir del mode de pàgina completa', + 'open_searchbox' => 'Obrir caixa de cerca', + 'close_searchbox' => 'Tancar caixa de cerca', + 'open_replacebox' => 'Obrir caixa de substitució', + 'close_replacebox' => 'Tancar caixa de substitució' + ], + 'asset' => [ + 'menu_label' => 'Recursos', + 'unsaved_label' => 'Recursos no guardats', + 'drop_down_add_title' => 'Afegir...', + 'drop_down_operation_title' => 'Acció...', + 'upload_files' => 'Pujar arxius', + 'create_file' => 'Crear arxiu', + 'create_directory' => 'Crear directori', + 'directory_popup_title' => 'Nou directori', + 'directory_name' => 'Nom del directori', + 'rename' => 'Reanomenar', + 'delete' => 'Eliminar', + 'move' => 'Moure', + 'select' => 'Seleccionar', + 'new' => 'Nou arxiu', + 'rename_popup_title' => 'Reanomenar', + 'rename_new_name' => 'Nou nom', + 'invalid_path' => 'La ruta només pot contenir números, lletres llatines, espais i els símbols: ._-/', + 'error_deleting_file' => "Error eliminant l'arxiu :name.", + 'error_deleting_dir_not_empty' => 'Error eliminant el directori :name. El directori no està buit.', + 'error_deleting_dir' => 'Error eliminant el directori :name.', + 'invalid_name' => 'El nom només pot contenir números, lletres llatines, espais i els símbols: ._-', + 'original_not_found' => "No s'ha trobat l'arxiu o directori original", + 'already_exists' => 'Ja existeix un arxiu o directori amb aquest nom', + 'error_renaming' => "Error reanomenant l'arxiu o directori", + 'name_cant_be_empty' => 'El nom no pot estar buit', + 'too_large' => "L'arxiu pujat és massa gran. La mida màxima d'arxiu és :max_size", + 'type_not_allowed' => "Només es permeten els següents tipus d'arxiu: :allowed_types", + 'file_not_valid' => "L'arxiu no és vàlid", + 'error_uploading_file' => "Error pujant l'arxiu ':name': :error", + 'move_please_select' => 'si us plau selecciona', + 'move_destination' => 'Directori de destí', + 'move_popup_title' => 'Moure recursos', + 'move_button' => 'Moure', + 'selected_files_not_found' => "No s'han trobat els arxius seleccionats", + 'select_destination_dir' => 'Si us plau selecciona un directori de destí', + 'destination_not_found' => "No s'ha trobat el directori de destí", + 'error_moving_file' => "Error movent l'arxiu :file", + 'error_moving_directory' => 'Error movent el directori :dir', + 'error_deleting_directory' => 'Error eliminant el directori original :dir', + 'no_list_records' => "No s'han trobat arxius", + 'delete_confirm' => 'Eliminar els arxius o directoris seleccionats?', + 'path' => 'Ruta' + ], + 'component' => [ + 'menu_label' => 'Components', + 'unnamed' => 'Sense nom', + 'no_description' => "No s'ha proveït una descripció", + 'alias' => 'Alies', + 'alias_description' => 'Un nom únic assignat a aquest component per utilitzar-lo al codi de la pàgina o plantilla.', + 'validation_message' => 'Els àlies de components són obligatoris i només poden contenir lletres llatines, números i subratllats. Han de començar amb una lletra.', + 'invalid_request' => 'La plantilla no es pot guardar perquè conté dades de components invàlides.', + 'no_records' => "No s'han trobat components", + 'not_found' => "No s'ha trobat el component ':name'.", + 'method_not_found' => "El component ':name' no conté un mètode ':method'." + ], + 'template' => [ + 'invalid_type' => 'Tipus de plantilla desconegut.', + 'not_found' => "No s'ha trobat la plantilla.", + 'saved' => 'Plantilla guardada.', + 'no_list_records' => "No s'han trobat registres", + 'delete_confirm' => 'Eliminar les plantilles seleccionades?', + 'order_by' => 'Ordenar per' + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Gestionar els arxius de contingut del lloc web', + 'manage_assets' => 'Gestionar els recursos del lloc web - imatges, arxius JavaScript, arxius CSS', + 'manage_pages' => 'Crear, modificar i eliminar pàgines del lloc web', + 'manage_layouts' => 'Crear, modificar i eliminar plantilles del CMS', + 'manage_partials' => 'Crear, modificar i eliminar parcials del CMS', + 'manage_themes' => 'Activar, desactivar and configurar temes del CMS', + 'manage_theme_options' => 'Configurar opcions de personalització pel tema actiu', + ], + 'theme_log' => [ + 'hint' => "Aquest registre mostra els canvis fets al tema des de l'àrea d'administració.", + 'menu_label' => 'Registre del tema', + 'menu_description' => 'Veure canvis fets al tema actiu.', + 'empty_link' => 'Buidar registre del tema', + 'empty_loading' => 'Buidant registre del tema...', + 'empty_success' => 'Registre del tema buit!', + 'return_link' => 'Tornar al registre del tema', + 'id' => 'ID', + 'id_label' => 'ID del registre', + 'created_at' => 'Data i hora', + 'user' => 'Usuari', + 'type' => 'Tipus', + 'type_create' => 'Crear', + 'type_update' => 'Modificar', + 'type_delete' => 'Eliminar', + 'theme_name' => 'Tema', + 'theme_code' => 'Codi del tema', + 'old_template' => 'Plantilla (antiga)', + 'new_template' => 'Plantilla (nova)', + 'template' => 'Plantilla', + 'diff' => 'Canvis', + 'old_value' => 'Valor antic', + 'new_value' => 'Valor nou', + 'preview_title' => 'Canvis de la plantilla', + 'template_updated' => "La plantilla s'ha modificat", + 'template_created' => "La plantilla s'ha creat", + 'template_deleted' => "La plantilla s'ha eliminat", + ], +]; diff --git a/modules/cms/lang/cs/lang.php b/modules/cms/lang/cs/lang.php new file mode 100644 index 0000000..0699e58 --- /dev/null +++ b/modules/cms/lang/cs/lang.php @@ -0,0 +1,295 @@ + [ + 'invalid_file' => 'Neplatný název souboru: :name. Názvy souborů mohou obsahovat pouze alfanumerické symboly, podtržítka, pomlčky a tečky. Některé příklady správných názvů souborů: stranka.htm, stranka, adresar/stranka', + 'invalid_property' => "Parametr ':name' není možno nastavit", + 'file_already_exists' => "Soubor ':name' již existuje.", + 'error_saving' => "Chyba ukládání souboru ':name'. Zkontrolujte práva k zápisu.", + 'error_creating_directory' => 'Chyba vytváření složky :name. Zkontrolujte práva k zápisu.', + 'invalid_file_extension'=>'Chybná přípona souboru: :invalid. Povolené přípony jsou: :allowed.', + 'error_deleting' => "Chyba mazání souboru s šablonou ':name'. Zkontrolujte práva k zápisu.", + 'delete_success' => 'Šablony úspěšně smazány: :count.', + 'file_name_required' => 'Je nutno vyplnit Název souboru.', + 'safe_mode_enabled' => 'Bezpěčný režim (safe mode) je aktivní.' + + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Webová stránka', + 'online' => 'Online', + 'maintenance' => 'Probíhá údržba', + 'manage_themes' => 'Spravovat témata vzhledu', + 'customize_theme' => 'Upravit téma vzhledu' + ] + ], + 'theme' => [ + 'not_found_name' => "Téma ':name' nebylo nalezeno.", + 'by_author' => 'Vytvořil :name', + 'active' => [ + 'not_set' => 'Aktivní téma nebylo nastaveno.', + 'not_found' => 'Aktivní téma nebylo nalezeno.' + ], + 'edit' => [ + 'not_set' => 'Editované téma nebylo uloženo.', + 'not_found' => 'Editované téma nebylo nalezeno.', + 'not_match' => "Objekt který chcete právě zobrazit nepatří do téma, které nyní editujete. Prosím obnovte stránku." + ], + 'settings_menu' => 'Témata vzhledu', + 'settings_menu_description' => 'Náhledy instalovaných témat a výběr aktivního téma.', + 'default_tab' => 'Parametry', + 'name_label' => 'Název', + 'name_create_placeholder' => 'Název nového téma', + 'author_label' => 'Autor', + 'author_placeholder' => 'Jméno osoby, nebo firmy', + 'description_label' => 'Popisek', + 'description_placeholder' => 'Popište svoje téma', + 'homepage_label' => 'Domovská stránka', + 'homepage_placeholder' => 'URL domovské stránky', + 'code_label' => 'Kód', + 'code_placeholder' => 'Unikátní kód téma pro distribuci aktualizační sítí', + 'preview_image_label' => 'Náhled', + 'preview_image_placeholder' => 'Cesta k souboru s náhledem vzhledu.', + 'dir_name_label' => 'Název složky', + 'dir_name_create_label' => 'Název cílové složky pro uložení téma', + 'theme_label' => 'Téma', + 'theme_title' => 'Téma', + 'activate_button' => 'Aktivovat', + 'active_button' => 'Aktivní', + 'customize_theme' => 'Přizpůsobení téma', + 'customize_button' => 'Přizpůsobit', + 'duplicate_button' => 'Duplikovat', + 'duplicate_title' => 'Duplikovat téma', + 'duplicate_theme_success' => 'Duplikace téma byla úspěšná!', + 'manage_button' => 'Správa téma', + 'manage_title' => 'Správa témat', + 'edit_properties_title' => 'Téma', + 'edit_properties_button' => 'Nastavit', + 'save_properties' => 'Uložit nastavení', + 'import_button' => 'Importovat', + 'import_title' => 'Importovat téma', + 'import_theme_success' => 'Téma úspěšně importováno!', + 'import_uploaded_file' => 'Soubor s tématem', + 'import_overwrite_label' => 'Přepsat existující soubory', + 'import_overwrite_comment' => 'Odškrtněte tento box pokud chcete importovat pouze nové soubory.', + 'import_folders_label' => 'Složky', + 'import_folders_comment' => 'Vyberte prosím složky, které chcete importovat', + 'export_button' => 'Exportovat', + 'export_title' => 'Exportovat téma', + 'export_folders_label' => 'Složky', + 'export_folders_comment' => 'Vyberte prosím složky, které chcete exportovat', + 'delete_button' => 'Smazat', + 'delete_confirm' => 'Jste si jistí, že chcete smazat toto téma? Tuto akci nelze vrátit zpět!', + 'delete_active_theme_failed' => 'Nelze smazat aktivní téma. Nejdříve aktivujte jiné téma.', + 'delete_theme_success' => 'Téma úspěšně smazáno!', + 'create_title' => 'Vytvořit téma', + 'create_button' => 'Vytvořit', + 'create_new_blank_theme' => 'Vytvořit nové čisté téma', + 'create_theme_success' => 'Téma úspěšně vytvořeno!', + 'create_theme_required_name' => 'Napište jméno pro nové téma.', + 'new_directory_name_label' => 'Složka téma', + 'new_directory_name_comment' => 'Zadejte název nové složky pro duplikaci téma.', + 'dir_name_invalid' => 'Název může obsahovat pouze čísla, písmena a následující symboly: _-', + 'dir_name_taken' => 'Tato složka s tématem již existuje.', + 'find_more_themes' => 'Vyhledat více témat', + 'saving' => 'Ukládám téma...', + 'return' => 'Zpět na seznam témat', + ], + 'maintenance' => [ + 'settings_menu' => 'Režim údržby', + 'settings_menu_description' => 'Nastavte stránku režimu údržby a její nastavení.', + 'is_enabled' => 'Aktivovat režim údržby', + 'is_enabled_comment' => 'Pokud je režim údržby aktivní, uživatelé uvidí stránku vybranou níže.', + 'hint' => 'Režim údržby zobrazí stránku údržby návštěvníkům, kteří nejsou přihlášeni do administrace.' + + ], + 'page' => [ + 'not_found_name' => "Stránka ':name' nebyla nalezena", + 'not_found' => [ + 'label' => 'Stránka nenalezena', + 'help' => 'Požadovaná stránka nebyla nalezena.' + ], + 'custom_error' => [ + 'label' => 'Chyba stránky', + 'help' => "Omlouváme se, ale požadovaná stránka nelze zobrazit z důvodu nějaké chyby." + ], + 'menu_label' => 'Stránky', + 'unsaved_label' => 'Neuložené stránky', + 'no_list_records' => 'Žádné stránky', + 'new' => 'Nová stránka', + 'invalid_url' => 'Špatný formát URL. URL musí začínat lomítkem a může obsahovat pouze číslice, písmena a následující znaky: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Opravdu chcete odstranit vybrané stránky?', + 'delete_confirm_single' => 'Opravdu chcete odstranit tuto stránku?', + 'no_layout' => '-- žádný layout --', + 'cms_page' => 'CMS stránka', + 'title' => 'Název stránky', + 'url' => 'URL stránky', + 'file_name' => 'Název souboru stránky' + ], + 'layout' => [ + 'not_found_name' => "Layout ':name' nebyl nalezen", + 'menu_label' => 'Layouty', + 'unsaved_label' => 'Neuložený layout(y)', + 'no_list_records' => 'Žádné layouty nebyly nalezeny', + 'new' => 'Nový layout', + 'delete_confirm_multiple' => 'Opravdu chcete odstranit vybrané layouty?', + 'delete_confirm_single' => 'Opravdu chcete odstranit tento layout?' + ], + 'partial' => [ + 'not_found_name' => "Dílčí šablona ':name' nebyla nalezena.", + 'invalid_name' => 'Chybný název dílčí šablony: :name.', + 'menu_label' => 'Dílčí šablony', + 'unsaved_label' => 'Neuložené dílčí šablony', + 'no_list_records' => 'Žádné dílčí šablony', + 'delete_confirm_multiple' => 'Opravdu chcete smazat tyto dílčí šablony?', + 'delete_confirm_single' => 'Opravdu chcete smazat tuto dílčí šablonu?', + 'new' => 'Nová šablona' + ], + 'content' => [ + 'not_found_name' => "Obsahový soubor ':name' nebyl nalezen.", + 'menu_label' => 'Obsahy', + 'unsaved_label' => 'Neuložený obsah', + 'no_list_records' => 'Žádné obsahové soubory', + 'delete_confirm_multiple' => 'Opravdu chcete smazat tyto obsahové soubory nebo složky?', + 'delete_confirm_single' => 'Opravdu chcete smazat tento obsahový soubor?', + 'new' => 'Žádný obsahový soubor' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Neplatný název AJAX handleru: :name.', + 'not_found' => "AJAX handler ':name' nebyl nalezen." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Přidat', + 'search' => 'Hledat...' + ], + 'editor' => [ + 'settings' => 'Nastavení', + 'title' => 'Název souboru', + 'new_title' => 'Nový název souboru', + 'url' => 'URL', + 'filename' => 'Název souboru', + 'layout' => 'Layout', + 'description' => 'Popisek', + 'preview' => 'Náhled', + 'meta' => 'Meta údaje', + 'meta_title' => 'Meta Nadpis (Title)', + 'meta_description' => 'Meta Popisek (Description)', + 'markup' => 'Kód', + 'code' => 'PHP kód', + 'content' => 'Obsah', + 'hidden' => 'Skrytý', + 'hidden_comment' => 'Skryté stránky jsou dostupné pouze přihlášeným administrátorům pro náhled.', + 'enter_fullscreen' => 'Zapnout režim celé obrazovky', + 'exit_fullscreen' => 'Opustit režim celé obrazovky', + 'open_searchbox' => 'Otevřít box hledávání', + 'close_searchbox' => 'Zavřít box hledání', + 'open_replacebox' => 'Otevřít box nahrazování', + 'close_replacebox' => 'Zavřít box nahrazování' + ], + 'asset' => [ + 'menu_label' => 'Soubory', + 'unsaved_label' => 'Neuložené soubory', + 'drop_down_add_title' => 'Přidat...', + 'drop_down_operation_title' => 'Akce...', + 'upload_files' => 'Nahrát soubor(y)', + 'create_file' => 'Vytvořit soubor', + 'create_directory' => 'Vytvořit složku', + 'directory_popup_title' => 'Vytvoření nové složky', + 'directory_name' => 'Název složky', + 'rename' => 'Přejmenovat', + 'delete' => 'Smazat', + 'move' => 'Přesunout', + 'select' => 'Vybrat', + 'new' => 'Nový soubor', + 'rename_popup_title' => 'Přejmenovat', + 'rename_new_name' => 'Nový název', + 'invalid_path' => 'Cesta může obsahovat pouze číslice, písmena, mezery nebo následující znaky: ._-/', + 'error_deleting_file' => 'Chyba mazání souboru :name.', + 'error_deleting_dir_not_empty' => 'Chyba mazání složky :name. Složka není prázdná.', + 'error_deleting_dir' => 'Chyba mazání souboru :name.', + 'invalid_name' => 'Název může obsahovat pouze číslice, písmena, mezery a následující soubory: ._-', + 'original_not_found' => 'Původní soubor nebo složka neexistují', + 'already_exists' => 'Soubor nebo složka s tímto názvem již existují', + 'error_renaming' => 'Chyba přejmenovávání souboru nebo složky', + 'name_cant_be_empty' => 'Název nemůže být prázdný', + 'too_large' => 'Nahrávaný soubor je příliš veliký. Maximální povolená velikost je :max_size', + 'type_not_allowed' => 'Je možno nahrávat pouze tyto typy souborů: :allowed_types', + 'file_not_valid' => 'Soubor není validní', + 'error_uploading_file' => "Chyba nahrávání souboru ':name': :error", + 'move_please_select' => 'prosím vyberte', + 'move_destination' => 'Cílová složka', + 'move_popup_title' => 'Přesunutí souborů', + 'move_button' => 'Přesunout', + 'selected_files_not_found' => 'Vybrané soubory nebyly nalezeny', + 'select_destination_dir' => 'Vyberte cílovou složku', + 'destination_not_found' => 'Cílová složka nebyla nalezena', + 'error_moving_file' => 'Chyba přesunu souboru :file', + 'error_moving_directory' => 'Chyba přesunu složky :dir', + 'error_deleting_directory' => 'Chyba přesunu původní složky :dir', + 'no_list_records' => 'Žádné soubory nebyly nalezeny', + 'delete_confirm' => 'Opravdu chcete smazat vybrané soubory nebo adresáře?', + 'path' => 'Cesta' + ], + 'component' => [ + 'menu_label' => 'Komponenty', + 'unnamed' => 'Bez jména', + 'no_description' => 'Popis nevyplněn', + 'alias' => 'Alias', + 'alias_description' => 'Unikátní název komponenty pro použití ve stránkách, nebo kodéch layoutu.', + 'validation_message' => 'Alias komponenty je povinný a může obsahovat pouze písmena, čísla a podtržítka. Alias by měl začínat písmenem.', + 'invalid_request' => 'Šablona nemohla být uložena, protože jedna z komponent nemá správně vyplněná data.', + 'no_records' => 'Žádná komponenta', + 'not_found' => "Komponenta ':name' nebyla nalezena.", + 'method_not_found' => "Komponenta ':name' nemá metodu ':method'." + ], + 'template' => [ + 'invalid_type' => 'Neznámý typ šablony.', + 'not_found' => 'Požadovaná šablona nebyla nalezena.', + 'saved'=> 'Šablona byla úspěšně uložena.', + 'no_list_records' => 'Žádné záznamy nebyly nalezeny', + 'delete_confirm' => 'Smazat vybraná témata?', + 'order_by' => 'Řadit podle' + ], + 'permissions' => [ + 'name' => 'Cms', + 'manage_content' => 'Správa obsahu', + 'manage_assets' => 'Správa souborů', + 'manage_pages' => 'Správa stránek', + 'manage_layouts' => 'Správa layoutů', + 'manage_partials' => 'Správa dílčích šablon', + 'manage_themes' => 'Správa témat', + 'manage_theme_options' => 'Nastavit možnosti přizpůsobení pro aktivní téma', + ], + 'theme_log' => [ + 'hint' => 'Tento protokol zobrazuje změny v tématu provedené administrátory v administraci.', + 'menu_label' => 'Protokol témat', + 'menu_description' => 'Zobrazení změn v aktivním tématu.', + 'empty_link' => 'Smazat protokol témat', + 'empty_loading' => 'Mazání protokolu témat...', + 'empty_success' => 'Protokol témat byl smazán', + 'return_link' => 'Zpět na protokol témat', + 'id' => 'ID', + 'id_label' => 'ID protokolu', + 'created_at' => 'Datum a čas', + 'user' => 'Uživatel', + 'type' => 'Typ', + 'type_create' => 'Vytvořeno', + 'type_update' => 'Změněno', + 'type_delete' => 'Smazáno', + 'theme_name' => 'Téma', + 'theme_code' => 'Kód tématu', + 'old_template' => 'Šablona (Původní)', + 'new_template' => 'Šablona (Nová)', + 'template' => 'Šablona', + 'diff' => 'Změny', + 'old_value' => 'Původní hodnota', + 'new_value' => 'Nová hodnota', + 'preview_title' => 'Změny šablony', + 'template_updated' => 'Šablona byla aktualizována', + 'template_created' => 'Šablona byla vytvořena', + 'template_deleted' => 'Šablona byla smazána', + ], +]; diff --git a/modules/cms/lang/da/lang.php b/modules/cms/lang/da/lang.php new file mode 100644 index 0000000..036aac0 --- /dev/null +++ b/modules/cms/lang/da/lang.php @@ -0,0 +1,249 @@ + [ + 'invalid_file' => 'Ugyldigt filnavn: :name. Filnavne må kun indeholde alphanumeriske karakterer, underscores, bindestreger og punktummer. Eksempler på gyldige navne: page.htm, page, subdirectory/page', + 'invalid_property' => "':name' kan ikke angives", + 'file_already_exists' => "Filen ':name' eksisterer allerede.", + 'error_saving' => "Fejl under geming af filen ':name'. Kontroller venligst skriverettigheder.", + 'error_creating_directory' => 'Fejl ved opretning af mappe :name. Kontroller venligst skriverettigheder.', + 'invalid_file_extension'=>'Ugyldig filendelse: :invalid. Tilladte endelser: :allowed.', + 'error_deleting' => "Fejl under sletning af skabelonfil ':name'. Kontroller venligst skriverettigheder.", + 'delete_success' => 'Slettede skabeloner: :count.', + 'file_name_required' => 'Filnavnet er påkrævet.', + 'safe_mode_enabled' => 'sikkerhedstilstand er aktiveret.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Hjemmeside', + 'online' => 'Online', + 'maintenance' => 'Under vedligeholdelse', + 'manage_themes' => 'Administrer temaer', + ] + ], + 'theme' => [ + 'not_found_name' => "Temaet ':name' blev ikke fundet.", + 'active' => [ + 'not_set' => 'Det aktive tema er ikke sat.', + 'not_found' => 'Det aktive tema kunne ikke findes.' + ], + 'edit' => [ + 'not_set' => 'The edit theme is not set.', + 'not_found' => 'The edit theme is not found.', + 'not_match' => "The object you're trying to access doesn't belong to the theme being edited. Please reload the page." + ], + 'settings_menu' => 'Frontend tema', + 'settings_menu_description' => 'Se oversigt over temaer, og vælg et aktivt tema.', + 'default_tab' => 'Indstillinger', + 'name_label' => 'Navn', + 'name_create_placeholder' => 'Nyt temanavn', + 'author_label' => 'Skaber', + 'author_placeholder' => 'Person eller virksomhedsnavn', + 'description_label' => 'Beskrivelse', + 'description_placeholder' => 'Tema beskrivelse', + 'homepage_label' => 'Hjemmeside', + 'homepage_placeholder' => 'Hjemmeside URL', + 'code_label' => 'Kode', + 'code_placeholder' => 'En unik kode for dette tema, brugt under distribuering', + 'dir_name_label' => 'Mappenavn', + 'dir_name_create_label' => 'Tema mappe', + 'theme_label' => 'Tema', + 'theme_title' => 'Temaer', + 'activate_button' => 'Aktiver', + 'active_button' => 'Aktiver', + 'customize_theme' => 'Tilpas tema', + 'customize_button' => 'Tilpas', + 'duplicate_button' => 'Dupliker', + 'duplicate_title' => 'Dupliker tema', + 'duplicate_theme_success' => 'Tema blev duplikeret!', + 'manage_button' => 'Administrer', + 'manage_title' => 'Administrer tema', + 'edit_properties_title' => 'Tema', + 'edit_properties_button' => 'Rediger indstillinger', + 'save_properties' => 'Gem indstillinger', + 'import_button' => 'Importer', + 'import_title' => 'Importer tema', + 'import_theme_success' => 'Tema importeret!', + 'import_uploaded_file' => 'Tema arkivfil', + 'import_overwrite_label' => 'Overskriv eksisterende filer', + 'import_overwrite_comment' => 'Afkryds i denne box, for kun at importere nye filer', + 'import_folders_label' => 'Mapper', + 'import_folders_comment' => 'Vælg venligst temamapperne du vil importere', + 'export_button' => 'Eksporter', + 'export_title' => 'Eksporter tema', + 'export_folders_label' => 'Mapper', + 'export_folders_comment' => 'Vælg venligst de temamapper du vil importere', + 'delete_button' => 'Slet', + 'delete_confirm' => 'Er du sikker på at du vil slette dette tema? Det kan ikke fortrydes!', + 'delete_active_theme_failed' => 'Kan ikke slette det aktive tema. Vælg et andet aktivt tema først.', + 'delete_theme_success' => 'Tema blev slettet!', + 'create_title' => 'Opret tema', + 'create_button' => 'Opret', + 'create_new_blank_theme' => 'Lav et nyt blankt tema', + 'create_theme_success' => 'Theme blev oprettet!', + 'create_theme_required_name' => 'Vælg venligst et navn til temaet.', + 'new_directory_name_label' => 'Temamappe', + 'new_directory_name_comment' => 'Amgiv en ny mappe til det duplikerede tema.', + 'dir_name_invalid' => 'Navnet må kun indeholde tal, latinske bogstaver og følgende symboler: _-', + 'dir_name_taken' => 'Den angivne temamappe eksisterer allerede.', + 'find_more_themes' => 'Find flere temaer', + 'saving' => 'Gemmer tema...', + 'return' => 'Tilbage til temaliste', + ], + 'maintenance' => [ + 'settings_menu' => 'Vedligeholdelsestilstand', + 'settings_menu_description' => 'Konfigurer vedligeholdelsestilstand og aktiver/deaktiver.', + 'is_enabled' => 'Aktiver vedligeholdelsestilstand', + 'is_enabled_comment' => 'Når vedligeholdelsestilstand er aktiveret, vil gæster se den nedfor valgte side.' + ], + 'page' => [ + 'not_found_name' => "Sidenavnet ':name' kunne ikke findes", + 'not_found' => [ + 'label' => 'Siden findes ikke', + 'help' => 'Den efterspurgte side findes ikke.' + ], + 'custom_error' => [ + 'label' => 'Side fejl', + 'help' => "Der skete desværre en fejl, og siden kan derfor ikke vises." + ], + 'menu_label' => 'Sider', + 'unsaved_label' => 'Ugemte side(r)', + 'no_list_records' => 'Ingen sider fundet', + 'new' => 'Ny side', + 'invalid_url' => 'Ugyldigt URL format. URL\'en skal starte med en skråstreg og kan indeholde tal, latinske bogstaver og følgende symboler: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Slet de valgte sider?', + 'delete_confirm_single' => 'Slet denne side?', + 'no_layout' => '-- Intet layout --' + ], + 'layout' => [ + 'not_found_name' => "Layoutet ':name' kunne ikke findes", + 'menu_label' => 'Layouts', + 'unsaved_label' => 'Ugemt(e) layout(s)', + 'no_list_records' => 'Ingen layouts fundet', + 'new' => 'Nyt layout', + 'delete_confirm_multiple' => 'Slet de valgte layouts?', + 'delete_confirm_single' => 'Slet dette layout?' + ], + 'partial' => [ + 'not_found_name' => "Partialen ':name' kunne ikke findes.", + 'invalid_name' => 'Ugyldigt partial navn: :name.', + 'menu_label' => 'Partials', + 'unsaved_label' => 'Ugemt(e) partial(s)', + 'no_list_records' => 'Ingen partials fundet', + 'delete_confirm_multiple' => 'Slet de valgte partials?', + 'delete_confirm_single' => 'Slet denne partial?', + 'new' => 'Ny partial' + ], + 'content' => [ + 'not_found_name' => "Indholdsfilen ':name' kunne ikke findes.", + 'menu_label' => 'Indhold', + 'unsaved_label' => 'Ugemt indhold', + 'no_list_records' => 'Ingen indholdsfiler fundet', + 'delete_confirm_multiple' => 'Slet valgte indholdsfiler eller mapper?', + 'delete_confirm_single' => 'Slet denne indholdsfil?', + 'new' => 'Ny indholdsfil' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Ugyldig AJAX handler navn: :name.', + 'not_found' => "AJAX handler ':name' kunne ikke findes." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Tilføj', + 'search' => 'Søg...' + ], + 'editor' => [ + 'settings' => 'Indstillinger', + 'title' => 'Titel', + 'new_title' => 'Ny side titel', + 'url' => 'URL', + 'filename' => 'Filnavn', + 'layout' => 'Layout', + 'description' => 'Beskrivelse', + 'preview' => 'Forhåndsvisning', + 'meta' => 'Meta', + 'meta_title' => 'Metatitel', + 'meta_description' => 'Metabeskrivelse', + 'markup' => 'Markup', + 'code' => 'Kode', + 'content' => 'Indhold', + 'hidden' => 'Gemt', + 'hidden_comment' => 'Gemte sider kan kun tilgås af backendbrugere.', + 'enter_fullscreen' => 'Start fuld skærm', + 'exit_fullscreen' => 'Afslut fuld skærm', + 'open_searchbox' => 'Åben søgeboks', + 'close_searchbox' => 'Luk søgeboks', + 'open_replacebox' => 'Åben erstartningsboks', + 'close_replacebox' => 'Luk erstatningsboks' + ], + 'asset' => [ + 'menu_label' => 'Assets', + 'unsaved_label' => 'Ugemt(e) asset(s)', + 'drop_down_add_title' => 'Tilføj...', + 'drop_down_operation_title' => 'Action...', + 'upload_files' => 'Upload file(r)', + 'create_file' => 'Opret fil', + 'create_directory' => 'Opret mappe', + 'directory_popup_title' => 'Ny mappe', + 'directory_name' => 'Mappenavn', + 'rename' => 'Omdøb', + 'delete' => 'Slet', + 'move' => 'Flyt', + 'select' => 'Vælg', + 'new' => 'Ny fil', + 'rename_popup_title' => 'Omdøb', + 'rename_new_name' => 'Nyt navn', + 'invalid_path' => 'Stien må kun indeholde tal, latinske bogstaver, mellemrum og følgende tegn: ._-/', + 'error_deleting_file' => 'Fejl ved sletning af fil :name.', + 'error_deleting_dir_not_empty' => 'Fejl ved sletning af mappe :name. Mappen er ikke tom.', + 'error_deleting_dir' => 'Fejl ved sletning af mappe :name.', + 'invalid_name' => 'Navn må kun indeholde tal, latinske bogstaver, mellemrum og følgende tegn: ._-/', + 'original_not_found' => 'Den originale fil eller mappe kunne ikke findes', + 'already_exists' => 'Fil eller mappe med dette navn, eksisterer allerede', + 'error_renaming' => 'Fejl ved omdøbning af fil eller mappe', + 'name_cant_be_empty' => 'Navn skal udfyldes', + 'too_large' => 'Den uploadede fil er for stor. Den størst tilladte filstørrelse er :max_size', + 'type_not_allowed' => 'Kun følgende filtyper tilladt: :allowed_types', + 'file_not_valid' => 'Filen er ikke gyldig', + 'error_uploading_file' => "Fejl ved upload af fil ':name': :error", + 'move_please_select' => 'Vælg venligst', + 'move_destination' => 'Destinationsmappe', + 'move_popup_title' => 'Flyt assets', + 'move_button' => 'Flyt', + 'selected_files_not_found' => 'Valgte filer ikke fundet', + 'select_destination_dir' => 'Vælg venligst en destinationsmappe', + 'destination_not_found' => 'Destinationsmappe ikke fundet', + 'error_moving_file' => 'Fejl ved flytning af fil :file', + 'error_moving_directory' => 'Fejl ved flytning af mappe :dir', + 'error_deleting_directory' => 'Fejl ved sletning af den originale mappe :dir', + 'path' => 'Sti' + ], + 'component' => [ + 'menu_label' => 'Komponenter', + 'unnamed' => 'Unavngivet', + 'no_description' => 'Ingen beskrivelse tilgængelig', + 'alias' => 'Alias', + 'alias_description' => 'Et unikt navn givet til dette komponent, ved brug på en side eller layout.', + 'validation_message' => 'Komponent aliaser er påkrævede og må kun indeholde latinske karakterer, tal og underscores.Aliaset skal starte med et latinsk bogstav.', + 'invalid_request' => 'Skabelonen kan ikke gemmes, pga. ugyldigt komponentdata.', + 'no_records' => 'Ingen komponenter fundet', + 'not_found' => "Komponentet ':name' kunne ikke findes.", + 'method_not_found' => "Komponentet ':name' indeholder ikke metoden ':method'." + ], + 'template' => [ + 'invalid_type' => 'Ukendt skabelontype.', + 'not_found' => 'Skabelon kunne ikke findes.', + 'saved'=> 'Skabelon blev gemt.' + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Administrer indholdsfiler', + 'manage_assets' => 'Administrer assets - billeder, JavaScript filer, CSS filer', + 'manage_pages' => 'Opret, rediger og slet CMS sider', + 'manage_layouts' => 'Opret, rediger og slet CMS layouts', + 'manage_partials' => 'Opret, rediger og slet CMS partials', + 'manage_themes' => 'aktiver, deaktiver og konfigurer CMS temaer', + ], +]; diff --git a/modules/cms/lang/de/lang.php b/modules/cms/lang/de/lang.php new file mode 100644 index 0000000..e8f5a35 --- /dev/null +++ b/modules/cms/lang/de/lang.php @@ -0,0 +1,303 @@ + [ + 'invalid_file' => 'Ungültiger Dateiname: :name. Diese dürfen nur alphanumerische Symbole, Unter- und Bindestriche sowie Punkte enthalten. Beispiele: page.htm, page, subdirectory/page', + 'invalid_property' => 'Die Eigenschaft ":name" kann nicht angewendet werden', + 'file_already_exists' => 'Datei ":name" existiert bereits.', + 'error_saving' => 'Fehler beim Speichern von ":name".', + 'error_creating_directory' => 'Fehler beim Erstellen von Verzeichnis mit Namen :name', + 'invalid_file_extension'=>'Ungültige Dateiendung: :invalid. Erlaubt sind: :allowed.', + 'error_deleting' => 'Fehler beim Löschen der Template-Datei ":name".', + 'delete_success' => 'Templates wurden erfolgreich gelöscht: :count.', + 'file_name_required' => 'Ein Dateiname ist erforderlich.', + 'safe_mode_enabled' => 'Der abgesicherte Modus ist derzeit aktiviert. Die Bearbeitung des PHP-Codes von CMS-Templates ist deaktiviert. Um den abgesicherten Modus zu deaktivieren, setzen Sie den Konfigurationswert `cms.enableSafeMode` auf `false`.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Website', + 'online' => 'Online', + 'maintenance' => 'In der Wartung', + 'manage_themes' => 'Themes Verwalten', + 'customize_theme' => 'Theme anpassen', + ], + ], + 'theme' => [ + 'not_found_name' => "Das Theme ':name' konnte nicht gefunden werden.", + 'by_author' => 'Von :name', + 'active' => [ + 'not_set' => "Aktives Theme nicht definiert", + 'not_found' => 'Aktives Theme wurde nicht gefunden.', + ], + 'edit' => [ + 'not_set' => "Edit Theme nicht definiert", + 'not_found' => "Edit Theme nicht gefunden.", + 'not_match' => "Das Objekt, das sie anzupassen versuchen gehört nicht zum Theme in Bearbeitung. Bitte laden Sie die Seite erneut." + ], + 'settings_menu' => 'Frontend Theme', + 'settings_menu_description' => 'Rufe eine Liste installierter Themes auf und wähle ein aktives aus.', + 'default_tab' => 'Eigenschaften', + 'name_label' => 'Name', + 'name_create_placeholder' => 'Neuer Themename', + 'author_label' => 'Autor', + 'author_placeholder' => 'Autor- oder Firmenname', + 'description_label' => 'Beschreibung', + 'description_placeholder' => 'Themebeschreibung', + 'homepage_label' => 'Homepage', + 'homepage_placeholder' => 'Webseiten URL', + 'code_label' => 'Code', + 'code_placeholder' => 'Ein einzigartiger Code genutzt bei der Weiterverbreitung dieses Themes', + 'preview_image_label' => 'Bildvorschau', + 'preview_image_placeholder' => 'Der Pfad des Theme-Vorschaubildes.', + 'dir_name_label' => 'Verzeichnisname', + 'dir_name_create_label' => 'Name des Zielverzeichnisses', + 'theme_label' => 'Theme', + 'theme_title' => 'Themes', + 'activate_button' => 'Aktivieren', + 'active_button' => 'Aktivieren', + 'customize_theme' => 'Theme anpassen', + 'customize_button' => 'Anpassen', + 'duplicate_button' => 'Duplizieren', + 'duplicate_title' => 'Theme duplizieren', + 'duplicate_theme_success' => 'Theme erfolgreich dupliziert!', + 'manage_button' => 'Verwalten', + 'manage_title' => 'Theme verwalten', + 'edit_properties_title' => 'Theme', + 'edit_properties_button' => 'Eigenschaften bearbeiten', + 'save_properties' => 'Eigenschaften speichern', + 'import_button' => 'Importieren', + 'import_title' => 'Theme importieren', + 'import_theme_success' => 'Theme erfolgreich importiert!', + 'import_uploaded_file' => 'Theme Archivdatei', + 'import_overwrite_label' => 'Überschreibe existierende Dateien', + 'import_overwrite_comment' => 'Deaktiviere diese Option, um ausschließlich neue Dateien zu importieren', + 'import_folders_label' => 'Ordner', + 'import_folders_comment' => 'Bitte wähle die Theme-Ordner zum Importieren aus', + 'export_button' => 'Exportieren', + 'export_title' => 'Exportiere Theme', + 'export_folders_label' => 'Ordner', + 'export_folders_comment' => 'Bitte wählen Sie die Ordner des Themes, die Sie exportieren wollen, aus.', + 'delete_button' => 'Löschen', + 'delete_confirm' => 'Sind Sie sicher, dass Sie dieses Theme löschen wollen? Dies kann nicht rückgängig gemacht werden!', + 'delete_active_theme_failed' => 'Das aktive Theme kann nicht gelöscht werden, aktivieren Sie zunächst ein anderes Theme.', + 'delete_theme_success' => 'Theme wurde erfolgreich gelöscht!', + 'create_title' => 'Theme erstellen', + 'create_button' => 'Erstellen', + 'create_new_blank_theme' => 'Erstelle ein neues (leeres) Theme', + 'create_theme_success' => 'Theme erfolgreich erstellt!', + 'create_theme_required_name' => 'Bitte benennen Sie das Theme.', + 'new_directory_name_label' => 'Theme Verzeichnis', + 'new_directory_name_comment' => 'Stellen Sie einen neuen Verzeichnisnamen für das duplizierte Theme bereit.', + 'dir_name_invalid' => 'Verzeichnisnamen können nur Zahlen, lateinische Buchstaben und die folgenden Symbole enthalten: _-', + 'dir_name_taken' => 'Gewünschter Verzeichnisname existiert bereits.', + 'find_more_themes' => 'Finde weitere Themen', + 'saving' => 'Theme speichern...', + 'return' => 'Zur Themeliste zurückkehren', + ], + 'maintenance' => [ + 'settings_menu' => 'Wartungsmodus', + 'settings_menu_description' => 'Konfigurieren Sie den Wartungsmodus.', + 'is_enabled' => 'Wartungsmodus aktivieren', + 'is_enabled_comment' => 'Sobald aktiviert, werden Besucher die unten ausgewählte Seite sehen.', + 'hint' => 'Im Wartungsmodus wird die Wartungsseite für Besucher angezeigt, die nicht im Back-End-Bereich angemeldet sind.', + ], + 'page' => [ + 'not_found_name' => "Die Seite ':name' konnte nicht gefunden werden", + 'not_found' => [ + 'label' => "Seite nicht gefunden", + 'help' => "Die angeforderte Seite kann nicht gefunden werden.", + ], + 'custom_error' => [ + 'label' => "Seitenfehler", + 'help' => "Entschuldigung, ein Fehler trat auf, sodass die gewünschte Seite nicht angezeigt werden kann.", + ], + 'menu_label' => 'Seiten', + 'unsaved_label' => 'Ungespeicherte Seite(n)', + 'no_list_records' => 'Keine Seiten gefunden', + 'new' => 'Neue Seite', + 'invalid_url' => 'Ungültiges URL-Format. Die URL muss mit einem Slash beginnen und darf nur Ziffern, lateinische Zeichen und die folgenden Symbole beinhalten: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Wollen Sie die ausgewählten Seiten wirklich löschen?', + 'delete_confirm_single' => 'Wollen Sie diese Seite wirklich löschen?', + 'no_layout' => '-- Kein Layout --', + 'cms_page' => 'CMS Seite', + 'title' => 'Seitentitel', + 'url' => 'Seiten-URL', + 'file_name' => 'Seiten-Dateiname', + ], + 'layout' => [ + 'not_found_name' => "Das Layout ':name' wurde nicht gefunden", + 'menu_label' => 'Layouts', + 'unsaved_label' => 'Ungespeicherte(s) Layout(s)', + 'no_list_records' => 'Keine Layouts gefunden', + 'new' => 'Neues Layout', + 'delete_confirm_multiple' => 'Wollen Sie die ausgewählten Layouts wirklich löschen?', + 'delete_confirm_single' => 'Wollen Sie das ausgewählte Layout wirklich löschen?' + ], + 'partial' => [ + 'not_found_name' => "Das Partial ':name' wurde nicht gefunden.", + 'invalid_name' => "Ungültiger Partial-Name: :name.", + 'menu_label' => 'Partials', + 'unsaved_label' => 'Ungespeicherte(s) Partial(s)', + 'no_list_records' => 'Keine Partials gefunden', + 'delete_confirm_multiple' => 'Wollen Sie die ausgewählten Partials wirklich löschen?', + 'delete_confirm_single' => 'Wollen Sie das ausgewählte Partial wirklich löschen?', + 'new' => 'Neues Partial' + ], + 'content' => [ + 'not_found_name' => "Die Inhaltsdatei ':name' wurde nicht gefunden.", + 'menu_label' => 'Inhalt', + 'unsaved_label' => 'Ungespeicherter Inhalt', + 'no_list_records' => 'Keine Inhaltsdateien gefunden', + 'delete_confirm_multiple' => 'Wollen Sie die ausgewählten Inhalte und Verzeichnisse wirklich löschen?', + 'delete_confirm_single' => 'Wollen Sie diese Inhaltsdatei wirklich löschen?', + 'new' => 'Neue Inhaltsdatei' + ], + 'ajax_handler' => [ + 'invalid_name' => "Ungültiger Name für AJAX Handler: :name.", + 'not_found' => "AJAX Handler ':name' wurde nicht gefunden.", + ], + 'cms' => [ + 'menu_label' => "CMS" + ], + 'sidebar' => [ + 'add' => 'Hinzufügen', + 'search' => 'Suchen...' + ], + 'editor' => [ + 'settings' => 'Einstellungen', + 'title' => 'Titel', + 'new_title' => 'Neuer Seitentitel', + 'url' => 'URL', + 'filename' => 'Dateiname', + 'layout' => 'Layout', + 'description' => 'Beschreibung', + 'preview' => 'Vorschau', + 'meta' => 'Meta', + 'meta_title' => 'Meta Titel', + 'meta_description' => 'Meta Beschreibung', + 'markup' => 'Markup', + 'code' => 'Code', + 'content' => 'Inhalt', + 'hidden' => 'Versteckt', + 'hidden_comment' => 'Versteckte Seiten können nur von eingeloggten Backend-Benutzern genutzt werden.', + 'enter_fullscreen' => 'In den Vollbildmodus wechseln', + 'exit_fullscreen' => 'Vollbildmodus beenden', + 'open_searchbox' => 'Suchfeld öffnen', + 'close_searchbox' => 'Suchfeld schließen', + 'open_replacebox' => 'Ersetzen-Feld öffnen', + 'close_replacebox' => 'Ersetzen-Feld schließen', + 'commit' => 'Commit', + 'reset' => 'Zurücksetzen', + 'commit_confirm' => 'Sind Sie sicher, dass Sie Ihre Änderungen an dieser Datei auf das Dateisystem übertragen wollen? Dies wird die bestehende Datei auf dem Dateisystem überschreiben', + 'reset_confirm' => 'Sind Sie sicher, dass Sie diese Datei auf die Kopie zurücksetzen wollen, die sich auf dem Dateisystem befindet? Dadurch wird sie vollständig durch die Datei ersetzt, die sich auf dem Dateisystem befindet.', + 'committing' => 'Committing', + 'resetting' => 'Zurücksetzen', + 'commit_success' => 'Der :type wurde auf das Dateisystem übertragen', + 'reset_success' => 'Der :type wurde auf die Dateisystemversion zurückgesetzt', + ], + 'asset' => [ + 'menu_label' => "Assets", + 'unsaved_label' => 'Ungespeicherte(s) Asset(s)', + 'drop_down_add_title' => 'Hinzufügen...', + 'drop_down_operation_title' => 'Aktion...', + 'upload_files' => 'Datei(en) hochladen', + 'create_file' => 'Datei erstellen', + 'create_directory' => 'Verzeichnis erstellen', + 'directory_popup_title' => 'Neues Verzeichnis', + 'directory_name' => 'Verzeichnisname', + 'rename' => 'Umbenennen', + 'delete' => 'Löschen', + 'move' => 'Verschieben', + 'select' => 'Auswählen', + 'new' => 'Neue Datei', + 'rename_popup_title' => 'Umbenennen', + 'rename_new_name' => 'Neuer Name', + 'invalid_path' => 'Pfade dürfen ausschließlich Ziffern, lateinische Zeichen, Leerzeichen sowie die folgenden Symbole enthalten: ._-/', + 'error_deleting_file' => 'Fehler beim Löschen der Datei :name.', + 'error_deleting_dir_not_empty' => 'Fehler beim Löschen des Verzeichnisses :name, da es nicht leer ist.', + 'error_deleting_dir' => 'Fehler beim Löschen der Datei :name.', + 'invalid_name' => 'Asset-Name darf nur Ziffern, lateinische Zeichen, Leerzeichen sowie die folgenden Symbole enthalten: ._-', + 'original_not_found' => 'Originaldatei oder -verzeichnis wurde nicht gefunden', + 'already_exists' => 'Datei oder Verzeichnis mit diesem Namen existiert bereits', + 'error_renaming' => 'Fehler beim Umbenennen der Datei bzw. des Verzeichnisses', + 'name_cant_be_empty' => 'Es muss ein Name angegeben werden', + 'too_large' => 'Die hochzuladende Datei ist zu groß. Sie dürfen maximal Dateien der Größe :max_size hochladen', + 'type_not_allowed' => 'Es sind ausschließlich folgende Dateiendungen erlaubt: :allowed_types', + 'file_not_valid' => 'Datei ist ungültig', + 'error_uploading_file' => 'Fehler beim Hochladen der Datei ":name": :error', + 'move_please_select' => 'Bitte auswählen', + 'move_destination' => 'Zielverzeichnis', + 'move_popup_title' => 'Assets verschieben', + 'move_button' => 'Verschieben', + 'selected_files_not_found' => 'Ausgewählte Dateien nicht gefunden', + 'select_destination_dir' => 'Bitte wählen Sie ein Zielverzeichnis aus', + 'destination_not_found' => 'Zielverzeichnis wurde nicht gefunden', + 'error_moving_file' => 'Fehler beim Verschieben der Datei :file', + 'error_moving_directory' => 'Fehler beim Verschieben des Verzeichnisses :dir', + 'error_deleting_directory' => 'Fehler beim Löschen des Originalverzeichnisses :dir', + 'no_list_records' => 'Keine Dateien gefunden', + 'delete_confirm' => 'Ausgewählte Dateien oder Verzeichnisse löschen?', + 'path' => 'Pfad' + ], + 'component' => [ + 'menu_label' => "Komponenten", + 'unnamed' => "Unbenannt", + 'no_description' => "Keine Beschreibung angegeben", + 'alias' => "Verknüpfung", + 'alias_description' => "Dieser Komponente wird ein eindeutiger Name gegeben, wenn sie im Code von Seite oder Layout benutzt wird.", + 'validation_message' => "Komponentenverknüpfungen werden benötigt und dürfen nur lateinische Zeichen, Ziffern und Unterstriche beinhalten. Die Verknüpfungen müssen mit einem lateinischen Zeichen beginnen.", + 'invalid_request' => "Aufgrund ungültiger Komponentendaten kann das Template nicht gespeichert werden.", + 'no_records' => 'Keine Komponenten gefunden', + 'not_found' => "Die Komponente ':name' wurde nicht gefunden.", + 'no_default_partial' => "Diese Komponente hat keinen 'default' Partial", + 'method_not_found' => "Die Komponente ':name' enthält keine Methode mit Namen ':method'.", + 'soft_component_description' => 'Diese Komponente fehlt, aber Sie ist optional.', + ], + 'template' => [ + 'invalid_type' => "Unbekannter Template-Typ.", + 'not_found' => "Das angeforderte Template wurde nicht gefunden.", + 'saved'=> "Das Template wurde erfolgreich gespeichert.", + 'no_list_records' => 'Keine Einträge gefunden', + 'delete_confirm' => 'Ausgewählte Templates löschen?', + 'order_by' => 'Sortieren nach', + ], + 'permissions' => [ + 'name' => 'Cms', + 'manage_content' => 'Inhalt verwalten', + 'manage_assets' => 'Assets verwalten', + 'manage_pages' => 'Seiten verwalten', + 'manage_layouts' => 'Layouts verwalten', + 'manage_partials' => 'Partials verwalten', + 'manage_themes' => 'Themes verwalten', + 'manage_theme_options' => 'Konfigurieren Sie Anpassungsoptionen für das aktive Theme', + ], + 'theme_log' => [ + 'hint' => 'Dieses Protokoll zeigt alle Änderungen an, die von Administratoren im Back-End-Bereich am Theme vorgenommen wurden.', + 'menu_label' => 'Theme Protokoll', + 'menu_description' => 'Zeigen Sie die am aktiven Theme vorgenommenen Änderungen an.', + 'empty_link' => 'Leeres Theme Protokoll', + 'empty_loading' => 'Leeren des Theme Protokolls...', + 'empty_success' => 'Theme Protokoll', + 'return_link' => 'Zurück zum Theme Protokoll', + 'id' => 'ID', + 'id_label' => 'Protokoll ID', + 'created_at' => 'Datum & Zeit', + 'user' => 'Benutzer', + 'type' => 'Typ', + 'type_create' => 'Erstellen', + 'type_update' => 'Aktualisieren', + 'type_delete' => 'Löschen', + 'theme_name' => 'Theme', + 'theme_code' => 'Theme Code', + 'old_template' => 'Template (Alt)', + 'new_template' => 'Template (Neu)', + 'template' => 'Template', + 'diff' => 'Änderungen', + 'old_value' => 'Alter Wert', + 'new_value' => 'Neuer Wert', + 'preview_title' => 'Templateänderungen', + 'template_updated' => 'Template wurde aktualisiert', + 'template_created' => 'Template wurde erstellt', + 'template_deleted' => 'Template wurde gelöscht', + ], +]; diff --git a/modules/cms/lang/el/lang.php b/modules/cms/lang/el/lang.php new file mode 100644 index 0000000..e4ac41d --- /dev/null +++ b/modules/cms/lang/el/lang.php @@ -0,0 +1,249 @@ + [ + 'invalid_file' => 'Μη έγκυρο όνομα αρχείου: :name. Τα ονόματα αρχείων μπορούν να περιέχουν μόνο αλφαριθμητικά σύμβολα, κάτω παύλες, παύλες και τελείες. Μερικά παραδείγματα σωστών ονομάτων αρχείων: page.htm, page, subdirectory/page', + 'invalid_property' => "Η ιδιότητα ':name' δεν μπορεί να οριστεί.", + 'file_already_exists' => "Το αρχείο ':name' υπάρχει ήδη.", + 'error_saving' => "Σφάλμα κατά την αποθήκευση του αρχείου ':name'. Παρακαλούμε ελέγξτε τα δικαιώματα εγγραφής.", + 'error_creating_directory' => 'Σφάλμα δημιουργίας του καταλόγου :name. Παρακαλούμε ελέγξτε τα δικαιώματα εγγραφής.', + 'invalid_file_extension'=>'Μη έγκυρη επέκταση αρχείου: :invalid. Οι επιτρεπόμενες επεκτάσεις είναι: :allowed.', + 'error_deleting' => "Σφάλμα διαγράφης του αρχείου ':name' του προτύπου. Παρακαλούμε ελέγξτε τα δικαιώματα εγγραφής.", + 'delete_success' => 'Θέματα που διαγράφηκαν: :count', + 'file_name_required' => 'Το πεδίο του Ονόματος του Αρχείου είναι υποχρεωτικό.', + 'safe_mode_enabled' => 'Η λειτουργία ασφαλείας ενεργοποιήθηκε', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Ιστότοπος', + 'online' => 'Σε λειτουργία', + 'maintenance' => 'Σε συντήρηση', + 'manage_themes' => 'Διαχείριση θεμάτων', + ] + ], + 'theme' => [ + 'not_found_name' => "Το θέμα ':name' δεν βρέθηκε.", + 'active' => [ + 'not_set' => 'Δεν έχει οριστεί το ενεργό θέμα.', + 'not_found' => 'Δεν βρέθηκε το ενεργό θέμα.', + ], + 'edit' => [ + 'not_set' => 'Δεν έχει οριστεί το θέμα επεξεργασίας.', + 'not_found' => 'Δεν βρέθηκε το θέμα επεξεργασίας.', + 'not_match' => "Το αντικείμενο το οποίο προσπαθείτε να προσπελάσετε δεν ανήκει στο θέμα το οποίο επεξεργάζεστε. Παρακαλούμε φορτώστε ξανά την σελίδα.", + ], + 'settings_menu' => 'Θέμα Front-End', + 'settings_menu_description' => 'Προεπισκόπηση των εγκατεστημένων θεμάτων και επιλογή του ενεργού θέματος.', + 'default_tab' => 'Ιδιότητες', + 'name_label' => 'Όνομα', + 'name_create_placeholder' => 'Νέο όνομα θέματος', + 'author_label' => 'Δημιουργός', + 'author_placeholder' => 'Άτομο ή όνομα εταιρίας', + 'description_label' => 'Περιγραφή', + 'description_placeholder' => 'Περιγραφή θέματος', + 'homepage_label' => 'Αρχική σελίδα', + 'homepage_placeholder' => 'URL Ιστοσελίδας', + 'code_label' => 'Κωδικας', + 'code_placeholder' => 'Ένας μοναδικός κωδικός για το θέμα ο οποίος χρησιμοποιείται για διανομή.', + 'dir_name_label' => 'Όνομα καταλόγου', + 'dir_name_create_label' => 'Ο κατάλογος προορισμού του θέματος', + 'theme_label' => 'Θέμα', + 'theme_title' => 'Θέματα', + 'activate_button' => 'Ενεργοποίηση', + 'active_button' => 'Ενεργοποίηση', + 'customize_theme' => 'Προσαρμογή Θέματος', + 'customize_button' => 'Προσαρμογή', + 'duplicate_button' => 'Διπλότυπο', + 'duplicate_title' => 'Διπλότυπο θέματος', + 'duplicate_theme_success' => 'Δημιουργήθηκε διπλότυπο του θέματος!', + 'manage_button' => 'Διαχείριση', + 'manage_title' => 'Διαχείριση θέματος', + 'edit_properties_title' => 'Θέμα', + 'edit_properties_button' => 'Επεξεργασία ιδιοτήτων', + 'save_properties' => 'Αποθήκευση ιδιοτήτων', + 'import_button' => 'Εισαγωγή', + 'import_title' => 'Εισαγωγή θέματος', + 'import_theme_success' => 'Το θεμα εισήχθη!', + 'import_uploaded_file' => 'Αρχείο αρχειοθέτησης θέματος.', + 'import_overwrite_label' => 'Αντικαταστήσετε τα υπάρχοντα αρχεία', + 'import_overwrite_comment' => 'Απόεπιλέξτε αυτό το πλαίσιο ελέγχου για την εισαγωγή μόνο των νέων αρχείων', + 'import_folders_label' => 'Κατάλογοι', + 'import_folders_comment' => 'Παρακαλούμε επιλέξτε τους καταλόγους του θέματος που θέλετε να εισαγάγετε', + 'export_button' => 'Εξαγωγή', + 'export_title' => 'Εξαγωγή θέματος', + 'export_folders_label' => 'Κατάλογοι', + 'export_folders_comment' => 'Παρακαλούμε επιλέξτε τους καταλόγους του θέματος που θέλετε να εξάγετε', + 'delete_button' => 'Διαγραφή', + 'delete_confirm' => 'Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό το θέμα; Αυτό δεν μπορεί να ανευρεθεί!', + 'delete_active_theme_failed' => 'Δεν μπορεί να διαγραφεί το ενεργό θέμα, προσπαθήστε να ενεργοποιήστε πρώτα εάν άλλο θέμα.', + 'delete_theme_success' => 'Το θέμα διαγράφηκε!', + 'create_title' => 'Δημιουργία θέματος', + 'create_button' => 'Δημιουργία', + 'create_new_blank_theme' => 'Δημιουργία ενός νέου κενού θέματος', + 'create_theme_success' => 'Το θέμα δημιουργήθηκε!', + 'create_theme_required_name' => 'Παρακαλούμε ορίστε ένα όνομα για το θέμα.', + 'new_directory_name_label' => 'Κατάλογος θέματος', + 'new_directory_name_comment' => 'Δώστε ένα νέο όνομα καταλόγου για το διπλότυπο θέμα.', + 'dir_name_invalid' => 'Το όνομα μπορεί να περιέχει μόνο ψηφιά, Λατινικά γράμματα και τα ακόλουθα σύμβολα: _-', + 'dir_name_taken' => 'Ο επιθυμητός κατάλογος για το θέμα υπάρχει ήδη.', + 'find_more_themes' => 'Εύρεση περισσοτέρων θεμάτων', + 'saving' => 'Αποθήκευση θέματος...', + 'return' => 'Επιστροφή στην λίστα θεμάτων', + ], + 'maintenance' => [ + 'settings_menu' => 'Λειτουργία συντήρησης', + 'settings_menu_description' => 'Διαμορφώστε τη σελίδα λειτουργίας συντήρησης και εναλλάξτε την ρύθμιση.', + 'is_enabled' => 'Ενεργοποίηση λειτουργίας συντήρησης', + 'is_enabled_comment' => 'Επιλέξτε την σελίδα που θα προβληθεί όταν η λειτουργεία συντήρησης ενεργοποιηθεί.', + 'hint' => 'Η λειτουργεία συντήρησης θα εμφανίσει την σελίδα συντήρησης στους επισκέπτες που δεν είναι συνδεδεμένοι στην περιοχή του back-end.', + ], + 'page' => [ + 'not_found_name' => "Η σελίδα ':name' δεν βρέθηκε", + 'not_found' => [ + 'label' => 'Η σελίδα δεν βρέθηκε!', + 'help' => 'Η σελίδα που ζητήσατε δεν μπορεί να βρεθεί.', + ], + 'custom_error' => [ + 'label' => 'Σφάλμα σελίδας', + 'help' => "Σας ζητούμε συγνώμη, αλλά κάτι πήγε λάθος και η σελίδα δεν μπορεί να προβληθεί.", + ], + 'menu_label' => 'Σελίδες', + 'unsaved_label' => 'Μη αποθηκευμένες σελίδες', + 'no_list_records' => 'Δεν βρέθηκαν σελίδες', + 'new' => 'Νεα Σελιδα', + 'invalid_url' => 'Μη έγκυρη μορφή URL. Η διεύθυνση URL πρέπει να ξεκινήσει με κανονικό slash και μπορεί να περιέχει ψηφία, Λατινικά γράμματα και τα ακόλουθα σύμβολα: ._- [] :? | / + * ^ $', + 'delete_confirm_multiple' => 'Να διαγραφούν οι επιλεγμένες σελίδες;', + 'delete_confirm_single' => 'Να διαγραφεί αυτή η σελίδα;', + 'no_layout' => '-- χωρίς διάταξη --', + ], + 'layout' => [ + 'not_found_name' => "The layout ':name' is not found", + 'menu_label' => 'Διατάξεις', + 'unsaved_label' => 'Μη αποθηκευμένες διατάξεις', + 'no_list_records' => 'Δεν βρέθηκε η διάταξη', + 'new' => 'Νέα Διάταξη', + 'delete_confirm_multiple' => 'Να διαγραφούν οι επιλεγμένες διατάξεις;', + 'delete_confirm_single' => 'Να διαγράφει αυτή η διάταξη;', + ], + 'partial' => [ + 'not_found_name' => "Το τμήμα ':name' δεν βρέθηκε.", + 'invalid_name' => 'Μη έγκυρο όνομα τμήματος: :name.', + 'menu_label' => 'Τμήματα', + 'unsaved_label' => 'Μη αποθηκευμένα τμήματα', + 'no_list_records' => 'Δεν βρέθηκαν τμήματα', + 'delete_confirm_multiple' => 'Να διαγράφουν τα επιλεγμένα τμήματα;', + 'delete_confirm_single' => 'Να διαγράφει αυτό το τμήμα;', + 'new' => 'Νέο Τμήμα', + ], + 'content' => [ + 'not_found_name' => "Το αρχείο περιεχομένου ':name' δεν βρέθηκε.", + 'menu_label' => 'Περιεχόμενο', + 'unsaved_label' => 'Μη αποθηκευμένο περιεχόμενο', + 'no_list_records' => 'Δεν βρέθηκαν αρχεία περιεχομένου.', + 'delete_confirm_multiple' => 'Να διαγραφούν τα επιλεγμένα αρχεία περιεχόμενου ή τους καταλόγους;', + 'delete_confirm_single' => 'Να διαγραφεί αυτό το αρχείο περιεχομένου;', + 'new' => 'Νέο Αρχ.Περ.', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Μη έγκυρο όνομα χειριστή AJAX: :name.', + 'not_found' => "Ο χειρίστης AJAX ':name' δεν βρέθηκε.", + ], + 'cms' => [ + 'menu_label' => 'CMS', + ], + 'sidebar' => [ + 'add' => 'Προσθήκη', + 'search' => 'Αναζήτηση...', + ], + 'editor' => [ + 'settings' => 'Ρυθμίσεις', + 'title' => 'Τίτλος', + 'new_title' => 'Νέος τίτλος σελίδας', + 'url' => 'URL', + 'filename' => 'Όνομα Αρχείου', + 'layout' => 'Διάταξη', + 'description' => 'Περιγραφή', + 'preview' => 'Προεπισκόπηση', + 'meta' => 'Meta', + 'meta_title' => 'Τίτλος Meta', + 'meta_description' => 'Περιγραφή Meta', + 'markup' => 'Markup', + 'code' => 'Κώδικας', + 'content' => 'Περιεχόμενο', + 'hidden' => 'Κρυφό', + 'hidden_comment' => 'Οι κρυφές σελίδες είναι προσβάσημες μόνο από τους συνδεδεμένους back-end χρήστες.', + 'enter_fullscreen' => 'Μετάβαση σε λειτουργία πλήρους οθόνης', + 'exit_fullscreen' => 'Έξοδος από την λειτουργία πλήρους οθόνης', + 'open_searchbox' => 'Άνοιγμα του πλαισίου Αναζήτησης', + 'close_searchbox' => 'Κλείσιμο του πλαισίου Αναζήτησης', + 'open_replacebox' => 'Άνοιγμα του πλαισίου Αντικατάστασης', + 'close_replacebox' => 'Κλείσιμο του πλαισίου Αντικατάστασης', + ], + 'asset' => [ + 'menu_label' => 'Πόροι', + 'unsaved_label' => 'Μη αποθηκευμένοι πόροι', + 'drop_down_add_title' => 'Προσθήκη...', + 'drop_down_operation_title' => 'Ενέργια...', + 'upload_files' => 'Ανέβασμα αρχείου(α)', + 'create_file' => 'Δημιουργία αρχείου', + 'create_directory' => 'Δημιουργία καταλόγου', + 'directory_popup_title' => 'Νέος κατάλογος', + 'directory_name' => 'Όνομα καταλόγου', + 'rename' => 'Μετονομασία', + 'delete' => 'Διαγραφή', + 'move' => 'Μετακίνηση', + 'select' => 'Επιλογή', + 'new' => 'Νέο αρχείο', + 'rename_popup_title' => 'Μετονομασία', + 'rename_new_name' => 'Νέο όνομα', + 'invalid_path' => 'Η διαδρομή μπορεί να περιέχει μόνο ψηφία, Λατινικούς χαρακτήρες, κενά και τα ακόλουθα σύμβολα: ._-/', + 'error_deleting_file' => 'Σφάλμα κατά την διαγραφή του αρχείου :name.', + 'error_deleting_dir_not_empty' => 'Σφάλμα κατά την διαγραφή του καταλόγου :name. Ο κατάλογος δεν είναι άδειος.', + 'error_deleting_dir' => 'Σφάλμα κατά την διαγραφή του καταλόγου :name.', + 'invalid_name' => 'Το όνομα μπορεί να περιέχει μόνο ψηφία, Λατινικούς χαρακτήρες, κενά και τα ακόλουθα σύμβολα: ._-', + 'original_not_found' => 'Το αρχικό αρχείο ή κατάλογος δεν βρέθηκε', + 'already_exists' => 'Το αρχείο ή ο κατάλογος με αυτό το όνομα υπάρχει ήδη', + 'error_renaming' => 'Σφάλμα κατά την μετονομασία του αρχείου ή του καταλόγου', + 'name_cant_be_empty' => 'Το όνομα δεν μπορεί να είναι άδειο', + 'too_large' => 'Το ανεβασμένο αρχείο είναι πολύ μεγάλο. Το μέγιστο επιτρεπόμενο μέγεθος αρχείου είναι :max_size', + 'type_not_allowed' => 'Επιτρέπονται μόνο οι επόμενοι τύποι αρχείων:allowed_types', + 'file_not_valid' => 'Το αρχείο δεν είναι έγκυρο', + 'error_uploading_file' => "Σφάλμα κατά το ανέβασμα του αρχείου ':name': :error", + 'move_please_select' => 'παρακαλούμε επιλέξτε', + 'move_destination' => 'Κατάλογος προορισμού', + 'move_popup_title' => 'Μετακίνηση πόρων', + 'move_button' => 'Μετακίνηση', + 'selected_files_not_found' => 'Τα επιλεγμένα αρχεία δεν βρέθηκαν', + 'select_destination_dir' => 'Παρακαλούμε επιλέξτε έναν κατάλογο προορισμού', + 'destination_not_found' => 'Ο κατάλογος προορισμού δεν βρέθηκε', + 'error_moving_file' => 'Σφάλμα κατά την μετακίνηση του αρχείου :file', + 'error_moving_directory' => 'Σφάλμα κατά την μετακίνηση του καταλόγου :dir', + 'error_deleting_directory' => 'Σφάλμα κατά την διαγραφή του αρχικού καταλόγου :dir', + 'path' => 'Διαδρομή', + ], + 'component' => [ + 'menu_label' => 'Συστατικά', + 'unnamed' => 'Χωρίς Όνομα', + 'no_description' => 'Δεν παρέχεται περιγραφή', + 'alias' => 'Ψευδώνυμο', + 'alias_description' => 'Ένα μοναδικό όνομα δίνεται σε αυτό το συστατικό όταν το χρησιμοποιείτε στον κώδικα της σελίδας ή της διάταξης.', + 'validation_message' => 'Τα ψευδώνυμα των συστατικών είναι υποχρεωτικά και μπορούν να περιέχουν μόνο Λατινικά σύμβολα, αριθμούς, και κάτω παύλες. Τα ψευδώνυμα θα πρέπει να αρχίζουν με ένα λατινικό σύμβολο.', + 'invalid_request' => 'Το πρότυπο δεν μπορεί να σωθεί λόγω των μη έγκυρων δεδομένων του συστατικού.', + 'no_records' => 'Δεν βρέθηκαν συστατικά', + 'not_found' => "Το συστατικό ':name' δεν βρέθηκε.", + 'method_not_found' => "Το συστατικό ':name' δεν περιέχει την μέθοδο ':method'.", + ], + 'template' => [ + 'not_found' => 'Το πρότυπο δεν βρέθηκε.', + 'saved'=> 'Το πρότυπο σώθηκε.', + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Διαχείριση των αρχείων περιεχομένου του ιστότοπου,//Manage website content files', + 'manage_assets' => 'Διαχείριση πόρων του ιστότοπου - εικόνες, αρχεία JavaScript, αρχεία CSS', + 'manage_pages' => 'Δημιουργία, τροποποίηση και διαγραφή των σελίδων του ιστότοπου,//Create, modify and delete website pages', + 'manage_layouts' => 'Δημιουργία, τροποποίηση και διαγραφή των διατάξεων του CMS', + 'manage_partials' => 'Δημιουργία, τροποποίηση και διαγραφή των τμημάτων του CMS', + 'manage_themes' => 'Ενεργοποίηση, απενεργοποίηση και ρύθμιση των θεμάτων του CMS', + ], +]; diff --git a/modules/cms/lang/en/lang.php b/modules/cms/lang/en/lang.php new file mode 100644 index 0000000..215bff8 --- /dev/null +++ b/modules/cms/lang/en/lang.php @@ -0,0 +1,304 @@ + [ + 'invalid_file' => 'Invalid file name: :name. File names can contain only alphanumeric symbols, underscores, dashes and dots. Some examples of correct file names: page.htm, page, subdirectory/page', + 'invalid_property' => "The property ':name' cannot be set", + 'file_already_exists' => "File ':name' already exists.", + 'error_saving' => "Error saving file ':name'. Please check write permissions.", + 'error_creating_directory' => 'Error creating directory :name. Please check write permissions.', + 'invalid_file_extension' => 'Invalid file extension: :invalid. Allowed extensions are: :allowed.', + 'error_deleting' => "Error deleting the template file ':name'. Please check write permissions.", + 'delete_success' => 'Templates deleted: :count.', + 'file_name_required' => 'The File Name field is required.', + 'safe_mode_enabled' => 'Safe mode is currently enabled. Editing the PHP code of CMS templates is disabled. To disable safe mode, set the `cms.enableSafeMode` configuration value to `false`.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Website', + 'online' => 'Online', + 'maintenance' => 'In maintenance', + 'manage_themes' => 'Manage themes', + 'customize_theme' => 'Customize theme', + ], + ], + 'theme' => [ + 'not_found_name' => "The theme ':name' is not found.", + 'by_author' => 'By :name', + 'active' => [ + 'not_set' => 'The active theme is not set.', + 'not_found' => 'The active theme is not found.', + ], + 'edit' => [ + 'not_set' => 'The edit theme is not set.', + 'not_found' => 'The edit theme is not found.', + 'not_match' => "The object you're trying to access doesn't belong to the theme being edited. Please reload the page.", + ], + 'settings_menu' => 'Front-end theme', + 'settings_menu_description' => 'Manage the front-end theme and customization options.', + 'default_tab' => 'Properties', + 'name_label' => 'Name', + 'name_create_placeholder' => 'New theme name', + 'author_label' => 'Author', + 'author_placeholder' => 'Person or company name', + 'description_label' => 'Description', + 'description_placeholder' => 'Theme description', + 'homepage_label' => 'Homepage', + 'homepage_placeholder' => 'Website URL', + 'code_label' => 'Code', + 'code_placeholder' => 'A unique code for this theme used for distribution', + 'preview_image_label' => 'Preview image', + 'preview_image_placeholder' => 'The path of theme preview image.', + 'dir_name_label' => 'Directory name', + 'dir_name_create_label' => 'The destination theme directory', + 'theme_label' => 'Theme', + 'theme_title' => 'Themes', + 'activate_button' => 'Activate', + 'active_button' => 'Activate', + 'customize_theme' => 'Customize Theme', + 'customize_button' => 'Customize', + 'duplicate_button' => 'Duplicate', + 'duplicate_title' => 'Duplicate theme', + 'duplicate_theme_success' => 'Theme duplicated!', + 'manage_button' => 'Manage', + 'manage_title' => 'Manage theme', + 'edit_properties_title' => 'Theme', + 'edit_properties_button' => 'Edit properties', + 'save_properties' => 'Save properties', + 'import_button' => 'Import', + 'import_title' => 'Import theme', + 'import_theme_success' => 'Theme imported!', + 'import_uploaded_file' => 'Theme archive file', + 'import_overwrite_label' => 'Overwrite existing files', + 'import_overwrite_comment' => 'Untick this box to only import new files', + 'import_folders_label' => 'Folders', + 'import_folders_comment' => 'Please select the theme folders you would like to import', + 'export_button' => 'Export', + 'export_title' => 'Export theme', + 'export_folders_label' => 'Folders', + 'export_folders_comment' => 'Please select the theme folders you would like to export', + 'delete_button' => 'Delete', + 'delete_confirm' => 'Delete this theme? It cannot be undone!', + 'delete_active_theme_failed' => 'Cannot delete the active theme, try making another theme active first.', + 'delete_theme_success' => 'Theme deleted!', + 'create_title' => 'Create theme', + 'create_button' => 'Create', + 'create_new_blank_theme' => 'Create a new blank theme', + 'create_theme_success' => 'Theme created!', + 'create_theme_required_name' => 'Please specify a name for the theme.', + 'new_directory_name_label' => 'Theme directory', + 'new_directory_name_comment' => 'Provide a new directory name for the duplicated theme.', + 'dir_name_invalid' => 'Name can contain only digits, Latin letters and the following symbols: _-', + 'dir_name_taken' => 'Desired theme directory already exists.', + 'find_more_themes' => 'Find more themes', + 'saving' => 'Saving theme...', + 'return' => 'Return to themes list', + ], + 'maintenance' => [ + 'settings_menu' => 'Maintenance mode', + 'settings_menu_description' => 'Configure the maintenance mode page and toggle the setting.', + 'is_enabled' => 'Enable maintenance mode', + 'is_enabled_comment' => 'Select the page to show when maintenance mode is activated.', + 'hint' => 'Maintenance mode will display the maintenance page to visitors who are not signed in to the back-end area.', + ], + 'page' => [ + 'not_found_name' => "The page ':name' is not found", + 'not_found' => [ + 'label' => 'Page not found', + 'help' => 'The requested page cannot be found.', + ], + 'custom_error' => [ + 'label' => 'Page error', + 'help' => "We're sorry, but something went wrong and the page cannot be displayed.", + ], + 'menu_label' => 'Pages', + 'unsaved_label' => 'Unsaved page(s)', + 'no_list_records' => 'No pages found', + 'new' => 'New page', + 'invalid_url' => 'Invalid URL format. The URL should start with the forward slash symbol and can contain digits, Latin letters and the following symbols: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Delete selected pages?', + 'delete_confirm_single' => 'Delete this page?', + 'no_layout' => '-- no layout --', + 'cms_page' => 'CMS page', + 'title' => 'Page title', + 'url' => 'Page URL', + 'file_name' => 'Page file name', + ], + 'layout' => [ + 'not_found_name' => "The layout ':name' is not found", + 'menu_label' => 'Layouts', + 'unsaved_label' => 'Unsaved layout(s)', + 'no_list_records' => 'No layouts found', + 'new' => 'New layout', + 'delete_confirm_multiple' => 'Delete selected layouts?', + 'delete_confirm_single' => 'Delete this layout?', + ], + 'partial' => [ + 'not_found_name' => "The partial ':name' is not found.", + 'invalid_name' => 'Invalid partial name: :name.', + 'menu_label' => 'Partials', + 'unsaved_label' => 'Unsaved partial(s)', + 'no_list_records' => 'No partials found', + 'delete_confirm_multiple' => 'Delete selected partials?', + 'delete_confirm_single' => 'Delete this partial?', + 'new' => 'New partial', + ], + 'content' => [ + 'not_found_name' => "The content file ':name' is not found.", + 'menu_label' => 'Content', + 'unsaved_label' => 'Unsaved content', + 'no_list_records' => 'No content files found', + 'delete_confirm_multiple' => 'Delete selected content files or directories?', + 'delete_confirm_single' => 'Delete this content file?', + 'new' => 'New content file', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Invalid AJAX handler name: :name.', + 'not_found' => "AJAX handler ':name' was not found.", + ], + 'cms' => [ + 'menu_label' => 'CMS', + ], + 'sidebar' => [ + 'add' => 'Add', + 'search' => 'Search...', + ], + 'editor' => [ + 'settings' => 'Settings', + 'title' => 'Title', + 'new_title' => 'New page title', + 'url' => 'URL', + 'filename' => 'File Name', + 'layout' => 'Layout', + 'description' => 'Description', + 'preview' => 'Preview', + 'meta' => 'Meta', + 'meta_title' => 'Meta Title', + 'meta_description' => 'Meta Description', + 'markup' => 'Markup', + 'code' => 'Code', + 'content' => 'Content', + 'hidden' => 'Hidden', + 'hidden_comment' => 'Hidden pages are accessible only by logged-in back-end users.', + 'enter_fullscreen' => 'Enter fullscreen mode', + 'exit_fullscreen' => 'Exit fullscreen mode', + 'open_searchbox' => 'Open Search box', + 'close_searchbox' => 'Close Search box', + 'open_replacebox' => 'Open Replace box', + 'close_replacebox' => 'Close Replace box', + 'commit' => 'Commit', + 'reset' => 'Reset', + 'commit_confirm' => 'Are you sure you want to commit your changes to this file to the filesystem? This will overwrite the existing file on the filesystem', + 'reset_confirm' => 'Are you sure you want to reset this file to the copy that is on the filesystem? This will completely replace it with the file that is on the filesystem', + 'committing' => 'Committing', + 'resetting' => 'Resetting', + 'commit_success' => 'The :type has been committed to the filesystem', + 'reset_success' => 'The :type has been reset to the filesystem version', + ], + 'asset' => [ + 'menu_label' => 'Assets', + 'unsaved_label' => 'Unsaved asset(s)', + 'drop_down_add_title' => 'Add...', + 'drop_down_operation_title' => 'Action...', + 'upload_files' => 'Upload file(s)', + 'create_file' => 'Create file', + 'create_directory' => 'Create directory', + 'directory_popup_title' => 'New directory', + 'directory_name' => 'Directory name', + 'rename' => 'Rename', + 'delete' => 'Delete', + 'move' => 'Move', + 'select' => 'Select', + 'new' => 'New file', + 'rename_popup_title' => 'Rename', + 'rename_new_name' => 'New name', + 'invalid_path' => 'Path can contain only digits, Latin letters, spaces and the following symbols: ._-/', + 'error_deleting_file' => 'Error deleting file :name.', + 'error_deleting_dir_not_empty' => 'Error deleting directory :name. The directory is not empty.', + 'error_deleting_dir' => 'Error deleting directory :name.', + 'invalid_name' => 'Name can contain only digits, Latin letters, spaces and the following symbols: ._-', + 'original_not_found' => 'Original file or directory not found', + 'already_exists' => 'File or directory with this name already exists', + 'error_renaming' => 'Error renaming the file or directory', + 'name_cant_be_empty' => 'The name cannot be empty', + 'too_large' => 'The uploaded file is too large. The maximum allowed file size is :max_size', + 'type_not_allowed' => 'Only the following file types are allowed: :allowed_types', + 'file_not_valid' => 'File is not valid', + 'error_uploading_file' => "Error uploading file ':name': :error", + 'move_please_select' => 'please select', + 'move_destination' => 'Destination directory', + 'move_popup_title' => 'Move assets', + 'move_button' => 'Move', + 'selected_files_not_found' => 'Selected files not found', + 'select_destination_dir' => 'Please select a destination directory', + 'destination_not_found' => 'Destination directory is not found', + 'error_moving_file' => 'Error moving file :file', + 'error_moving_directory' => 'Error moving directory :dir', + 'error_deleting_directory' => 'Error deleting the original directory :dir', + 'no_list_records' => 'No files found', + 'delete_confirm' => 'Delete selected files or directories?', + 'path' => 'Path', + ], + 'component' => [ + 'menu_label' => 'Components', + 'unnamed' => 'Unnamed', + 'no_description' => 'No description provided', + 'alias' => 'Alias', + 'alias_description' => 'A unique name given to this component when using it in the page or layout code.', + 'validation_message' => 'Component aliases are required and can contain only Latin symbols, digits, and underscores. The aliases should start with a Latin symbol.', + 'invalid_request' => 'The template cannot be saved because of invalid component data.', + 'no_records' => 'No components found', + 'not_found' => "The component ':name' is not found.", + 'no_default_partial' => "This component does not have a 'default' partial", + 'method_not_found' => "The component ':name' does not contain a method ':method'.", + 'soft_component' => 'Soft Component', + 'soft_component_description' => 'This component is missing but optional.', + ], + 'template' => [ + 'invalid_type' => 'Unknown template type.', + 'not_found' => 'Template not found.', + 'saved' => 'Template saved.', + 'no_list_records' => 'No records found', + 'delete_confirm' => 'Delete selected templates?', + 'order_by' => 'Order by', + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Manage website content files', + 'manage_assets' => 'Manage website assets - images, JavaScript files, CSS files', + 'manage_pages' => 'Create, modify and delete website pages', + 'manage_layouts' => 'Create, modify and delete CMS layouts', + 'manage_partials' => 'Create, modify and delete CMS partials', + 'manage_themes' => 'Activate, deactivate and configure CMS themes', + 'manage_theme_options' => 'Configure customization options for the active theme', + ], + 'theme_log' => [ + 'hint' => 'This log displays any changes made to the theme by administrators in the back-end area.', + 'menu_label' => 'Theme log', + 'menu_description' => 'View changes made to the active theme.', + 'empty_link' => 'Empty theme log', + 'empty_loading' => 'Emptying theme log...', + 'empty_success' => 'Theme log emptied', + 'return_link' => 'Return to theme log', + 'id' => 'ID', + 'id_label' => 'Log ID', + 'created_at' => 'Date & Time', + 'user' => 'User', + 'type' => 'Type', + 'type_create' => 'Create', + 'type_update' => 'Update', + 'type_delete' => 'Delete', + 'theme_name' => 'Theme', + 'theme_code' => 'Theme code', + 'old_template' => 'Template (Old)', + 'new_template' => 'Template (New)', + 'template' => 'Template', + 'diff' => 'Changes', + 'old_value' => 'Old value', + 'new_value' => 'New value', + 'preview_title' => 'Template changes', + 'template_updated' => 'Template was updated', + 'template_created' => 'Template was created', + 'template_deleted' => 'Template was deleted', + ], +]; diff --git a/modules/cms/lang/es-ar/lang.php b/modules/cms/lang/es-ar/lang.php new file mode 100644 index 0000000..4c5d62f --- /dev/null +++ b/modules/cms/lang/es-ar/lang.php @@ -0,0 +1,170 @@ + [ + 'invalid_file' => 'Nombre inválido del archivo: :name. El nombre del archivo debe contener solamente caracteres alfanuméricos, guiones bajos, barras y puntos. Algunos ejemplos de nombres correctos son: archivo.htm, archivo, subdirectorio/archivo', + 'invalid_property' => 'La propiedad ":name" no puede establecerse', + 'file_already_exists' => 'Archivo ":name" ya existe.', + 'error_saving' => 'Error guardando archivo ":name". Por favor revisar los permisos de escritura.', + 'error_creating_directory' => 'Error creando el directorio :name. Por favor revisar los permisos de escritura.', + 'invalid_file_extension'=>'Extensión de archivo inválida: :invalid. Las extensiones permitidas son: :allowed.', + 'error_deleting' => 'Error borrando el archivo template ":name". Por favor revisar los permisos de escritura.', + 'delete_success' => 'Los templates fueron borrados exitosamente: :count.', + 'file_name_required' => 'Falta el nombre del campo del archivo.' + ], + 'theme' => [ + 'active' => [ + 'not_set' => "El tema activo no se ha establecido.", + 'not_found' => "El tema activo no se encuentra.", + ], + 'edit' => [ + 'not_set' => "El tema de edición no se ha establecido.", + 'not_found' => "El tema de edición no se encuentra.", + 'not_match' => "El objeto que está intentando acceder no pertenece al tema que se está editando. Vuelve a cargar la página." + ], + 'settings_menu' => 'Plantilla', + 'settings_menu_description' => 'Vista previa de la lista de las plantillas instaladas.', + 'find_more_themes' => 'Busque más Plantillas', + 'activate_button' => 'Activar', + 'active_button' => 'Activar', + ], + 'page' => [ + 'not_found' => [ + 'label' => "Página no encontrada", + 'help' => "La página solicitada no se puede encontrar.", + ], + 'custom_error' => [ + 'label' => "Error de página", + 'help' => "Lo sentimos, ha ocurrido un error y la página no se puede mostrar.", + ], + 'menu_label' => 'Páginas', + 'no_list_records' => 'No se encontraron páginas', + 'new' => 'Nueva página', + 'invalid_url' => 'Formato de URL inválido. El URL debe comenzar con el símbolo de barra diagonal y puede contener dígitos, letras latinas y los siguientes símbolos: _-[]:?|/+*^$', + 'delete_confirm_multiple' => '¿Realmente quiere eliminar las páginas seleccionadas?', + 'delete_confirm_single' => '¿Realmente quieres eliminar esta página?', + 'no_layout' => '-- ninguna disposición --' + ], + 'layout' => [ + 'not_found_name' => "El diseño ':name' no se encuentra", + 'menu_label' => 'Diseños', + 'no_list_records' => 'No se ecnontraron diseños', + 'new' => 'Nuevo diseño', + 'delete_confirm_multiple' => 'Realmente quiere borrar los diseños seleccionados?', + 'delete_confirm_single' => 'Realmente quiere borrar este diseño?' + ], + 'partial' => [ + 'not_found_name' => "El nombre parcial ':name' no se encuentra.", + 'invalid_name' => "Nombre parcial inválido: :name.", + 'menu_label' => 'Parciales', + 'no_list_records' => 'No se encontraron parciales', + 'delete_confirm_multiple' => 'Realmente quiere borrar los parciales seleccionados?', + 'delete_confirm_single' => 'Realmente quiere borrar este parcial?', + 'new' => 'Nuevo parcial' + ], + 'content' => [ + 'not_found_name' => "El contenido del archivo ':name' no se encuentra.", + 'menu_label' => 'Contenido', + 'no_list_records' => 'No se encuentra el conteinod de los archivos', + 'delete_confirm_multiple' => 'Realmente desea borrar los contenidos seleccionados de los archivos o directorios?', + 'delete_confirm_single' => 'Realmente desea borrar el contenido de este archivo?', + 'new' => 'Nuevo contenido de archivo' + ], + 'ajax_handler' => [ + 'invalid_name' => "Manejador de AJAX inválido: :name.", + 'not_found' => "El manejador de AJAX ':name' no se encuentra.", + ], + 'cms' => [ + 'menu_label' => "Gestión" + ], + 'sidebar' => [ + 'add' => 'Agregar', + 'search' => 'Buscar...' + ], + 'editor' => [ + 'settings' => 'Configuración', + 'title' => 'Título', + 'new_title' => 'Nuevo título de la página', + 'url' => 'URL', + 'filename' => 'Nombre del archivo', + 'layout' => 'Disposición', + 'description' => 'Descripción', + 'preview' => 'Vista previa', + 'meta' => 'Meta', + 'meta_title' => 'Meta Título', + 'meta_description' => 'Meta Descripción', + 'markup' => 'Marcado', + 'code' => 'Código', + 'content' => 'Contenido', + 'hidden' => 'Oculto', + 'hidden_comment' => 'A las páginas ocultas solamente pueden acceder los usuarios del back-end que se encuentren logueados.', + 'enter_fullscreen' => 'Ingresar en el modo pantalla completa', + 'exit_fullscreen' => 'Salir de pantalla completa' + ], + 'asset' => [ + 'menu_label' => "Assets", + 'drop_down_add_title' => 'Add...', + 'drop_down_operation_title' => 'Action...', + 'upload_files' => 'Upload file(s)', + 'create_file' => 'Create file', + 'create_directory' => 'Create directory', + 'directory_popup_title' => 'Nuevo directorio', + 'directory_name' => 'Nombre del directorio', + 'rename' => 'Renombrar', + 'delete' => 'Borrar', + 'move' => 'Mover', + 'select' => 'Seleccionar', + 'new' => 'Nuevo archivo', + 'rename_popup_title' => 'Renombrar', + 'rename_new_name' => 'Nuevo nombre', + 'invalid_path' => 'El path solamente puede contener dígitos, letras, espacios y los símbolos siguientes: ._-/', + 'error_deleting_file' => 'Error al borrar el archivo :name.', + 'error_deleting_dir_not_empty' => 'Error borrando el directorio :name. El directorio no está vacío.', + 'error_deleting_dir' => 'Error borrando el archivo :name.', + 'invalid_name' => 'El nombre solamente puede contener dígitos, letras, espacios y los símbolos siguientes: ._-', + 'original_not_found' => 'El archivo o directorio original no se encuentra', + 'already_exists' => 'Un archivo o directorio con este nombre ya existe', + 'error_renaming' => 'Error renombrando el archivo o directorio', + 'name_cant_be_empty' => 'El nombre no puede estar vacío', + 'too_large' => 'El archivo subido es demasiado pesado. El tamaño máximo permitido es :max_size', + 'type_not_allowed' => 'Solamente los siguientes tipos de archivos están permitidos: :allowed_types', + 'file_not_valid' => 'El archivo no es válido', + 'error_uploading_file' => 'Error subiendo el archivo ":name": :error', + 'move_please_select' => 'por favor seleccionar', + 'move_destination' => 'Directorio destino', + 'move_popup_title' => 'Mover los títulos emergentes', + 'move_button' => 'Mover', + 'selected_files_not_found' => 'Los archivos seleccionados no se encuentran', + 'select_destination_dir' => 'Por favor seleccione un directorio destino', + 'destination_not_found' => 'El directorio destino no se encuentra', + 'error_moving_file' => 'Error moviendo archivo :file', + 'error_moving_directory' => 'Error moviendo el directorio :dir', + 'error_deleting_directory' => 'Error borrando el directorio original :dir', + 'path' => 'Path' + ], + 'component' => [ + 'menu_label' => "Componentes", + 'unnamed' => "Sin nombre", + 'no_description' => "No se proporciona descripción", + 'alias' => "Alias", + 'alias_description' => "Se le ha asignado un nombre único a este componente cuando se lo utilizaba en la página o en el código de disposición.", + 'validation_message' => "El componente alias es requerido y puede contener solamente letras, números y guión bajo. El alias debe empezar con una letra.", + 'invalid_request' => "La plantilla no puede ser guardada porque tiene datos inválidos.", + 'no_records' => 'No se encontraron componentes', + 'not_found' => "El componente ':name' no se encuentra.", + 'method_not_found' => "El componente ':name' no contiene un método ':method'.", + ], + 'template' => [ + 'invalid_type' => "Tipo de plantilla Desconocido.", + 'not_found' => "No se encontró la plantilla solicitada.", + 'saved'=> "La plantilla se ha guardado correctamente." + ], + 'permissions' => [ + 'manage_content' => 'Gestionar contenido', + 'manage_assets' => 'Gestionar archivos', + 'manage_pages' => 'Gestionar páginas', + 'manage_layouts' => 'Gestionar diseños', + 'manage_partials' => 'Gestionar parciales', + 'manage_themes' => 'Gestionar plantilla' + ] +]; diff --git a/modules/cms/lang/es/lang.php b/modules/cms/lang/es/lang.php new file mode 100644 index 0000000..dd54be4 --- /dev/null +++ b/modules/cms/lang/es/lang.php @@ -0,0 +1,291 @@ + [ + 'invalid_file' => 'Nombre inválido del archivo: :name. El nombre del archivo puede contener solo caracteres alfanuméricos, guiones bajos, barras y puntos. Algunos ejemplos de nombres correctos son: pagina.htm, pagina, subdirectorio/pagina', + 'invalid_property' => "La propiedad ':name' no se puede establecer", + 'file_already_exists' => "El archivo ':name' ya existe.", + 'error_saving' => "Error guardando archivo ':name'. Por favor, revisa los permisos de escritura.", + 'error_creating_directory' => 'Error creando el directorio :name. Por favor, revisa los permisos de escritura.', + 'invalid_file_extension' => 'Extensión de archivo inválida: :invalid. Las extensiones permitidas son: :allowed.', + 'error_deleting' => 'Error eliminando el archivo de plantilla ":name". Por favor, revisa los permisos de escritura.', + 'delete_success' => 'Las plantillas fueron eliminadas satisfactoriamente: :count.', + 'file_name_required' => 'El campo Nombre es obligatorio.', + 'safe_mode_enabled' => 'El modo seguro está activado actualmente.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Sitio Web', + 'online' => 'en línea', + 'maintenance' => 'en mantenimiento', + 'manage_themes' => 'Gestionar temas', + 'customize_theme' => 'Personalizar tema' + ] + ], + 'theme' => [ + 'not_found_name' => "El tema ':name' no se encuentra.", + 'active' => [ + 'not_set' => 'El tema activo no se ha establecido.', + 'not_found' => 'El tema activo no se encuentra.' + ], + 'edit' => [ + 'not_set' => 'El tema de edición no se ha establecido.', + 'not_found' => 'El tema de edición no se encuentra.', + 'not_match' => 'El objeto que está intentando acceder no pertenece al tema que se está editando. Porfavor recarga la página.' + ], + 'settings_menu' => 'Tema para el Front-end', + 'settings_menu_description' => 'Previsualiza la lista de temas instalados y selecciona un tema activo.', + 'default_tab' => 'Propiedades', + 'name_label' => 'Nombre', + 'name_create_placeholder' => 'Nombre del nuevo tema', + 'author_label' => 'Autor', + 'author_placeholder' => 'Nombre de la persona o empresa', + 'description_label' => 'Descripción', + 'description_placeholder' => 'Descripción del tema', + 'homepage_label' => 'Página de inicio', + 'homepage_placeholder' => 'URL de la web', + 'code_label' => 'Código', + 'code_placeholder' => 'Código único para el tema usado para su distribución', + 'preview_image_label' => 'Imagen de previsualización', + 'preview_image_placeholder' => 'La ruta de la imagen de previsualización del tema.', + 'dir_name_label' => 'Nombre del directorio', + 'dir_name_create_label' => 'El directorio de destino del tema', + 'theme_label' => 'Tema', + 'theme_title' => 'Temas', + 'activate_button' => 'Activar', + 'active_button' => 'Activar', + 'customize_theme' => 'Personalizar Tema', + 'customize_button' => 'Personalizar', + 'duplicate_button' => 'Duplicar', + 'duplicate_title' => 'Duplicar tema', + 'duplicate_theme_success' => 'Tema duplicado!', + 'manage_button' => 'Gestionar', + 'manage_title' => 'Gestionar tema', + 'edit_properties_title' => 'Tema', + 'edit_properties_button' => 'Editar propiedades', + 'save_properties' => 'Guardar propiedades', + 'import_button' => 'Importar', + 'import_title' => 'Importar tema', + 'import_theme_success' => 'Tema importado!', + 'import_uploaded_file' => 'Fichero de archivo de tema', + 'import_overwrite_label' => 'Sobreescribir archivos existentes', + 'import_overwrite_comment' => 'Desmarca esta casilla para importar sólo los archivos nuevos', + 'import_folders_label' => 'Carpetas', + 'import_folders_comment' => 'Por favor, selecciona las carpetas del tema que quieres importar', + 'export_button' => 'Exportar', + 'export_title' => 'Exportar tema', + 'export_folders_label' => 'Carpetas', + 'export_folders_comment' => 'Por favor, selecciona las carpetas del tema que quieres exportar', + 'delete_button' => 'Eliminar', + 'delete_confirm' => '¿Deseas eliminar este tema? Esta acción no se puede deshacer!', + 'delete_active_theme_failed' => 'No puedes eliminar el tema activo, intenta activar otro tema primero.', + 'delete_theme_success' => 'Tema eliminado!', + 'create_title' => 'Crear tema', + 'create_button' => 'Crear', + 'create_new_blank_theme' => 'Crear un tema en blanco', + 'create_theme_success' => 'Tema creado!', + 'create_theme_required_name' => 'Por favor, especifica un nombre para el tema.', + 'new_directory_name_label' => 'Directorio del tema', + 'new_directory_name_comment' => 'Introduce un nombre para el directorio del tema duplicado.', + 'dir_name_invalid' => 'El nombre sólo puede contener dígitos, letras latinas y los siguientes símbolos: _-', + 'dir_name_taken' => 'Este directorio ya existe.', + 'find_more_themes' => 'Buscar nuevos temas', + 'saving' => 'Guardando tema...', + 'return' => 'Volver a la lista de temas' + ], + 'maintenance' => [ + 'settings_menu' => 'Modo de mantenimiento', + 'settings_menu_description' => 'Configura la página del modo de mantenimiento y cambia su configuración', + 'is_enabled' => 'Activar el modo de mantenimiento', + 'is_enabled_comment' => 'Selecciona la página para mostrar cuando el modo de mantenimiento esté activado.', + 'hint' => 'El modo de mantenimiento mostrará la página de mantenimiento a los visitantes que no estén conectados en el área de back-end.' + ], + 'page' => [ + 'not_found_name' => "La página ':name' no se encuentra", + 'not_found' => [ + 'label' => 'Página no encontrada', + 'help' => 'La página solicitada no se encuentra.' + ], + 'custom_error' => [ + 'label' => 'Error en la página', + 'help' => 'Lo sentimos, pero algo salió mal y la página no se puede mostrar.' + ], + 'menu_label' => 'Páginas', + 'unsaved_label' => 'Página(s) sin guardar', + 'no_list_records' => 'No se encuentran páginas', + 'new' => 'Nueva página', + 'invalid_url' => 'Formato de URL incorrecto. La URL debe empezar con el símbolo de barra diagonal y puede contener dígitos, letras latinas y los siguientes símbolos: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => '¿Deseas eliminar las páginas seleccionadas?', + 'delete_confirm_single' => '¿Deseas eliminar esta página?', + 'no_layout' => '-- sin diseño --', + 'cms_page' => 'Página de CMS', + 'title' => 'Título de página', + 'url' => 'URL de página', + 'file_name' => 'Nombre de archivo de página' + ], + 'layout' => [ + 'not_found_name' => "El diseño ':name' no se encuentra", + 'menu_label' => 'Diseños', + 'unsaved_label' => 'Diseño(s) sin guardar', + 'no_list_records' => 'No se encuentran diseños', + 'new' => 'Nuevo diseño', + 'delete_confirm_multiple' => '¿Deseas eliminar los diseños seleccionados?', + 'delete_confirm_single' => '¿Deseas eliminar este diseño?' + ], + 'partial' => [ + 'not_found_name' => "El nombre de parcial ':name' no se encuentra.", + 'invalid_name' => 'Nombre de parcial inválido: :name.', + 'menu_label' => 'Parciales', + 'unsaved_label' => 'Parcial(es) sin guardar', + 'no_list_records' => 'No se encontraron parciales', + 'delete_confirm_multiple' => '¿Deseas eliminar los parciales seleccionados?', + 'delete_confirm_single' => '¿Deseas eliminar este parcial?', + 'new' => 'Nuevo parcial' + ], + 'content' => [ + 'not_found_name' => "El archivo de contenido ':name' no se encuentra.", + 'menu_label' => 'Contenido', + 'unsaved_label' => 'Contenido sin guardar', + 'no_list_records' => 'No se encuentran archivos de contenido', + 'delete_confirm_multiple' => '¿Deseas eliminar los archivos o directorios de contenido seleccionados?', + 'delete_confirm_single' => '¿Deseas eliminar este archivo de contenido?', + 'new' => 'Nuevo archivo de contenido' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Manejador de AJAX inválido: :name.', + 'not_found' => "El manejador de AJAX ':name' no se encuentra." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Agregar', + 'search' => 'Buscar...' + ], + 'editor' => [ + 'settings' => 'Configuración', + 'title' => 'Título', + 'new_title' => 'Título de la nueva página', + 'url' => 'URL', + 'filename' => 'Nombre del archivo', + 'layout' => 'Diseño', + 'description' => 'Descripción', + 'preview' => 'Vista previa', + 'meta' => 'Meta', + 'meta_title' => 'Meta Título', + 'meta_description' => 'Meta Descripción', + 'markup' => 'Marcado', + 'code' => 'Código', + 'content' => 'Contenido', + 'hidden' => 'Oculto', + 'hidden_comment' => 'Las páginas ocultas sólo son accesibles por los usuarios que han iniciado sesión en el back-end.', + 'enter_fullscreen' => 'Abrir en pantalla completa', + 'exit_fullscreen' => 'Salir de pantalla completa', + 'open_searchbox' => 'Abrir caja de búsqueda', + 'close_searchbox' => 'Cerrar caja de búsqueda', + 'open_replacebox' => 'Abrir caja de reemplazo', + 'close_replacebox' => 'Cerrar caja de reemplazo' + ], + 'asset' => [ + 'menu_label' => 'Recursos', + 'unsaved_label' => 'Recurso(s) sin guardar', + 'drop_down_add_title' => 'Añadir...', + 'drop_down_operation_title' => 'Acción...', + 'upload_files' => 'Subir archivo(s)', + 'create_file' => 'Crear archivo', + 'create_directory' => 'Crear directorio', + 'directory_popup_title' => 'Nuevo directorio', + 'directory_name' => 'Nombre del directorio', + 'rename' => 'Renombrar', + 'delete' => 'Borrar', + 'move' => 'Mover', + 'select' => 'Seleccionar', + 'new' => 'Nuevo archivo', + 'rename_popup_title' => 'Renombrar', + 'rename_new_name' => 'Nuevo nombre', + 'invalid_path' => 'La ruta sólo puede contener dígitos, letras, espacios y los símbolos siguientes: ._-/', + 'error_deleting_file' => 'Error al borrar el archivo :name.', + 'error_deleting_dir_not_empty' => 'Error borrando el directorio :name. El directorio no está vacío.', + 'error_deleting_dir' => 'Error borrando el archivo :name.', + 'invalid_name' => 'El nombre sólo puede contener dígitos, letras, espacios y los símbolos siguientes: ._-', + 'original_not_found' => 'El archivo o directorio original no se encuentra', + 'already_exists' => 'Un archivo o directorio con este nombre ya existe', + 'error_renaming' => 'Error renombrando el archivo o directorio', + 'name_cant_be_empty' => 'El nombre no puede estar vacío', + 'too_large' => 'El archivo subido es demasiado grande. El tamaño máximo permitido es :max_size', + 'type_not_allowed' => 'Sólo los siguientes tipos de archivos están permitidos: :allowed_types', + 'file_not_valid' => 'El archivo no es válido', + 'error_uploading_file' => 'Error subiendo el archivo ":name": :error', + 'move_please_select' => 'por favor seleccionar', + 'move_destination' => 'Directorio de destino', + 'move_popup_title' => 'Mover recursos', + 'move_button' => 'Mover', + 'selected_files_not_found' => 'Los archivos seleccionados no se encuentran', + 'select_destination_dir' => 'Por favor seleccione un directorio de destino', + 'destination_not_found' => 'El directorio de destino no se encuentra', + 'error_moving_file' => 'Error moviendo el archivo :file', + 'error_moving_directory' => 'Error moviendo el directorio :dir', + 'error_deleting_directory' => 'Error borrando el directorio original :dir', + 'no_list_records' => 'No se encontraron archivos', + 'delete_confirm' => '¿Deseas eliminar los archivos o directorios seleccionados?', + 'path' => 'Ruta' + ], + 'component' => [ + 'menu_label' => 'Componentes', + 'unnamed' => 'Sin nombre', + 'no_description' => 'No se proporcionó descripción', + 'alias' => 'Alias', + 'alias_description' => 'Un nombre único asignado a este componente cuando se utilice en el código de la página o del diseño.', + 'validation_message' => 'El alias de componente es requerido y puede contener solamente letras, números y guión bajo. El alias debe empezar con una letra.', + 'invalid_request' => 'La plantilla no puede ser guardada porque tiene datos de componente inválidos.', + 'no_records' => 'No se encontraron componentes', + 'not_found' => "El componente ':name' no se encuentra.", + 'method_not_found' => "El componente ':name' no contiene un método ':method'." + ], + 'template' => [ + 'invalid_type' => 'Tipo de plantilla desconocido.', + 'not_found' => 'No se encontró la plantilla.', + 'saved' => 'La plantilla se guardó correctamente.', + 'no_list_records' => 'No se encontraron registros', + 'delete_confirm' => '¿Deseas eliminar las plantillas seleccionadas?', + 'order_by' => 'Ordenar por' + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Gestionar archivos de contenido del sitio', + 'manage_assets' => 'Gestionar recursos del sitio - imágenes, archivos JavasCript, archivos CSS', + 'manage_pages' => 'Crear, modificar y eliminar páginas del sitio', + 'manage_layouts' => 'Crear, modificar y eliminar diseños del CMS', + 'manage_partials' => 'Crear, modificar y eliminar parciales del CMS', + 'manage_themes' => 'Activar, desactivar y configurar temas del CMS', + ], + 'theme_log' => [ + 'hint' => 'Este registro muestra todos los cambios hechos al tema por los administradores en el área de back-end.', + 'menu_label' => 'Registro del tema', + 'menu_description' => 'Ver cambios hechos al tema activo.', + 'empty_link' => 'Registro del tema vacío', + 'empty_loading' => 'Vaciando registro del tema...', + 'empty_success' => 'Registro del tema vaciado', + 'return_link' => 'Volver al registro del tema', + 'id' => 'ID', + 'id_label' => 'ID de registro', + 'created_at' => 'Fecha y hora', + 'user' => 'Usuario', + 'type' => 'Tipo', + 'type_create' => 'Crear', + 'type_update' => 'Modificar', + 'type_delete' => 'Eliminar', + 'theme_name' => 'Tema', + 'theme_code' => 'Código de tema', + 'old_template' => 'Plantilla (Antigua)', + 'new_template' => 'Plantilla (Nueva)', + 'template' => 'Plantilla', + 'diff' => 'Cambios', + 'old_value' => 'Valor antiguo', + 'new_value' => 'Valor nuevo', + 'preview_title' => 'Cambios de la plantilla', + 'template_updated' => 'La plantilla se modificó', + 'template_created' => 'La plantilla se creó', + 'template_deleted' => 'La plantilla se eliminó', + ], +]; diff --git a/modules/cms/lang/et/lang.php b/modules/cms/lang/et/lang.php new file mode 100644 index 0000000..12841b1 --- /dev/null +++ b/modules/cms/lang/et/lang.php @@ -0,0 +1,292 @@ + [ + 'invalid_file' => 'Invalid file name: :name. File names can contain only alphanumeric symbols, underscores, dashes and dots. Some examples of correct file names: page.htm, page, subdirectory/page', + 'invalid_property' => "The property ':name' cannot be set", + 'file_already_exists' => "File ':name' already exists.", + 'error_saving' => "Error saving file ':name'. Please check write permissions.", + 'error_creating_directory' => 'Error creating directory :name. Please check write permissions.', + 'invalid_file_extension' => 'Invalid file extension: :invalid. Allowed extensions are: :allowed.', + 'error_deleting' => "Error deleting the template file ':name'. Please check write permissions.", + 'delete_success' => 'Templates deleted: :count.', + 'file_name_required' => 'The File Name field is required.', + 'safe_mode_enabled' => 'Safe mode is currently enabled.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Koduleht', + 'online' => 'Online', + 'maintenance' => 'Hooldusrežiimis', + 'manage_themes' => 'Halda teemasid', + 'customize_theme' => 'Kohanda teemat' + ] + ], + 'theme' => [ + 'not_found_name' => "Teemat ':name' ei leitud.", + 'by_author' => 'Autor: :name', + 'active' => [ + 'not_set' => 'Aktiivset teemat pole määratud.', + 'not_found' => 'Aktiivset teemat ei leitud.' + ], + 'edit' => [ + 'not_set' => 'Muutmise teemat pole määratud.', + 'not_found' => 'Muutmise teemat ei leitud.', + 'not_match' => "Objekt, mida üritad muuta ei kuulu hetkel muudetava teema alla. Palun laadi leht uuesti." + ], + 'settings_menu' => 'Kodulehe teema', + 'settings_menu_description' => 'Vaata paigaldatud teemasid ja vali endale sobiv.', + 'default_tab' => 'Seaded', + 'name_label' => 'Nimi', + 'name_create_placeholder' => 'Uus teema nimi', + 'author_label' => 'Autor', + 'author_placeholder' => 'Inimese või ettevõtte nimi', + 'description_label' => 'Kirjeldus', + 'description_placeholder' => 'Teema kirjeldus', + 'homepage_label' => 'Koduleht', + 'homepage_placeholder' => 'Kodulehe URL', + 'code_label' => 'Kood', + 'code_placeholder' => 'Unikaalne teema kood, mida kasutatakse teema levitamisel', + 'preview_image_label' => 'Eelvaate pilt', + 'preview_image_placeholder' => 'Teema eelvaate pildi asukohta.', + 'dir_name_label' => 'Kataloogi nimi', + 'dir_name_create_label' => 'Teema kataloog', + 'theme_label' => 'Teema', + 'theme_title' => 'Teemad', + 'activate_button' => 'Aktiveeri', + 'active_button' => 'Aktiveeri', + 'customize_theme' => 'Kohanda teemat', + 'customize_button' => 'Kohanda', + 'duplicate_button' => 'Kopeeri', + 'duplicate_title' => 'Kopeeri teema', + 'duplicate_theme_success' => 'Teema kopeeritud!', + 'manage_button' => 'Halda', + 'manage_title' => 'Halda teemat', + 'edit_properties_title' => 'Teema', + 'edit_properties_button' => 'Muuda seadeid', + 'save_properties' => 'Salvesta seaded', + 'import_button' => 'Impordi', + 'import_title' => 'Impordi teema', + 'import_theme_success' => 'Teema imporditud!', + 'import_uploaded_file' => 'Teema arhiivi fail', + 'import_overwrite_label' => 'Kirjuta olemasolevad failid üle', + 'import_overwrite_comment' => 'Jäta see kast märgistamata, et importida ainult uued failid', + 'import_folders_label' => 'Kataloogid', + 'import_folders_comment' => 'Palun vali teema kataloogid, mida soovid importida', + 'export_button' => 'Eksport', + 'export_title' => 'Ekspordi teema', + 'export_folders_label' => 'Kataloogid', + 'export_folders_comment' => 'Palun vali teema kataloogid, mida soovid eksportida', + 'delete_button' => 'Kustuta', + 'delete_confirm' => 'Kustuta teema? Seda tegevust ei saa tagasi võtta!', + 'delete_active_theme_failed' => 'Aktiivset teemat ei saa kustutada. Aktiveeri kõigepealt mõni teine teema.', + 'delete_theme_success' => 'Teema kustutatud!', + 'create_title' => 'Loo teema', + 'create_button' => 'Loo', + 'create_new_blank_theme' => 'Loo uus tühi teema', + 'create_theme_success' => 'Teema loodud!', + 'create_theme_required_name' => 'Palun määra teemale nimi.', + 'new_directory_name_label' => 'Teema kataloog', + 'new_directory_name_comment' => 'Sisesta kopeeritud teemale uus kataloogi nimi.', + 'dir_name_invalid' => 'Nimi võib sisaldada ainult numbreid, tähti ja järgnevaid sümboleid: _-', + 'dir_name_taken' => 'Soovitud kataloog on juba olemas.', + 'find_more_themes' => 'Otsi uusi teemasid', + 'saving' => 'Salvestan teemat...', + 'return' => 'Tagasi teemade nimekirja' + ], + 'maintenance' => [ + 'settings_menu' => 'Maintenance mode', + 'settings_menu_description' => 'Configure the maintenance mode page and toggle the setting.', + 'is_enabled' => 'Enable maintenance mode', + 'is_enabled_comment' => 'Select the page to show when maintenance mode is activated.', + 'hint' => 'Maintenance mode will display the maintenance page to visitors who are not signed in to the back-end area.' + ], + 'page' => [ + 'not_found_name' => "The page ':name' is not found", + 'not_found' => [ + 'label' => 'Page not found', + 'help' => 'The requested page cannot be found.' + ], + 'custom_error' => [ + 'label' => 'Page error', + 'help' => "We're sorry, but something went wrong and the page cannot be displayed." + ], + 'menu_label' => 'Pages', + 'unsaved_label' => 'Unsaved page(s)', + 'no_list_records' => 'No pages found', + 'new' => 'New page', + 'invalid_url' => 'Invalid URL format. The URL should start with the forward slash symbol and can contain digits, Latin letters and the following symbols: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Delete selected pages?', + 'delete_confirm_single' => 'Delete this page?', + 'no_layout' => '-- no layout --', + 'cms_page' => 'CMS page', + 'title' => 'Page title', + 'url' => 'Page URL', + 'file_name' => 'Page file name' + ], + 'layout' => [ + 'not_found_name' => "The layout ':name' is not found", + 'menu_label' => 'Layouts', + 'unsaved_label' => 'Unsaved layout(s)', + 'no_list_records' => 'No layouts found', + 'new' => 'New layout', + 'delete_confirm_multiple' => 'Delete selected layouts?', + 'delete_confirm_single' => 'Delete this layout?' + ], + 'partial' => [ + 'not_found_name' => "The partial ':name' is not found.", + 'invalid_name' => 'Invalid partial name: :name.', + 'menu_label' => 'Partials', + 'unsaved_label' => 'Unsaved partial(s)', + 'no_list_records' => 'No partials found', + 'delete_confirm_multiple' => 'Delete selected partials?', + 'delete_confirm_single' => 'Delete this partial?', + 'new' => 'New partial' + ], + 'content' => [ + 'not_found_name' => "The content file ':name' is not found.", + 'menu_label' => 'Content', + 'unsaved_label' => 'Unsaved content', + 'no_list_records' => 'No content files found', + 'delete_confirm_multiple' => 'Delete selected content files or directories?', + 'delete_confirm_single' => 'Delete this content file?', + 'new' => 'New content file' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Invalid AJAX handler name: :name.', + 'not_found' => "AJAX handler ':name' was not found." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Add', + 'search' => 'Search...' + ], + 'editor' => [ + 'settings' => 'Settings', + 'title' => 'Title', + 'new_title' => 'New page title', + 'url' => 'URL', + 'filename' => 'File Name', + 'layout' => 'Layout', + 'description' => 'Description', + 'preview' => 'Preview', + 'meta' => 'Meta', + 'meta_title' => 'Meta Title', + 'meta_description' => 'Meta Description', + 'markup' => 'Markup', + 'code' => 'Code', + 'content' => 'Content', + 'hidden' => 'Hidden', + 'hidden_comment' => 'Hidden pages are accessible only by logged-in back-end users.', + 'enter_fullscreen' => 'Enter fullscreen mode', + 'exit_fullscreen' => 'Exit fullscreen mode', + 'open_searchbox' => 'Open Search box', + 'close_searchbox' => 'Close Search box', + 'open_replacebox' => 'Open Replace box', + 'close_replacebox' => 'Close Replace box' + ], + 'asset' => [ + 'menu_label' => 'Assets', + 'unsaved_label' => 'Unsaved asset(s)', + 'drop_down_add_title' => 'Add...', + 'drop_down_operation_title' => 'Action...', + 'upload_files' => 'Upload file(s)', + 'create_file' => 'Create file', + 'create_directory' => 'Create directory', + 'directory_popup_title' => 'New directory', + 'directory_name' => 'Directory name', + 'rename' => 'Rename', + 'delete' => 'Delete', + 'move' => 'Move', + 'select' => 'Select', + 'new' => 'New file', + 'rename_popup_title' => 'Rename', + 'rename_new_name' => 'New name', + 'invalid_path' => 'Path can contain only digits, Latin letters, spaces and the following symbols: ._-/', + 'error_deleting_file' => 'Error deleting file :name.', + 'error_deleting_dir_not_empty' => 'Error deleting directory :name. The directory is not empty.', + 'error_deleting_dir' => 'Error deleting directory :name.', + 'invalid_name' => 'Name can contain only digits, Latin letters, spaces and the following symbols: ._-', + 'original_not_found' => 'Original file or directory not found', + 'already_exists' => 'File or directory with this name already exists', + 'error_renaming' => 'Error renaming the file or directory', + 'name_cant_be_empty' => 'The name cannot be empty', + 'too_large' => 'The uploaded file is too large. The maximum allowed file size is :max_size', + 'type_not_allowed' => 'Only the following file types are allowed: :allowed_types', + 'file_not_valid' => 'File is not valid', + 'error_uploading_file' => "Error uploading file ':name': :error", + 'move_please_select' => 'please select', + 'move_destination' => 'Destination directory', + 'move_popup_title' => 'Move assets', + 'move_button' => 'Move', + 'selected_files_not_found' => 'Selected files not found', + 'select_destination_dir' => 'Please select a destination directory', + 'destination_not_found' => 'Destination directory is not found', + 'error_moving_file' => 'Error moving file :file', + 'error_moving_directory' => 'Error moving directory :dir', + 'error_deleting_directory' => 'Error deleting the original directory :dir', + 'no_list_records' => 'No files found', + 'delete_confirm' => 'Delete selected files or directories?', + 'path' => 'Path' + ], + 'component' => [ + 'menu_label' => 'Components', + 'unnamed' => 'Unnamed', + 'no_description' => 'No description provided', + 'alias' => 'Alias', + 'alias_description' => 'A unique name given to this component when using it in the page or layout code.', + 'validation_message' => 'Component aliases are required and can contain only Latin symbols, digits, and underscores. The aliases should start with a Latin symbol.', + 'invalid_request' => 'The template cannot be saved because of invalid component data.', + 'no_records' => 'No components found', + 'not_found' => "The component ':name' is not found.", + 'method_not_found' => "The component ':name' does not contain a method ':method'." + ], + 'template' => [ + 'invalid_type' => 'Unknown template type.', + 'not_found' => 'Template not found.', + 'saved' => 'Template saved.', + 'no_list_records' => 'No records found', + 'delete_confirm' => 'Delete selected templates?', + 'order_by' => 'Order by' + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Halda kodulehe sisufaile', + 'manage_assets' => 'Manage website assets - images, JavaScript files, CSS files', + 'manage_pages' => 'Loo, muuda ja kustuta kodulehe lehti', + 'manage_layouts' => 'Create, modify and delete CMS layouts', + 'manage_partials' => 'Create, modify and delete CMS partials', + 'manage_themes' => 'Activate, deactivate and configure CMS themes', + ], + 'theme_log' => [ + 'hint' => 'This log displays any changes made to the theme by administrators in the back-end area.', + 'menu_label' => 'Theme log', + 'menu_description' => 'View changes made to the active theme.', + 'empty_link' => 'Empty theme log', + 'empty_loading' => 'Emptying theme log...', + 'empty_success' => 'Theme log emptied', + 'return_link' => 'Return to theme log', + 'id' => 'ID', + 'id_label' => 'Log ID', + 'created_at' => 'Date & Time', + 'user' => 'User', + 'type' => 'Type', + 'type_create' => 'Create', + 'type_update' => 'Update', + 'type_delete' => 'Delete', + 'theme_name' => 'Theme', + 'theme_code' => 'Theme code', + 'old_template' => 'Template (Old)', + 'new_template' => 'Template (New)', + 'template' => 'Template', + 'diff' => 'Changes', + 'old_value' => 'Old value', + 'new_value' => 'New value', + 'preview_title' => 'Template changes', + 'template_updated' => 'Template was updated', + 'template_created' => 'Template was created', + 'template_deleted' => 'Template was deleted', + ], +]; diff --git a/modules/cms/lang/fa/lang.php b/modules/cms/lang/fa/lang.php new file mode 100644 index 0000000..c9d4733 --- /dev/null +++ b/modules/cms/lang/fa/lang.php @@ -0,0 +1,293 @@ + [ + 'invalid_file' => 'نام :name برای فایل نام معتبر است. نام فایل میتواند شامل کاراکتر انگلیسی ، خط تیره و نقطه باشد. بعنوان مثال page.htm، page و subdirectory/page', + 'invalid_property' => 'عدم توانایی در تغییر خاصیت ":name"', + 'file_already_exists' => 'فایلی با نام ":name" موجود است.', + 'error_saving' => 'خطا در ذخیره فایل ":name". لطفا سطح دسترسی ها را بررسی نمایید.', + 'error_creating_directory' => 'خطا در ایجاد پوشه ی :name. لطفا سطح دسترسی ها را بررسی نمایید.', + 'invalid_file_extension'=>'پسوند :invalid برای فایل نا معتبر است. پسوند های معتبر عبارتند از: :allowed.', + 'error_deleting' => 'خطا در خذف فایل ":name". لطفا سطح دسترسی ها را بررسی نمایید.', + 'delete_success' => 'تعداد :count فایل با موفقیت حذف شد.', + 'file_name_required' => 'نام فایل را وارد نمایید.', + 'safe_mode_enabled' => 'حالت محافظت شده فعال می باشد.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'وب سایت', + 'online' => 'online', + 'maintenance' => 'در حال به روز رسانی', + 'manage_themes' => 'مدیریت قالب ها', + 'customize_theme' => 'سفارشی سازی قالب' + ] + ], + 'theme' => [ + 'not_found_name' => "یافتن قالبی با نام ':name یافت نشد.'", + 'by_author' => 'توسط :name', + 'active' => [ + 'not_set' => "قالب فعال انتخاب نشده است.", + 'not_found' => "قالب فعال یافت نشد", + ], + 'edit' => [ + 'not_set' => "قالب ویرایش مشخص نشده است.", + 'not_found' => "قالب ویرایش یافت نشد.", + 'not_match' => "شی مورد نظر شما در قالبی که ویرایش می کنید یافت نشد. لطفا صفحه را مجددا بارگذاری نمایید." + ], + 'settings_menu' => 'قالب نمایشی', + 'settings_menu_description' => 'پیش نمایش قالب های موجود و انتخاب قالب فعال.', + 'default_tab' => 'خصوصیات', + 'name_label' => 'نام', + 'name_create_placeholder' => 'نام قالب جدید', + 'author_label' => 'تهیه کننده', + 'author_placeholder' => 'نام شخص یا شرکت', + 'description_label' => 'توضیحات', + 'description_placeholder' => 'توضیحات قالب', + 'homepage_label' => 'آدرس سایت', + 'homepage_placeholder' => 'آدرس سایت مربوط به قالب', + 'code_label' => 'کد', + 'code_placeholder' => 'کد یکتای قالبی که میخواهید ایجاد نمایید', + 'preview_image_label' => 'پیش نمایش تصویر', + 'preview_image_placeholder' => 'آدرس تصویر پیش نمایش قالب.', + 'dir_name_label' => 'نام پوشه', + 'dir_name_create_label' => 'نام پوشه قالب در دست تهیه', + 'theme_label' => 'قالب', + 'theme_title' => 'قالب ها', + 'activate_button' => 'فعال کردن', + 'active_button' => 'فعال', + 'customize_theme' => 'شخصی سازی قالب', + 'customize_button' => 'شخصی سازی', + 'duplicate_button' => 'ایجاد کپی', + 'duplicate_title' => 'ایجاد یک کپی از قالب', + 'duplicate_theme_success' => 'عملیات ایجاد کپی از قالب با موفقیت انجام شد.', + 'manage_button' => 'مدیریت', + 'manage_title' => 'مدیریت قالب', + 'edit_properties_title' => 'قالب', + 'edit_properties_button' => 'ویرایش مشخصه ها', + 'save_properties' => 'ذخیره مشخصه ها', + 'import_button' => 'وارد کردن', + 'import_title' => 'وارد کردن قالب', + 'import_theme_success' => 'عملیات وارد کردن قالب با موفقیت انجام شد', + 'import_uploaded_file' => 'فایل قالب', + 'import_overwrite_label' => 'جایگزینی فایلها در صورت موجود بودن آنها', + 'import_overwrite_comment' => 'اگر میخواهید فقط فایل های جدید وارد شوند این گزینه را غیر فعال کنید.', + 'import_folders_label' => 'پوشه ها', + 'import_folders_comment' => 'لطفا پوشه قالب هایی را که میخواهید وارد کنید را انتخاب نمایید', + 'export_button' => 'صادر کردن', + 'export_title' => 'صادر کردن قالب', + 'export_folders_label' => 'پوشه ها', + 'export_folders_comment' => 'لطفا پوشه هایی را که میخواهید از قالب صادر کنید را انتخاب نمایید', + 'delete_button' => 'حذف', + 'delete_confirm' => 'آیا از حذف این قالب اطمینان دارید؟ ان کار غیر قابل بازگشت می باشد.', + 'delete_active_theme_failed' => 'شما نمیتوانید قالب فعال را حذف کنید. جهت حذف آن یک قالب دیگر را فعال کنید.', + 'delete_theme_success' => 'حذف قالب موفقیت آمیز بود', + 'create_title' => 'ایجاد قالب', + 'create_button' => 'ایجاد', + 'create_new_blank_theme' => 'ایجاد یک قالب جدید خالی', + 'create_theme_success' => 'قالب با موفقیت ایجاد شد.', + 'create_theme_required_name' => 'لطفا نام قالب را وارد نمایید.', + 'new_directory_name_label' => 'پوشه قالب', + 'new_directory_name_comment' => 'نام پوشه قالب جدید را جهت کپی کردن وارد نمایید.', + 'dir_name_invalid' => 'نام میتواند شامل اعداد ، حروف انگلیسی و این کاراکتر ها باشد: _-', + 'dir_name_taken' => 'نام پوشه وارد شده موجود است.', + 'find_more_themes' => 'نصب قالب های جدید', + 'saving' => 'درحال ذخیره سازی قالب', + 'return' => 'بازگشت به صفحه لیست قالب ها', + ], + 'maintenance' => [ + 'settings_menu' => 'حالت تعمیرات', + 'settings_menu_description' => 'تنظیم کردن صفحه مربوط به تعمیرات و تغییر تنظیمات این حالت.', + 'is_enabled' => 'فعال سازی حالت تعمیرات', + 'is_enabled_comment' => 'اگر فعال شود کاربران به این صفحه هدایت خواهند شد.', + 'hint' => 'حالت تعمیرات کاربرانی را که در بخش مدیریت وارد نشده اند را به صفحه تعمیرات منتقل می کند.', + ], + 'page' => [ + 'not_found_name' => "صفحه ای با نام ':name' یافت نشد", + 'not_found' => [ + 'label' => "صفحه مورد نظر یافت نشد", + 'help' => 'متاسفانه صفحه ای که شما درخواست کرده اید یافت نشد', + ], + 'custom_error' => [ + 'label' => "خطای صفحه", + 'help' => "متاسفانه مشکلی در نمایش صفحه مورد نظر به وجود آمده است.", + ], + 'menu_label' => 'صفحات', + 'unsaved_label' => 'صفحه(های) ذخیره نشده', + 'no_list_records' => 'صفحه ای یافت نشد', + 'new' => 'صفحه جدید', + 'invalid_url' => 'قالب آدرس صحیح نمی باشد. آدرس باید با اسلش شروع شده و می تواند شامل اعداد، حروف لاتین و این کاراکتر ها باشد: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'آیا از حذف صفحات انتخاب شده اطمینان دارید؟', + 'delete_confirm_single' => 'آیا از حذف این صفحه اطمینان دارید؟', + 'no_layout' => '-- بدون طرح بندی --', + 'cms_page' => 'صفحات مدیریت محتوی', + 'title' => 'عنوان صفحه', + 'url' => 'آدرس صفحه', + 'file_name' => 'نام فایل' + ], + 'layout' => [ + 'not_found_name' => "طرح بندی ی ':name' یافت نشد", + 'menu_label' => 'طرح بندی ها', + 'unsaved_label' => 'طرح بندی(های) ذخیره نشده', + 'no_list_records' => 'طرح بندی یافت نشد', + 'new' => 'طرح بندی جدید', + 'delete_confirm_multiple' => 'آیا از حذف طرح بندی های انتخاب شده اطمینان دارید؟', + 'delete_confirm_single' => 'آیا از حذف این طرح بندی اطمینان دارید؟' + ], + 'partial' => [ + 'not_found_name' => "بخشی با نام ':name' یافت نشد.", + 'invalid_name' => "نام بخش نا معتبر است: :name.", + 'menu_label' => 'بخش ها', + 'unsaved_label' => 'بخش(های) ذخیره نشده', + 'no_list_records' => 'بخشی وجود ندارد', + 'delete_confirm_multiple' => 'آیا از حذف بخش های انتخاب شده اطمینان دارید؟', + 'delete_confirm_single' => 'آیا از حذف این بخش بندی اطمینان دارید؟', + 'new' => 'بخش بندی جدید' + ], + 'content' => [ + 'not_found_name' => "فایل محتوای ':name' یافت نشد.", + 'menu_label' => 'محتوا', + 'unsaved_label' => 'محتوای ذخیره نشده', + 'no_list_records' => 'هیچ فایل محتوایی وجود ندارد', + 'delete_confirm_multiple' => 'آیا از حذف فایل ها و یا پوشه های انتخاب شده اطمینان دارید؟', + 'delete_confirm_single' => 'آیا از حذف این فایل اطمینان دارید؟', + 'new' => 'فایل محتوی جدید' + ], + 'ajax_handler' => [ + 'invalid_name' => "نام کنترل کننده آژاکس نا معتبر است: :name.", + 'not_found' => "کنترل کننده آژاکس ':name' یافت نشد.", + ], + 'cms' => [ + 'menu_label' => "مدیریت محتوی" + ], + 'sidebar' => [ + 'add' => 'افزودن', + 'search' => 'جستجو...' + ], + 'editor' => [ + 'settings' => 'تنظیمات', + 'title' => 'عنوان', + 'new_title' => 'عنوان صفحه جدید', + 'url' => 'آدرس', + 'filename' => 'نام فایل', + 'layout' => 'طرح بندی', + 'description' => 'توضیحات', + 'preview' => 'پیش نمایش', + 'meta' => 'متا', + 'meta_title' => 'عنوان متا', + 'meta_description' => 'توضیحات متا', + 'markup' => 'نشانه گذاری', + 'code' => 'کد', + 'content' => 'محتوی', + 'hidden' => 'مخفی', + 'hidden_comment' => 'صفحات مخفی فقط برای کاربران وارد شده به سیستم نمایش داده می شود.', + 'enter_fullscreen' => 'حالت تمام صفحه', + 'exit_fullscreen' => 'خروج از حالت تمام صفحه', + 'open_searchbox' => 'نمایش جستجو', + 'close_searchbox' => 'بستن جستجو', + 'open_replacebox' => 'نمایش جایگزینی', + 'close_replacebox' => 'بستن جایگزینی' + ], + 'asset' => [ + 'menu_label' => "فایلها", + 'unsaved_label' => 'فایل(های) ذخیره نشده', + 'drop_down_add_title' => 'افزودن...', + 'drop_down_operation_title' => 'عملیات...', + 'upload_files' => 'افزودن فایل(ها)', + 'create_file' => 'ایجاد فایل', + 'create_directory' => 'ایجاد پوشه', + 'directory_popup_title' => 'پوشه ی جدید', + 'directory_name' => 'نام پوشه', + 'rename' => 'تغییر نام', + 'delete' => 'حذف', + 'move' => 'جابحایی', + 'select' => 'انتخاب', + 'new' => 'فایل جدید', + 'rename_popup_title' => 'تغییر نام', + 'rename_new_name' => 'نام جدید', + 'invalid_path' => 'مسیر می تواند فقط شامل اعداد، حروف لاتین، حط فاصله و این کاراکتر ها باشد: ._-/', + 'error_deleting_file' => 'در حذف فایل :name مشکلی به وجود آمده است.', + 'error_deleting_dir_not_empty' => 'در حذف پوشه ی :name مشکلی به وجود آمده است. پوشه خالی نیست.', + 'error_deleting_dir' => 'خطایی در حذف :name به وجود آمده است.', + 'invalid_name' => 'نام میتوامد شامل اعداد، خروف لاتین، خط فاصله و این کاراکتر ها باشد: ._-', + 'original_not_found' => 'فایل یا پوشه ی اصلی یافت نشد.', + 'already_exists' => 'فایل یا پوشه ای با این نام وجود دارد.', + 'error_renaming' => 'در تغییر نام فایل یا پوشه مورد نظر خطایی رخ داده است', + 'name_cant_be_empty' => 'نام نمی تواند خالی باشد', + 'too_large' => 'فایل ارسال شده بیش از حد مجاز است. بیشترین حجم مورد قبول :max_size می باشد', + 'type_not_allowed' => 'فقط این نوع فایل ها قابل قبول می باشد: :allowed_types', + 'file_not_valid' => 'فایل نامعتبر است', + 'error_uploading_file' => 'خطا در ارسال فال ":name": :error', + 'move_please_select' => 'لطفا انتخاب نمایید', + 'move_destination' => 'پوشه مورد نظر', + 'move_popup_title' => 'جابجایی فایل', + 'move_button' => 'جابجایی', + 'selected_files_not_found' => 'فایل انتخاب شده یافت نشد', + 'select_destination_dir' => 'لطفا پوشه ی مورد نظر را انتخاب نمایید', + 'destination_not_found' => 'پوشه مورد نظر یافت نشد', + 'error_moving_file' => 'خطایی در جابجایی :file رخ داده است', + 'error_moving_directory' => 'خطایی در جابجایی :dir رخ داده است', + 'error_deleting_directory' => 'خطایی در حذف :dir رخ داده است', + 'no_list_records' => 'فایلی وجود ندارد', + 'delete_confirm' => 'آیا از حذف فایل ها یا پوشه های انتخاب شده اطمینان دارید؟', + 'path' => 'محل قرار گیری' + ], + 'component' => [ + 'menu_label' => "ابزارها", + 'unnamed' => "بدون نام", + 'no_description' => "توصیحات وجود ندارد", + 'alias' => "نام مستعار", + 'alias_description' => "نام یکتایی که به این ابزار داده می شود تا درون صفحات و طرح بندی ها به این ابزار اشاره کند.", + 'validation_message' => "نام مستعار برای ابزار مورد نیاز بوده و می تواند شامل حروف لاتین، اعداد، و خط زیر باشد و باید با حرف لاتین شروع شود.", + 'invalid_request' => "بدلیل داده ی نا معتبر ابزار امکان ذخیره قالب وجود ندارد.", + 'no_records' => 'ابزاری یافت نشد', + 'not_found' => "ابزار ':name' یافت نشد.", + 'method_not_found' => "ابزار ':name' شامل متدی با نام ':method' نمی باشد.", + ], + 'template' => [ + 'invalid_type' => "نوع قالب معتبر نمی باشد.", + 'not_found' => "قالب درخواست شده یافت نشد.", + 'saved'=> "قالب با موفقیت ذخیره شد.", + 'no_list_records' => 'موردی یافت نشد', + 'delete_confirm' => 'آیا از حذف قالب های انتخاب شده اطمینان دارید؟', + 'order_by' => 'مرتب سازی با' + ], + 'permissions' => [ + 'name' => 'مدیریت محتوی', + 'manage_content' => 'مدیریت محتوی', + 'manage_assets' => 'مدیریت فایلها', + 'manage_pages' => 'مدیریت صفحات', + 'manage_layouts' => 'مدیریت طرح بندی ها', + 'manage_partials' => 'مدیریت بخش ها', + 'manage_themes' => 'مدیریت قالب ها', + 'manage_theme_options' => 'تنظیمات گزینه های شخصی سازی برای قالب فعلی', + ], + 'theme_log' => [ + 'hint' => 'این بخش تمام تغییراتی که توسط مدیریت بر روی قالب انجام شده است را به نمایش در می آورد.', + 'menu_label' => 'وقایع قالب', + 'menu_description' => 'نمایش تغییرات انجام شده بر روی قالب فعلی', + 'empty_link' => 'پاک سازی همه وقایع', + 'empty_loading' => 'در حال پاک سازی وقایع قالب...', + 'empty_success' => 'وقایع قالب پاک شدند', + 'return_link' => 'بازگشت به وقایع قالب', + 'id' => 'شناسه', + 'id_label' => 'شناسه واقعه', + 'created_at' => 'تاریخ و زمان', + 'user' => 'کاربر', + 'type' => 'نوع', + 'type_create' => 'ایجاد', + 'type_update' => 'به روز رسانی', + 'type_delete' => 'حذف', + 'theme_name' => 'قالب', + 'theme_code' => 'کد قالب', + 'old_template' => 'قالب (قدیمی)', + 'new_template' => 'قالب (جدید)', + 'template' => 'قالب', + 'diff' => 'تغییرات', + 'old_value' => 'مقدار قبلی', + 'new_value' => 'مقدار جدید', + 'preview_title' => 'تغییرات قالب', + 'template_updated' => 'قالب به روزرسانی شد', + 'template_created' => 'قالب جدید ایجاد شد', + 'template_deleted' => 'قالب جذف شد', + ], +]; diff --git a/modules/cms/lang/fi/lang.php b/modules/cms/lang/fi/lang.php new file mode 100644 index 0000000..756b438 --- /dev/null +++ b/modules/cms/lang/fi/lang.php @@ -0,0 +1,293 @@ + [ + 'invalid_file' => 'Virheellinen tiedostonimi: :name. nimessä voi olla vain kiraimia, numeroita, alaviiva, viiva ja pisteitä. Esimerkkejä tiedotonimistä: page.htm, page, subdirectory/page', + 'invalid_property' => "Ominaisuutta ':name' ei voida asettaa", + 'file_already_exists' => "Tiedosto ':name' on jo olemassa.", + 'error_saving' => "Virhe tallennettaessa tiedostoa ':name'. Tarkista kirjoitusoikeudet.", + 'error_creating_directory' => 'Virhe luotaessa kansiota :name. Tarkista kirjoitusoikeudet.', + 'invalid_file_extension' => 'Virheellinen tiedostopääte: :invalid. Sallitut päätteet ovat: :allowed.', + 'error_deleting' => "Virhe poistaessa teemaa ':name'. Tarkista kirjoitusoikeudet.", + 'delete_success' => 'Poistetut teemat: :count.', + 'file_name_required' => 'Tiedoston nimi -kenttä on vaadittu.', + 'safe_mode_enabled' => 'Turvatila on käytössä.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Verkkosivusto', + 'online' => 'Online', + 'maintenance' => 'Ylläpitotila', + 'manage_themes' => 'Hallitse teemoja', + 'customize_theme' => 'Kustomoi teema' + ] + ], + 'theme' => [ + 'not_found_name' => "Teemaa ':name' ei löydy.", + 'by_author' => 'Tekijä: :name', + 'active' => [ + 'not_set' => 'Aktiivista teemaa ei ole asetettu.', + 'not_found' => 'Aktiivista teemaa ei löytynyt.' + ], + 'edit' => [ + 'not_set' => 'Muokattavaa teemaa ei ole asetettu.', + 'not_found' => 'Muokattavaa teemaa ei löydy.', + 'not_match' => 'Objektia, jota yrität muokata, ei kuulu muokattavaan teemaan. Päivitä sivu uudelleen.' + ], + 'settings_menu' => 'Sivuston teema', + 'settings_menu_description' => 'Esikatsele luettelo asennetuista teemoista ja valitse aktiivinen teema.', + 'default_tab' => 'Ominaisuudet', + 'name_label' => 'Nimi', + 'name_create_placeholder' => 'Uuden teeman nimi', + 'author_label' => 'Julkaisija', + 'author_placeholder' => 'Henkilön tai yrityksen nimi', + 'description_label' => 'Kuvaus', + 'description_placeholder' => 'Teeman kuvaus', + 'homepage_label' => 'Kotisivu', + 'homepage_placeholder' => 'Verkkosivuston URL-osoite', + 'code_label' => 'Koodi', + 'code_placeholder' => 'Uniikki koodi teeman jakeluun', + 'preview_image_label' => 'Esikatselukuva', + 'preview_image_placeholder' => 'Polku teeman esikatselukuvaan.', + 'dir_name_label' => 'Hakemiston nimi', + 'dir_name_create_label' => 'Teeman kohdehakemisto', + 'theme_label' => 'Teema', + 'theme_title' => 'Teemat', + 'activate_button' => 'Aktivoi', + 'active_button' => 'Aktivoi', + 'customize_theme' => 'Kustomoi teema', + 'customize_button' => 'Kustomoi', + 'duplicate_button' => 'Monista', + 'duplicate_title' => 'Monista teema', + 'duplicate_theme_success' => 'Teema monistettu!', + 'manage_button' => 'Hallinnoi', + 'manage_title' => 'Hallinnoi teemaa', + 'edit_properties_title' => 'Teemaa', + 'edit_properties_button' => 'Muokkaa ominaisuuksia', + 'save_properties' => 'Tallenna ominaisuudet', + 'import_button' => 'Tuonti', + 'import_title' => 'Tuo teema', + 'import_theme_success' => 'Teema tuotu!', + 'import_uploaded_file' => 'Teemaarkistotiedosto', + 'import_overwrite_label' => 'Ylikirjoita olemassaolevat tiedostot', + 'import_overwrite_comment' => 'Poistä tämä käytöstä tuodaksesi vain uudet tiedostot', + 'import_folders_label' => 'Kansiot', + 'import_folders_comment' => 'Valitse teeman kansiot, jotka haluat tuoda.', + 'export_button' => 'Vie', + 'export_title' => 'Vie teema', + 'export_folders_label' => 'Kansiot', + 'export_folders_comment' => 'Valitse teeman kansiot, jotka haluat viedä', + 'delete_button' => 'Poista', + 'delete_confirm' => 'Positetaanko tämä teema? Toimintoa ei voi perua!', + 'delete_active_theme_failed' => 'Aktiivista teemaa ei voida poistaa. Ota ensin toinen teema käyttöön', + 'delete_theme_success' => 'Teema poistettu!', + 'create_title' => 'Luo teema', + 'create_button' => 'Luo', + 'create_new_blank_theme' => 'Luo uusi tyhjä teema', + 'create_theme_success' => 'Teema luotu!', + 'create_theme_required_name' => 'Anna teemalle nimi.', + 'new_directory_name_label' => 'Teemakansio', + 'new_directory_name_comment' => 'Anna uusi hakemisto monistetulle teemalle.', + 'dir_name_invalid' => 'Nimi voi sisältää ainoastaan numeroja, latinalaisia kirjaimia sekä seuraavia merkkejä: _-', + 'dir_name_taken' => 'Haluttu teemakansio on jo olemassa.', + 'find_more_themes' => 'Etsi lisää teemoja', + 'saving' => 'Tallennetaan teemaa...', + 'return' => 'Palaa teemalistaan' + ], + 'maintenance' => [ + 'settings_menu' => 'Ylläpitotila', + 'settings_menu_description' => 'Muokkaa huoltotilan sivua ja valitse asetus.', + 'is_enabled' => 'Ota huoltotila käyttöön', + 'is_enabled_comment' => 'Valitse sivu näytettäväksi kun huoltotila on käytössä.', + 'hint' => 'Huoltotila näyttää huoltosivun vierailijoille, jotka eivät ole kirjautuneena hallintapaneeliin.' + ], + 'page' => [ + 'not_found_name' => "Sivua ':name' ei löytynyt", + 'not_found' => [ + 'label' => 'Sivua ei löytynyt', + 'help' => 'Haettua sivua ei löydy.' + ], + 'custom_error' => [ + 'label' => 'Sivuvirhe', + 'help' => "Olemme pahoillamme, mutta joku meni vikaan ja sivua ei voida näyttää." + ], + 'menu_label' => 'Sivut', + 'unsaved_label' => 'Tallenntamattomat sivu(t)', + 'no_list_records' => 'Yhtään sivua ei löytynyt', + 'new' => 'Uusi sivu', + 'invalid_url' => 'Virheellinen URL-muoto. URL täytyy alkaa kauttamerkillä ja saa sisältää ainoastaan numeroita, latinalaisia kirjaimia sekä seuraavia merkkejä: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Poista valitut sivut?', + 'delete_confirm_single' => 'Posita tämä sivu?', + 'no_layout' => '-- ei ulkoasua --', + 'cms_page' => 'CMS-sivu', + 'title' => 'Sivun nimi', + 'url' => 'Sivun URL-osoite', + 'file_name' => 'Sivun tiedostonimi' + ], + 'layout' => [ + 'not_found_name' => "Ulkoasua ':name' ei löytynyt", + 'menu_label' => 'Ulkoasut', + 'unsaved_label' => 'Tallentamattomat ulkoasu(t)', + 'no_list_records' => 'Ei ulkoasuja', + 'new' => 'Uusi ulkoasu', + 'delete_confirm_multiple' => 'Poista valitut ulkoasut?', + 'delete_confirm_single' => 'Poista tämä ulkoasu?' + ], + 'partial' => [ + 'not_found_name' => "Osiota ':name' ei löydy.", + 'invalid_name' => 'Osion nimi: :name ei ole kelvollinen.', + 'menu_label' => 'Osiot', + 'unsaved_label' => 'Tallentamaton osio(t)', + 'no_list_records' => 'Osioita ei löydy', + 'delete_confirm_multiple' => 'Poista valitut osiot?', + 'delete_confirm_single' => 'Poista tämä osio?', + 'new' => 'Uusio osio' + ], + 'content' => [ + 'not_found_name' => "Sisältötiedostoa ':name' ei löydy.", + 'menu_label' => 'Sisältö', + 'unsaved_label' => 'Tallentamaton sisältö', + 'no_list_records' => 'Sisältötiedostoja ei löydy', + 'delete_confirm_multiple' => 'Poista valitut sisältötiedostot tai hakemistot?', + 'delete_confirm_single' => 'Poista tämä sisältötiedosto?', + 'new' => 'Uusi sisältötiedosto' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Ajax käsittelijän nimi: :name ei ole kelvollinen.', + 'not_found' => "AJAX käsittelijää ':name' ei löydy." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Lisää', + 'search' => 'Etsi...' + ], + 'editor' => [ + 'settings' => 'Asetukset', + 'title' => 'Nimi', + 'new_title' => 'Uusi sivun nimi', + 'url' => 'URL', + 'filename' => 'Tiedostonimi', + 'layout' => 'Ulkoasu', + 'description' => 'Kuvaus', + 'preview' => 'Esikatselu', + 'meta' => 'Meta', + 'meta_title' => 'Meta-otsikko', + 'meta_description' => 'Meta-kuvaus', + 'markup' => 'Markup-kieli', + 'code' => 'Koodi', + 'content' => 'Sisältö', + 'hidden' => 'Piilotettu', + 'hidden_comment' => 'Piilotetut sivut ovat saatavilla ainoastaan hallintapaneeliin kirjautuneille käyttäjille.', + 'enter_fullscreen' => 'Siirry kokoruudun tilaan', + 'exit_fullscreen' => 'Poistu kokoruudun tilasta', + 'open_searchbox' => 'Avaa haku', + 'close_searchbox' => 'Sulje haku', + 'open_replacebox' => 'Avaa korvaa', + 'close_replacebox' => 'Sulje korvaa' + ], + 'asset' => [ + 'menu_label' => 'Aineistot', + 'unsaved_label' => 'Tallentamattomia aineistoja', + 'drop_down_add_title' => 'Lisää...', + 'drop_down_operation_title' => 'Toiminto...', + 'upload_files' => 'Siirrä tiedoto(ja)', + 'create_file' => 'Luo tiedosto', + 'create_directory' => 'Luo kansio', + 'directory_popup_title' => 'Uusi kansio', + 'directory_name' => 'Kansion nimi', + 'rename' => 'Nimeä uudelleen', + 'delete' => 'Poista', + 'move' => 'Siirrä', + 'select' => 'Valitse', + 'new' => 'Uusi tiedosto', + 'rename_popup_title' => 'Nimeä uudelleen', + 'rename_new_name' => 'Uusi nimi', + 'invalid_path' => 'Polku voi sisältää ainoastaan numeroita, latinalaisia kirjaimia, välilyöntejä sekä seuraavia merkkejä: ._-/', + 'error_deleting_file' => 'Virhe poistettaessa tiedostoa :name.', + 'error_deleting_dir_not_empty' => 'Virhe poistaessa hakemistoa :name. Hakemisto ei ole tyhjä.', + 'error_deleting_dir' => 'Virhe poistaessa hakemistoa :name.', + 'invalid_name' => 'Nimessä voi olla vain numeroita, kirjaimia, välilyöntejä ja seuraavia merkkejä: ._-', + 'original_not_found' => 'Alkuperäistä tiedostoa tai hakemistoa ei löydy', + 'already_exists' => 'Tiedosto tai hakemisto tällä nimillä on jo olemassa', + 'error_renaming' => 'Virhe tiedoston tai hakemiston uudelleennimeämisessä', + 'name_cant_be_empty' => 'Nimi on pakollinen', + 'too_large' => 'Tiedosto on liian iso. Suurin sallittu koko on :max_size', + 'type_not_allowed' => 'Vain seuraavat tiedostotyypit ovat sallittuja: :allowed_types', + 'file_not_valid' => 'Tiedosto ei kelpaa', + 'error_uploading_file' => "Virhe siirrettäessä tiedostoa ':name': :error", + 'move_please_select' => 'ole hyvä ja valitse', + 'move_destination' => 'Kohdekansio', + 'move_popup_title' => 'Siirrä aineistoja', + 'move_button' => 'Siirrä', + 'selected_files_not_found' => 'Valittuja tiedostoja ei löydy', + 'select_destination_dir' => 'Valitse kohdehakemisto', + 'destination_not_found' => 'Kohdehakemistoa ei löydy', + 'error_moving_file' => 'Virhe siirtäessä tiedostoa :file', + 'error_moving_directory' => 'Virhe siirrettäessä kansiota :dir', + 'error_deleting_directory' => 'Virhe poistettaessa alkuperäinen kansio :dir', + 'no_list_records' => 'Tiedostoja ei löytynyt', + 'delete_confirm' => 'Poista valitut tiedostot ja/tai kansiot?', + 'path' => 'Polku' + ], + 'component' => [ + 'menu_label' => 'Komponentit', + 'unnamed' => 'Nimeämätön', + 'no_description' => 'Ei annettua kuvausta', + 'alias' => 'Alias', + 'alias_description' => 'Uniikki nimi komponentille kun käytössä sivulla tai ulkoasun koodissa.', + 'validation_message' => 'Komponentin alias on vaadittu ja se voi sisältää ainoastaan latinalaisia kirjaimia, numeroita ja alaviivoja. Aliaksien pitäisi alkaa latinalaisella kirjaisimella.', + 'invalid_request' => 'Mallia ei voida tallentaa koska komponentin tiedot eivät ole kelvollisia.', + 'no_records' => 'Komponentteja ei löytynyt', + 'not_found' => "Komponenttia ':name' ei löydy.", + 'method_not_found' => "Komponentti ':name' ei sisällä metodia ':method'." + ], + 'template' => [ + 'invalid_type' => 'Tuntematon teeman tyyppi.', + 'not_found' => 'Teemaa ei löytynyt.', + 'saved' => 'Teema tallennettu.', + 'no_list_records' => 'Tietueita ei löytynyt', + 'delete_confirm' => 'Poista valitut teemat?', + 'order_by' => 'Järjestä' + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Hallinnoi sivuston sisältötiedostoja', + 'manage_assets' => 'Hallinnoi sivuston assetteja - kuvat, JavaScript-tiedostot, CSS-tiedostot', + 'manage_pages' => 'Luo, muokkaa ja poista sivuston sivuja', + 'manage_layouts' => 'Luo, muokkaa ja poista sivuston ulkoasuja', + 'manage_partials' => 'Luo, muokkaa ja poista CMS-järjestelmän osioita', + 'manage_themes' => 'Ota käyttöön ja poista käytöstä CMS-järjestelmän teemoja', + 'manage_media' => 'Siirrä ja hallinnoi mediatiedostoja - kuvia, videoita, ääniä, dokumentteja' + ], + 'theme_log' => [ + 'hint' => 'Tämä loki näyttää muutokset teemaan järjestelmänvalvojilta hallintapaneelissa.', + 'menu_label' => 'Teemaloki', + 'menu_description' => 'Katso tehdyt muutokset aktiiviseen teemaan.', + 'empty_link' => 'Tyhjennä teemaloki', + 'empty_loading' => 'Tyhjennetään teemaloki...', + 'empty_success' => 'Teemaloki tyhjätty', + 'return_link' => 'Palaa teemalokiin', + 'id' => 'ID', + 'id_label' => 'Loki ID', + 'created_at' => 'Pvm & aika', + 'user' => 'Käyttäjä', + 'type' => 'Tyyppi', + 'type_create' => 'Luo', + 'type_update' => 'Päivitä', + 'type_delete' => 'Poista', + 'theme_name' => 'Teema', + 'theme_code' => 'Teeman koodi', + 'old_template' => 'Teema (vanha)', + 'new_template' => 'Teema (uusi)', + 'template' => 'Teema', + 'diff' => 'Muutokset', + 'old_value' => 'Vanha arvo', + 'new_value' => 'Uusi arvo', + 'preview_title' => 'Teeman muutokset', + 'template_updated' => 'Teema on päivitetty', + 'template_created' => 'Teema on luotu', + 'template_deleted' => 'Teema on poistettu', + ], +]; diff --git a/modules/cms/lang/fr/lang.php b/modules/cms/lang/fr/lang.php new file mode 100644 index 0000000..c22cf06 --- /dev/null +++ b/modules/cms/lang/fr/lang.php @@ -0,0 +1,304 @@ + [ + 'invalid_file' => 'Nom de fichier invalide : :name. Les noms de fichiers ne peuvent contenir que des caractères alphanumériques, des tirets bas, des tirets et des points. Voici des exemples de noms de fichiers valides : page.htm, ma-page, sous_repertoire/nouvelle.page', + 'invalid_property' => 'L’attribut ":name" ne peut pas être défini', + 'file_already_exists' => 'Le fichier ":name" existe déjà.', + 'error_saving' => 'Erreur lors de l’enregistrement du fichier ":name". Veuillez vérifier les permissions en écriture.', + 'error_creating_directory' => 'Erreur lors de la création du répertoire :name. Veuillez vérifier les permissions en écriture.', + 'invalid_file_extension' => 'Extension de fichier invalide : :invalid. Les extensions autorisées sont : :allowed.', + 'error_deleting' => 'Erreur lors de la suppression du modèle ":name". Veuillez vérifier les permissions en écriture.', + 'delete_success' => 'Les modèles ont été supprimés avec succès : :count.', + 'file_name_required' => 'Le nom du fichier est requis.', + 'safe_mode_enabled' => 'Le mode protégé est activé.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Site Web', + 'online' => 'En ligne', + 'maintenance' => 'En cours de maintenance', + 'manage_themes' => 'Gestion des thèmes', + 'customize_theme' => 'Personnaliser le thème', + ] + ], + 'theme' => [ + 'not_found_name' => 'Le thème ":name" n’a pas été trouvé.', + 'by_author' => 'Par :name', + 'active' => [ + 'not_set' => 'Aucun thème n’est activé.', + 'not_found' => 'Le thème activé est introuvable.', + ], + 'edit' => [ + 'not_set' => 'Le thème à modifier n’est pas activé.', + 'not_found' => 'Le thème à modifier est introuvable.', + 'not_match' => 'L’objet auquel vous souhaitez accéder n’appartient pas au thème en cours de modification. Veuillez recharger la page.' + ], + 'settings_menu' => 'Thème frontal', + 'settings_menu_description' => 'Aperçu des thèmes installés et sélection du thème actif.', + 'default_tab' => 'Propriétés', + 'name_label' => 'Nom', + 'name_create_placeholder' => 'Nom du nouveau thème', + 'author_label' => 'Auteur', + 'author_placeholder' => 'Nom de la personne ou de la compagnie', + 'description_label' => 'Description', + 'description_placeholder' => 'Description du thème', + 'homepage_label' => 'Page d’accueil', + 'homepage_placeholder' => 'Adresse URL du site Web', + 'code_label' => 'Code', + 'code_placeholder' => 'Un nom de code unique pour la distribution de ce thème', + 'preview_image_label' => 'Aperçu', + 'preview_image_placeholder' => 'Chemin de l’aperçu.', + 'dir_name_label' => 'Nom du répertoire', + 'dir_name_create_label' => 'Le répertoire de destination du thème', + 'theme_label' => 'Thème', + 'theme_title' => 'Thèmes', + 'activate_button' => 'Activer', + 'active_button' => 'Activer', + 'customize_theme' => 'Personnaliser le thème', + 'customize_button' => 'Personnaliser', + 'duplicate_button' => 'Dupliquer', + 'duplicate_title' => 'Dupliquer le thème', + 'duplicate_theme_success' => 'Duplication réalisée avec succès !', + 'manage_button' => 'Gérer', + 'manage_title' => 'Gérer le thème', + 'edit_properties_title' => 'Thème', + 'edit_properties_button' => 'Modifier les propriétés', + 'save_properties' => 'Enregistrer les propriétés', + 'import_button' => 'Importer', + 'import_title' => 'Importer le thème', + 'import_theme_success' => 'Thème importé avec succès !', + 'import_uploaded_file' => 'Fichier archive du thème', + 'import_overwrite_label' => 'Écraser les fichiers existants', + 'import_overwrite_comment' => 'Décocher cette case pour importer uniquement les nouveaux fichiers', + 'import_folders_label' => 'Répertoires', + 'import_folders_comment' => 'Sélectionner les répertoires du thème à importer', + 'export_button' => 'Exporter', + 'export_title' => 'Exporter le thème', + 'export_folders_label' => 'Répertoire', + 'export_folders_comment' => 'Sélectionner les répertoires du thème à exporter', + 'delete_button' => 'Supprimer', + 'delete_confirm' => 'Confirmer la suppression de ce thème ? Cette action est irréversible !', + 'delete_active_theme_failed' => 'Impossible de supprimer le thème actif, merci d’activer une autre thème au préalable.', + 'delete_theme_success' => 'Thème supprimé avec succès !', + 'create_title' => 'Créer un thème', + 'create_button' => 'Créer', + 'create_new_blank_theme' => 'Créer un nouveau thème vierge', + 'create_theme_success' => 'Thème créé avec succès !', + 'create_theme_required_name' => 'Saisir un nom pour ce thème.', + 'new_directory_name_label' => 'Répertoire du thème', + 'new_directory_name_comment' => 'Indiquer un nouveau nom de répertoire pour le thème en dupliqué.', + 'dir_name_invalid' => 'Le nom doit contenir uniquement des chiffres, des symboles latins et les symboles suivants : _-', + 'dir_name_taken' => 'Le nom du répertoire indiqué existe déjà.', + 'find_more_themes' => 'Trouver davantage de thèmes sur le site du CMS October.', + 'saving' => 'Enregistrement du thème en cours…', + 'return' => 'Retourner à la liste des thèmes', + ], + 'maintenance' => [ + 'settings_menu' => 'Maintenance', + 'settings_menu_description' => 'Configurer la page de maintenance et ajuster ses options.', + 'is_enabled' => 'Activer la maintenance', + 'is_enabled_comment' => 'Si activé, la page choisie ci-dessous sera affichée pour les visiteurs du site Web.', + 'hint' => 'Le mode maintenance affichera la page de maintenance pour les visiteurs qui ne sont pas authentifiés dans l’interface d’administration.' + ], + 'page' => [ + 'not_found_name' => 'La page ":name" est introuvable', + 'not_found' => [ + 'label' => 'La page est introuvable', + 'help' => 'La page demandée est introuvable.', + ], + 'custom_error' => [ + 'label' => 'Erreur sur la page', + 'help' => 'Nous sommes désolés, un problème est survenu et la page ne peut être affichée.', + ], + 'menu_label' => 'Pages', + 'unsaved_label' => 'Page(s) non enregistrée(s)', + 'no_list_records' => 'Aucune page n’a été trouvée', + 'new' => 'Nouvelle page', + 'invalid_url' => 'Format d’adresse URL invalide. L’adresse URL doit commencer par un / et peut contenir des chiffres, des lettres et les symboles suivants : ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Confirmer la suppression des pages sélectionnées ?', + 'delete_confirm_single' => 'Confirmer la suppression de cette page ?', + 'no_layout' => '-- aucune maquette --', + 'cms_page' => 'Page CMS', + 'title' => 'Titre de la page', + 'url' => 'URL de la page', + 'file_name' => 'Nom du fichier de la page' + ], + 'layout' => [ + 'not_found_name' => 'La maquette ":name" est introuvable', + 'menu_label' => 'Maquettes', + 'unsaved_label' => 'Maquette(s) non enregistrée(s)', + 'no_list_records' => 'Aucune maquette n’a été trouvée', + 'new' => 'Nouvelle maquette', + 'delete_confirm_multiple' => 'Confirmer la suppression des maquettes sélectionnées ?', + 'delete_confirm_single' => 'Confirmer la suppression de cette maquette ?' + ], + 'partial' => [ + 'not_found_name' => 'Le modèle partiel ":name" est introuvable.', + 'invalid_name' => 'Nom du modèle partiel invalide : :name.', + 'menu_label' => ' Modèles partiels', + 'unsaved_label' => 'Modèle(s) partiel(s) non enregistré(s)', + 'no_list_records' => 'Aucun modèle partiel n’a été trouvé', + 'delete_confirm_multiple' => 'Confirmer la suppression des modèles partiels sélectionnés ?', + 'delete_confirm_single' => 'Confirmer la suppression de ce modèle partiel ?', + 'new' => 'Nouveau modèle partiel' + ], + 'content' => [ + 'not_found_name' => 'Le fichier de contenu ":name" est introuvable.', + 'menu_label' => 'Contenu', + 'unsaved_label' => 'Contenu non enregistré', + 'no_list_records' => 'Aucun fichier de contenu n’a été trouvé', + 'delete_confirm_multiple' => 'Confirmer la suppression des fichiers de contenu ou répertoires sélectionnés ?', + 'delete_confirm_single' => 'Confirmer la suppression de ce fichier de contenu ?', + 'new' => 'Nouveau fichier de contenu' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Nom du gestionnaire AJAX invalide : :name.', + 'not_found' => 'Le gestionnaire AJAX ":name" est introuvable.', + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Ajouter', + 'search' => 'Rechercher…' + ], + 'editor' => [ + 'settings' => 'Configuration', + 'title' => 'Titre', + 'new_title' => 'Nouveau titre de la page', + 'url' => 'Adresse URL', + 'filename' => 'Nom du fichier', + 'layout' => 'Maquette', + 'description' => 'Description', + 'preview' => 'Aperçu', + 'meta' => 'Meta', + 'meta_title' => 'Meta Titre', + 'meta_description' => 'Meta Description', + 'markup' => 'Balisage', + 'code' => 'Code', + 'content' => 'Contenu', + 'hidden' => 'Caché', + 'hidden_comment' => 'Les pages cachées sont seulement accessibles aux administrateurs connectés.', + 'enter_fullscreen' => 'Activer le mode plein écran', + 'exit_fullscreen' => 'Annuler le mode plein écran', + 'open_searchbox' => 'Ouvrir la boîte de dialogue Rechercher', + 'close_searchbox' => 'Fermer la boîte de dialogue Rechercher', + 'open_replacebox' => 'Ouvrir la boîte de dialogue Remplacer', + 'close_replacebox' => 'Fermer la boîte de dialogue Remplacer', + 'commit' => 'Envoyer', + 'reset' => 'Rétablir', + 'commit_confirm' => 'Êtes-vous sûr de vouloir envoyer vos changements apportés à ce fichier au système de fichier? Cela écrasera le fichier existant sur le système de fichier', + 'reset_confirm' => 'Êtes-vous sûr de vouloir rétablir ce fichier depuis la version présente sur le système de fichier? Cela le remplacera totalement par la version présente sur le système de fichier', + 'committing' => 'Envoi', + 'resetting' => 'Rétablissement', + 'commit_success' => 'Le :type a été envoyé au système de fichier', + 'reset_success' => 'Le :type a été rétabli depuis la verison du système de fichier', + ], + 'asset' => [ + 'menu_label' => 'Assets', + 'unsaved_label' => 'Asset(s) non sauvegardé(s)', + 'drop_down_add_title' => 'Ajouter…', + 'drop_down_operation_title' => 'Action…', + 'upload_files' => 'Déposer des fichiers', + 'create_file' => 'Créer un fichier', + 'create_directory' => 'Créer un répertoire', + 'directory_popup_title' => 'Nouveau répertoire', + 'directory_name' => 'Nom du répertoire', + 'rename' => 'Renommer', + 'delete' => 'Supprimer', + 'move' => 'Déplacer', + 'select' => 'Sélectionner', + 'new' => 'Nouveau fichier', + 'rename_popup_title' => 'Renommer', + 'rename_new_name' => 'Nouveau nom', + 'invalid_path' => 'Le chemin doit contenir uniquement des chiffres, des lettres, des espaces et les symboles suivants : ._-/', + 'error_deleting_file' => 'Erreur lors de la suppression du fichier :name.', + 'error_deleting_dir_not_empty' => 'Erreur lors de la suppression du répertoire :name. Le répertoire n’est pas vide.', + 'error_deleting_dir' => 'Erreur lors de la suppression du répertoire :name.', + 'invalid_name' => 'Le nom doit contenir uniquement des chiffres, des lettres, des espaces et les symboles suivants : ._-', + 'original_not_found' => 'Le fichier original ou son répertoire est introuvable', + 'already_exists' => 'Un fichier ou un répertoire avec le même nom existe déjà', + 'error_renaming' => 'Erreur lors du renommage du fichier ou du répertoire', + 'name_cant_be_empty' => 'Le nom ne peut être vide', + 'too_large' => 'Le fichier téléchargé est trop volumineux. La taille maximum autorisée est de :max_size', + 'type_not_allowed' => 'Les types de fichiers autorisés sont les suivants : :allowed_types', + 'file_not_valid' => 'Fichier invalide', + 'error_uploading_file' => 'Erreur lors du dépôt du fichier ":name" : :error', + 'move_please_select' => 'Faire une sélection', + 'move_destination' => 'Répertoire de destination', + 'move_popup_title' => 'Déplacer les assets', + 'move_button' => 'Déplacer', + 'selected_files_not_found' => 'Les fichiers sélectionnés sont introuvables', + 'select_destination_dir' => 'Veuillez sélectionner un répertoire de destination', + 'destination_not_found' => 'Le répertoire de destination est introuvable', + 'error_moving_file' => 'Erreur lors du déplacement du fichier :file', + 'error_moving_directory' => 'Erreur lors du déplacement du répertoire :dir', + 'error_deleting_directory' => 'Erreur lors de la suppression du répertoire d’origine :dir', + 'no_list_records' => 'Aucun fichier trouvé', + 'delete_confirm' => 'Supprimer les fichiers ou répertoires sélectionnés ?', + 'path' => 'Chemin' + ], + 'component' => [ + 'menu_label' => 'Composants', + 'unnamed' => 'Sans nom', + 'no_description' => 'Aucune description n’a été fournie', + 'alias' => 'Alias', + 'alias_description' => 'Nom unique fourni lors de l’utilisation du composant sur une page ou une maquette.', + 'validation_message' => 'Les alias du composant sont requis et doivent contenir uniquement des symboles latins, des chiffres et des tirets bas. Les alias doivent commencer par un symbole latin.', + 'invalid_request' => 'Le modèle ne peut être enregistré car les données d’un composant ne sont pas valides.', + 'no_records' => 'Aucun composant n’a été trouvé', + 'not_found' => 'Le composant ":name" est introuvable.', + 'no_default_partial' => 'Ce composant n’as aucun partiel par défaut', + 'method_not_found' => 'Le composant ":name" ne contient pas de méthode ":method".', + 'soft_component' => 'Composant Soft', + 'soft_component_description' => 'Ce composant est manquant mais facultatif.', + ], + 'template' => [ + 'invalid_type' => 'Type de modèle inconnu.', + 'not_found' => 'Le modèle est introuvable.', + 'saved'=> 'Le modèle a été sauvegardé avec succès.', + 'no_list_records' => 'Aucun enregistrement trouvé', + 'delete_confirm' => 'Supprimer les modèles sélectionnés ?', + 'order_by' =>'Trier par' + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Gérer le contenu du site web', + 'manage_assets' => 'Gérer les assets site web - images, fichiers JavaScript et CSS', + 'manage_pages' => 'Créer, modifier et supprimer des pages du site web', + 'manage_layouts' => 'Créer, modifier et supprimer des maquettes du CMS', + 'manage_partials' => 'Créer, modifier et supprimer des modèles partiels du CMS', + 'manage_themes' => 'Activer, désactiver et configurer les thèmes', + 'manage_theme_options' => 'Gérer les options de personnalisation du thème actif', + ], + 'theme_log' => [ + 'hint' => 'Ce journal affiche tous les changements fait sur le thème actif par les administrateurs via le panneau d’administration.', + 'menu_label' => 'Journal du thème', + 'menu_description' => 'Affiche la liste des modifications apportées au thème actif.', + 'empty_link' => 'Purger le journal du thème', + 'empty_loading' => 'Purge du journal du thème...', + 'empty_success' => 'Journal du thème purgé avec succès', + 'return_link' => 'Retourner au journal du thème', + 'id' => 'ID', + 'id_label' => 'ID du journal', + 'created_at' => 'Date & Heure', + 'user' => 'Utilisateur', + 'type' => 'Type', + 'type_create' => 'Créer', + 'type_update' => 'Modifier', + 'type_delete' => 'Supprimer', + 'theme_name' => 'Thème', + 'theme_code' => 'Code du thème', + 'old_template' => 'Modèle (Ancien)', + 'new_template' => 'Modèle (Nouveau)', + 'template' => 'Modèle', + 'diff' => 'Changements', + 'old_value' => 'Ancienne valeur', + 'new_value' => 'Nouvelle valeur', + 'preview_title' => 'Changement du odèle', + 'template_updated' => 'Le modèle a été modifié', + 'template_created' => 'Le modèle a été créé', + 'template_deleted' => 'Le modèle a été supprimé', + ], +]; diff --git a/modules/cms/lang/hu/lang.php b/modules/cms/lang/hu/lang.php new file mode 100644 index 0000000..21553f0 --- /dev/null +++ b/modules/cms/lang/hu/lang.php @@ -0,0 +1,304 @@ + [ + 'invalid_file' => 'Érvénytelen fájlnév. Csak latin betűket, számokat, aláhúzásokat, kötőjeleket és pontokat tartalmazhat. Néhány példa a megfelelő fájlnévre: kapcsolat.htm, impresszum, konyvtar/oldalnev', + 'invalid_property' => "A(z) ':name' tulajdonság nem állítható be.", + 'file_already_exists' => "Már létezik ':name' nevű fájl.", + 'error_saving' => "Hiba a(z) ':name' fájl mentésekor. Ellenőrizze az írási engedélyeket.", + 'error_creating_directory' => 'Hiba a(z) :name könyvtár létrehozásakor. Ellenőrizze az írási engedélyeket.', + 'invalid_file_extension' => 'Érvénytelen kiterjesztés: :invalid. Engedélyezett kiterjesztések: :allowed.', + 'error_deleting' => "Hiba a(z) ':name' sablonfájl törlésekor. Ellenőrizze az írási engedélyeket.", + 'delete_success' => 'A sablonok törlése sikerült: :count.', + 'file_name_required' => 'A fájlnév mező kitöltése kötelező.', + 'safe_mode_enabled' => 'A biztonságos mód jelenleg aktív.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Weboldal', + 'online' => 'Online', + 'maintenance' => 'Karbantartás alatt', + 'manage_themes' => 'Témák kezelése', + 'customize_theme' => 'Téma testreszabása' + ] + ], + 'theme' => [ + 'not_found_name' => "A következő téma nem található: ':name'", + 'by_author' => 'Fejlesztő: :name', + 'active' => [ + 'not_set' => 'Nincs beállítva az aktív téma.', + 'not_found' => 'Az aktív téma nem található.' + ], + 'edit' => [ + 'not_set' => 'Nincs beállítva a szerkesztés alatt lévő téma.', + 'not_found' => 'A szerkesztés alatt lévő téma nem található.', + 'not_match' => 'Az objektum melyhez hozzáférni próbál, nem a szerkesztés alatt lévő témához tartozik. Töltse be újra az oldalt.', + ], + 'settings_menu' => 'Megjelenés', + 'settings_menu_description' => 'A telepített témák listája és azok testreszabása.', + 'default_tab' => 'Tulajdonságok', + 'name_label' => 'Név', + 'name_create_placeholder' => 'Az új téma neve', + 'author_label' => 'Szerző', + 'author_placeholder' => 'Magánszemély vagy cég neve', + 'description_label' => 'Leírás', + 'description_placeholder' => 'A téma ismertetője', + 'homepage_label' => 'Weboldal', + 'homepage_placeholder' => 'A honlap webcíme', + 'code_label' => 'Kód', + 'code_placeholder' => 'Egyedi azonosító ehhez a témához', + 'preview_image_label' => 'Előnézet', + 'preview_image_placeholder' => 'A téma előnézet képének elérési útvonala.', + 'dir_name_label' => 'Könyvtár', + 'dir_name_create_label' => 'A célkönyvtár', + 'theme_label' => 'Téma', + 'theme_title' => 'Témák', + 'activate_button' => 'Aktiválás', + 'active_button' => 'Aktiválva', + 'customize_theme' => 'Téma testreszabása', + 'customize_button' => 'Testreszabás', + 'duplicate_button' => 'Duplikálás', + 'duplicate_title' => 'Téma duplikálása', + 'duplicate_theme_success' => 'A téma duplikálása sikeresen megtörtént!', + 'manage_button' => 'Műveletek', + 'manage_title' => 'Téma menedzselése', + 'edit_properties_title' => 'Téma', + 'edit_properties_button' => 'Tulajdonságok', + 'save_properties' => 'Mentés', + 'import_button' => 'Importálás', + 'import_title' => 'Téma importálása', + 'import_theme_success' => 'A téma importálása sikeresen megtörtént!', + 'import_uploaded_file' => 'Téma archív fájl', + 'import_overwrite_label' => 'Létező fájlok felülírása', + 'import_overwrite_comment' => 'Ne jelölje be ezt a négyzetet, ha csak új fájlokat akar importálni.', + 'import_folders_label' => 'Könyvtárak', + 'import_folders_comment' => 'Válassza ki azokat a könyvtárakat, amiket importálni szeretne.', + 'export_button' => 'Exportálás', + 'export_title' => 'Téma exportálása', + 'export_folders_label' => 'Könyvtárak', + 'export_folders_comment' => 'Válassza ki azokat a könyvtárakat, amiket exportálni szeretne.', + 'delete_button' => 'Törlés', + 'delete_confirm' => 'Valóban törölni akarja a témát?', + 'delete_active_theme_failed' => 'Nem lehet törölni a témát. Először tegyen aktívvá egy másik témát.', + 'delete_theme_success' => 'A téma törlése sikeresen megtörtént!', + 'create_title' => 'Sablon létrehozása', + 'create_button' => 'Létrehozás', + 'create_new_blank_theme' => 'Üres téma létrehozása', + 'create_theme_success' => 'A téma létrehozása sikeresen megtörtént!', + 'create_theme_required_name' => 'Kérem adjon meg egy nevet a témának.', + 'new_directory_name_label' => 'Téma helye', + 'new_directory_name_comment' => 'Adjon meg egy új könyvtárat a duplikált témának.', + 'dir_name_invalid' => 'A név csak számokat, latin betűket, aláhúzásokat és kötőjeleket tartalmazhat.', + 'dir_name_taken' => 'A megadott könyvtár már létezik.', + 'find_more_themes' => 'További témák az OctoberCMS piacterén', + 'saving' => 'Téma mentése...', + 'return' => 'Vissza a témákhoz' + ], + 'maintenance' => [ + 'settings_menu' => 'Karbantartás', + 'settings_menu_description' => 'A weboldal ideiglenes felfüggesztése a látogatók számára.', + 'is_enabled' => 'Karbantartás engedélyezése', + 'is_enabled_comment' => 'Aktiválása esetén a weboldal látogatói csak a kiválasztott oldalt fogják látni.', + 'hint' => 'Karbantartás módban a lentebb megadott oldal fog megjelenni azon látogatók számára, akik nincsenek bejelentkezve az admin felületre.', + ], + 'page' => [ + 'not_found_name' => "A következő oldal nem található: ':name'", + 'not_found' => [ + 'label' => 'Az oldal nem található', + 'help' => 'A kért oldal nem található.', + ], + 'custom_error' => [ + 'label' => 'Oldal hiba', + 'help' => 'Sajnos valami elromlott, ezért az oldal nem jeleníthető meg.', + ], + 'menu_label' => 'Oldalak', + 'unsaved_label' => 'Nem mentett oldal(ok)', + 'no_list_records' => 'Nincs találat', + 'new' => 'Új oldal', + 'invalid_url' => 'Érvénytelen a formátum. A webcímnek perjellel kell kezdődnie, és számokat, latin betűket, valamint a következő karaktereket tartalmazhatja: ._-[]:?|/+*', + 'delete_confirm_multiple' => 'Valóban törölni akarja a kijelölt oldalakat?', + 'delete_confirm_single' => 'Valóban törölni akarja ezt az oldalt?', + 'no_layout' => '-- nincs --', + 'cms_page' => 'Oldalak', + 'title' => 'Elnevezés szerint', + 'url' => 'Webcím szerint', + 'file_name' => 'Fájlnév szerint' + ], + 'layout' => [ + 'not_found_name' => "A(z) ':name' elrendezés nem található", + 'menu_label' => 'Elrendezések', + 'unsaved_label' => 'Nem mentett elrendezés(ek)', + 'no_list_records' => 'Nincs találat', + 'new' => 'Új elrendezés', + 'delete_confirm_multiple' => 'Valóban törölni akarja a kijelölt elrendezéseket?', + 'delete_confirm_single' => 'Valóban törölni akarja ezt az elrendezést?' + ], + 'partial' => [ + 'not_found_name' => "A(z) ':name' részlap nem található.", + 'invalid_name' => 'Érvénytelen részlapnév: :name.', + 'menu_label' => 'Részlapok', + 'unsaved_label' => 'Nem mentett részlap(ok)', + 'no_list_records' => 'Nincs találat', + 'delete_confirm_multiple' => 'Valóban törölni akarja a kijelölt részlapokat?', + 'delete_confirm_single' => 'Valóban törölni akarja ezt a részlapot?', + 'new' => 'Új részlap' + ], + 'content' => [ + 'not_found_name' => "A(z) ':name' tartalomfájl nem található.", + 'menu_label' => 'Tartalom', + 'unsaved_label' => 'Nem mentett tartalom', + 'no_list_records' => 'Nincs találat', + 'delete_confirm_multiple' => 'Valóban törölni akarja a kijelölt tartalomfájlokat vagy könyvtárakat?', + 'delete_confirm_single' => 'Valóban törölni akarja ezt a tartalomfájlt?', + 'new' => 'Új tartalomfájl' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Érvénytelen AJAX kezelő név: :name.', + 'not_found' => "A(z) ':name' AJAX kezelő nem található." + ], + 'cms' => [ + 'menu_label' => 'Testreszabás' + ], + 'sidebar' => [ + 'add' => 'Hozzáadás', + 'search' => 'Keresés...' + ], + 'editor' => [ + 'settings' => 'Beállítások', + 'title' => 'Elnevezés', + 'new_title' => 'Az új oldal címe', + 'url' => 'Webcím', + 'filename' => 'Fájlnév', + 'layout' => 'Elrendezés', + 'description' => 'Leírás', + 'preview' => 'Előnézet', + 'meta' => 'Továbbiak', + 'meta_title' => 'Keresőbarát cím', + 'meta_description' => 'Keresőbarát leírás', + 'markup' => 'HTML', + 'code' => 'PHP', + 'content' => 'Tartalom', + 'hidden' => 'Rejtett', + 'hidden_comment' => 'Csak a bejelentkezett felhasználók láthatják.', + 'enter_fullscreen' => 'Váltás teljes képernyőre', + 'exit_fullscreen' => 'Kilépés a teljes képernyőből', + 'open_searchbox' => 'Keresési panel megnyitása', + 'close_searchbox' => 'Keresési panel bezárása', + 'open_replacebox' => 'Cserepanel megnyitása', + 'close_replacebox' => 'Cserepanel bezárása', + 'commit' => 'Végrehajtás', + 'reset' => 'Visszaállítás', + 'commit_confirm' => 'Biztos, hogy végrehajtja a fájl módosításait? Ez felülírja a meglévő fájlt.', + 'reset_confirm' => 'Biztos, hogy vissza akarja állítani ezt a fájlt a másolatra? Ez teljesen lecseréli a meglévő fájlt.', + 'committing' => 'Végrehajtás', + 'resetting' => 'Visszaállítás', + 'commit_success' => 'The :type has been committed to the filesystem', + 'reset_success' => 'The :type has been reset to the filesystem version', + ], + 'asset' => [ + 'menu_label' => 'Fájlok', + 'unsaved_label' => 'Nem mentett fájl(ok)', + 'drop_down_add_title' => 'Hozzáadás...', + 'drop_down_operation_title' => 'Művelet...', + 'upload_files' => 'Fájl(ok) feltöltése', + 'create_file' => 'Fájl létrehozása', + 'create_directory' => 'Könyvtár létrehozása', + 'directory_popup_title' => 'Új könyvtár', + 'directory_name' => 'Könyvtár neve', + 'rename' => 'Átnevezés', + 'delete' => 'Törlés', + 'move' => 'Áthelyezés', + 'select' => 'Kijelölés', + 'new' => 'Új fájl', + 'rename_popup_title' => 'Átnevezés', + 'rename_new_name' => 'Új név', + 'invalid_path' => 'Az elérési út neve csak számokat, latin betűket, szóközöket és a következő szimbólumokat tartalmazhatja: ._-/', + 'error_deleting_file' => 'Hiba a(z) :name fájl törlésekor.', + 'error_deleting_dir_not_empty' => 'Hiba a(z) :name könyvtár törlésekor. A könyvtár nem üres.', + 'error_deleting_dir' => 'Hiba a(z) :name fájl törlésekor.', + 'invalid_name' => 'A név csak számokat, latin betűket, szóközöket és a következő szimbólumokat tartalmazhatja: ._-', + 'original_not_found' => 'Nem található az eredeti fájl vagy könyvtár.', + 'already_exists' => 'Már létezik ilyen nevű fájl vagy könyvtár.', + 'error_renaming' => 'Hiba a fájl vagy a könyvtár átnevezésekor.', + 'name_cant_be_empty' => 'A név nem lehet üres.', + 'too_large' => 'A feltöltött fájl túl nagy. A maximálisan engedélyezett fájlméret: :max_size', + 'type_not_allowed' => 'Csak a következő fájltípusok engedélyezettek: :allowed_types', + 'file_not_valid' => 'A fájl nem érvényes.', + 'error_uploading_file' => "Hiba a(z) ':name' fájl feltöltésekor: :error", + 'move_please_select' => 'válasszon', + 'move_destination' => 'Célkönyvtár', + 'move_popup_title' => 'Fájl(ok) áthelyezése', + 'move_button' => 'Áthelyezés', + 'selected_files_not_found' => 'A kijelölt fájlok nem találhatók.', + 'select_destination_dir' => 'Válasszon egy célkönyvtárat.', + 'destination_not_found' => 'A célkönyvtár nem található.', + 'error_moving_file' => 'Hiba a(z) :file fájl áthelyezésekor.', + 'error_moving_directory' => 'Hiba a(z) :dir könyvtár áthelyezésekor.', + 'error_deleting_directory' => 'Hiba a(z) :dir eredeti könyvtár áthelyezésekor.', + 'no_list_records' => 'Nincs találat', + 'delete_confirm' => 'Valóban törölni akarja a fájlokat és a könyvtárakat?', + 'path' => 'Elérési út' + ], + 'component' => [ + 'menu_label' => 'Komponensek', + 'unnamed' => 'Névtelen', + 'no_description' => 'Nincs megadott leírás', + 'alias' => 'Alias', + 'alias_description' => 'Ennek a komponensnek az oldal vagy az elrendezés kódjában való használatkor adott egyedi név.', + 'validation_message' => 'A komponens aliasok kötelezőek, és csak latin betűket, számokat, valamint aláhúzásokat tartalmazhatnak. Az aliasoknak latin szimbólummal kell kezdődniük.', + 'invalid_request' => 'A sablon érvénytelen komponens adatok miatt nem menthető.', + 'no_records' => 'Nem találhatók komponensek', + 'not_found' => "A(z) ':name' komponens nem található.", + 'no_default_partial' => 'Ennek a komponensek nincs alapértelmezett részlapja.', + 'method_not_found' => "A(z) ':name' komponens nem tartalmaz a(z) ':method' metódust.", + 'soft_component' => 'Opcionális komponens', + 'soft_component_description' => 'Ez a komponens hiányzik, viszont nem kötelező.', + ], + 'template' => [ + 'invalid_type' => 'Ismeretlen sablon típus.', + 'not_found' => 'A kért sablon nem található.', + 'saved' => 'A módosítások sikeresen mentésre kerültek.', + 'no_list_records' => 'Nincs találat', + 'delete_confirm' => 'Valóban törölni akarja a témát?', + 'order_by' => 'Rendezés' + ], + 'permissions' => [ + 'name' => 'Testreszabás', + 'manage_content' => 'Tartalom kezelése', + 'manage_assets' => 'Fájlok kezelése', + 'manage_pages' => 'Oldalak kezelése', + 'manage_layouts' => 'Elrendezések kezelése', + 'manage_partials' => 'Részlapok kezelése', + 'manage_themes' => 'Témák kezelése', + 'manage_theme_options' => 'Aktív téma testreszabása', + ], + 'theme_log' => [ + 'hint' => 'Az adminok által elvégzett módosítások az aktív téma fájlaiban, amiket az admin felületen keresztül hajtottak végre.', + 'menu_label' => 'Téma napló', + 'menu_description' => 'Változtatások listája az aktív témánál.', + 'empty_link' => 'Kiürítés', + 'empty_loading' => 'A kiürítés folyamatban...', + 'empty_success' => 'A téma napló kiürítése megtörtént.', + 'return_link' => 'Vissza a téma naplóhoz', + 'id' => 'ID', + 'id_label' => 'Napló ID', + 'created_at' => 'Dátum', + 'user' => 'Felhasználó', + 'type' => 'Művelet', + 'type_create' => 'Létrehozás', + 'type_update' => 'Módosítás', + 'type_delete' => 'Törlés', + 'theme_name' => 'Téma', + 'theme_code' => 'Kódnév', + 'old_template' => 'Fájl (régi)', + 'new_template' => 'Fájl (új)', + 'template' => 'Fájl', + 'diff' => 'Változtatások', + 'old_value' => 'Régi tartalom', + 'new_value' => 'Új tartalom', + 'preview_title' => 'Változtatások', + 'template_updated' => 'A fájl frissítve lett.', + 'template_created' => 'A fájl létre lett hozva.', + 'template_deleted' => 'A fájl törölve lett.' + ] +]; diff --git a/modules/cms/lang/id/lang.php b/modules/cms/lang/id/lang.php new file mode 100644 index 0000000..c7a066d --- /dev/null +++ b/modules/cms/lang/id/lang.php @@ -0,0 +1,189 @@ + [ + 'invalid_file' => 'Nama berkas: :name tidak valid. Nama berkas hanya dapat memuat angka, huruf, garis bawah, strip, dan titik. Contoh penamaan berkas yang benar: laman.htm, laman, subdirektori/laman', + 'invalid_property' => "Properti ':name' tidak dapat diatur", + 'file_already_exists' => "Berkas ':name' sudah ada.", + 'error_saving' => "Galat menyimpan berkas ':name'. Silakan periksa izin tulis.", + 'error_creating_directory' => 'Galat membuat direktori :name. Silakan periksa izin tulis.', + 'invalid_file_extension'=>'Ekstensi berkas: :invalid tidak valid. Ekstensi yang diperbolehkan: :allowed.', + 'error_deleting' => "Galat menghapus berkas acuan ':name'. Silakan periksa izin tulis.", + 'delete_success' => 'Acuan: :count berhasil dihapus.', + 'file_name_required' => 'Bidang nama berkas diperlukan.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'online' => 'daring', + 'maintenance' => 'dalam perawatan', + ] + ], + 'theme' => [ + 'active' => [ + 'not_set' => 'Tema aktif tidak diatur.', + 'not_found' => 'Tema aktif tidak ditemukan.' + ], + 'edit' => [ + 'not_set' => 'Tema tersunting tidak diatur.', + 'not_found' => 'Tema tersunting tidak ditemukan.', + 'not_match' => "Objek yang Anda coba akses tidak dimiliki oleh tema yang akan disunting. Silakan muat ulang laman." + ], + 'settings_menu' => 'Tema front-end', + 'settings_menu_description' => 'Tinjau senarai tema terpasang dan pilih tema aktif.', + 'find_more_themes' => 'Temukan lebih banyak tema pada Toko Tema OctoberCMS.', + 'activate_button' => 'Aktifkan', + 'active_button' => 'Aktif', + 'customize_button' => 'Ubah suai' + ], + 'maintenance' => [ + 'settings_menu' => 'Mode perbaikan', + 'settings_menu_description' => 'Penyusunan laman mode perbaikan dan tukar pengaturan.', + 'is_enabled' => 'Berdayakan mode perbaikan', + 'is_enabled_comment' => 'Bila diaktifkan, pengunjung website akan melihat laman terpilih berikut.' + ], + 'page' => [ + 'not_found' => [ + 'label' => 'Laman tidak ditemukan', + 'help' => 'Laman yang diminta tidak dapat ditemukan.' + ], + 'custom_error' => [ + 'label' => 'Lamat galat', + 'help' => "Mohon maaf, ada sesuatu yang salah dan laman tidak dapat ditampilkan." + ], + 'menu_label' => 'Laman', + 'unsaved_label' => 'Laman tak tersimpan', + 'no_list_records' => 'Tidak ada laman ditemukan', + 'new' => 'Laman baru', + 'invalid_url' => 'Format URL tidak valid. URL harus diawali dengan garis miring terbalik dan memuat huruf latin, angka dan simbol-simbol ini: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Anda yakin akan menghapus laman terpilih?', + 'delete_confirm_single' => 'Anda yakin akan menghapus laman ini?', + 'no_layout' => '-- tanpa tata letak --' + ], + 'layout' => [ + 'not_found' => "Tata letak ':name' tidak ditemukan", + 'menu_label' => 'Tata letak', + 'unsaved_label' => 'Tata letak tak tersimpan', + 'no_list_records' => 'Tidak ada tata letak ditemukan', + 'new' => 'Tata letak baru', + 'delete_confirm_multiple' => 'Anda yakin akan menghapus tata letak terpilih?', + 'delete_confirm_single' => 'Anda yakin akan menghapus tata letak ini?' + ], + 'partial' => [ + 'invalid_name' => 'Nama bagian: :name tidak valid.', + 'not_found' => "Bagian ':name' tidak ditemukan.", + 'menu_label' => 'Bagian', + 'unsaved_label' => 'Bagian tak tersimpan', + 'no_list_records' => 'Tidak ada bagian ditemukan', + 'delete_confirm_multiple' => 'Anda yakin akan menghapus bagian terpilih?', + 'delete_confirm_single' => 'Anda yakin akan menghapus bagian ini?', + 'new' => 'Bagian baru' + ], + 'content' => [ + 'not_found' => "Berkas muatan ':name' tidak ditemukan.", + 'menu_label' => 'Muatan', + 'unsaved_label' => 'Muatan tak tersimpan', + 'no_list_records' => 'Tidak ada muatan ditemukan', + 'delete_confirm_multiple' => 'Anda yakin akan menghapus berkas atau direktori muatan terpilih?', + 'delete_confirm_single' => 'Anda yakin akan menghapus berkas muatan ini?', + 'new' => 'Berkas muatan baru' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Nama AJAX handler: :name tidak valid.', + 'not_found' => "AJAX handler ':name' tidak ditemukan." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Tambah', + 'search' => 'Pencarian...' + ], + 'editor' => [ + 'settings' => 'Pengaturan', + 'title' => 'Judul', + 'new_title' => 'Judul laman baru', + 'url' => 'URL', + 'filename' => 'Nama berkas', + 'layout' => 'Tata letak', + 'description' => 'Jabaran', + 'preview' => 'Tinjau', + 'meta' => 'Meta', + 'meta_title' => 'Judul Meta', + 'meta_description' => 'Jabaran Meta', + 'markup' => 'Markup', + 'code' => 'Kode', + 'content' => 'Muatan', + 'hidden' => 'Tersembunyi', + 'hidden_comment' => 'Laman tersembunyi hanya dapat diakses oleh pengguna back-end yang telah catat masuk.', + 'enter_fullscreen' => 'Masuk mode layar penuh', + 'exit_fullscreen' => 'Keluar mode layar penuh' + ], + 'asset' => [ + 'menu_label' => 'Aset', + 'unsaved_label' => 'Aset tak tersimpan', + 'drop_down_add_title' => 'Tambah...', + 'drop_down_operation_title' => 'Aksi...', + 'upload_files' => 'Unggah berkas', + 'create_file' => 'Buat berkas', + 'create_directory' => 'Buat direktori', + 'directory_popup_title' => 'Direktori baru', + 'directory_name' => 'Nama direktori', + 'rename' => 'Ganti nama', + 'delete' => 'Hapus', + 'move' => 'Pindah', + 'select' => 'Pilih', + 'new' => 'Berkas baru', + 'rename_popup_title' => 'Ganti nama', + 'rename_new_name' => 'Nama baru', + 'invalid_path' => 'Jalur hanya dapat memuat angka, huruf Latin, spasi dan simbol-simbol ini: ._-/', + 'error_deleting_file' => 'Galat menghapus berkas :name.', + 'error_deleting_dir_not_empty' => 'Galat menghapus direktori :name. Direktori tersebut berisi.', + 'error_deleting_dir' => 'Galat menghapus berkas :name.', + 'invalid_name' => 'Nama hanya dapat memuat angka, huruf Latin, spasi dan simbol-simbol ini: ._-', + 'original_not_found' => 'Berkas atau direktori asal tidak ditemukan', + 'already_exists' => 'Sudah ada berkas atau direktori dengan nama ini', + 'error_renaming' => 'Galat ganti nama berkas atau direktori', + 'name_cant_be_empty' => 'Nama tidak boleh kosong', + 'too_large' => 'Berkas unggahan terlalu besar. Ukuran maksimal yang diperbolahkan adalah :max_size', + 'type_not_allowed' => 'Hanya jenis-jenis berkas berikut yang diperbolahkan: :allowed_types', + 'file_not_valid' => 'Berkas tidak valid', + 'error_uploading_file' => "Galat mengunggah berkas ':name': :error", + 'move_please_select' => 'silakan pilih', + 'move_destination' => 'Direktori tujuan', + 'move_popup_title' => 'Pindahkan aset', + 'move_button' => 'Pindahkan', + 'selected_files_not_found' => 'Berkas terpilih tidak ditemukan', + 'select_destination_dir' => 'Silakan pilih direktori tujuan', + 'destination_not_found' => 'Direktori tujuan tidak ditemukan', + 'error_moving_file' => 'Galat memindahkan berkas :file', + 'error_moving_directory' => 'Galat memindahkan direktori :dir', + 'error_deleting_directory' => 'Galat menghapus direktori asal :dir', + 'path' => 'Jalur' + ], + 'component' => [ + 'menu_label' => 'Komponen', + 'unnamed' => 'Tak bernama', + 'no_description' => 'Tidak ada jabaran', + 'alias' => 'Alias', + 'alias_description' => 'Nama unik untuk komponen ini saat digunakan di dalam kode laman atau tata letak.', + 'validation_message' => 'Alias komponen diperlukan dan hanya dapat memuat simbol Latin, angka, dan garis bawah. Alias harus diawali dengan simbol Latin.', + 'invalid_request' => 'Acuan tidak dapat disimpan dikarenakan data komponen tidak valid.', + 'no_records' => 'Tidak ada komponen ditemukan', + 'not_found' => "Komponen ':name' tidak ditemukan.", + 'method_not_found' => "Komponen ':name' tidak berisi metode ':method'." + ], + 'template' => [ + 'invalid_type' => 'Jenis acuan tidak diketahui.', + 'not_found' => 'Acuan yang diminta tidak ditemukan.', + 'saved'=> 'Acuan berhasil disimpan.' + ], + 'permissions' => [ + 'name' => 'Cms', + 'manage_content' => 'Kelola muatan', + 'manage_assets' => 'Kelola aset', + 'manage_pages' => 'Kelola laman', + 'manage_layouts' => 'Kelola tata letak', + 'manage_partials' => 'Kelola bagian', + 'manage_themes' => 'Kelola tema' + ] +]; diff --git a/modules/cms/lang/it/lang.php b/modules/cms/lang/it/lang.php new file mode 100644 index 0000000..72ba542 --- /dev/null +++ b/modules/cms/lang/it/lang.php @@ -0,0 +1,249 @@ + [ + 'invalid_file' => 'Nome file non valido: :name. I nomi dei file possono contenere solo caratteri alfanumerici, underscores, trattini e punti. Alcuni esempi di nome di file corretti: page.htm, page, subdirectory/page', + 'invalid_property' => "La proprietà ':name' non può essere impostata", + 'file_already_exists' => "File ':name' già esistente.", + 'error_saving' => "Errore nel salvataggio del file ':name'. Verifica le autorizzazioni di scrittura.", + 'error_creating_directory' => 'Errore nella creazione della cartella :name. Verifica le autorizzazioni di scrittura.', + 'invalid_file_extension'=>'Estensione del file non valida: :invalid. Le estensioni consentite sono: :allowed.', + 'error_deleting' => "Errore nella cancellazione del file ':name'. Verifica le autorizzazioni di scrittura.", + 'delete_success' => 'Template eliminati correttamente: :count.', + 'file_name_required' => 'Il campo Nome file è obbligatorio.', + 'safe_mode_enabled' => 'La modalità sicura è attualmente abilitata.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Sito web', + 'online' => 'Online', + 'maintenance' => 'In manutenzione', + 'manage_themes' => 'Gestione temi', + ] + ], + 'theme' => [ + 'not_found_name' => "Tema ':name' non trovato.", + 'active' => [ + 'not_set' => 'Il tema attivo non è impostato.', + 'not_found' => 'Il tema attivo non è stato trovato.', + ], + 'edit' => [ + 'not_set' => 'Il tema modificato non è impostato.', + 'not_found' => 'Il tema modificato non è stato trovato.', + 'not_match' => "L'oggetto a cui stai cercando di accedere non appartiene al tema che stai modificando. Si prega di ricaricare la pagina." + ], + 'settings_menu' => 'Tema del sito', + 'settings_menu_description' => 'Visualizza l\'anteprima dei temi installati e seleziona un tema attivo.', + 'default_tab' => 'Proprietà', + 'name_label' => 'Nome', + 'name_create_placeholder' => 'Nome del nuovo tema', + 'author_label' => 'Autore', + 'author_placeholder' => 'Nome della persona o della società', + 'description_label' => 'Descrizione', + 'description_placeholder' => 'Descrizione del tema', + 'homepage_label' => 'Homepage', + 'homepage_placeholder' => 'URL Sito web', + 'code_label' => 'Codice', + 'code_placeholder' => 'Un codice univoco per questo tema, utilizzato per la distribuzione', + 'dir_name_label' => 'Nome della cartella', + 'dir_name_create_label' => 'La cartella di destinazione del tema', + 'theme_label' => 'Tema', + 'theme_title' => 'Temi', + 'activate_button' => 'Attiva', + 'active_button' => 'Attivo', + 'customize_theme' => 'Personalizza tema', + 'customize_button' => 'Personalizza', + 'duplicate_button' => 'Duplica', + 'duplicate_title' => 'Duplica tema', + 'duplicate_theme_success' => 'Tema duplicato con successo!', + 'manage_button' => 'Gestisci', + 'manage_title' => 'Gestisci tema', + 'edit_properties_title' => 'Tema', + 'edit_properties_button' => 'Modifica proprietà', + 'save_properties' => 'Salva proprietà', + 'import_button' => 'Importa', + 'import_title' => 'Importa tema', + 'import_theme_success' => 'Tema importato con successo!', + 'import_uploaded_file' => 'File di archivio del tema', + 'import_overwrite_label' => 'Sovrascrivi file esistenti', + 'import_overwrite_comment' => 'Deseleziona per importare solamente i nuovi file', + 'import_folders_label' => 'Cartelle', + 'import_folders_comment' => 'Seleziona le cartelle del tema che vuoi importare', + 'export_button' => 'Esporta', + 'export_title' => 'Esporta tema', + 'export_folders_label' => 'Cartelle', + 'export_folders_comment' => 'Seleziona le cartelle del tema che vuoi esportare', + 'delete_button' => 'Elimina', + 'delete_confirm' => 'Sei sicuro di voler cancellare questo tema? L\'operazione non può essere annullata!', + 'delete_active_theme_failed' => 'Impossibile eliminare il tema attivo, prova prima ad attivare un altro tema.', + 'delete_theme_success' => 'Tema eliminato con successo!', + 'create_title' => 'Crea tema', + 'create_button' => 'Crea', + 'create_new_blank_theme' => 'Crea un nuovo tema vuoto', + 'create_theme_success' => 'Tema creato con successo!', + 'create_theme_required_name' => 'Specifica un nome per il tema.', + 'new_directory_name_label' => 'Cartella di destinazione del tema', + 'new_directory_name_comment' => 'Inserisci una nuova cartella per il tema duplicato.', + 'dir_name_invalid' => 'Il nome della cartella può contenere solo numeri, lettere latine e i seguenti simboli: _-', + 'dir_name_taken' => 'Cartelle di destinazione del tema già esistente.', + 'find_more_themes' => 'Trova nuovi temi', + 'saving' => 'Salvataggio tema in corso...', + 'return' => 'Ritorna all\'elenco del temi', + ], + 'maintenance' => [ + 'settings_menu' => 'Modalità di manutenzione', + 'settings_menu_description' => 'Configura la pagina da visualizzare in modalità di manutenzione e cambia l\'impostazione.', + 'is_enabled' => 'Abilita modalità di manutenzione', + 'is_enabled_comment' => 'Se attivo i visitatori del sito vedranno la pagina selezionata sotto.' + ], + 'page' => [ + 'not_found_name' => "Pagina ':name' non trovata", + 'not_found' => [ + 'label' => 'Pagina non trovata', + 'help' => 'La pagina richiesta non è stata trovata.', + ], + 'custom_error' => [ + 'label' => 'Errore nella pagina', + 'help' => "Siamo spiacenti, ma qualcosa è andato storto e la pagina non può essere visualizzata.", + ], + 'menu_label' => 'Pagine', + 'unsaved_label' => 'Pagina/e non salvate', + 'no_list_records' => 'Pagine non trovate', + 'new' => 'Nuova pagina', + 'invalid_url' => 'Formato URL non valido. L\'URL deve iniziare con una barra e può contenere numeri, lettere latine e i seguenti simboli: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Sei sicuro di voler eliminare le pagine selezionate?', + 'delete_confirm_single' => 'Sei sicuro di voler eliminare questa pagina?', + 'no_layout' => '-- nessun layout --' + ], + 'layout' => [ + 'not_found_name' => "Il layout ':name' non è stato trovato", + 'menu_label' => 'Layout', + 'unsaved_label' => 'Layout non salvati', + 'no_list_records' => 'Nessun layout trovato', + 'new' => 'Nuovo layout', + 'delete_confirm_multiple' => 'Sei sicuro di voler eliminare i layouts selezionati?', + 'delete_confirm_single' => 'Sei sicuro di voler eliminare questo layout?' + ], + 'partial' => [ + 'not_found_name' => "La vista parziale ':name' non è stata trovata.", + 'invalid_name' => 'Nome della vista parziale non valido: :name.', + 'menu_label' => 'Viste parziali', + 'unsaved_label' => 'Viste parziali non salvate', + 'no_list_records' => 'Nessuna vista parziale trovata', + 'delete_confirm_multiple' => 'Sei sicuro di voler eliminare le viste parziali selezionate?', + 'delete_confirm_single' => 'Sei sicuro di voler eliminare questa vista parziale?', + 'new' => 'Nuova vista parziale' + ], + 'content' => [ + 'not_found_name' => "Il file di contenuti ':name' non è stato trovato.", + 'menu_label' => 'Contenuti', + 'unsaved_label' => 'Contenuti non salvati', + 'no_list_records' => 'Nessun file di contenuto trovato', + 'delete_confirm_multiple' => 'Sei sicuro di voler eliminare i file o le cartelle di contenuti selezionate?', + 'delete_confirm_single' => 'Sei sicuro di voler eliminare questo file di contenuti?', + 'new' => 'Nuovo file di contenuti' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Nome del gestore AJAX non valido: :name.', + 'not_found' => "Il gestore AJAX ':name' non è stato trovato.", + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Aggiungi', + 'search' => 'Cerca...' + ], + 'editor' => [ + 'settings' => 'Impostazioni', + 'title' => 'Titolo', + 'new_title' => 'Titolo nuova pagina', + 'url' => 'URL', + 'filename' => 'Nome file', + 'layout' => 'Layout', + 'description' => 'Descrizione', + 'preview' => 'Anteprima', + 'meta' => 'Metadati', + 'meta_title' => 'Meta Titolo', + 'meta_description' => 'Meta Descrizione', + 'markup' => 'Markup', + 'code' => 'Codice', + 'content' => 'Contenuto', + 'hidden' => 'Nascosto', + 'hidden_comment' => 'Le pagine nascoste sono accessibili solo dagli utenti collegati al pannello di controllo.', + 'enter_fullscreen' => 'Visualizza a schermo intero', + 'exit_fullscreen' => 'Esci dalla visualizzazione a schermo intero', + 'open_searchbox' => 'Apri casella di ricerca', + 'close_searchbox' => 'Chiudi casella di ricerca', + 'open_replacebox' => 'Apri casella di sostituzione', + 'close_replacebox' => 'Chiudi casella di sostituzione' + ], + 'asset' => [ + 'menu_label' => 'Assets', + 'unsaved_label' => 'Asset(s) non salvati', + 'drop_down_add_title' => 'Aggiungi...', + 'drop_down_operation_title' => 'Azioni...', + 'upload_files' => 'Carica file(s)', + 'create_file' => 'Crea file', + 'create_directory' => 'Crea cartella', + 'directory_popup_title' => 'Nuova cartella', + 'directory_name' => 'Nome della cartella', + 'rename' => 'Rinomina', + 'delete' => 'Elimina', + 'move' => 'Sposta', + 'select' => 'Seleziona', + 'new' => 'Nuovo file', + 'rename_popup_title' => 'Rinomina', + 'rename_new_name' => 'Nuovo nome', + 'invalid_path' => 'Il percorso può contenere solo numeri, lettere latine, spazi e i simboli seguenti: ._-/', + 'error_deleting_file' => 'Errore durante l\'eliminazione del file :name.', + 'error_deleting_dir_not_empty' => 'Errore durante l\'eliminazione della cartella :name. La cartella non è vuota.', + 'error_deleting_dir' => 'Errore durante l\'eliminazinoe della cartella :name.', + 'invalid_name' => 'Il nome può contenere solo numeri, lettere latine, spazi e i simboli seguenti: ._-', + 'original_not_found' => 'Il file o la cartella originali non sono stati trovati', + 'already_exists' => 'Un file o cartella con questo nome è già esistente', + 'error_renaming' => 'Errore nella rinominazione del file o della cartella', + 'name_cant_be_empty' => 'Il nome non può essere vuoto', + 'too_large' => 'Il file caricato è troppo grande. La dimensione massima consentita è :max_size', + 'type_not_allowed' => 'Solo i seguenti tipi di file sono consentiti: :allowed_types', + 'file_not_valid' => 'File non valido', + 'error_uploading_file' => "Errore durante il caricamento del file ':name': :error", + 'move_please_select' => 'seleziona', + 'move_destination' => 'Cartella di destinazione', + 'move_popup_title' => 'Sposta assets', + 'move_button' => 'Sposta', + 'selected_files_not_found' => 'Files selezionati non trovati.', + 'select_destination_dir' => 'Seleziona una cartella di destinazione', + 'destination_not_found' => 'Cartella di destinazione non trovata', + 'error_moving_file' => 'Errore durante lo spostamento del file :file', + 'error_moving_directory' => 'Errore durante lo spostamento della cartella :dir', + 'error_deleting_directory' => 'Errore durante l\'eliminazione della cartella originale :dir', + 'path' => 'Percorso' + ], + 'component' => [ + 'menu_label' => 'Componenti', + 'unnamed' => 'Senza nome', + 'no_description' => 'Nessuna descrizione fornita', + 'alias' => 'Alias', + 'alias_description' => 'Un nome univoco fornito a questo componente quando utilizzato nella pagina o nel layout.', + 'validation_message' => 'L\'alias del componente è obbligatorio e può contenere solo lettere latine, numeri e underscores. L\'alias deve iniziare con una lettera.', + 'invalid_request' => 'Il template non può essere salvato a causa di dati dei componenti non validi.', + 'no_records' => 'Nessun componente trovato', + 'not_found' => "Il componente ':name' non è stato trovato.", + 'method_not_found' => "Il componente ':name' non contiene il metodo ':method'." + ], + 'template' => [ + 'invalid_type' => 'Tipo di template sconosciuto.', + 'not_found' => 'Il template richiesto non è stato trovato.', + 'saved'=> 'Il template è stato salvato con successo' + ], + 'permissions' => [ + 'name' => 'Cms', + 'manage_content' => 'Gestisci contenuti', + 'manage_assets' => 'Gestisci assets', + 'manage_pages' => 'Gestisci pagine', + 'manage_layouts' => 'Gesstisci layouts', + 'manage_partials' => 'Gestisci viste parziali', + 'manage_themes' => 'Gestisci temi', + ], +]; diff --git a/modules/cms/lang/ja/lang.php b/modules/cms/lang/ja/lang.php new file mode 100644 index 0000000..a410309 --- /dev/null +++ b/modules/cms/lang/ja/lang.php @@ -0,0 +1,189 @@ + [ + 'invalid_file' => '正しくないファイル名::name。ファイル名は英文字、下線(_)、ダッシュ(-)、ピリオド(.)で構成されなくてはなりません。(正しいファイル名の例:page, page.htm, subdirectory/page)', + 'invalid_property' => '":name"プロパティーをセットできません。', + 'file_already_exists' => '":name"ファイルは既に存在しています。', + 'error_saving' => '":name"ファイル保存エラー', + 'error_creating_directory' => ':nameディレクトリー作成エラー', + 'invalid_file_extension'=>'正しくないファイル拡張子::invalid。許されている拡張子は、:allowedです。', + 'error_deleting' => '":name"一時ファイル削除エラー', + 'delete_success' => ':count個のテンプレートを削除しました。', + 'file_name_required' => 'ファイル名フィールドが必要です。', + ], + 'dashboard' => [ + 'active_theme' => [ + 'online' => 'オンライン', + 'maintenance' => 'メンテナンスモード', + ] + ], + 'theme' => [ + 'active' => [ + 'not_set' => "アクティブなテーマが設定されていません。", + 'not_found' => 'アクティブなテーマが見つかりません。', + ], + 'edit' => [ + 'not_set' => "編集テーマが設定されていません。", + 'not_found' => "編集テーマが見つかりません。", + 'not_match' => "アクセスしようとしてるオブジェクトは、編集中のテーマに所属していません。ページを再読み込みしてください。", + ], + 'settings_menu' => 'フロントエンドのテーマ', + 'settings_menu_description' => 'インストール済みのテーマのプレビュー一覧とアクティブテーマの選択。', + 'find_more_themes' => 'OctoberCMSマーケットプレースで、もっとテーマを探す。', + 'activate_button' => 'これをアクティブにする', + 'active_button' => '現在アクティブ中です', + 'customize_button' => 'カスタマイズ', + ], + 'maintenance' => [ + 'settings_menu' => 'メンテナンスモード', + 'settings_menu_description' => 'メンテナンスモードページの設定と切り替えをします。', + 'is_enabled' => 'メンテナンスモードを有効にする', + 'is_enabled_comment' => 'メンテナンスモードの時、Webサイト訪問者が見るページを選択してください。', + ], + 'page' => [ + 'not_found' => [ + 'label' => "ページが見つかりません。", + 'help' => "要求されているページが見つかりません。", + ], + 'custom_error' => [ + 'label' => "ページエラー。", + 'help' => "申し訳ありません。何かが間違っているようで、ページが表示できません。", + ], + 'menu_label' => 'ページ', + 'unsaved_label' => '保存されていないページ', + 'no_list_records' => 'ページが見つかりません', + 'new' => '新ページ', + 'invalid_url' => '正しくないURL形式。URLはスラッシュ(/)で始まり、数字、ラテン文字、._-[]:?|/+*^$で構成します。', + 'delete_confirm_multiple' => '指定した全ページを本当に削除しますか?', + 'delete_confirm_single' => '本当にこのページを削除しますか?', + 'no_layout' => '-- レイアウト無し --', + ], + 'layout' => [ + 'not_found_name' => "レイアウト':name'が見つかりません。", + 'menu_label' => 'レイアウト', + 'unsaved_label' => '保存されていないレイアウト', + 'no_list_records' => 'レイアウトが見つかりません', + 'new' => '新レイアウト', + 'delete_confirm_multiple' => '指定した全ページを本当に削除しますか?', + 'delete_confirm_single' => '本当にこのページを削除しますか?', + ], + 'partial' => [ + 'not_found_name' => "':name'パーシャルが見つかりません。", + 'invalid_name' => "正しくないパーシャル名::name。", + 'menu_label' => 'パーシャル', + 'unsaved_label' => '保存されていないパーシャル(s)', + 'no_list_records' => 'パーシャルが見つかりません。', + 'delete_confirm_multiple' => '指定した全パーシャルを本当に削除しますか?', + 'delete_confirm_single' => '本当にこのパーシャルを削除しますか?', + 'new' => '新パーシャル', + ], + 'content' => [ + 'not_found_name' => "':name'コンテンツファイルが見つかりません。", + 'menu_label' => 'コンテンツ', + 'unsaved_label' => '保存されていないコンテンツ', + 'no_list_records' => 'コンテンツファイルが見つかりません', + 'delete_confirm_multiple' => '指定した全コンテンツファイル/ディレクトリーを本当に削除しますか?', + 'delete_confirm_single' => '本当にこのコンテンツファイルを削除しますか?', + 'new' => '新コンテンツファイル', + ], + 'ajax_handler' => [ + 'invalid_name' => "正しくないAjaxハンドラ名::name。", + 'not_found' => "':name' Ajaxハンドラが見つかりません。", + ], + 'cms' => [ + 'menu_label' => "CMS", + ], + 'sidebar' => [ + 'add' => '追加', + 'search' => '検索...', + ], + 'editor' => [ + 'settings' => '設定', + 'title' => 'タイトル', + 'new_title' => '新ページタイトル', + 'url' => 'URL', + 'filename' => 'ファイル名', + 'layout' => 'レイアウト', + 'description' => '説明', + 'preview' => 'プレビュー', + 'meta' => 'メタ', + 'meta_title' => 'メタタイトル', + 'meta_description' => 'メタ説明', + 'markup' => 'マークアップ', + 'code' => 'コード', + 'content' => 'コンテンツ', + 'hidden' => '非表示', + 'hidden_comment' => 'フロントエンドでページを表示しないようにします。バックエンドでのみ閲覧・編集できます。', + 'enter_fullscreen' => '全画面モードに移行する', + 'exit_fullscreen' => '全画面モードを解除する', + ], + 'asset' => [ + 'menu_label' => "アセット", + 'unsaved_label' => '保存されていないアセット', + 'drop_down_add_title' => '追加...', + 'drop_down_operation_title' => 'アクション...', + 'upload_files' => 'ファイルアップロード', + 'create_file' => 'ファイル作成', + 'create_directory' => 'ディレクトリ作成', + 'directory_popup_title' => '新規ディレクトリ', + 'directory_name' => 'ディレクトリ名', + 'rename' => '名前変更', + 'delete' => '削除', + 'move' => '移動', + 'select' => '選択', + 'new' => '新ファイル', + 'rename_popup_title' => '名前変更', + 'rename_new_name' => '新しい名前', + 'invalid_path' => 'パスは数字、ラテン文字、空白、._-/で構成されなくてはなりません。', + 'error_deleting_file' => ':nameファイル削除エラー。', + 'error_deleting_dir_not_empty' => ':nameディレクトリ削除エラー。ディレクトリが空ではありません。', + 'error_deleting_dir' => ':nameディレクトリ削除エラー。', + 'invalid_name' => '名前は数字、ラテン文字、空白、._-で構成されなくてはなりません。', + 'original_not_found' => '元のファイル/ディレクトリが見つかりません', + 'already_exists' => 'この名前のファイル/ディレクトリは既に存在します。', + 'error_renaming' => 'ファイル/ディレクトリ名前変更エラー', + 'name_cant_be_empty' => '名前は空白にできません', + 'too_large' => 'アップロードファイルは大きすぎます。ファイルサイズは最大で、:max_sizeです。', + 'type_not_allowed' => '許可されているファイルタイプは、:allowed_typesだけです。', + 'file_not_valid' => 'ファイルが正しくありません。', + 'error_uploading_file' => '":name":ファイルアップロードエラー。(:error)', + 'move_please_select' => '選択してください', + 'move_destination' => '移動先ディレクトリー', + 'move_popup_title' => 'アセット移動', + 'move_button' => '移動', + 'selected_files_not_found' => '選択されたファイルは存在しません。', + 'select_destination_dir' => '移動先ディレクトリーを選択してください', + 'destination_not_found' => '移動先ディレクトリーは存在しません。', + 'error_moving_file' => ':fileファイル移動エラー', + 'error_moving_directory' => ':dirディレクトリー移動エラー', + 'error_deleting_directory' => '移動元:dirディレクトリー削除エラー', + 'path' => 'パス', + ], + 'component' => [ + 'menu_label' => "コンポーネント", + 'unnamed' => "名前なし", + 'no_description' => "説明なし", + 'alias' => "エイリアス", + 'alias_description' => "ページやレイアウトコードの中で使用される、一意のコンポーネント名。", + 'validation_message' => "ラテン文字、数字、下線(_)で構成された、コンポーネントエイリアスが必要です。エイリアスはラテン文字で始まらなくてなりません。", + 'invalid_request' => "コンポーネントデータが正しくないため、テンプレートは保存できません。", + 'no_records' => 'コンポーネントが見つかりません。', + 'not_found' => "':name'コンポーネントが見つかりません。", + 'method_not_found' => "':name'コンポーネントは、':method'メソッドを持っていません。", + ], + 'template' => [ + 'invalid_type' => "未知のテンプレートタイプ。", + 'not_found' => "リクエストされたテンプレートが見つかりません。", + 'saved'=> "テンプレートを保存しました。", + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'コンテンツ管理', + 'manage_assets' => 'アセット管理', + 'manage_pages' => 'ページ管理', + 'manage_layouts' => 'レイアウト管理', + 'manage_partials' => 'パーシャル管理', + 'manage_themes' => 'テーマ管理', + ], +]; diff --git a/modules/cms/lang/kr/lang.php b/modules/cms/lang/kr/lang.php new file mode 100644 index 0000000..ef3d8e3 --- /dev/null +++ b/modules/cms/lang/kr/lang.php @@ -0,0 +1,292 @@ + [ + 'invalid_file' => '올바르지않은 파일명: :name .파일명은 영문자, 언더스코어(_), 하이픈(-), 피리오드(.) 로만 구성되어야 합니다. (올바른파일명예: page, page.htm, subdirectory/page)', + 'invalid_property' => '":name" 속성(Property)을 할당할 수 없습니다.', + 'file_already_exists' => '이미 ":name"이 존재합니다.', + 'error_saving' => '":name" 파일 저장 오류', + 'error_creating_directory' => ':name 디렉토리 작성 오류', + 'invalid_file_extension'=>'올바르지 않은 파일 확장자: :invalid. 허가된 확장자는 :allowed 입니다.', + 'error_deleting' => '":name" 파일 삭제 오류', + 'delete_success' => ':count 개의 템플릿을 삭제했습니다.', + 'file_name_required' => '파일명 필드가 필요합니다.', + 'safe_mode_enabled' => '안전모드가 활성화 되었습니다.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => '웹사이트', + 'online' => '온라인', + 'maintenance' => '유지보수중', + 'manage_themes' => '테마관리', + 'customize_theme' => '테마변경' + ] + ], + 'theme' => [ + 'not_found_name' => "':name' 테마를 찾을 수 없습니다.", + 'by_author' => 'By :name', + 'active' => [ + 'not_set' => "활성 테마가 설정되어 있지 않습니다.", + 'not_found' => '활성 테마를 발견할 수 없습니다.', + ], + 'edit' => [ + 'not_set' => "편집 테마가 설정되어있지 않습니다.", + 'not_found' => "편집 테마를 발견할 수 없습니다.", + 'not_match' => "접근하려는 오브젝트는 편집 테마에 속할 수 없습니다. 페이지를 다시 로드해주세요.", + ], + 'settings_menu' => '프론트엔드 테마', + 'settings_menu_description' => '설치된 테마와 활성 테마 목록의 미리보기.', + 'default_tab' => '속성', + 'name_label' => '이름', + 'name_create_placeholder' => '신규 테마명', + 'author_label' => '작성자', + 'author_placeholder' => '개인/회사 이름', + 'description_label' => '설명', + 'description_placeholder' => '테마 설명', + 'homepage_label' => '홈페이지', + 'homepage_placeholder' => '웹사이트 URL', + 'code_label' => '코드', + 'code_placeholder' => '배포를 위한 고유한 코드', + 'preview_image_label' => '이미지 미리보기', + 'preview_image_placeholder' => '테마 미리보기 이미지 경로', + 'dir_name_label' => '디렉토리 이름', + 'dir_name_create_label' => '목표 테마 디렉토리', + 'theme_label' => '테마', + 'theme_title' => '테마목록', + 'activate_button' => '활성화', + 'active_button' => '활성화', + 'customize_theme' => '테마 변경', + 'customize_button' => '테마변경', + 'duplicate_button' => '테마복사', + 'duplicate_title' => '테마 복사', + 'duplicate_theme_success' => '테마가 복사되었습니다!', + 'manage_button' => '테마관리', + 'manage_title' => '테마 관리', + 'edit_properties_title' => '속성 변경', + 'edit_properties_button' => '속성변경', + 'save_properties' => '속성 저장', + 'import_button' => '가져오기', + 'import_title' => '테마 가져오기', + 'import_theme_success' => '테마 가져오기가 완료되었습니다!', + 'import_uploaded_file' => '테마 보관 파일', + 'import_overwrite_label' => '현재 파일 덮어쓰기', + 'import_overwrite_comment' => '없는 파일판 가져오기 원할경우 체크 해제', + 'import_folders_label' => '폴더목록', + 'import_folders_comment' => '가져오기 원하는 테마 폴더를 선택하세요.', + 'export_button' => '내보내기', + 'export_title' => '테마 내보내기', + 'export_folders_label' => '폴더목록', + 'export_folders_comment' => '내보내기 원하는 테마 폴더를 선택하세요.', + 'delete_button' => '삭제', + 'delete_confirm' => '이 테마를 삭제하시겠습니까? 되돌릴 수 없습니다!', + 'delete_active_theme_failed' => '활성 테마는 삭제할 수 없습니다. 다른 테마를 활성상태로 변경하세요.', + 'delete_theme_success' => '테마가 삭제되었습니다!', + 'create_title' => '테마 생성', + 'create_button' => '생성', + 'create_new_blank_theme' => '신규 테마 생성', + 'create_theme_success' => '테마가 생성되었습니다!', + 'create_theme_required_name' => '테마 이름을 설정하세요.', + 'new_directory_name_label' => '테마 디렉토리', + 'new_directory_name_comment' => '복제된 테마를 위한 신규 디렉토리 이름을 설정하세요.', + 'dir_name_invalid' => '디렉토리 이름은 오직 숫자, 알파벳, 언더스코어와 하이픈(_,-)만 가능합니다.', + 'dir_name_taken' => '원하는 디렉토리가 이미 있습니다.', + 'find_more_themes' => '테마 더 찾아보기', + 'saving' => '테마를 저장하는 중입니다...', + 'return' => '테마 목록으로 돌아가기' + ], + 'maintenance' => [ + 'settings_menu' => '유지보수모드', + 'settings_menu_description' => '유지보수모드 페이지의 설정과 변경을 합니다.', + 'is_enabled' => '유지보수모드 활성화', + 'is_enabled_comment' => '유지보수모드일때 웹사이트 방문자가 보는 페이지를 선택해주세요.', + 'hint' => '유지보수모드는 백엔드에 로그인하지않은 방문자에 유지보수안내 페이지를 표시합니다.' + ], + 'page' => [ + 'not_found_name' => "':name' 페이지가 없습니다.", + 'not_found' => [ + 'label' => "페이지를 찾을 수 없습니다.", + 'help' => "요청 페이지를 찾을 수 없었습니다.", + ], + 'custom_error' => [ + 'label' => "페이지 오류", + 'help' => "죄송합니다. 뭔가 문제가 있는것 같아 페이지를 표시할 수 없습니다.", + ], + 'menu_label' => '페이지', + 'unsaved_label' => '저장안한 페이지', + 'no_list_records' => '페이지를 찾을 수 없습니다', + 'new' => '신규 페이지', + 'invalid_url' => '올바르지 않은 URL형식。URL은 슬래쉬(/)로 시작 숫자, 알파벳, ._-[]:?|/+*^$ 로 구성됩니다.', + 'delete_confirm_multiple' => '선택하신 페이지 전체를 정말로 삭제하시겠습니까?', + 'delete_confirm_single' => '선택하신 페이지를 삭제하시겠습니까?', + 'no_layout' => '-- 레이아웃 없음 --', + 'cms_page' => 'CMS 페이지', + 'title' => '페이지 제목', + 'url' => '페이지 URL', + 'file_name' => '페이지 파일 이름' + ], + 'layout' => [ + 'not_found_name' => "':name' 레이아웃이 없습니다.", + 'menu_label' => '레이아웃', + 'unsaved_label' => '저장하지 않은 레이아웃', + 'no_list_records' => '레이아웃을 발견할 수 없습니다', + 'new' => '신규 레이아웃', + 'delete_confirm_multiple' => '선택하신 레이아웃 전체를 정말로 삭제하시겠습니까?', + 'delete_confirm_single' => '선택하신 레이아웃을 삭제하시겠씁니까?', + ], + 'partial' => [ + 'not_found_name' => "':name' 파셜이 없습니다.", + 'invalid_name' => "올바르지 않은 파셜명: :name", + 'menu_label' => '파셜', + 'unsaved_label' => '저장하지 않은 파셜', + 'no_list_records' => '파셜을 발견할 수 없습니다', + 'delete_confirm_multiple' => '선택하신 파셜 전체를 정말로 삭제하시겠습니까?', + 'delete_confirm_single' => '선택하신 파셜을 삭제하시겠습니까?', + 'new' => '신규 파셜', + ], + 'content' => [ + 'not_found_name' => "':name' 콘텐츠 파일이 없습니다.", + 'menu_label' => '콘텐츠', + 'unsaved_label' => '저장하지 않은 콘텐츠', + 'no_list_records' => '콘텐츠 파일을 발견할 수 없습니다', + 'delete_confirm_multiple' => '선택하신 콘텐츠/디렉토리 전체를 정말로 삭제하시겠습니까?', + 'delete_confirm_single' => '선택하신 콘첸츠 파일을 삭제하시겠습니까?', + 'new' => '신규 콘텐츠 파일', + ], + 'ajax_handler' => [ + 'invalid_name' => "올바르지 않은 Ajax핸들러이름: :name", + 'not_found' => "':name' Ajax핸들러를 찾을 수 없습니다.", + ], + 'cms' => [ + 'menu_label' => "CMS", + ], + 'sidebar' => [ + 'add' => '추가', + 'search' => '검색...', + ], + 'editor' => [ + 'settings' => '설정', + 'title' => '타이틀', + 'new_title' => '신규 페이지 타이틀', + 'url' => 'URL', + 'filename' => '파일명', + 'layout' => '레이아웃', + 'description' => '설명', + 'preview' => '미리보기', + 'meta' => '메타', + 'meta_title' => '메타 타이틀', + 'meta_description' => '메타 설명', + 'markup' => '마크업', + 'code' => '코드', + 'content' => '콘텐츠', + 'hidden' => '표시안함', + 'hidden_comment' => '프론트엔드에 페이지를 표시하지 않습니다. 백엔드에서 보기/편집이 가능합니다.', + 'enter_fullscreen' => '전체화면모드', + 'exit_fullscreen' => '전체화면모드 해제', + 'open_searchbox' => '검색 열기', + 'close_searchbox' => '검색 닫기', + 'open_replacebox' => '교체 열기', + 'close_replacebox' => '교체 닫기' + ], + 'asset' => [ + 'menu_label' => "자산", + 'unsaved_label' => '저장하지 않은 자산', + 'drop_down_add_title' => '추가...', + 'drop_down_operation_title' => '동작...', + 'upload_files' => '파일 업로드', + 'create_file' => '파일 작성', + 'create_directory' => '디렉토리 작성', + 'directory_popup_title' => '신규 디렉토리', + 'directory_name' => '디렉토리명', + 'rename' => '이름변경', + 'delete' => '삭제', + 'move' => '이동', + 'select' => '선택', + 'new' => '신규 파일', + 'rename_popup_title' => '이름변경', + 'rename_new_name' => '새 이름', + 'invalid_path' => '경로는 숫자, 알파벳, 공백, ._-/로 구성되어야 합니다.', + 'error_deleting_file' => ':name 파일 삭제 오류', + 'error_deleting_dir_not_empty' => ':name 디렉토리 삭제 오류. 디렉토리가 비어있지 않습니다.', + 'error_deleting_dir' => ':name 디렉토리 삭제 오류.', + 'invalid_name' => '이름은 숫자, 알파벳, 공백, ._-로 구성되어야 합니다.', + 'original_not_found' => '본래의 파일/디렉토리를 발견할 수 없습니다', + 'already_exists' => '이 이름의 파일/디렉토리가 이미 존재합니다.', + 'error_renaming' => '파일/디렉토리 이름변경 오류', + 'name_cant_be_empty' => '이름은 공백으로만 할 수 없습니다', + 'too_large' => '업로드 파일이 너무 큽니다. 파일 사이즈는 최대 :max_size 입니다.', + 'type_not_allowed' => '허가된 파일타입은 :allowed_types 입니다.', + 'file_not_valid' => '파일이 올바르지 않습니다.', + 'error_uploading_file' => '파일 업로드 오류: ":name"', + 'move_please_select' => '선택해 주세요', + 'move_destination' => '목표 디렉토리', + 'move_popup_title' => '자산 이동', + 'move_button' => '이동', + 'selected_files_not_found' => '선택한 파일이 존재하지 않습니다.', + 'select_destination_dir' => '이동 목적지 디렉토리를 선택해주세요.', + 'destination_not_found' => '이동 목적지 디렉토리가 존재하지 않습니다.', + 'error_moving_file' => ':file 파일 이동 오류', + 'error_moving_directory' => ':dir 디렉토리 이동 오류', + 'error_deleting_directory' => ':dir 디렉토리 삭제 오류', + 'no_list_records' => '파일을 발견할 수 없습니다', + 'delete_confirm' => '선택한 파일이나 폴더를 삭제하시겠습니까?', + 'path' => '경로', + ], + 'component' => [ + 'menu_label' => "컴포넌트", + 'unnamed' => "이름없음", + 'no_description' => "설명없음", + 'alias' => "별칭", + 'alias_description' => "페이지나 레이아웃 코드에서 사용하는 고유 컴포넌트 이름.", + 'validation_message' => "알파벳, 숫자, 언더스코어(_)로 구성한 컴포넌트 별칭이 필요합니다. 별칭은 알파벳으로 시작해야 합니다.", + 'invalid_request' => "컴포넌트 데이터가 올바르지 않아서 템플릿을 저장할 수 없습니다.", + 'no_records' => '컴포넌트가 없습니다.', + 'not_found' => "':name' 컴포넌트를 발견할 수 없습니다.", + 'method_not_found' => "':name' 컴포넌트는 ':method' 메소드를 가지고있지 않습니다.", + ], + 'template' => [ + 'invalid_type' => "알수없는 템플릿 타입", + 'not_found' => "요청한 템플릿이 없습니다.", + 'saved'=> "템플릿을 저장합니다.", + 'no_list_records' => '템플릿을 찾을 수 없습니다', + 'delete_confirm' => '선택한 템플릿을 삭제하시겠습니까?', + 'order_by' => '정렬방법' + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => '콘텐츠 관리', + 'manage_assets' => '자산 관리', + 'manage_pages' => '페이지 관리', + 'manage_layouts' => '레이아웃 관리', + 'manage_partials' => '파셜 관리', + 'manage_themes' => '테마 관리', + ], + 'theme_log' => [ + 'hint' => '백엔드에서 관리자에 의해 변경된 테마의 변경사항에 대한 로그를 표시합니다.', + 'menu_label' => '테마 로그', + 'menu_description' => '활성 테마 변경 표시', + 'empty_link' => '테마 로그 비우기', + 'empty_loading' => '테마 로그 비우는 중...', + 'empty_success' => '테마 로그를 비웠습니다', + 'return_link' => '테마 로그로 돌아가기', + 'id' => 'ID', + 'id_label' => '로그 ID', + 'created_at' => '날짜 & 시간', + 'user' => '유저', + 'type' => '타입', + 'type_create' => '생성', + 'type_update' => '변경', + 'type_delete' => '삭제', + 'theme_name' => '테마명', + 'theme_code' => '테마코드', + 'old_template' => '템플릿(이전)', + 'new_template' => '템플릿(신규)', + 'template' => '템플릿', + 'diff' => '변경점', + 'old_value' => '이전 값', + 'new_value' => '신규 값', + 'preview_title' => '템플릿 변경', + 'template_updated' => '템플릿이 변경되었습니다', + 'template_created' => '템플릿이 생성되었습니다', + 'template_deleted' => '템플릿이 삭제되었습니다', + ], +]; diff --git a/modules/cms/lang/lt/lang.php b/modules/cms/lang/lt/lang.php new file mode 100644 index 0000000..35120f9 --- /dev/null +++ b/modules/cms/lang/lt/lang.php @@ -0,0 +1,261 @@ + [ + 'invalid_file' => 'Netinkamas failo pavadinimas: :name. Failo pavadinimą gali sudaryti tik skaičiai, raidės, brūkšneliai bei taškai. Keletas pavyzdžių: puslapis.htm, puslapis, direktorija/puslapis, puslapis_2, naujas-puslapis', + 'invalid_property' => "Savybės ':name' negalima nustatyti", + 'file_already_exists' => "Failas pavadinimu ':name' jau yra.", + 'error_saving' => "Klaida išsaugant failą ':name'. Patikrinkite katalogo įrašymo nustatymus serveryje.", + 'error_creating_directory' => 'Nepavyko sukurti direktorijos :name. Patikrinkite katalogo įrašymo nustatymus serveryje.', + 'invalid_file_extension' => 'Netinkama failo galūnė: :invalid. Leistinos galūnės yra: :allowed.', + 'error_deleting' => "Nepavyko ištrinti šablono ':name'. Patikrinkite katalogo įrašymo nustatymus serveryje.", + 'delete_success' => 'Ištrinta šablonų: :count.', + 'file_name_required' => 'Failko pavadinimo laukelis yra būtinas.', + 'safe_mode_enabled' => 'Saugusis režimas šiuo metu įjungtas.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Tinklalapis', + 'online' => 'Įjungtas', + 'maintenance' => 'Aptarnavimo režime', + 'manage_themes' => 'Tvarkyti dizainus' + ] + ], + 'theme' => [ + 'not_found_name' => "Dizainas ':name' nerastas.", + 'active' => [ + 'not_set' => 'Aktyvusis dizainas yra nenustatytas.', + 'not_found' => 'Aktyvusis dizainas nerastas.' + ], + 'edit' => [ + 'not_set' => 'Redaguojamas dizainas nenustatytas.', + 'not_found' => 'Redaguojamas dizainas nerastas.', + 'not_match' => "Objektas, kurį bandote prieiti nepriklauso redaguojamam dizainui. Perkraukite puslapį." + ], + 'settings_menu' => 'Svetainės dizainas', + 'settings_menu_description' => 'Peržiūrėkite įdiegtų dizainų sąrašą ir pasirinkite aktyvųjį dizainą.', + 'default_tab' => 'Savybės', + 'name_label' => 'Pavadinimas', + 'name_create_placeholder' => 'Naujo dizaino pavadinimas', + 'author_label' => 'Autorius', + 'author_placeholder' => 'Asmuo arba įmonė', + 'description_label' => 'Aprašymas', + 'description_placeholder' => 'Dizaino aprašymas', + 'homepage_label' => 'Tinklalapis', + 'homepage_placeholder' => 'Svetainės URL', + 'code_label' => 'Kodas', + 'code_placeholder' => 'Unikalus dizaino kodas naudojamas platinant', + 'preview_image_label' => 'Demo paveiksliukas', + 'preview_image_placeholder' => 'Kelias į demo paveiksliuką.', + 'dir_name_label' => 'Direktorijos pavadinimas', + 'dir_name_create_label' => 'Kelias į dizaino direktoriją', + 'theme_label' => 'Dizainas', + 'theme_title' => 'Dizainai', + 'activate_button' => 'Aktyvuoti', + 'active_button' => 'Aktyvuoti', + 'customize_theme' => 'Modifikuoti Dizainą', + 'customize_button' => 'Modifikuoti', + 'duplicate_button' => 'Duplikuoti', + 'duplicate_title' => 'Duplikuoti dizainą', + 'duplicate_theme_success' => 'Dizainą duplikavome!', + 'manage_button' => 'Tvarkyti', + 'manage_title' => 'Tvarkyti dizainą', + 'edit_properties_title' => 'Dizainas', + 'edit_properties_button' => 'Redaguoti nustatymus', + 'save_properties' => 'Išsaugoti nustatymus', + 'import_button' => 'Importuoti', + 'import_title' => 'Importuoti dizainą', + 'import_theme_success' => 'Dizainą importavome!', + 'import_uploaded_file' => 'Dizaino archyvas', + 'import_overwrite_label' => 'Perrašyti esančius failus', + 'import_overwrite_comment' => 'Nuimkite varnelę jei norite įkelti tik naujus failus', + 'import_folders_label' => 'Katalogai', + 'import_folders_comment' => 'Pasirinkite katalogus, kuriuos norite importuoti', + 'export_button' => 'Eksportuoti', + 'export_title' => 'Eksportuoti dizainą', + 'export_folders_label' => 'Katalogai', + 'export_folders_comment' => 'Pasirinkite katalogus, kuriuos norite eksportuoti', + 'delete_button' => 'Trinti', + 'delete_confirm' => 'Ar tikrai norite ištrinti šį dizainą? Atstatyti nebus įmanoma!', + 'delete_active_theme_failed' => 'Negalime ištrinti aktyviojo dizaino. Priskirkite kitą dizainą kaip aktyvųjį ir bandykite dar kartą.', + 'delete_theme_success' => 'Dizainą ištrynėme!', + 'create_title' => 'Kurti dizainą', + 'create_button' => 'Kurti', + 'create_new_blank_theme' => 'Kurti naują tuščią dizainą', + 'create_theme_success' => 'Dizainas sukurtas!', + 'create_theme_required_name' => 'Nurodykite dizaino pavadinimą.', + 'new_directory_name_label' => 'Dizaino direktorija', + 'new_directory_name_comment' => 'Nurodykite naujos direktorijos pavadinimą duplikuojamam dizainui.', + 'dir_name_invalid' => 'Pavadinimą gali sudaryti tik skaičiai, Lotyniškos raidės bei simboliai: _-', + 'dir_name_taken' => 'Norimo dizaino direktorija jau egzistuoja.', + 'find_more_themes' => 'Raskite daugiau dizainų', + 'saving' => 'Išsaugome dizainą...', + 'return' => 'Grįžti į dizainų sąrašą' + ], + 'maintenance' => [ + 'settings_menu' => 'Aptarnavimo režimas', + 'settings_menu_description' => 'Konfigūruokite aptarnavimo režimo puslapį bei perjunkite režimo statusą.', + 'is_enabled' => 'Įjungti aptarnavimo režimą', + 'is_enabled_comment' => 'Parinkite kurį puslapį rodysite lankytojams aptarnavimo režimo metu.', + 'hint' => 'Aptarnavimo režimo metu lankytojams, kurie nėra prisijungę į administracinę zoną, bus rodomas Jūsų nustatytas puslapis.' + ], + 'page' => [ + 'not_found_name' => "Puslapis ':name' nerastas", + 'not_found' => [ + 'label' => 'Puslapis nerstas', + 'help' => 'Negalime rasti užklaustojo puslapio.' + ], + 'custom_error' => [ + 'label' => 'Puslapio klaida', + 'help' => "Atsiprašome, tačiau dėl galimų klaidų užklaustojo puslapio rodyti nepavyko." + ], + 'menu_label' => 'Puslapiai', + 'unsaved_label' => 'Neišsaugoti puslapiai', + 'no_list_records' => 'Puslapių nėra', + 'new' => 'Naujas puslapis', + 'invalid_url' => 'Netinkamas URL formatas. URL turėtų prasidėti simboliu / ir susidaryti iš skaitmenų, Lotyniškų raidžių bei šių simbolių: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Trinti pasirinktus puslapius?', + 'delete_confirm_single' => 'Trinti šį puslapį?', + 'no_layout' => '-- be šablono --', + 'cms_page' => 'CMS puslapis', + 'title' => 'Puslapio pavadinimas', + 'url' => 'Puslapio URL', + 'file_name' => 'Puslapio failo pavadinimas' + ], + 'layout' => [ + 'not_found_name' => "Šablonas ':name' nerastas", + 'menu_label' => 'Šablonai', + 'unsaved_label' => 'Neišsaugoti šablonai', + 'no_list_records' => 'Šablonų nėra', + 'new' => 'Naujas šablonas', + 'delete_confirm_multiple' => 'Trinti pasirinktus šablonus?', + 'delete_confirm_single' => 'Trinti šį šabloną?' + ], + 'partial' => [ + 'not_found_name' => "Priedėlis ':name' nerastas.", + 'invalid_name' => 'Netinkamas priedėlio pavadinimas: :name.', + 'menu_label' => 'Priedėliai', + 'unsaved_label' => 'Neišsaugoti priedėliai', + 'no_list_records' => 'Priedėlių nėra', + 'delete_confirm_multiple' => 'Trinti pasirinktus priedėlius?', + 'delete_confirm_single' => 'Trinti šį priedėlį?', + 'new' => 'Naujas priedėlis' + ], + 'content' => [ + 'not_found_name' => "Turinio failas ':name' nerastas.", + 'menu_label' => 'Turinys', + 'unsaved_label' => 'Neišsaugotas turinys', + 'no_list_records' => 'Turinio failų nėra', + 'delete_confirm_multiple' => 'Trinti pasirinktus turinio failus ar direktorijas?', + 'delete_confirm_single' => 'Trinti šį turinio failą?', + 'new' => 'Nauajs turinio failas' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Netinkamas AJAX tvarkiklis pavadinimas: :name.', + 'not_found' => "AJAX tvarkiklis ':name' nerastas." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Pridėti', + 'search' => 'Ieškoti...' + ], + 'editor' => [ + 'settings' => 'Nustatymai', + 'title' => 'Pavadinimas', + 'new_title' => 'Naujas puslapio pavadinimas', + 'url' => 'URL', + 'filename' => 'Failo pavadinimas', + 'layout' => 'Šablonas', + 'description' => 'Aprašymas', + 'preview' => 'Peržiūra', + 'meta' => 'Meta', + 'meta_title' => 'Meta Pavadinimas', + 'meta_description' => 'Meta Aprašymas', + 'markup' => 'Aprašas (markup)', + 'code' => 'Kodas', + 'content' => 'Turinys', + 'hidden' => 'Paslėptas', + 'hidden_comment' => 'paslėptus puslapius gali matyti tik į administracinę zoną prisijungę nariai.', + 'enter_fullscreen' => 'Eiti į pilno ekrano vaizdą', + 'exit_fullscreen' => 'Išeiti iš pilno ekrano vaizdo', + 'open_searchbox' => 'Atidaryti paieškos laukelį', + 'close_searchbox' => 'Uždaryti paieškos laukelį', + 'open_replacebox' => 'Atidaryti pakeitimo laukelį', + 'close_replacebox' => 'Uždaryti pakeitimo laukelį' + ], + 'asset' => [ + 'menu_label' => 'Aktyvai', + 'unsaved_label' => 'Neišsaugoti aktyvai', + 'drop_down_add_title' => 'Pridėti...', + 'drop_down_operation_title' => 'Veiksmas...', + 'upload_files' => 'Įkelti failus', + 'create_file' => 'Sukurti failą', + 'create_directory' => 'Sukurti direktoriją', + 'directory_popup_title' => 'Nauja direktorija', + 'directory_name' => 'Direktorijos pavadinimas', + 'rename' => 'Pervadinti', + 'delete' => 'Ištrinti', + 'move' => 'Perkelti', + 'select' => 'Pasirinkti', + 'new' => 'Naujas failas', + 'rename_popup_title' => 'Pervadinti', + 'rename_new_name' => 'Naujas pavadinimas', + 'invalid_path' => 'Kelią gali sudaryti tik skaitmenys, Lotyniškos raidės, tarpeliai bei šie simboliai: ._-/', + 'error_deleting_file' => 'Klaida trinant failą :name.', + 'error_deleting_dir_not_empty' => 'Klaida trinant direktoriją :name. Direktorija nėra tuščia.', + 'error_deleting_dir' => 'Klaida trinant direktoriją :name.', + 'invalid_name' => 'Pavadinimą gali sudaryti tik skaitmenys, Lotyniškos raidės, tarpeliai bei šie simboliai: ._-', + 'original_not_found' => 'Nerandame pirminio failo ar direktorijos', + 'already_exists' => 'Failas ar direktorija šiuo pavadinimu jau yra', + 'error_renaming' => 'Klaida pervadinant failą ar direktoriją', + 'name_cant_be_empty' => 'Pavadinimas negali būti tuščias', + 'too_large' => 'Įkeliamas failas yra per didelis. Leistinas failo dydis yra :max_size', + 'type_not_allowed' => 'Tik šie failų tipai yra leistini: :allowed_types', + 'file_not_valid' => 'Netinkamas failas', + 'error_uploading_file' => "Klaida įkeliant failą ':name': :error", + 'move_please_select' => 'prašome pasirinkti', + 'move_destination' => 'Direktorija', + 'move_popup_title' => 'Perkelti aktyvus', + 'move_button' => 'Perkelti', + 'selected_files_not_found' => 'Neradome pasirinktų failų', + 'select_destination_dir' => 'Pasirinkite direktoriją', + 'destination_not_found' => 'Direktorijos neradome', + 'error_moving_file' => 'Klaida perkeliant failą :file', + 'error_moving_directory' => 'Klaida perkeliant direktoriją :dir', + 'error_deleting_directory' => 'Klaida trinant pirminę direktoriją :dir', + 'no_list_records' => 'Failų nėra', + 'delete_confirm' => 'Trinti pasirinktus failus ar direktorijas?', + 'path' => 'Kelias' + ], + 'component' => [ + 'menu_label' => 'Komponentai', + 'unnamed' => 'Neužvadintas', + 'no_description' => 'Nėra aprašymo', + 'alias' => 'Užvadintas', + 'alias_description' => 'Unikalus vardas skiriamas šiam komponentui kai naudojate jį puslapyje ar šablone.', + 'validation_message' => 'Komponentų užvadiniai yra būtini ir gali susidaryti tik iš Lotyniškų raidžių, skaitmenų bei _. Užvadiniai turi prasidėti Lotyniška reide.', + 'invalid_request' => 'Šablono išsaugoti nepavyko dėl netinkamų komponento savybių.', + 'no_records' => 'Komponentų nėra', + 'not_found' => "Komponento ':name' neradome.", + 'method_not_found' => "Komponente ':name' nėra metodo ':method'." + ], + 'template' => [ + 'invalid_type' => 'Nežinomas šablono tipas.', + 'not_found' => 'Šablonas nerastas.', + 'saved' => 'Šablonas išsaugotas.', + 'no_list_records' => 'Įrašų nėra', + 'delete_confirm' => 'Ištrinti pasirinktus šablonus?', + 'order_by' => 'Rūšiuoti pagal' + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Tvarkyti svetainės turinio failus', + 'manage_assets' => 'Tvarkyti svetainės aktyvus - paveiksliukus, JavaScript failus, CSS failus', + 'manage_pages' => 'Kurti, redaguoti ir trinti svetainės puslapius', + 'manage_layouts' => 'Kurti, redaguoti ir trinti CMS išvaizdos šablonus', + 'manage_partials' => 'Kurti, redaguoti ir trinti CMS priedėlius', + 'manage_themes' => 'Aktyvuoti, deaktyvuoti bei konfigūruoti CMS dizainus', + ], +]; diff --git a/modules/cms/lang/lv/lang.php b/modules/cms/lang/lv/lang.php new file mode 100644 index 0000000..cb895d3 --- /dev/null +++ b/modules/cms/lang/lv/lang.php @@ -0,0 +1,242 @@ + [ + 'invalid_file' => 'Nederīgs faila nosaukums: :name. Failu nosaukumi drīkst sastāvēt tikai no cipariem/burtiem, apakšsvītrām, šķērssvītrām un punktiem. Daži pareizi piemēri: lapa.htm, lapa, direktorija/lapa', + 'invalid_property' => "Īpašuma nosaukums ':name' nevar tikt iestatīts", + 'file_already_exists' => "Fails ':name' jau eksistē.", + 'error_saving' => "Kļūda saglabājot failu ':name'. Lūdzu pārbaudiet rakstīšanas tiesības.", + 'error_creating_directory' => 'Kļūda izveidojot direktoriju :name. Lūdzu pārbaudiet rakstīšanas tiesības.', + 'invalid_file_extension'=>'Nederīgs faila tips: :invalid. Atļautie tipi: :allowed.', + 'error_deleting' => "Kūda dzēšot veidnes failu ':name'. Lūdzu pārbaudiet rakstīšanas tiesības.", + 'delete_success' => 'Tika veiksmīgi izdzēstas veidnes: :count.', + 'file_name_required' => 'Faila nosaukuma lauks ir obligāts.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'online' => 'online', + 'maintenance' => 'atkopšana', + ] + ], + 'theme' => [ + 'not_found_name' => "Tēma ':name' netika atrasta.", + 'active' => [ + 'not_set' => 'Aktīvā tēma netika iestatīta.', + 'not_found' => 'Aktīvā tēma netika atrasta.' + ], + 'edit' => [ + 'not_set' => 'Labotā tēma netika iestatīta.', + 'not_found' => 'Labotā tēma netika atrasta.', + 'not_match' => "Objekts, kuru mēģinat labot nepieder tēmai, kuru šobrīd labojat. Lūdzu pārlādējiet lapu." + ], + 'settings_menu' => 'Front-end tēma', + 'settings_menu_description' => 'Priekšskatiet instalētās tēmas un izvēlieties aktīvo tēmu.', + 'default_tab' => 'Rekvizīti', + 'name_label' => 'Nosaukums', + 'name_create_placeholder' => 'Jaunas tēmas nosaukums', + 'author_label' => 'Autors', + 'author_placeholder' => 'Personas vai kompānijas nosaukums', + 'description_label' => 'Apraksts', + 'description_placeholder' => 'Tēmas apraksts', + 'homepage_label' => 'Mājaslapa', + 'homepage_placeholder' => 'Mājaslapas URL', + 'code_label' => 'Kods', + 'code_placeholder' => 'Unikāls kods šai tēmai, tiek lietots pārdošanai', + 'dir_name_label' => 'Direktorijas nosaukums', + 'dir_name_create_label' => 'Tēmas mērķdirektorija', + 'theme_label' => 'Tēma', + 'theme_title' => 'Tēmas', + 'activate_button' => 'Aktivizēt', + 'active_button' => 'Aktivizēt', + 'customize_theme' => 'Pielāgot tēmu', + 'customize_button' => 'Pielāgot', + 'duplicate_button' => 'Dublēt', + 'duplicate_title' => 'Dublēt tēmu', + 'duplicate_theme_success' => 'Tēmas dublēšana notika veiksmīgi!', + 'manage_button' => 'Pārvaldīt', + 'manage_title' => 'Pārvaldīt tēmu', + 'edit_properties_title' => 'Tēma', + 'edit_properties_button' => 'Labot iestatījumus', + 'save_properties' => 'Saglabāt iestatījumus', + 'import_button' => 'Importēt', + 'import_title' => 'Importēt tēmu', + 'import_theme_success' => 'Tēmas importēšanas notika veiksmīgi!', + 'import_uploaded_file' => 'Tēmas arhivētais fails', + 'import_overwrite_label' => 'Pārrakstīt esošos failus', + 'import_overwrite_comment' => 'Izņemiet ķeksi, lai importētu tikai jaunos failus', + 'import_folders_label' => 'Mapes', + 'import_folders_comment' => 'Lūdzu izvēlieties tēmas mapes, kuras vēlaties importēt', + 'export_button' => 'Eksportēt', + 'export_title' => 'Eksportēt tēmu', + 'export_folders_label' => 'Mapes', + 'export_folders_comment' => 'Lūdzu izvēlieties tēmas mapes, kuras vēlaties eksportēt', + 'delete_button' => 'Dzēst', + 'delete_confirm' => 'Vai esat pārliecināts, ka vēlaties dzēst šo tēmu? Izmaiņas nevarēs atcelt!', + 'delete_active_theme_failed' => 'Aktīvo tēmu nevar idzēst, vispirms padariet citu tēmu par aktīvo.', + 'delete_theme_success' => 'Tēma veiksmīgi izdzēsta!', + 'create_title' => 'Izveidot tēmu', + 'create_button' => 'Izveidot', + 'create_new_blank_theme' => 'Izveidot jaunu tukšu tēmu', + 'create_theme_success' => 'Tēma tika veiksmīgi izveidota!', + 'create_theme_required_name' => 'Lūdzu norādiet tēmas nosaukumu.', + 'new_directory_name_label' => 'Tēmas mape', + 'new_directory_name_comment' => 'Norādiet mapi priekš dublētās tēmas.', + 'dir_name_invalid' => 'Nosaukums drīkst saturēt tikai skaitļus, Latīņu burtus un sekojošos simbolus: _-', + 'dir_name_taken' => 'Izvēlētā tēmas mape jau pastāv.', + 'find_more_themes' => 'Atrodast vairāk tēmas', + 'saving' => 'Saglabājam tēmu...', + 'return' => 'Atgriezties tēmu sarakstā', + ], + 'maintenance' => [ + 'settings_menu' => 'Apkopes režīms', + 'settings_menu_description' => 'Konfigurējiet apkopes režīma lapu un pielāgojiet iestatījumus.', + 'is_enabled' => 'Iespējot apkopes režīmu', + 'is_enabled_comment' => 'Kad aktivizēts mājaslapas apmeklētāji redzēs zemāk izvēlēto lapu.' + ], + 'page' => [ + 'not_found_name' => "Lapa ':name' netika atrasta", + 'not_found' => [ + 'label' => 'Lapa nav atrasta', + 'help' => 'Pieprasītā lapa nav atrasta.' + ], + 'custom_error' => [ + 'label' => 'Lapas kļūda', + 'help' => "Mums žēl, bet kaut kas nogāja greizi un lapa nevar tikt attēlota." + ], + 'menu_label' => 'Lapas', + 'unsaved_label' => 'Nesaglabāta lapa(s)', + 'no_list_records' => 'Nav lapu', + 'new' => 'Jauna lapa', + 'invalid_url' => 'Nederīgs URL formāts. URL vajadzētu sākties ar šķērssvītras simbolu un tā var saturēt skaitļus, Latīņu burtus un sekojošos simbolus: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Vai tiešām vēlaties idzēst izvēlētās lapas?', + 'delete_confirm_single' => 'Vai tiešām vēlaties dzēst šo lapu?', + 'no_layout' => '-- bez izkārtojuma --' + ], + 'layout' => [ + 'not_found_name' => "Izkārtojums ':name' netika atrasts", + 'menu_label' => 'Izkārtojumi', + 'unsaved_label' => 'Nesaglabāts izkārtojums(i)', + 'no_list_records' => 'Nav izkārtojumu', + 'new' => 'Jauns izkārtojums', + 'delete_confirm_multiple' => 'Vai tiešām vēlaties izdzēst izvēlētos izkārtojumus?', + 'delete_confirm_single' => 'Vai tiešām vēlaties dzēst šo izkārtojumu?' + ], + 'partial' => [ + 'not_found_name' => "Daļa ':name' netika atrasta.", + 'invalid_name' => 'Nederīgs daļas nosaukums: :name.', + 'menu_label' => 'Daļas', + 'unsaved_label' => 'Nesaglabāta daļa(s)', + 'no_list_records' => 'Daļas nav atrastas', + 'delete_confirm_multiple' => 'Vai tiešām vēlaties izdzēst izvēlētās daļas?', + 'delete_confirm_single' => 'Vai tiešām vēlaties dzēst šo daļu?', + 'new' => 'Jauna daļa' + ], + 'content' => [ + 'not_found_name' => "Satura fails ':name' netika atrasts.", + 'menu_label' => 'Saturs', + 'unsaved_label' => 'Nesaglabāts saturs', + 'no_list_records' => 'Nav satura failu', + 'delete_confirm_multiple' => 'Vai tiešām vēlaties izdzēst izbēlētos satura failus vai mapes?', + 'delete_confirm_single' => 'Vai tiešām vēlaties dzēst šo satura failu?', + 'new' => 'Jauns satura fails' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Nederīgs AJAX handler nosaukums: :name.', + 'not_found' => "AJAX handler ':name' netika atrasts." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Pievienot', + 'search' => 'Meklēt...' + ], + 'editor' => [ + 'settings' => 'Iestatījumi', + 'title' => 'Virsraksts', + 'new_title' => 'Jauns lapas virsraksts', + 'url' => 'URL', + 'filename' => 'Faila nosaukums', + 'layout' => 'Izkārtojums', + 'description' => 'Apraksts', + 'preview' => 'Priekšskatījums', + 'meta' => 'Meta', + 'meta_title' => 'Meta Virsraksts', + 'meta_description' => 'Meta Apraksts', + 'markup' => 'Markup', + 'code' => 'Code', + 'content' => 'Saturs', + 'hidden' => 'Paslēpt', + 'hidden_comment' => 'Paslēptās lapas ir pieejamas tikai autorizētiem back-end lietotājiem.', + 'enter_fullscreen' => 'Pilnkekrāna režīms', + 'exit_fullscreen' => 'Iziet no pilnekrāna režīma' + ], + 'asset' => [ + 'menu_label' => 'Papildinājumi', + 'unsaved_label' => 'Nesaglabāts papildinājums(i)', + 'drop_down_add_title' => 'Pievienot...', + 'drop_down_operation_title' => 'Daarbība...', + 'upload_files' => 'Augšupielādēt failu(us)', + 'create_file' => 'Izveidot failu', + 'create_directory' => 'Izveidot mapi', + 'directory_popup_title' => 'Jauna mape', + 'directory_name' => 'Mapes nosaukums', + 'rename' => 'Pārsaukt', + 'delete' => 'Dzēst', + 'move' => 'Pārvietot', + 'select' => 'Izvēlēties', + 'new' => 'Jauns fails', + 'rename_popup_title' => 'Pārsaukt', + 'rename_new_name' => 'Jauns nosaukums', + 'invalid_path' => 'Ceļš var saturēt tikai skaitļus, Latīņu burtus, atstarpes un sekojošos simbolus: ._-/', + 'error_deleting_file' => 'Kļūda dzēšot failu :name.', + 'error_deleting_dir_not_empty' => 'Kļūda dzēšot mapi :name. Mape nav tukša.', + 'error_deleting_dir' => 'Kļūda dzēšot failu :name.', + 'invalid_name' => 'Nosaukums var saturēt tikai skaitļus, Latīņu burtus, atstarpes un sekojošos simbolus: ._-', + 'original_not_found' => 'Oriģinālais fails vai mape netika atrasts', + 'already_exists' => 'Fails vai mape ar šo nosaukumu jau eksistē', + 'error_renaming' => 'Kļūda pārdēvējot failu vai mapi', + 'name_cant_be_empty' => 'Nosaukums nevar būt tukšums', + 'too_large' => 'Augšupielādētais fails ir pārāk liels. Maksimālais atļautais faila izmērs :max_size', + 'type_not_allowed' => 'Tikai sekojošie failu tipi ir atļauti: :allowed_types', + 'file_not_valid' => 'Fails nav derīgs', + 'error_uploading_file' => "Kļūda augšupielādējot failu ':name': :error", + 'move_please_select' => 'lūdzu izvēlieties', + 'move_destination' => 'Mērķa mape', + 'move_popup_title' => 'Pārvietot papildinājumus', + 'move_button' => 'Pārvietot', + 'selected_files_not_found' => 'Izvēlētie faili nav atrasti', + 'select_destination_dir' => 'Lūdzu izvēlieties mērķdirektoriju', + 'destination_not_found' => 'Mērķdirektorija nav atrasta', + 'error_moving_file' => 'Kļūda pārvietojot failu :file', + 'error_moving_directory' => 'Kļūda pārvietojot mapi :dir', + 'error_deleting_directory' => 'Kļūda dzēšot oriģinālo mapi :dir', + 'path' => 'Ceļš' + ], + 'component' => [ + 'menu_label' => 'Komponenti', + 'unnamed' => 'Nenosaukts', + 'no_description' => 'Apraksts nav norādīts', + 'alias' => 'Saīsinājums', + 'alias_description' => 'Unikāls nosaukums šim komponentam kad tas tiek izmantots lapas vai izkārtojuma kodā.', + 'validation_message' => 'Komponenta saīsinājums ir obligāts un var sastāvēt tikai no Latīņu simboliem, skaitļiem un apakšsvītrām. Saīsinājumiem vajadzētu sākties ar Latīņu simbolu.', + 'invalid_request' => 'The template cannot be saved because of invalid component data.', + 'no_records' => 'Nav komponentu', + 'not_found' => "Komponents ':name' netika atrasts.", + 'method_not_found' => "Komponents ':name' nesatur metodi ':method'." + ], + 'template' => [ + 'invalid_type' => 'Nezināms veidnes tips.', + 'not_found' => 'Pieprasītā veidne nav atrasta.', + 'saved'=> 'Fails tika veiksmīgi saglabāts.' + ], + 'permissions' => [ + 'name' => 'Cms', + 'manage_content' => 'Pārvaldīt saturu', + 'manage_assets' => 'Pārvaldīt papildinājumus', + 'manage_pages' => 'Pārvaldīt lapas', + 'manage_layouts' => 'Pārvaldīt izkārtojumus', + 'manage_partials' => 'Pārvaldīt daļas', + 'manage_themes' => 'Pārvaldīt tēmas', + ], +]; diff --git a/modules/cms/lang/nb-no/lang.php b/modules/cms/lang/nb-no/lang.php new file mode 100644 index 0000000..c0d4416 --- /dev/null +++ b/modules/cms/lang/nb-no/lang.php @@ -0,0 +1,250 @@ + [ + 'invalid_file' => 'Ugyldig filnavn: :name. Filnavn kan kun inneholde alfanumeriske tegn, understrek, bindestrek og punktum. Eksempel: page.htm, page, subdirectory/page', + 'invalid_property' => "Egenskapen ':name' kan ikke settes", + 'file_already_exists' => "Filen ':name' eksisterer allerede.", + 'error_saving' => "Kunne ikke lagre filen ':name'. Vennligst sjekk skriverettigheter på serveren.", + 'error_creating_directory' => 'Kunne ikke opprette mappen :name. Vennligst sjekk skriverettigheter på serveren.', + 'invalid_file_extension' => 'Ugyldig filtype: :invalid. Tillatte filtyper er: :allowed.', + 'error_deleting' => "Kunne ikke slette filen ':name'. Vennligst sjekk skriverettigheter på serveren.", + 'delete_success' => 'Templates som ble slettet: :count.', + 'file_name_required' => 'Filnavnfeltet er obligatorisk.', + 'safe_mode_enabled' => 'Sikkert modus er aktivert.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Website', + 'online' => 'Online', + 'maintenance' => 'Vedlikeholdsmodus', + 'manage_themes' => 'Administrer temaer', + ] + ], + 'theme' => [ + 'not_found_name' => "Tema ':name' ble ikke funnet.", + 'active' => [ + 'not_set' => 'Aktivt tema er ikke valgt.', + 'not_found' => 'Aktivt tema ikke funnet.' + ], + 'edit' => [ + 'not_set' => 'Redigeringstema er ikke valgt.', + 'not_found' => 'Redigeringstema ikke funnet.', + 'not_match' => "Objektet du prøver å åpne tilhører ikke temaet som endres. Vennligst oppdater siden." + ], + 'settings_menu' => 'Frontend tema', + 'settings_menu_description' => 'Forhåndsvis en liste over installerte temaer og velg et aktivt tema.', + 'default_tab' => 'Egenskaper', + 'name_label' => 'Navn', + 'name_create_placeholder' => 'Temanavn', + 'author_label' => 'Forfatter', + 'author_placeholder' => 'Person eller bedrift', + 'description_label' => 'Beskrivelse', + 'description_placeholder' => 'Temabeskrivelse', + 'homepage_label' => 'Hjemmeside', + 'homepage_placeholder' => 'Nettside-URL', + 'code_label' => 'Kode', + 'code_placeholder' => 'En unik kode som brukes for distribusjon', + 'dir_name_label' => 'Mappenavn', + 'dir_name_create_label' => 'Temaets mappenavn', + 'theme_label' => 'Tema', + 'theme_title' => 'Temaer', + 'activate_button' => 'Aktivér', + 'active_button' => 'Aktivér', + 'customize_theme' => 'Tilpass tema', + 'customize_button' => 'Tilpass', + 'duplicate_button' => 'Duplisér', + 'duplicate_title' => 'Duplisér tema', + 'duplicate_theme_success' => 'Temaet har blitt duplisert!', + 'manage_button' => 'Administrer', + 'manage_title' => 'Administrer tema', + 'edit_properties_title' => 'Tema', + 'edit_properties_button' => 'Endre egenskaper', + 'save_properties' => 'Lagre egenskaper', + 'import_button' => 'Importér', + 'import_title' => 'Importér tema', + 'import_theme_success' => 'Temaet har blitt importert!', + 'import_uploaded_file' => 'Temaets arkivfil', + 'import_overwrite_label' => 'Overskriv eksisterende filer', + 'import_overwrite_comment' => 'Fjern kryss for å kun importere nye filer', + 'import_folders_label' => 'Mapper', + 'import_folders_comment' => 'Vennligst velg mappene du vil importere', + 'export_button' => 'Eksportér', + 'export_title' => 'Eksportér tema', + 'export_folders_label' => 'Mapper', + 'export_folders_comment' => 'Vennligst velg mappene du vil eksportere', + 'delete_button' => 'Slett', + 'delete_confirm' => 'Vil du virkelig slette dette temaet? Handlingen kan ikke angres!', + 'delete_active_theme_failed' => 'Kan ikke slette det aktive temaet. Gjør et annet tema aktivt først.', + 'delete_theme_success' => 'Temaet har blitt slettet!', + 'create_title' => 'Opprett tema', + 'create_button' => 'Opprett', + 'create_new_blank_theme' => 'Lag et nytt blankt tema', + 'create_theme_success' => 'Temaet har blitt opprettet!', + 'create_theme_required_name' => 'Vennligst gi temaet et navn.', + 'new_directory_name_label' => 'Temamappe', + 'new_directory_name_comment' => 'Oppgi en ny mappe for det dupliserte temaet.', + 'dir_name_invalid' => 'Navnet kan kun inneholde tall, latinske bokstaver og følgende symbol: _-', + 'dir_name_taken' => 'Temamappen eksiterer allerede.', + 'find_more_themes' => 'Finn flere temaer på OctoberCMS Theme Marketplace', + 'saving' => 'Lagrer tema...', + 'return' => 'Tilbake til temaliste', + ], + 'maintenance' => [ + 'settings_menu' => 'Vedlikeholdsmodus', + 'settings_menu_description' => 'Konfigurer vedlikeholdsmodussiden og endre innstillinger.', + 'is_enabled' => 'Aktivér vedlikeholdsmodus', + 'is_enabled_comment' => 'Når aktivert, vil besøkende se følgende side:', + 'hint' => 'Vedlikeholdsmodus vil vise vedlikehodsmodussiden til besøkende som ikke er logget inn.', + ], + 'page' => [ + 'not_found_name' => "Siden ':name' ble ikke funnet", + 'not_found' => [ + 'label' => 'Side ikke funnet', + 'help' => 'Den forespurte siden ble ikke funnet.' + ], + 'custom_error' => [ + 'label' => 'Side-feil', + 'help' => "Noe gikk galt. Siden kan ikke vises." + ], + 'menu_label' => 'Sider', + 'unsaved_label' => 'Ulagrede sider', + 'no_list_records' => 'Ingen sider funnet', + 'new' => 'Ny side', + 'invalid_url' => 'Ugyldig URL-format. URL-en skal starte med skråstrek og kan inneholde tall, latinske bokstaver og følgende symbol: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Vil du virkelig slette valgte sider?', + 'delete_confirm_single' => 'Vil du virkelig slette denne siden?', + 'no_layout' => '-- ingen layout --' + ], + 'layout' => [ + 'not_found_name' => "Layouten ':name' ble ikke funnet", + 'menu_label' => 'Layouts', + 'unsaved_label' => 'Ulagrede layouts', + 'no_list_records' => 'Ingen layouts funnet', + 'new' => 'Ny layout', + 'delete_confirm_multiple' => 'Vil du virkelig slette valgte layouts?', + 'delete_confirm_single' => 'Vil du virkelig slette denne layout?' + ], + 'partial' => [ + 'not_found_name' => "Partial ':name' ble ikke funnet.", + 'invalid_name' => 'Ugyldig partial navn: :name.', + 'menu_label' => 'Partials', + 'unsaved_label' => 'Ulagrede partials', + 'no_list_records' => 'Ingen partials funnet', + 'delete_confirm_multiple' => 'Vil du virkelig slette valgte partials?', + 'delete_confirm_single' => 'Vil du virkelig slette denne partialen?', + 'new' => 'Ny partial' + ], + 'content' => [ + 'not_found_name' => "Innholdsfilen ':name' ble ikke funnet.", + 'menu_label' => 'Innhold', + 'unsaved_label' => 'Ulagret innhold', + 'no_list_records' => 'No content files found', + 'delete_confirm_multiple' => 'Vil du virkelig slette valgte innholdsfiler eller -mapper?', + 'delete_confirm_single' => 'Vil du virkelig slette denne innholdsfilen eller -mappen?', + 'new' => 'Ny innholdsfil' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Ugyldig AJAX handler navn: :name.', + 'not_found' => "AJAX handler ':name' ble ikke funnet." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Legg til', + 'search' => 'Søk...' + ], + 'editor' => [ + 'settings' => 'Innstillinger', + 'title' => 'Tittel', + 'new_title' => 'Ny side tittel', + 'url' => 'URL', + 'filename' => 'Filnavn', + 'layout' => 'Layout', + 'description' => 'Beskrivelse', + 'preview' => 'Forhåndsvis', + 'meta' => 'Meta', + 'meta_title' => 'Meta-tittel', + 'meta_description' => 'Meta-beskrivelse', + 'markup' => 'Markup', + 'code' => 'Kode', + 'content' => 'Innhold', + 'hidden' => 'Skjult', + 'hidden_comment' => 'Kun backend-brukere har tilgang til skjulte sider.', + 'enter_fullscreen' => 'Fullskjermmodus', + 'exit_fullscreen' => 'Avslutt fullskjermmodus', + 'open_searchbox' => 'Vis søkefelt', + 'close_searchbox' => 'Skjul søkefelt', + 'open_replacebox' => 'Vis erstatt-felt', + 'close_replacebox' => 'Skjul erstatt-felt' + ], + 'asset' => [ + 'menu_label' => 'Ressurser', + 'unsaved_label' => 'Ulagrede ressurser', + 'drop_down_add_title' => 'Legg til...', + 'drop_down_operation_title' => 'Handling...', + 'upload_files' => 'Last opp fil(er)', + 'create_file' => 'Opprett fil', + 'create_directory' => 'Opprett mappe', + 'directory_popup_title' => 'Ny mappe', + 'directory_name' => 'Mappenavn', + 'rename' => 'Nytt navn', + 'delete' => 'Slett', + 'move' => 'Flytt', + 'select' => 'Velg', + 'new' => 'Ny fil', + 'rename_popup_title' => 'Nytt navn', + 'rename_new_name' => 'Nytt navn', + 'invalid_path' => 'Mappestien kan kun inneholde tall, latinske bokstaver, mellomrom og følgende symbol: ._-/', + 'error_deleting_file' => 'Kunne ikke slette :name.', + 'error_deleting_dir_not_empty' => 'Kunne ikke slette :name. Mappen er ikke tom.', + 'error_deleting_dir' => 'Kunne ikke slette :name.', + 'invalid_name' => 'Navnet kan kun inneholde tall, latinske bokstaver, mellomrom og følgende symbol: ._-', + 'original_not_found' => 'Original fil eller mappe ikke funnet', + 'already_exists' => 'Fil eller mappe med samme navn eksiterer allerede', + 'error_renaming' => 'Kunne ikke gi filen eller mappen nytt navn', + 'name_cant_be_empty' => 'Navnet kan ikke være tomt', + 'too_large' => 'Opplastet fil er for stor. Maksimum filstørrelse er :max_size', + 'type_not_allowed' => 'Kun følgende filtyper er tillat: :allowed_types', + 'file_not_valid' => 'Filen er ugyldig', + 'error_uploading_file' => "Kunne ikke laste opp filen ':name': :error", + 'move_please_select' => 'velg', + 'move_destination' => 'Målmappe', + 'move_popup_title' => 'Flytt ressurser', + 'move_button' => 'Flytt', + 'selected_files_not_found' => 'Valgte filer ikke funnet', + 'select_destination_dir' => 'Vennligst velg en målmappe', + 'destination_not_found' => 'Målmappe ikke funnet', + 'error_moving_file' => 'Kunne ikke flytte filen :file', + 'error_moving_directory' => 'Kunne ikke flytte mappen :dir', + 'error_deleting_directory' => 'Kunne ikke slette original mappe :dir', + 'path' => 'Mål' + ], + 'component' => [ + 'menu_label' => 'Komponenter', + 'unnamed' => 'Navnløs', + 'no_description' => 'Ingen beskrivelse spesifisert', + 'alias' => 'Alias', + 'alias_description' => 'Et unikt navn gitt til komponenten for å benytte den i sider og layouts.', + 'validation_message' => 'Komponentaliaser kan kun inneholde latinske symboler, tall og understreker. Aliaser skal starte med et latinsk symbol.', + 'invalid_request' => 'Templaten kan ikke lagres på grunn av ugyldig komponentdata.', + 'no_records' => 'Ingen komponenter funnet', + 'not_found' => "Komponenten ':name' ble ikke funnet.", + 'method_not_found' => "Komponenten ':name' inneholder ikke en metode ':method'." + ], + 'template' => [ + 'invalid_type' => 'Ukjent template-type.', + 'not_found' => 'Forespurt template ikke funnet.', + 'saved' => 'Templaten har blitt lagret.' + ], + 'permissions' => [ + 'name' => 'Cms', + 'manage_content' => 'Administrer innholdsfiler', + 'manage_assets' => 'Administrer ressurser', + 'manage_pages' => 'Administrer sider', + 'manage_layouts' => 'Administrer layouts', + 'manage_partials' => 'Administrer partials', + 'manage_themes' => 'Administrer maler', + ], +]; diff --git a/modules/cms/lang/nl/lang.php b/modules/cms/lang/nl/lang.php new file mode 100644 index 0000000..defd171 --- /dev/null +++ b/modules/cms/lang/nl/lang.php @@ -0,0 +1,304 @@ + [ + 'invalid_file' => 'Ongeldige bestandsnaam: :name. Bestandsnamen mogen enkel bestaan uit letters, cijfers, underscores, streepjes en punten. Voorbeelden van correcte bestandsnamen: pagina.htm, pagina, map/pagina', + 'invalid_property' => 'Parameter ":name" kan niet worden gewijzigd', + 'file_already_exists' => 'Bestand ":name" bestaat al.', + 'error_saving' => 'Bestand opslaan mislukt: ":name". Controleer de schrijfrechten.', + 'error_creating_directory' => 'Map aanmaken mislukt: ":name". Controleer de schrijfrechten.', + 'invalid_file_extension' => 'Ongeldige bestandsextensie: :invalid. Toegestane extensies zijn: :allowed.', + 'error_deleting' => 'Fout bij het verwijderen van template: ":name". Controleer de schrijfrechten.', + 'delete_success' => 'Templates zijn succesvol verwijderd: :count.', + 'file_name_required' => 'Het invullen van een bestandsnaam is verplicht.', + 'safe_mode_enabled' => 'Veilige modus is op dit moment ingeschakeld.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Website', + 'online' => 'online', + 'maintenance' => 'in onderhoud', + 'manage_themes' => 'Beheer thema\'s', + 'customize_theme' => 'Thema aanpassen', + ], + ], + 'theme' => [ + 'not_found_name' => 'Het thema \':name\' is niet gevonden.', + 'by_author' => 'Door :name', + 'active' => [ + 'not_set' => 'Er is geen actief thema geselecteerd.', + 'not_found' => 'Het actieve thema is niet gevonden.', + ], + 'edit' => [ + 'not_set' => 'Er is geen thema ingesteld om te kunnen bewerken.', + 'not_found' => 'Het te bewerken thema is niet gevonden.', + 'not_match' => 'Het object dat je probeert te openen behoort niet tot het te bewerken thema. Herlaad de pagina.', + ], + 'settings_menu' => 'Front-end thema', + 'settings_menu_description' => 'Bekijk de lijst met geïnstalleerde thema\'s en selecteer een beschikbaar thema.', + 'default_tab' => 'Eigenschappen', + 'name_label' => 'Naam', + 'name_create_placeholder' => 'Thema naam', + 'author_label' => 'Auteur', + 'author_placeholder' => 'Naam of bedrijfsnaam', + 'description_label' => 'Omschrijving', + 'description_placeholder' => 'Thema omschrijving', + 'homepage_label' => 'Website', + 'homepage_placeholder' => 'Website URL', + 'code_label' => 'Code', + 'code_placeholder' => 'Een unieke code voor dit thema (wordt gebruikt voor distributie)', + 'preview_image_label' => 'Voorbeeld afbeelding', + 'preview_image_placeholder' => 'Het pad van de voorbeeld afbeelding.', + 'dir_name_label' => 'Mapnaam', + 'dir_name_create_label' => 'Mapnaam van het thema', + 'theme_label' => 'Thema', + 'theme_title' => 'Thema\'s', + 'activate_button' => 'Activeren', + 'active_button' => 'Activeren', + 'customize_theme' => 'Thema aanpassen', + 'customize_button' => 'Aanpassen', + 'duplicate_button' => 'Dupliceren', + 'duplicate_title' => 'Dupliceer thema', + 'duplicate_theme_success' => 'Thema succesvol gedupliceerd!', + 'manage_button' => 'Beheer', + 'manage_title' => 'Beheer thema', + 'edit_properties_title' => 'Thema', + 'edit_properties_button' => 'Wijzig eigenschappen', + 'save_properties' => 'Eigenschappen opslaan', + 'import_button' => 'Importeren', + 'import_title' => 'Importeer thema', + 'import_theme_success' => 'Thema succesvol geïmporteerd!', + 'import_uploaded_file' => 'Thema archiefbestand', + 'import_overwrite_label' => 'Overschijf bestaande bestanden', + 'import_overwrite_comment' => 'Vink uit om alleen nieuwe bestanden te importeren', + 'import_folders_label' => 'Mappen', + 'import_folders_comment' => 'Selecteer de mappen die je wilt importeren:', + 'export_button' => 'Exporteren', + 'export_title' => 'Exporteer thema', + 'export_folders_label' => 'Mappen', + 'export_folders_comment' => 'Selecteer de mappen die je wilt exporteren:', + 'delete_button' => 'Verwijderen', + 'delete_confirm' => 'Weet je zeker dat je dit thema wilt verwijderen? Dit kan niet ongedaan worden gemaakt!', + 'delete_active_theme_failed' => 'Kan het actieve thema niet verwijderen, maak eerst een ander thema actief.', + 'delete_theme_success' => 'Thema succesvol verwijderd!', + 'create_title' => 'Thema aanmaken', + 'create_button' => 'Aanmaken', + 'create_new_blank_theme' => 'Maak een nieuw leeg thema', + 'create_theme_success' => 'Thema succesvol aangemaakt!', + 'create_theme_required_name' => 'Geef a.u.b. een naam op voor dit thema.', + 'new_directory_name_label' => 'Thema mapnaam', + 'new_directory_name_comment' => 'Geef een nieuwe mapnaam op voor het gedupliceerde thema.', + 'dir_name_invalid' => 'Naam mag alleen cijfers, letters en de volgende symbolen bevatten: _-', + 'dir_name_taken' => 'Opgegeven mapnaam bestaat reeds.', + 'find_more_themes' => 'Zoek meer thema\'s', + 'saving' => 'Thema opslaan...', + 'return' => 'Terug naar thema lijst', + ], + 'maintenance' => [ + 'settings_menu' => 'Onderhoudsmodus', + 'settings_menu_description' => 'Instellingen voor de onderhoudsmodus pagina.', + 'is_enabled' => 'Onderhoudsmodus inschakelen', + 'is_enabled_comment' => 'Toon de volgende pagina als onderhoudsmodus is ingeschakeld:', + 'hint' => 'Onderhoudsmodus zal de onderhoudspagina tonen aan bezoekers die niet ingelogd zijn in het CMS.', + ], + 'page' => [ + 'not_found_name' => 'De pagina \':name\' is niet gevonden.', + 'not_found' => [ + 'label' => 'Pagina niet gevonden', + 'help' => 'De opgevraagde pagina kan niet worden gevonden.', + ], + 'custom_error' => [ + 'label' => 'Paginafout', + 'help' => 'Onze excuses, er is iets mis gegaan. De opgevraagde pagina kan niet worden getoond.', + ], + 'menu_label' => 'Pagina\'s', + 'unsaved_label' => 'Niet opgeslagen pagina\'s', + 'no_list_records' => 'Geen pagina\'s gevonden', + 'new' => 'Nieuwe pagina', + 'invalid_url' => 'Ongeldig URL formaat. De URL moet beginnen met een schuine streep en mag enkel bestaan uit letters, cijfers en de volgende tekens: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Weet je zeker dat je de geselecteerde pagina\'s wilt verwijderen?', + 'delete_confirm_single' => 'Weet je zeker dat je deze pagina wilt verwijderen?', + 'no_layout' => '-- geen layout --', + 'cms_page' => 'CMS pagina', + 'title' => 'Paginatitel', + 'url' => 'Pagina URL', + 'file_name' => 'Pagina bestandsnaam', + ], + 'layout' => [ + 'not_found_name' => "De layout ':name' is niet gevonden", + 'menu_label' => 'Layouts', + 'unsaved_label' => 'Niet opgeslagen layouts', + 'no_list_records' => 'Geen layouts gevonden', + 'new' => 'Nieuwe layout', + 'delete_confirm_multiple' => 'Weet je zeker dat je de geselecteerde layouts wilt verwijderen?', + 'delete_confirm_single' => 'Weet je zeker dat je deze layout wilt verwijderen?', + ], + 'partial' => [ + 'not_found_name' => 'Het sjabloon (partial) \':name\' is niet gevonden.', + 'invalid_name' => 'Ongeldige naam voor sjabloon (partial): :name.', + 'menu_label' => 'Sjablonen', + 'unsaved_label' => 'Niet opgeslagen sjablonen', + 'no_list_records' => 'Geen sjablonen (partial) gevonden', + 'delete_confirm_multiple' => 'Weet je zeker dat je de geselecteerde sjablonen wilt verwijderen?', + 'delete_confirm_single' => 'Weet je zeker dat je dit sjabloon wilt verwijderen?', + 'new' => 'Nieuw sjabloon', + ], + 'content' => [ + 'not_found_name' => "Het tekstblok (content) ':name' is niet gevonden.", + 'menu_label' => 'Tekstblokken', + 'unsaved_label' => 'Niet opgeslagen tekstblokken', + 'no_list_records' => 'Geen tekstblokken (content) gevonden', + 'delete_confirm_multiple' => 'Weet je zeker dat je de geselecteerde tekstblokken of mappen wilt verwijderen?', + 'delete_confirm_single' => 'Weet je zeker dat je dit tekstblok wilt verwijderen?', + 'new' => 'Nieuw tekstblok', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Ongeldige AJAX handlernaam: :name.', + 'not_found' => 'AJAX handler \':name\' is niet gevonden.', + ], + 'cms' => [ + 'menu_label' => 'CMS', + ], + 'sidebar' => [ + 'add' => 'Toevoegen', + 'search' => 'Zoeken...', + ], + 'editor' => [ + 'settings' => 'Instellingen', + 'title' => 'Titel', + 'new_title' => 'Nieuwe paginatitel', + 'url' => 'URL', + 'filename' => 'Bestandsnaam', + 'layout' => 'Layout', + 'description' => 'Omschrijving', + 'preview' => 'Voorbeeld', + 'meta' => 'Meta', + 'meta_title' => 'Meta titel', + 'meta_description' => 'Meta omschrijving', + 'markup' => 'Opmaak', + 'code' => 'Code', + 'content' => 'Content', + 'hidden' => 'Verborgen', + 'hidden_comment' => 'Verborgen pagina zijn alleen toegankelijk voor ingelogde gebruikers.', + 'enter_fullscreen' => 'Volledig scherm starten', + 'exit_fullscreen' => 'Volledig scherm afsluiten', + 'open_searchbox' => 'Open zoekveld', + 'close_searchbox' => 'Sluit zoekveld', + 'open_replacebox' => 'Open vervang veld', + 'close_replacebox' => 'Sluit vervang veld', + 'commit' => 'Commit', + 'reset' => 'Reset', + 'commit_confirm' => 'Weet je zeker dat je je wijzigingen wilt opslaan op het bestandssysteem? Deze actie zal het huidige bestand overschrijven.', + 'reset_confirm' => 'Weet je zeker dat je wilt terugkeren naar de vorige versie? Deze actie zal de vorige versie terugzetten en je wijzigingen zullen verloren gaan.', + 'committing' => 'Committen', + 'resetting' => 'Resetten', + 'commit_success' => ':type is ge-commit naar het bestandssysteem', + 'reset_success' => ':type is ge-reset op het bestandssysteem', + ], + 'asset' => [ + 'menu_label' => 'Middelen', + 'unsaved_label' => 'Niet opgeslagen middelen', + 'drop_down_add_title' => 'Toevoegen...', + 'drop_down_operation_title' => 'Actie...', + 'upload_files' => 'Bestand(en) uploaden', + 'create_file' => 'Nieuw bestand', + 'create_directory' => 'Nieuwe map', + 'directory_popup_title' => 'Nieuwe map', + 'directory_name' => 'Mapnaam', + 'rename' => 'Hernoemen', + 'delete' => 'Verwijderen', + 'move' => 'Verplaatsen', + 'select' => 'Selecteren', + 'new' => 'Nieuw bestand', + 'rename_popup_title' => 'Hernoemen', + 'rename_new_name' => 'Nieuwe naam', + 'invalid_path' => 'Pad mag enkel bestaan uit letters, cijfers, spaties en de volgende tekens: ._-/', + 'error_deleting_file' => 'Fout bij verwijderen van het bestand :name.', + 'error_deleting_dir_not_empty' => 'Fout bij verwijderen van map :name. De map is niet leeg.', + 'error_deleting_dir' => 'Fout bij verwijderen van de map :name.', + 'invalid_name' => 'Naam mag enkel bestaan uit letters, cijfers, spaties en de volgende tekens: ._-', + 'original_not_found' => 'Oorspronkelijke bestand of map is niet gevonden', + 'already_exists' => 'Bestand of map met deze naam bestaat al', + 'error_renaming' => 'Fout bij hernoemen van bestand of map', + 'name_cant_be_empty' => 'De naam mag niet leeg zijn', + 'too_large' => 'Het geüploadete bestand is te groot. De maximaal toegestane bestandsgrootte is :max_size', + 'type_not_allowed' => 'Enkel de volgende bestandstypen zijn toegestaand: :allowed_types', + 'file_not_valid' => 'Bestand is ongeldig', + 'error_uploading_file' => 'Fout tijdens uploaden bestand ":name": :error', + 'move_please_select' => 'selecteer', + 'move_destination' => 'Doelmap', + 'move_popup_title' => 'Verplaats middelen', + 'move_button' => 'Verplaats', + 'selected_files_not_found' => 'Geselecteerde bestanden zijn niet gevonden', + 'select_destination_dir' => 'Selecteer een doelmap', + 'destination_not_found' => 'Doelmap is niet gevonden', + 'error_moving_file' => 'Fout bij verplaatsen bestand :file', + 'error_moving_directory' => 'Fout bij verplaatsen map :dir', + 'error_deleting_directory' => 'Fout bij het verwijderen van de oorspronkelijke map :dir', + 'no_list_records' => 'Geen bestanden gevonden', + 'delete_confirm' => 'Verwijder geselecteerde bestanden of mappen?', + 'path' => 'Pad', + ], + 'component' => [ + 'menu_label' => 'Componenten', + 'unnamed' => 'Naamloos', + 'no_description' => 'Geen beschrijving opgegeven', + 'alias' => 'Alias', + 'alias_description' => 'Een unieke naam voor dit component voor gebruik in de code van een pagina of layout.', + 'validation_message' => 'Een alias voor de component is verplicht en mag alleen bestaan uit letters, cijfers en underscores. De alias moet beginnen met een letter.', + 'invalid_request' => 'De template kan niet worden opgeslagen vanwege ongeldige componentgegevens.', + 'no_records' => 'Geen componenten gevonden', + 'not_found' => 'De component \':name\' is niet gevonden.', + 'no_default_partial' => "De component bevat geen 'standaard' sjabloon", + 'method_not_found' => 'De component \':name\' bevat geen \':method\' methode.', + 'soft_component' => 'Soft Component', + 'soft_component_description' => 'Dit component ontbreekt, maar is optioneel.', + ], + 'template' => [ + 'invalid_type' => 'Onbekend type template.', + 'not_found' => 'De opgevraagde template is niet gevonden.', + 'saved' => 'De template is succesvol opgeslagen.', + 'no_list_records' => 'Geen records gevonden', + 'delete_confirm' => 'Verwijder geselecteerde templates?', + 'order_by' => 'Sorteer op', + ], + 'permissions' => [ + 'name' => 'Cms', + 'manage_content' => 'Beheer inhoud', + 'manage_assets' => 'Beheer middelen', + 'manage_pages' => 'Beheer pagina\'s', + 'manage_layouts' => 'Beheer layouts', + 'manage_partials' => 'Beheer sjablonen', + 'manage_themes' => 'Beheer thema\'s', + 'manage_theme_options' => 'Beheer maatwerk instellingen voor het huidige thema', + ], + 'theme_log' => [ + 'hint' => 'Dit logboek laat alle wijzigingen in het thema zien die aangebracht zijn door de beheerders in de back-end omgeving.', + 'menu_label' => 'Thema logboek', + 'menu_description' => 'Toon wijzigingen op het actieve thema.', + 'empty_link' => 'Thema logboek legen', + 'empty_loading' => 'Bezig met legen van thema logboek...', + 'empty_success' => 'Thema logboek is geleegd', + 'return_link' => 'Terug naar thema logboek', + 'id' => 'ID', + 'id_label' => 'Logboek ID', + 'created_at' => 'Datum & Tijd', + 'user' => 'Gebruiker', + 'type' => 'Type', + 'type_create' => 'Aanmaken', + 'type_update' => 'Wijzigen', + 'type_delete' => 'Verwijderen', + 'theme_name' => 'Thema', + 'theme_code' => 'Thema code', + 'old_template' => 'Template (Oud)', + 'new_template' => 'Template (Nieuw)', + 'template' => 'Template', + 'diff' => 'Wijzigingen', + 'old_value' => 'Oude waarde', + 'new_value' => 'Nieuwe waarde', + 'preview_title' => 'Template wijzigingen', + 'template_updated' => 'Template was gewijzigd', + 'template_created' => 'Template was aangemaakt', + 'template_deleted' => 'Template was verwijderd', + ], +]; diff --git a/modules/cms/lang/pl/lang.php b/modules/cms/lang/pl/lang.php new file mode 100644 index 0000000..e69932f --- /dev/null +++ b/modules/cms/lang/pl/lang.php @@ -0,0 +1,250 @@ + [ + 'invalid_file' => 'Nieprawidłowa nazwa pliku: :name. Nazwy pliku mogą zawierać tylko symbole alfanumeryczne, podkreślenia, kreski i kropki. Przykłady prawidłowych nazw: strona.htm, strona, podfolder/strona', + 'invalid_property' => "Własność ':name' nie może zostać ustawiona.", + 'file_already_exists' => "Plik o nazwie ':name' już istnieje.", + 'error_saving' => "Błąd przy zapisywaniu pliku ':name'. Proszę sprawdzić uprawnienia zapisu/modyfikacji.", + 'error_creating_directory' => 'Błąd przy tworzeniu folderu :name. Proszę sprawdzić uprawnienia zapisu/modyfikacji.', + 'invalid_file_extension' => 'Nieprawidłowe rozszerzenie pliku: :invalid. Dozwolone rozszerzenia to: :allowed.', + 'error_deleting' => "Błąd przy usuwaniu pliku szablonu ':name'. Proszę sprawdzić uprawnienia zapisu/modyfikacji.", + 'delete_success' => 'Szablony zostały prawidłowo usunięte: :count.', + 'file_name_required' => 'Pole Nazwa Pliku jest wymagane.', + 'safe_mode_enabled' => 'Safe mode jest obecnie włączony.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Strona', + 'online' => 'Online', + 'maintenance' => 'W konserwacji', + 'manage_themes' => 'Zarządzaj motywami', + ] + ], + 'theme' => [ + 'not_found_name' => "Motyw ':name' nie został odnaleziony.", + 'active' => [ + 'not_set' => 'Brak aktywnego motywu.', + 'not_found' => 'Aktywny motyw nie został odnaleziony.' + ], + 'edit' => [ + 'not_set' => 'Edytowany motyw nie jest ustawiony.', + 'not_found' => 'Edytowany motyw nie został znaleziony.', + 'not_match' => "Obiekt który próbujesz edytować nie należy do wybranego motywu. Proszę przeładować stronę." + ], + 'settings_menu' => 'Motyw strony', + 'settings_menu_description' => 'Zobacz listę zainstalowanych motywów i wybierz, który aktywować.', + 'default_tab' => 'Właściwości', + 'name_label' => 'Nazwa', + 'name_create_placeholder' => 'Nowa nazwa motywu', + 'author_label' => 'Autor', + 'author_placeholder' => 'Osoba lub nazwa firmy', + 'description_label' => 'Opis', + 'description_placeholder' => 'Opis motywu', + 'homepage_label' => 'Strona domowa', + 'homepage_placeholder' => 'URL strony domowej', + 'code_label' => 'Kod', + 'code_placeholder' => 'Unikalny kod motywu używany do dystrybucji', + 'dir_name_label' => 'Nazwa katalogu', + 'dir_name_create_label' => 'Docelowy katalog motywu', + 'theme_label' => 'Motyw', + 'theme_title' => 'Motywy', + 'activate_button' => 'Aktywuj', + 'active_button' => 'Aktywuj', + 'customize_theme' => 'Personalizuj Motyw', + 'customize_button' => 'Personalizuj', + 'duplicate_button' => 'Duplikuj', + 'duplicate_title' => 'Duplikuj motyw', + 'duplicate_theme_success' => 'Pomyślnie utworzono kopię motywu!', + 'manage_button' => 'Zarządzaj', + 'manage_title' => 'Zarządzaj motywem', + 'edit_properties_title' => 'Motyw', + 'edit_properties_button' => 'Edytuj właściwości', + 'save_properties' => 'Zapisz właściwości', + 'import_button' => 'Zaimportuj', + 'import_title' => 'Zaimportuj motyw', + 'import_theme_success' => 'Pomyślnie zaimportowano motyw!', + 'import_uploaded_file' => 'Plik archiwum motywu', + 'import_overwrite_label' => 'Nadpisz istniejące pliki', + 'import_overwrite_comment' => 'Odznacz aby zaimportować tylko nowe pliki', + 'import_folders_label' => 'Foldery', + 'import_folders_comment' => 'Proszę zaznaczyć foldery do importu', + 'export_button' => 'Eksportuj', + 'export_title' => 'Eksportuj motyw', + 'export_folders_label' => 'Foldery', + 'export_folders_comment' => 'Proszę zaznaczyć foldery do eksportu', + 'delete_button' => 'Usuń', + 'delete_confirm' => 'Czy na pewno usunąć ten motyw? Tej operacji nie można cofnąć!', + 'delete_active_theme_failed' => 'Nie można usunąć aktywnego motywu. Spróbuj zmienić aktywny motyw na inny.', + 'delete_theme_success' => 'Pomyślnie usunięto motyw!', + 'create_title' => 'Utwórz motyw', + 'create_button' => 'Utwórz', + 'create_new_blank_theme' => 'Utwórz nowy pusty motyw', + 'create_theme_success' => 'Pomyślnie utworzono motyw!', + 'create_theme_required_name' => 'Proszę podać nazwę nowego motywu.', + 'new_directory_name_label' => 'Katalog motywu', + 'new_directory_name_comment' => 'Podaj nazwę nowego katalogu dla kopii motywu.', + 'dir_name_invalid' => 'Nazwa może zawierać tylko cyfry, znaki łacińskie oraz następujące znaki: _-', + 'dir_name_taken' => 'Żądany katalog motywu już istnieje.', + 'find_more_themes' => 'Znajdź więcej motywów', + 'saving' => 'Zapisywanie motywu...', + 'return' => 'Wróć do listy motywów', + ], + 'maintenance' => [ + 'settings_menu' => 'Tryb konserwacji', + 'settings_menu_description' => 'Konfiguruj oraz włącz tryb konserwacji strony.', + 'is_enabled' => 'Włącz tryb konserwacji', + 'is_enabled_comment' => 'Kiedy włączony odwiedzający zamiast normalnej strony zobaczą stronę wybraną poniżej.', + 'hint' => 'Tryb konserwacji wyświetli stronę konserwacji dla odwiedzających, którzy nie są zalogowani do panelu administracyjnego.', + ], + 'page' => [ + 'not_found_name' => "Strona ':name' nie została znaleziona", + 'not_found' => [ + 'label' => 'Nie znaleziono strony', + 'help' => 'Żądana strona nie została znaleziona.' + ], + 'custom_error' => [ + 'label' => 'Błąd strony', + 'help' => "Bardzo przepraszamy, jednak coś poszło nie tak i strona nie może zostać wyświetlona." + ], + 'menu_label' => 'Strony', + 'unsaved_label' => 'Niezapisane strony', + 'no_list_records' => 'Nie znaleziono stron', + 'new' => 'Nowa strona', + 'invalid_url' => 'Nieprawidłowy format URL. Powinien rozpoczynać się od ukośnika (/) i może zawierać cyfry, znaki oraz następujące symbole: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Czy na pewno chcesz usunąć zaznaczone strony?', + 'delete_confirm_single' => 'Czy na pewno chcesz usunąć tę stronę?', + 'no_layout' => '-- brak układu --' + ], + 'layout' => [ + 'not_found_name' => "Nie znaleziono układu ':name'", + 'menu_label' => 'Układy', + 'unsaved_label' => 'Niezapisane układy', + 'no_list_records' => 'Nie znaleziono układów', + 'new' => 'Nowy układ', + 'delete_confirm_multiple' => 'Czy na pewno chcesz usunąć zaznaczone układy?', + 'delete_confirm_single' => 'Czy na pewno chcesz usunąć ten układ?' + ], + 'partial' => [ + 'not_found_name' => "Fragment ':name' nie został znaleziony.", + 'invalid_name' => 'Nieprawidłowa nazwa fragmentu: :name.', + 'menu_label' => 'Fragmenty', + 'unsaved_label' => 'Niezapisane fragmenty', + 'no_list_records' => 'Nie znaleziono fragmentów', + 'delete_confirm_multiple' => 'Czy na pewno chcesz usunąć zaznaczone fragmenty?', + 'delete_confirm_single' => 'Czy na pewno chcesz usunąć ten fragment?', + 'new' => 'Nowy fragment' + ], + 'content' => [ + 'not_found_name' => "Plik treści ':name' nie został znaleziony.", + 'menu_label' => 'Treść', + 'unsaved_label' => 'Niezapisana treść', + 'no_list_records' => 'Nie znaleziono plików treści', + 'delete_confirm_multiple' => 'Czy na pewno chcesz usunąć zaznaczone pliki treści?', + 'delete_confirm_single' => 'Czy na pewno chcesz usunąć ten plik treści?', + 'new' => 'Nowy plik treści' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Nieprawidłowa nazwa handlera AJAX: :name.', + 'not_found' => "Handler AJAX ':name' nie został znaleziony." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Dodaj', + 'search' => 'Szukaj...' + ], + 'editor' => [ + 'settings' => 'Ustawienia', + 'title' => 'Tytuł', + 'new_title' => 'Tytuł nowej strony', + 'url' => 'URL', + 'filename' => 'Nazwa pliku', + 'layout' => 'Układ', + 'description' => 'Opis', + 'preview' => 'Podgląd', + 'meta' => 'Meta', + 'meta_title' => 'SEO Tytuł', + 'meta_description' => 'SEO Opis', + 'markup' => 'Markup', + 'code' => 'Kod', + 'content' => 'Treść', + 'hidden' => 'Ukryta', + 'hidden_comment' => 'Ukryte strony są widoczne tylko dla użytkowników panelu administracyjnego, którzy są zalogowani.', + 'enter_fullscreen' => 'Włącz tryb pełnoekranowy', + 'exit_fullscreen' => 'Wyłącz tryb pełnoekranowy', + 'open_searchbox' => 'Otwórz wyszukiwanie', + 'close_searchbox' => 'Zamknij wyszukiwanie', + 'open_replacebox' => 'Otwórz zamienianie tekstu', + 'close_replacebox' => 'Zamknij zamienianie tekstu' + ], + 'asset' => [ + 'menu_label' => 'Zasoby', + 'unsaved_label' => 'Niezapisane zasoby', + 'drop_down_add_title' => 'Dodaj...', + 'drop_down_operation_title' => 'Akcja...', + 'upload_files' => 'Wyślij plik(i)', + 'create_file' => 'Stwórz plik', + 'create_directory' => 'Stwórz folder', + 'directory_popup_title' => 'Nowy folder', + 'directory_name' => 'Nazwa folderu', + 'rename' => 'Zmień nazwę', + 'delete' => 'Usuń', + 'move' => 'Przenieś', + 'select' => 'Wybierz', + 'new' => 'Nowy plik', + 'rename_popup_title' => 'Zmień nazwę', + 'rename_new_name' => 'Nowa nazwa', + 'invalid_path' => 'Ścieżka może zawierać tylko cyfry, litery alfabetu łacińskiego, spacje oraz następujące znaki: ._-/', + 'error_deleting_file' => 'Błąd przy usuwaniu pliku :name.', + 'error_deleting_dir_not_empty' => 'Błąd przy usuwaniu folderu :name. Katalog nie jest pusty.', + 'error_deleting_dir' => 'Błąd przy usuwaniu pliku :name.', + 'invalid_name' => 'Nazwa może zawierać tylko cyfry, litery alfabetu łacińskiego, spacje oraz następujące znaki: ._-', + 'original_not_found' => 'Oryginalny plik lub ścieżka nie zostały odnalezione', + 'already_exists' => 'Plik lub folder o tej samej nazwie już istnieją', + 'error_renaming' => 'Błąd przy zmianie nazwy pliku lub folderu', + 'name_cant_be_empty' => 'Nazwa nie może być pusta', + 'too_large' => 'Wyślany plik jest zbyt duży. Maksymalny dopuszczalny rozmiar pliku to :max_size', + 'type_not_allowed' => 'Dopuszczalne są tylko następujące formaty plików: :allowed_types', + 'file_not_valid' => 'Plik jest nieprawidłowy', + 'error_uploading_file' => "Błąd przy wysyłaniu pliku ':name': :error", + 'move_please_select' => 'proszę wybierz', + 'move_destination' => 'Katalog docelowy', + 'move_popup_title' => 'Przenieś zasoby', + 'move_button' => 'Przenieś', + 'selected_files_not_found' => 'Nie znaleziono wybranych plików', + 'select_destination_dir' => 'Proszę wybrać folder docelowy', + 'destination_not_found' => 'Folder docelowy nie został znaleziony', + 'error_moving_file' => 'Błąd przy przenoszeniu pliku :file', + 'error_moving_directory' => 'Błąd przy przenoszeniu folderu :dir', + 'error_deleting_directory' => 'Błąd przy usuwaniu oryginalnego folderu :dir', + 'path' => 'Ścieżka' + ], + 'component' => [ + 'menu_label' => 'Komponenty', + 'unnamed' => 'Bez nazwy', + 'no_description' => 'Brak opisu', + 'alias' => 'Alias', + 'alias_description' => 'A unique name given to this component when using it in the page or layout code.', + 'validation_message' => 'Component aliases are required and can contain only Latin symbols, digits, and underscores. The aliases should start with a Latin symbol.', + 'invalid_request' => 'The template cannot be saved because of invalid component data.', + 'no_records' => 'Nie znaleziono komponentów', + 'not_found' => "Komponent ':name' nie został znaleziony.", + 'method_not_found' => "Komponent ':name' nie zawiera metody ':method'." + ], + 'template' => [ + 'invalid_type' => 'Nieznany typ szablonu.', + 'not_found' => 'Szablon nie został znaleziony.', + 'saved'=> 'Szablon został zapisany pomyślnie.' + ], + 'permissions' => [ + 'name' => 'Cms', + 'manage_content' => 'Zarządzaj treścią', + 'manage_assets' => 'Zarządzaj zasobami', + 'manage_pages' => 'Zarządzaj stronami', + 'manage_layouts' => 'Zarządzaj układami', + 'manage_partials' => 'Zarządzaj blokami', + 'manage_themes' => 'Zarządzaj motywami', + ], +]; diff --git a/modules/cms/lang/pt-br/lang.php b/modules/cms/lang/pt-br/lang.php new file mode 100644 index 0000000..6044128 --- /dev/null +++ b/modules/cms/lang/pt-br/lang.php @@ -0,0 +1,304 @@ + [ + 'invalid_file' => 'Nome de arquivo inválido: ":name". Os nomes de arquivos podem conter apenas letras, números, sublinhados, traços e pontos. Veja alguns exemplos de nomes de arquivos corretos: pagina.htm, pagina, subdiretorio/pagina', + 'invalid_property' => 'A propriedade ":nome" não pode ser definida', + 'file_already_exists' => 'Arquivo ":name" já existe.', + 'error_saving' => 'Erro ao salvar arquivo ":name". Verifique as permissões de escrita.', + 'error_creating_directory' => 'Erro ao criar o diretório :name. Verifique as permissões de escrita.', + 'invalid_file_extension'=>'Extensão de arquivo inválida: :invalid. Extensões válidas: :allowed.', + 'error_deleting' => 'Erro ao excluir o arquivo de modelo ":name". Verifique as permissões de escrita.', + 'delete_success' => 'Modelos excluídos com sucesso: :count.', + 'file_name_required' => 'O campo de Nome do Arquivo é necessário.', + 'safe_mode_enabled' => 'Modo de segurança está ativado.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Site', + 'online' => 'online', + 'maintenance' => 'em manutenção', + 'manage_themes' => 'Gerenciar temas', + 'customize_theme' => 'Customizar tema' + ] + ], + 'theme' => [ + 'not_found_name' => 'O tema ":name" não foi encontrado.', + 'by_author' => 'Por :name', + 'active' => [ + 'not_set' => 'O tema ativo não foi definido.', + 'not_found' => 'O tema ativo não foi encontrado.', + ], + 'edit' => [ + 'not_set' => 'O tema de edição não foi definido.', + 'not_found' => 'O tema de edição não foi encontrado.', + 'not_match' => 'O objeto que você está tentando acessar não pertence ao tema que está sendo editado. Por favor, recarregue a página.', + ], + 'settings_menu' => 'Temas', + 'settings_menu_description' => 'Veja a lista de temas instalados e selecione o tema ativo.', + 'default_tab' => 'Propriedades', + 'name_label' => 'Nome', + 'name_create_placeholder' => 'Nome do novo tema', + 'author_label' => 'Autor', + 'author_placeholder' => 'Nome do autor', + 'description_label' => 'Descrição', + 'description_placeholder' => 'Descrição do tema', + 'homepage_label' => 'Site', + 'homepage_placeholder' => 'URL do site', + 'code_label' => 'Código', + 'code_placeholder' => 'Um código exclusivo para esse tema a ser usado para distribuição', + 'preview_image_label' => 'Imagem de pré-visualização', + 'preview_image_placeholder' => 'O caminho da imagem de pré-visualização do tema.', + 'dir_name_label' => 'Nome do diretório', + 'dir_name_create_label' => 'O diretório-alvo de temas', + 'theme_label' => 'Tema', + 'theme_title' => 'Temas', + 'activate_button' => 'Ativar', + 'active_button' => 'Ativado', + 'customize_theme' => 'Personalizar Tema', + 'customize_button' => 'Personalizar', + 'duplicate_button' => 'Duplicar', + 'duplicate_title' => 'Duplicar tema', + 'duplicate_theme_success' => 'Tema duplicado com sucesso!', + 'manage_button' => 'Gerenciar', + 'manage_title' => 'Gerenciar tema', + 'edit_properties_title' => 'Tema', + 'edit_properties_button' => 'Editar propriedades', + 'save_properties' => 'Salvar propriedades', + 'import_button' => 'Importar', + 'import_title' => 'Importar tema', + 'import_theme_success' => 'Tema importado com sucesso!', + 'import_uploaded_file' => 'Arquivo de tema', + 'import_overwrite_label' => 'Sobrescrever arquivos existentes', + 'import_overwrite_comment' => 'Desmarque para importar apenas arquivos novos', + 'import_folders_label' => 'Pastas', + 'import_folders_comment' => 'Por favor selecione as pastas de temas que deseja importar', + 'export_button' => 'Exportar', + 'export_title' => 'Exportar tema', + 'export_folders_label' => 'Pastas', + 'export_folders_comment' => 'Por favor selecione as pastas de temas que deseja exportar', + 'delete_button' => 'Excluir', + 'delete_confirm' => 'Tem certeza que deseja excluir este tema? Isto não pode ser revertido!', + 'delete_active_theme_failed' => 'Não é possível excluir o tema ativo, torne outro tema ativo antes.', + 'delete_theme_success' => 'Tema excluído com sucesso!', + 'create_title' => 'Criar tema', + 'create_button' => 'Criar', + 'create_new_blank_theme' => 'Criar novo tema em branco', + 'create_theme_success' => 'Tema criado com sucesso!', + 'create_theme_required_name' => 'Por favor forneça um nome para o tema.', + 'new_directory_name_label' => 'Diretório do tema', + 'new_directory_name_comment' => 'Forneça um novo nome de diretório para o tema duplicado.', + 'dir_name_invalid' => 'O nome só pode conter letras, números, e os símbolos: _-', + 'dir_name_taken' => 'Diretório de tema escolhido já existe.', + 'find_more_themes' => 'Encontrar mais temas.', + 'saving' => 'Salvando tema...', + 'return' => 'Retornar à lista de temas', + ], + 'maintenance' => [ + 'settings_menu' => 'Modo de manutenção', + 'settings_menu_description' => 'Configurar modo de manutenção e a página exibida.', + 'is_enabled' => 'Ativar modo de manutenção', + 'is_enabled_comment' => 'Quando ativado visitantes do site vão ver a página selecionada.', + 'hint' => 'O modo de manutenção exibirá a página de manutenção para visitantes que não estão conectados à área de back-end.' + ], + 'page' => [ + 'not_found_name' => 'A página ":name" não foi encontrada', + 'not_found' => [ + 'label' => 'Página não encontrada', + 'help' => 'A página solicitada não pode ser encontrada.', + ], + 'custom_error' => [ + 'label' => 'Erro na página', + 'help' => 'Lamentamos, mas algo deu errado e que a página não pode ser exibida.', + ], + 'menu_label' => 'Páginas', + 'unsaved_label' => 'Página(s) não salva(s)', + 'no_list_records' => 'Nenhuma página encontrada', + 'new' => 'Nova página', + 'invalid_url' => 'Formato de URL inválido. A URL deve começar com uma barra e pode conter letras, números e os símbolos: _-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Você realmente deseja excluir as páginas selecionadas?', + 'delete_confirm_single' => 'Você realmente deseja excluir esta página?', + 'no_layout' => '-- sem esboço --', + 'cms_page' => 'Página do CMS', + 'title' => 'Título da página', + 'url' => 'URL da página', + 'file_name' => 'Nome do arquivo da página' + ], + 'layout' => [ + 'not_found_name' => 'O esboço ":name" não foi encontrado', + 'menu_label' => 'Esboços', + 'unsaved_label' => 'Esboço(s) não salvo(s)', + 'no_list_records' => 'Nenhum esboço encontrado', + 'new' => 'Novo esboço', + 'delete_confirm_multiple' => 'Você realmente deseja excluir os esboços selecionados?', + 'delete_confirm_single' => 'Você realmente deseja excluir este esboço?', + ], + 'partial' => [ + 'not_found_name' => 'O bloco ":name" não foi encontrado.', + 'invalid_name' => 'Nome de bloco inválido: :name.', + 'menu_label' => 'Blocos', + 'unsaved_label' => 'Bloco(s) não salvo(s)', + 'no_list_records' => 'Nenhum bloco encontrado', + 'delete_confirm_multiple' => 'Você realmente deseja apagar os blocos selecionados?', + 'delete_confirm_single' => 'Você realmente deseja apagar este bloco?', + 'new' => 'Novo bloco', + ], + 'content' => [ + 'not_found_name' => 'O arquivo de conteúdo ":name" não foi encontrado.', + 'menu_label' => 'Conteúdo', + 'unsaved_label' => 'Conteúdo não salvo', + 'no_list_records' => 'Nenhum arquivo de conteúdo encontrado', + 'delete_confirm_multiple' => 'Você realmente deseja apagar arquivos ou diretórios de conteúdo selecionados?', + 'delete_confirm_single' => 'Você realmente deseja apagar este arquivo de conteúdo?', + 'new' => 'Novo arquivo de conteúdo', + ], + 'ajax_handler' => [ + 'invalid_name' => 'O nome do manipulador AJAX é inválido: :name.', + 'not_found' => 'Manipulador AJAX ":name" não encontrado.', + ], + 'cms' => [ + 'menu_label' => 'CMS', + ], + 'sidebar' => [ + 'add' => 'Adicionar', + 'search' => 'Buscar...', + ], + 'editor' => [ + 'settings' => 'Configurações', + 'title' => 'Título', + 'new_title' => 'Título da nova página', + 'url' => 'URL', + 'filename' => 'Nome do Arquivo', + 'layout' => 'Esboço', + 'description' => 'Descrição', + 'preview' => 'Visualizar', + 'meta' => 'Meta', + 'meta_title' => 'Título Meta', + 'meta_description' => 'Descrição Meta', + 'markup' => 'Edição', + 'code' => 'Código', + 'content' => 'Conteúdo', + 'hidden' => 'Oculta', + 'hidden_comment' => 'Páginas ocultas são acessíveis somente para administradores.', + 'enter_fullscreen' => 'Entrar no modo de tela cheia', + 'exit_fullscreen' => 'Sair do modo de tela cheia', + 'open_searchbox' => 'Abrir caixa de busca', + 'close_searchbox' => 'Fechar caixa de busca', + 'open_replacebox' => 'Abrir caixa de substituição', + 'close_replacebox' => 'Fechar caixa de substituição', + 'commit' => 'Persistir', + 'reset' => 'Redefinir', + 'commit_confirm' => 'Tem certeza de que deseja enviar suas alterações para este arquivo no sistema de arquivos? Isso sobrescreverá o arquivo existente no sistema de arquivos', + 'reset_confirm' => 'Tem certeza de que deseja redefinir este arquivo para a cópia que está no sistema de arquivos? Isso irá substituí-lo completamente com o arquivo que está no sistema de arquivos', + 'committing' => 'Persistindo', + 'resetting' => 'Redefinindo', + 'commit_success' => 'O :type foi confirmado no sistema de arquivos', + 'reset_success' => 'O :type foi redefinido para a versão do sistema de arquivos', + ], + 'asset' => [ + 'menu_label' => 'Arquivos', + 'unsaved_label' => 'Arquivo(s) não salvo(s)', + 'drop_down_add_title' => 'Adicionar...', + 'drop_down_operation_title' => 'Ação...', + 'upload_files' => 'Enviar arquivo(s)', + 'create_file' => 'Criar arquivo', + 'create_directory' => 'Criar diretório', + 'directory_popup_title' => 'Novo diretório', + 'directory_name' => 'Nome do diretório', + 'rename' => 'Renomear', + 'delete' => 'Excluir', + 'move' => 'Mover', + 'select' => 'Selecionar', + 'new' => 'Novo arquivo', + 'rename_popup_title' => 'Renomear', + 'rename_new_name' => 'Novo nome', + 'invalid_path' => 'O caminho pode conter apenas letras, números, espaços e os símbolos: ._-/', + 'error_deleting_file' => 'Erro ao excluir arquivo :name.', + 'error_deleting_dir_not_empty' => 'Erro ao excluir diretório :name. O diretório não está vazio.', + 'error_deleting_dir' => 'Erro ao excluir diretório :name.', + 'invalid_name' => 'O nome pode conter apenas letras, números, espaços e os símbolos: ._-', + 'original_not_found' => 'Arquivo ou diretório original não encontrado', + 'already_exists' => 'Um arquivo ou diretório com este nome já existe', + 'error_renaming' => 'Erro ao renomear o arquivo ou diretório', + 'name_cant_be_empty' => 'O nome não pode estar vazio', + 'too_large' => 'O arquivo enviado é muito grande. O tamanho máximo permitido é :max_size', + 'type_not_allowed' => 'Apenas os seguintes tipos de arquivos são permitidos: :allowed_types', + 'file_not_valid' => 'O arquivo não é válido', + 'error_uploading_file' => 'Error uploading file ":name": :error', + 'move_please_select' => 'por favor selecione', + 'move_destination' => 'Diretório de destino', + 'move_popup_title' => 'Mover arquivos', + 'move_button' => 'Mover', + 'selected_files_not_found' => 'Arquivos selecionados não encontrados', + 'select_destination_dir' => 'Por favor, selecione um diretório de destino', + 'destination_not_found' => 'Diretório de destino não encontrado', + 'error_moving_file' => 'Erro ao mover arquivo :file', + 'error_moving_directory' => 'Erro ao mover diretório :dir', + 'error_deleting_directory' => 'Erro ao excluir o diretório original :dir', + 'no_list_records' => 'Nenhum arquivo encontrado', + 'delete_confirm' => 'Excluir arquivos ou diretórios selecionados?', + 'path' => 'Caminho', + ], + 'component' => [ + 'menu_label' => 'Componentes', + 'unnamed' => 'Sem nome', + 'no_description' => 'Nenhuma descrição fornecida', + 'alias' => 'Apelido', + 'alias_description' => 'Um nome exclusivo dado a este componente quando usá-lo no código de uma página ou esboço.', + 'validation_message' => 'Apelidos de componentes são necessários e podem conter letras, números e sublinhados. Os apelidos devem começar com uma letra.', + 'invalid_request' => 'O modelo não pode ser salvo devido a dados inválidos nos componentes.', + 'no_records' => 'Nenhum componente encontrado', + 'not_found' => 'O componente ":name" não foi encontrado.', + 'no_default_partial' => "Este componente não tem um bloco 'padrão'", + 'method_not_found' => 'O componente ":name" não tem um método ":method".', + 'soft_component' => 'Componente Soft', + 'soft_component_description' => 'Este componente está faltando, mas é opcional.', + ], + 'template' => [ + 'invalid_type' => 'Tipo de modelo desconhecido.', + 'not_found' => 'O modelo solicitado não foi encontrado.', + 'saved'=> 'O modelo foi salvo com sucesso.', + 'no_list_records' => 'Nenhum registro foi encontrado', + 'delete_confirm' => 'Excluir modelos selecionados?', + 'order_by' => 'Ordenar por' + ], + 'permissions' => [ + 'name' => 'Cms', + 'manage_content' => 'Gerenciar conteúdo', + 'manage_assets' => 'Gerenciar arquivos', + 'manage_pages' => 'Gerenciar páginas', + 'manage_layouts' => 'Gerenciar esboços', + 'manage_partials' => 'Gerenciar blocos', + 'manage_themes' => 'Gerenciar temas', + 'manage_theme_options' => 'Configure as opções de personalização para o tema ativo', + ], + 'theme_log' => [ + 'hint' => 'Esses registros exibe as alterações feitas no tema pelos administradores na área de backend.', + 'menu_label' => 'Registros do tema', + 'menu_description' => 'Veja as alterações feitas no tema ativo.', + 'empty_link' => 'Registros do tema vazio', + 'empty_loading' => 'Esvaziando registros de tema...', + 'empty_success' => 'Registros do tema esvaziado', + 'return_link' => 'Retornar aos registros deo tema', + 'id' => 'ID', + 'id_label' => 'Registro ID', + 'created_at' => 'Data & Hora', + 'user' => 'Usuário', + 'type' => 'Tipo', + 'type_create' => 'Criado', + 'type_update' => 'Atualizado', + 'type_delete' => 'Apagado', + 'theme_name' => 'Tema', + 'theme_code' => 'Código do tema', + 'old_template' => 'Modelo (antigo)', + 'new_template' => 'Template (novo)', + 'template' => 'Modelo', + 'diff' => 'Mudanças', + 'old_value' => 'Valor antigo', + 'new_value' => 'Novo valor', + 'preview_title' => 'Mudanças no modelo', + 'template_updated' => 'Modelo foi atualizado', + 'template_created' => 'Modelo foi criado', + 'template_deleted' => 'O modelo foi apagado', + ], +]; diff --git a/modules/cms/lang/pt-pt/lang.php b/modules/cms/lang/pt-pt/lang.php new file mode 100644 index 0000000..27979eb --- /dev/null +++ b/modules/cms/lang/pt-pt/lang.php @@ -0,0 +1,291 @@ + [ + 'invalid_file' => 'Nome de ficheiro inválido: ":name". Os nomes de ficheiros podem conter apenas letras, números, sublinhados, traços e pontos. Veja alguns exemplos de nomes de ficheiros correctos: pagina.htm, pagina, subdiretoria/pagina', + 'invalid_property' => 'A propriedade ":nome" não pode ser definida', + 'file_already_exists' => 'O ficheiro ":name" já existe.', + 'error_saving' => 'Erro ao guardar ficheiro ":name". Verifique as permissões de escrita.', + 'error_creating_directory' => 'Erro ao criar a diretória :name. Verifique as permissões de escrita.', + 'invalid_file_extension'=>'Extensão de ficheiro inválida: :invalid. Extensões válidas: :allowed.', + 'error_deleting' => 'Erro ao apagar o ficheiro de modelo ":name". Verifique as permissões de escrita.', + 'delete_success' => 'Modelos excluídos com sucesso: :count.', + 'file_name_required' => 'O campo de nome do ficheiro é necessário.', + 'safe_mode_enabled' => 'Modo de segurança está activado.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Sitio', + 'online' => 'Online', + 'maintenance' => 'em manutenção', + 'manage_themes' => 'Gerir temas', + 'customize_theme' => 'Personalizar tema' + ] + ], + 'theme' => [ + 'not_found_name' => 'O tema ":name" não foi encontrado.', + 'active' => [ + 'not_set' => 'O tema activo não foi definido.', + 'not_found' => 'O tema activo não foi encontrado.', + ], + 'edit' => [ + 'not_set' => 'O tema de edição não foi definido.', + 'not_found' => 'O tema de edição não foi encontrado.', + 'not_match' => 'O objeto que está tentando aceder não pertence ao tema que está sendo editado. Por favor, recarregue a página.', + ], + 'settings_menu' => 'Tema de front-end', + 'settings_menu_description' => 'Veja a lista de temas instalados e selecione o tema acivo.', + 'default_tab' => 'Propriedades', + 'name_label' => 'Nome', + 'name_create_placeholder' => 'Nome do novo tema', + 'author_label' => 'Autor', + 'author_placeholder' => 'Nome do autor', + 'description_label' => 'Descrição', + 'description_placeholder' => 'Descrição do tema', + 'homepage_label' => 'Sitio', + 'homepage_placeholder' => 'URL do sitio', + 'code_label' => 'Código', + 'code_placeholder' => 'Um código exclusivo para distribuição deste tema', + 'preview_image_label' => 'Imagem de prévisualização do tema', + 'preview_image_placeholder' => 'Caminho da imagem de prévisualização do tema.', + 'dir_name_label' => 'Nome da diretória', + 'dir_name_create_label' => 'A diretória-alvo do tema', + 'theme_label' => 'Tema', + 'theme_title' => 'Temas', + 'activate_button' => 'Activar', + 'active_button' => 'Activado', + 'customize_theme' => 'Personalizar Tema', + 'customize_button' => 'Personalizar', + 'duplicate_button' => 'Duplicar', + 'duplicate_title' => 'Duplicar tema', + 'duplicate_theme_success' => 'Tema duplicado com sucesso!', + 'manage_button' => 'Gerir', + 'manage_title' => 'Gerir tema', + 'edit_properties_title' => 'Tema', + 'edit_properties_button' => 'Editar propriedades', + 'save_properties' => 'Guardar propriedades', + 'import_button' => 'Importar', + 'import_title' => 'Importar tema', + 'import_theme_success' => 'Tema importado com sucesso!', + 'import_uploaded_file' => 'Ficheiro de tema', + 'import_overwrite_label' => 'Sobrescrever ficheiros existentes', + 'import_overwrite_comment' => 'Desmarque para importar apenas ficheiros novos', + 'import_folders_label' => 'Pastas', + 'import_folders_comment' => 'Por favor selecione as pastas de temas que deseja importar', + 'export_button' => 'Exportar', + 'export_title' => 'Exportar tema', + 'export_folders_label' => 'Pastas', + 'export_folders_comment' => 'Por favor selecione as pastas de temas que deseja exportar', + 'delete_button' => 'Apagar', + 'delete_confirm' => 'Tem certeza que deseja apagar este tema? Isto não pode ser revertido!', + 'delete_active_theme_failed' => 'Não é possível apagar o tema activo, torne outro tema activo antes.', + 'delete_theme_success' => 'Tema apagado com sucesso!', + 'create_title' => 'Criar tema', + 'create_button' => 'Criar', + 'create_new_blank_theme' => 'Criar novo tema em branco', + 'create_theme_success' => 'Tema criado com sucesso!', + 'create_theme_required_name' => 'Por favor forneça um nome para o tema.', + 'new_directory_name_label' => 'Diretoria do tema', + 'new_directory_name_comment' => 'Forneça um novo nome de diretoria para o tema duplicado.', + 'dir_name_invalid' => 'O nome só pode conter letras, números, e os símbolos: _-', + 'dir_name_taken' => 'Diretoria de tema escolhido já existe.', + 'find_more_themes' => 'Encontrar mais temas.', + 'saving' => 'Guardando tema...', + 'return' => 'Regressar à lista de temas', + ], + 'maintenance' => [ + 'settings_menu' => 'Modo de manutenção', + 'settings_menu_description' => 'Configurar modo de manutenção e a página exibida.', + 'is_enabled' => 'Activar modo de manutenção', + 'is_enabled_comment' => 'Quando activado visitantes do site vão ver a página selecionada.', + 'hint' => 'Modo de manutenção mostra a página de manutenção aos visitantes que não tenham feito acesso na área de backend.' + ], + 'page' => [ + 'not_found_name' => 'A página ":name" não foi encontrada', + 'not_found' => [ + 'label' => 'Página não encontrada', + 'help' => 'A página solicitada não pode ser encontrada.', + ], + 'custom_error' => [ + 'label' => 'Erro na página', + 'help' => 'Lamentamos, mas algo deu errado, a página não pode ser exibida.', + ], + 'menu_label' => 'Páginas', + 'unsaved_label' => 'Página(s) por guardar', + 'no_list_records' => 'Nenhuma página encontrada', + 'new' => 'Nova página', + 'invalid_url' => 'Formato de URL inválido. A URL deve começar com uma barra e pode conter letras, números e os símbolos: _-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Deseja excluir as páginas selecionadas?', + 'delete_confirm_single' => 'Deseja excluir esta página?', + 'no_layout' => '-- sem esboço --', + 'cms_page' => 'Página do CMS', + 'title' => 'Título da página', + 'url' => 'URL da página', + 'file_name' => 'Nome ficheiro da página' + ], + 'layout' => [ + 'not_found_name' => 'O esboço ":name" não foi encontrado', + 'menu_label' => 'Esboços', + 'unsaved_label' => 'Esboço(s) por guardar', + 'no_list_records' => 'Nenhum esboço encontrado', + 'new' => 'Novo esboço', + 'delete_confirm_multiple' => 'Deseja excluir os esboços selecionados?', + 'delete_confirm_single' => 'Deseja excluir este esboço?', + ], + 'partial' => [ + 'not_found_name' => 'O bloco ":name" não foi encontrado.', + 'invalid_name' => 'Nome de bloco inválido: :name.', + 'menu_label' => 'Blocos', + 'unsaved_label' => 'Bloco(s) por guardar', + 'no_list_records' => 'Nenhum bloco encontrado', + 'delete_confirm_multiple' => 'Deseja apagar os blocos selecionados?', + 'delete_confirm_single' => 'Deseja apagar este bloco?', + 'new' => 'Novo bloco', + ], + 'content' => [ + 'not_found_name' => 'O ficheiro de conteúdo ":name" não foi encontrado.', + 'menu_label' => 'Conteúdo', + 'unsaved_label' => 'Conteúdo por guardar', + 'no_list_records' => 'Nenhum ficheiro de conteúdo encontrado', + 'delete_confirm_multiple' => 'Deseja apagar ficheiros ou diretórios de conteúdo selecionados?', + 'delete_confirm_single' => 'Deseja apagar este ficheiro de conteúdo?', + 'new' => 'Novo ficheiro de conteúdo', + ], + 'ajax_handler' => [ + 'invalid_name' => 'O nome do manipulador AJAX é inválido: :name.', + 'not_found' => 'Manipulador AJAX ":name" não encontrado.', + ], + 'cms' => [ + 'menu_label' => 'CMS', + ], + 'sidebar' => [ + 'add' => 'Adicionar', + 'search' => 'Pesquisar...', + ], + 'editor' => [ + 'settings' => 'Configurações', + 'title' => 'Título', + 'new_title' => 'Título da nova página', + 'url' => 'URL', + 'filename' => 'Nome do ficheiro', + 'layout' => 'Esboço', + 'description' => 'Descrição', + 'preview' => 'Visualizar', + 'meta' => 'Meta', + 'meta_title' => 'Título Meta', + 'meta_description' => 'Descrição Meta', + 'markup' => 'Edição', + 'code' => 'Código', + 'content' => 'Conteúdo', + 'hidden' => 'Oculta', + 'hidden_comment' => 'Páginas ocultas são acessíveis apenas para administradores.', + 'enter_fullscreen' => 'Entrar no modo de tela cheia', + 'exit_fullscreen' => 'Sair do modo de tela cheia', + 'open_searchbox' => 'Abrir caixa de pesquisa', + 'close_searchbox' => 'Fechar caixa de pesquisa', + 'open_replacebox' => 'Abrir caixa de substituição', + 'close_replacebox' => 'Fechar caixa de substituição' + ], + 'asset' => [ + 'menu_label' => 'Ficheiros', + 'unsaved_label' => 'Ficheiro(s) por guardar', + 'drop_down_add_title' => 'Adicionar...', + 'drop_down_operation_title' => 'Acção...', + 'upload_files' => 'Enviar ficheiro(s)', + 'create_file' => 'Criar ficheiro', + 'create_directory' => 'Criar diretoria', + 'directory_popup_title' => 'Novo diretoria', + 'directory_name' => 'Nome do diretoria', + 'rename' => 'Renomear', + 'delete' => 'Apagar', + 'move' => 'Mover', + 'select' => 'Selecionar', + 'new' => 'Novo ficheiro', + 'rename_popup_title' => 'Renomear', + 'rename_new_name' => 'Novo nome', + 'invalid_path' => 'O caminho pode conter apenas letras, números, espaços e os símbolos: ._-/', + 'error_deleting_file' => 'Erro ao apagar ficheiro :name.', + 'error_deleting_dir_not_empty' => 'Erro ao apagar diretoria :name. A diretoria não está vazia.', + 'error_deleting_dir' => 'Erro ao apagar diretoria :name.', + 'invalid_name' => 'O nome pode conter apenas letras, números, espaços e os símbolos: ._-', + 'original_not_found' => 'ficheiro ou diretoria original não encontrado', + 'already_exists' => 'Um ficheiro ou diretoria com este nome já existe', + 'error_renaming' => 'Erro ao renomear o ficheiro ou diretoria', + 'name_cant_be_empty' => 'O nome não pode estar vazio', + 'too_large' => 'O ficheiro enviado é muito grande. O tamanho máximo permitido é :max_size', + 'type_not_allowed' => 'Apenas os seguintes tipos de ficheiros são permitidos: :allowed_types', + 'file_not_valid' => 'O ficheiro não é válido', + 'error_uploading_file' => 'Erro carregando ficheiro ":name": :error', + 'move_please_select' => 'por favor selecione', + 'move_destination' => 'Diretoria de destino', + 'move_popup_title' => 'Mover ficheiros', + 'move_button' => 'Mover', + 'selected_files_not_found' => 'ficheiros selecionados não encontrados', + 'select_destination_dir' => 'Por favor, selecione uma diretoria de destino', + 'destination_not_found' => 'Diretoria de destino não encontrada', + 'error_moving_file' => 'Erro ao mover ficheiro :file', + 'error_moving_directory' => 'Erro ao mover diretoria :dir', + 'error_deleting_directory' => 'Erro ao apagar o diretoria original :dir', + 'no_list_records' => 'Não foram encontrados ficheiros', + 'delete_confirm' => 'Apagar ficheiros ou directorias selecionadas?', + 'path' => 'Caminho', + ], + 'component' => [ + 'menu_label' => 'Componentes', + 'unnamed' => 'Sem nome', + 'no_description' => 'Nenhuma descrição fornecida', + 'alias' => 'Apelido', + 'alias_description' => 'Um nome exclusivo dado a este componente quando utilizado no código de uma página ou esboço.', + 'validation_message' => 'Apelidos de componentes são necessários e podem conter letras, números e sublinhados. Os apelidos devem começar com uma letra.', + 'invalid_request' => 'O modelo não pode ser guardado devido a dados inválidos nos componentes.', + 'no_records' => 'Nenhum componente encontrado', + 'not_found' => 'O componente ":name" não foi encontrado.', + 'method_not_found' => 'O componente ":name" não tem um método ":method".', + ], + 'template' => [ + 'invalid_type' => 'Tipo de modelo desconhecido.', + 'not_found' => 'O modelo solicitado não foi encontrado.', + 'saved'=> 'O modelo foi salvo com sucesso.', + 'no_list_records' => 'Não foram encontrados registos', + 'delete_confirm' => 'Apagar modelos selecionados?', + 'order_by' => 'Ordenar por' + ], + 'permissions' => [ + 'name' => 'Cms', + 'manage_content' => 'Gerir conteúdo', + 'manage_assets' => 'Gerir ficheiros', + 'manage_pages' => 'Gerir páginas', + 'manage_layouts' => 'Gerir esboços', + 'manage_partials' => 'Gerir blocos', + 'manage_themes' => 'Gerir temas', + ], + 'theme_log' => [ + 'hint' => 'Este registo mostra as alterações efectuadas ao tema por administradores na área de backend.', + 'menu_label' => 'Registo de tema', + 'menu_description' => 'Ver alterações ao tema activo.', + 'empty_link' => 'Registo de tema vazio', + 'empty_loading' => 'Esvaziar registos de tema...', + 'empty_success' => 'Registo de temas vazio', + 'return_link' => 'Regressar ao registo de temas', + 'id' => 'ID', + 'id_label' => 'Registo ID', + 'created_at' => 'Data & Hora', + 'user' => 'Utilizador', + 'type' => 'Tipo', + 'type_create' => 'Criar', + 'type_update' => 'Alterar', + 'type_delete' => 'Apagar', + 'theme_name' => 'Tema', + 'theme_code' => 'Código de tema', + 'old_template' => 'Modelo (antigo)', + 'new_template' => 'Modelo (novo)', + 'template' => 'Modelo', + 'diff' => 'Alterações', + 'old_value' => 'Valor antigo', + 'new_value' => 'Novo valor', + 'preview_title' => 'Modelo alterado', + 'template_updated' => 'O modelo foi actualizado', + 'template_created' => 'O modelo foi criado', + 'template_deleted' => 'O modelo foi apagado', + ], +]; diff --git a/modules/cms/lang/ro/lang.php b/modules/cms/lang/ro/lang.php new file mode 100644 index 0000000..9fad120 --- /dev/null +++ b/modules/cms/lang/ro/lang.php @@ -0,0 +1,167 @@ + [ + 'invalid_file' => 'Nume de fisier invalid: :name. Numele de fisiere pot sa contina doar caractere alfanumerice, linii si puncte. Unele exemple de nume de fisiere corecte: pagina_1.htm, pagina-2, subdirector/pagina', + 'invalid_property' => 'Proprietatea ":name" nu poate fi setata', + 'file_already_exists' => 'Fisierul ":name" deja exista.', + 'error_saving' => 'Eroare la salvarea fisierului ":name". Verificati permisiunile de scriere.', + 'error_creating_directory' => 'Eroare la crearea directorului :name. Verificati permisiunile de scriere.', + 'invalid_file_extension'=>'Extensie de fisier invalida: :invalid. Extensiile permise sunt: :allowed.', + 'error_deleting' => 'Eroare la stergerea fisierului sablon ":name". Verificati permisiunile de scriere.', + 'delete_success' => 'Sabloanele au fost sterse cu succes, in total: :count.', + 'file_name_required' => 'Campul nume fisier este necesar.' + ], + 'theme' => [ + 'active' => [ + 'not_set' => "Tema activa nu este setata.", + 'not_found' => "Tema activa nu a fost gasita.", + ], + 'edit' => [ + 'not_set' => "Tema de editare nu este setata.", + 'not_found' => "Tema de editare nu a fost gasita.", + 'not_match' => "Obiectul pe care incercati sa-l accesati nu apartine temei care este in curs de editare. Va rugam reincarcati pagina." + ], + 'settings_menu' => 'Tema Front-end', + 'settings_menu_description' => 'Previzualizati lista de teme instalate si selectati o tema activa.', + 'find_more_themes' => 'Gasiti mai multe teme in "Piata OctoberCMS".', + 'activate_button' => 'Activare', + 'active_button' => 'Activare', + ], + 'page' => [ + 'not_found' => [ + 'label' => "Pagina negasita", + 'help' => "Pagina cautata nu a putut fi gasita.", + ], + 'custom_error' => [ + 'label' => "Eroare pagina", + 'help' => "Ne cerem scuze, dar a aparut o problema si pagina nu poate fi afisata.", + ], + 'menu_label' => 'Pagini', + 'no_list_records' => 'Nu au fost gasite pagini', + 'new' => 'Pagina noua', + 'invalid_url' => 'Format URL invalid. URL-ul ar trebui sa inceapa cu un slash ( / ) si poate sa contina cifre, caractere latine si urmatoarele simboluri: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Vreti sa stergeti paginile selectate?', + 'delete_confirm_single' => 'Vreti sa stergeti aceasta pagina?', + 'no_layout' => '-- fara macheta --' + ], + 'layout' => [ + 'not_found_name' => "Macheta ':name' nu a fost gasita", + 'menu_label' => 'Machete', + 'no_list_records' => 'Nu au fost gasite machete', + 'new' => 'Macheta noua', + 'delete_confirm_multiple' => 'Vreti sa stergeti machetele selectate?', + 'delete_confirm_single' => 'Vreti sa stergeti macheta selectata?' + ], + 'partial' => [ + 'not_found_name' => "Componenta partiala ':name' nu a fost gasita.", + 'invalid_name' => "Nume invalid pentru componenta partiala: :name.", + 'menu_label' => 'Componente partiale', + 'no_list_records' => 'Nu au fost gasite componente partiale', + 'delete_confirm_multiple' => 'Vreti sa stergeti componentele partiale selectate?', + 'delete_confirm_single' => 'Vreti sa stergeti aceasta componenta partiala?', + 'new' => 'Componenta partiala noua' + ], + 'content' => [ + 'not_found_name' => "Fisierul de continut ':name' nu a fost gasit.", + 'menu_label' => 'Continut', + 'no_list_records' => 'Nu au fost gasite fisiere de continut', + 'delete_confirm_multiple' => 'Vreti sa stergeti fisierele si directoarele cu continut?', + 'delete_confirm_single' => 'Vreti sa stergeti acest fisier cu continut?', + 'new' => 'Fisier nou cu continut' + ], + 'ajax_handler' => [ + 'invalid_name' => "Nume Functie AJAX invalid: :name.", + 'not_found' => "Functia AJAX ':name' nu a fost gasita.", + ], + 'cms' => [ + 'menu_label' => "CMS" + ], + 'sidebar' => [ + 'add' => 'Adaugare', + 'search' => 'Cautare...' + ], + 'editor' => [ + 'settings' => 'Setari', + 'title' => 'Titlu', + 'new_title' => 'Titlu de pagina noua', + 'url' => 'URL', + 'filename' => 'Nume fisier', + 'layout' => 'Macheta', + 'description' => 'Descriere', + 'preview' => 'Previzualizare', + 'meta' => 'Meta', + 'meta_title' => 'Titlu Meta', + 'meta_description' => 'Descriere Meta', + 'markup' => 'Markup', + 'code' => 'Cod', + 'content' => 'Continut', + 'hidden' => 'Ascuns', + 'hidden_comment' => 'Fisierele ascunse sunt vizibile doar administratorilor logati in sistem', + 'enter_fullscreen' => 'Intrare in mod ecran complet', + 'exit_fullscreen' => 'Iesire din mod ecran complet' + ], + 'asset' => [ + 'menu_label' => "Fisiere design", + 'drop_down_add_title' => 'Adaure...', + 'drop_down_operation_title' => 'Actiune...', + 'upload_files' => 'Incarcare fisier(e)', + 'create_file' => 'Creare fisier', + 'create_directory' => 'Creare director', + 'rename' => 'Redenumire', + 'delete' => 'Stergere', + 'move' => 'Mutare', + 'new' => 'Fisier nou', + 'rename_popup_title' => 'Redenumire', + 'rename_new_name' => 'Nume nou', + 'invalid_path' => 'Calea poate sa contina doar cifre, caractere latine, spatii si urmatoarele simboluri: ._-/', + 'error_deleting_file' => 'Eroare la stergerea fisierului :name.', + 'error_deleting_dir_not_empty' => 'Eroare la stergerea directorului :name. Directorul nu este gol.', + 'error_deleting_dir' => 'Eroare la stergerea fisierului :name.', + 'invalid_name' => 'Numele poate sa contina doar cifre, caractere latine si urmatoarele simboluri: ._-', + 'original_not_found' => 'Fisierul sau directorul original nu a fost gasit', + 'already_exists' => 'Fisierul sau directorul cu acest nume exista deja', + 'error_renaming' => 'Eroare la redenumirea fisierului sau directorului', + 'name_cant_be_empty' => 'Numele nu poate fi gol', + 'too_large' => 'Fisierul incarcat este prea mare. Dimensiunea maxima permisa este: :max_size', + 'type_not_allowed' => 'Doar urmatoarele tipuri de fisiere sunt permise: :allowed_types', + 'file_not_valid' => 'Fisierul nu este valid', + 'error_uploading_file' => 'Eroare la incarcarea fisierului ":name", eroare: :error', + 'move_please_select' => 'selectati', + 'move_destination' => 'Director destinatie', + 'move_popup_title' => 'Mutare fisiere', + 'move_button' => 'Mutare', + 'selected_files_not_found' => 'Fisierele selectate nu au fost gasite', + 'select_destination_dir' => 'Selectati un director pentru destinatie', + 'destination_not_found' => 'Directorul destinatie nu a fost gasit', + 'error_moving_file' => 'Eroare la mutarea fisierului :file', + 'error_moving_directory' => 'Eroare la mutarea directorului :dir', + 'error_deleting_directory' => 'Eroare la stergerea directorului original :dir', + 'path' => 'Cale' + ], + 'component' => [ + 'menu_label' => "Componente", + 'unnamed' => "Fara nume", + 'no_description' => "Nicio descriere furnizata", + 'alias' => "Alias", + 'alias_description' => "Numele unic dat acestei componente atunci cand este folosita intr-o pagina sau intr-o macheta.", + 'validation_message' => "Aliasul componentei este necesar si poate sa contina doar caractere latine, cifre si caractere underscore. Denumirile are trebui sa inceapa cu un caracter latin.", + 'invalid_request' => "Sablonul nu a putut fi salvat din cauza datelor invalide ale componentei.", + 'no_records' => 'Nicio componenta nu a fost gasita', + 'not_found' => "Componenta ':name' nu a fost gasita.", + 'method_not_found' => "Componenta ':name' nu contine nicio metoda ':method'.", + ], + 'template' => [ + 'invalid_type' => "Tip de sablon necunoscut.", + 'not_found' => "Sablonul solicitat nu a fost gasit.", + 'saved'=> "Sablonul a fost salvat cu succes." + ], + 'permissions' => [ + 'manage_content' => 'Gestioneaza continut', + 'manage_assets' => 'Gestioneaza fisiere design', + 'manage_pages' => 'Gestioneaza pagini', + 'manage_layouts' => 'Gestioneaza machete', + 'manage_partials' => 'Gestioneaza componente partiale', + 'manage_themes' => 'Gestioneaza teme' + ] +]; diff --git a/modules/cms/lang/rs/lang.php b/modules/cms/lang/rs/lang.php new file mode 100644 index 0000000..046600b --- /dev/null +++ b/modules/cms/lang/rs/lang.php @@ -0,0 +1,303 @@ + [ + 'invalid_file' => 'Naziv fajla nije validan: :name. Nazivi fajlova mogu sadržati samo alfanumeričke simbole, donje crte, povlake i tačke. Validni primeri su: strana.htm, strana, direktorijum/strana', + 'invalid_property' => "Svojstvo ':name' se ne može postaviti", + 'file_already_exists' => "Fajl ':name' već postoji.", + 'error_saving' => "Greška pri čuvanju fajla ':name'. Proveri dozvole na sistemu.", + 'error_creating_directory' => 'Greška pri pravljenju direktorijuma :name. Proveri dozvole na sistemu.', + 'invalid_file_extension' => 'Ekstenzija fajla nije validna: :invalid. Dozvoljene ekstenzije su: :allowed.', + 'error_deleting' => "Greška pri brisanju šablonskog fajla ':name'. Proveri dozvole na sistemu.", + 'delete_success' => 'Izbrisani šabloni: :count.', + 'file_name_required' => 'Polje za naziv fajla je obavezno.', + 'safe_mode_enabled' => 'Signurni režim je trenutno omogućen. Izmena PHP koda u CMS šablonima je trenutno onemogućena. Da isključiš siguran režim rada, izmeni vrednost konfiguracione promenljive `cms.enableSafeMode` u `false`.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Sajt', + 'online' => 'Na mreži', + 'maintenance' => 'U fazi održavanju', + 'manage_themes' => 'Upravljaj temama', + 'customize_theme' => 'Izmeni temu', + ], + ], + 'theme' => [ + 'not_found_name' => "Tema ':name' nije pronađena.", + 'by_author' => 'Autor: :name', + 'active' => [ + 'not_set' => 'Aktivna tema nije postavljena.', + 'not_found' => 'Aktivna tema nije pronađena.', + ], + 'edit' => [ + 'not_set' => 'Tema za izmenu nije postavljena.', + 'not_found' => 'Tema za izmenu nije pronađena.', + 'not_match' => "Objekat kojem pokušavaš da pristupiš ne pripada temi koju menjaš. Osveži stranicu.", + ], + 'settings_menu' => 'Teme', + 'settings_menu_description' => 'Upravljaj temama i opcijama prilagođavanja.', + 'default_tab' => 'Svojstva', + 'name_label' => 'Naziv', + 'name_create_placeholder' => 'Naziv nove teme', + 'author_label' => 'Autor', + 'author_placeholder' => 'Pravno ili privatno lice', + 'description_label' => 'Opis', + 'description_placeholder' => 'Opis teme', + 'homepage_label' => 'Početna stranica', + 'homepage_placeholder' => 'URL sajta', + 'code_label' => 'Kod', + 'code_placeholder' => 'Jedinstveni kod ove teme za distribuciju', + 'preview_image_label' => 'Slika pregleda', + 'preview_image_placeholder' => 'Putanja za sliku pregleda teme.', + 'dir_name_label' => 'Naziv direktorijuma', + 'dir_name_create_label' => 'Odredišni direktorijum za temu', + 'theme_label' => 'Tema', + 'theme_title' => 'Teme', + 'activate_button' => 'Aktiviraj', + 'active_button' => 'Aktiviraj', + 'customize_theme' => 'Izmeni temu', + 'customize_button' => 'Izmeni', + 'duplicate_button' => 'Duplikat', + 'duplicate_title' => 'Dupliraj temu', + 'duplicate_theme_success' => 'Tema duplirana!', + 'manage_button' => 'Upravljaj', + 'manage_title' => 'Upravljaj temom', + 'edit_properties_title' => 'Tema', + 'edit_properties_button' => 'Izmeni svojstva', + 'save_properties' => 'Snimi svojstva', + 'import_button' => 'Uvezi', + 'import_title' => 'Uvezi temu', + 'import_theme_success' => 'Tema uvežena!', + 'import_uploaded_file' => 'Arhivni fajl teme', + 'import_overwrite_label' => 'Pregazi postojeće fajlove', + 'import_overwrite_comment' => 'Nemoj čekirati ovo polje ako želiš samo da uvezeš nove fajlove', + 'import_folders_label' => 'Direktorijumi', + 'import_folders_comment' => 'Odaberi direktorijume teme koje želiš da uvezeš', + 'export_button' => 'Eksportuj', + 'export_title' => 'Eksportuj temu', + 'export_folders_label' => 'Direktorijumi', + 'export_folders_comment' => 'Odaberi direktorijume teme koje želiš da izvezeš', + 'delete_button' => 'Izbriši', + 'delete_confirm' => 'Izbriši ovu temu? Ova radnja se ne može poništiti.', + 'delete_active_theme_failed' => 'Aktivna tema se ne može izbrisati, pokušaj prvo da napraviš i aktiviraš drugu.', + 'delete_theme_success' => 'Tema izbrisana!', + 'create_title' => 'Napravi temu', + 'create_button' => 'Napravi', + 'create_new_blank_theme' => 'Napravi novu praznu temu', + 'create_theme_success' => 'Tema napravljena!', + 'create_theme_required_name' => 'Odaberi naziv za temu.', + 'new_directory_name_label' => 'Direktorijum teme', + 'new_directory_name_comment' => 'Odaberi drugi naziv za direktorijum teme koja je duplikat.', + 'dir_name_invalid' => 'Naziv može sadržati samo brojeve, latinska slova, kao i sledeće simbole: _-', + 'dir_name_taken' => 'Direktorijum za željenu temu postoji.', + 'find_more_themes' => 'Pronađi još tema', + 'saving' => 'Čuvanje tema...', + 'return' => 'Nazad na listu tema', + ], + 'maintenance' => [ + 'settings_menu' => 'Mod održavanja', + 'settings_menu_description' => 'Konfiguriši mod održavanja stranice i uključi/isključi isti.', + 'is_enabled' => 'Uključi mod održavanja', + 'is_enabled_comment' => 'Izaberi stranicu za prikazivanje kada je mod održavanja uključen.', + 'hint' => 'Mod održavanja će prikazati odabranu stranicu korisnicima koji nisu ulogovani preko pozadinskog sistema.', + ], + 'page' => [ + 'not_found_name' => "Strana ':name' nije pronađena", + 'not_found' => [ + 'label' => 'Strana nije pronađena', + 'help' => 'Tražena strana nije pronađena.', + ], + 'custom_error' => [ + 'label' => 'Greška sa stranom', + 'help' => "Žao nam je, nešto je pošlo po zlu pa strana ne može biti prikazana.", + ], + 'menu_label' => 'Strane', + 'unsaved_label' => 'Nesačuvana strana(e)', + 'no_list_records' => 'Nema pronađenih strana', + 'new' => 'Nova strana', + 'invalid_url' => 'Format URL-a nije validan. URL treba početi sa kosom crtom i može sadržati brojeve, latinska slova, kao i sledeće simbole: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Izbriši odabrane strane?', + 'delete_confirm_single' => 'Izbriši ovu stranu?', + 'no_layout' => '-- nema plana --', + 'cms_page' => 'CMS strana', + 'title' => 'Naslov strane', + 'url' => 'URL strane', + 'file_name' => 'Naziv fajla strane', + ], + 'layout' => [ + 'not_found_name' => "Plan ':name' nije pronađen", + 'menu_label' => 'Planovi', + 'unsaved_label' => 'Nesačuvani plan(ovi)', + 'no_list_records' => 'Nema pronađenih planova', + 'new' => 'Novi plan', + 'delete_confirm_multiple' => 'Izbriši izabrane planove?', + 'delete_confirm_single' => 'Izbriši ovaj plan?', + ], + 'partial' => [ + 'not_found_name' => "Parcijal ':name' nije pronađen", + 'invalid_name' => 'Naziv parcijala nije validan: :name.', + 'menu_label' => 'Parcijal', + 'unsaved_label' => 'Nesačuvan parcijal(i)', + 'no_list_records' => 'Nema pronađenih parcijala', + 'delete_confirm_multiple' => 'Izbriši izabrane parcijale?', + 'delete_confirm_single' => 'Izbriši ovaj parcijal?', + 'new' => 'Novi parcijal', + ], + 'content' => [ + 'not_found_name' => "Fajl sadržaja ':name' nije pronađen", + 'menu_label' => 'Sadržaj', + 'unsaved_label' => 'Nesačuvani sadržaj', + 'no_list_records' => 'Fajlovi za sardžaj nisu pronađeni', + 'delete_confirm_multiple' => 'Izbriši odabrane fajlove ili direktorijume za sadržaj?', + 'delete_confirm_single' => 'Izbriši ovaj fajl za sadržaj?', + 'new' => 'Novi fajl za sadržaj', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Naziv za AJAX rukovatelja nije validan: :name.', + 'not_found' => "AJAX rukovatelj ':name' nije pronađen.", + ], + 'cms' => [ + 'menu_label' => 'CMS', + ], + 'sidebar' => [ + 'add' => 'Dodaj', + 'search' => 'Traži...', + ], + 'editor' => [ + 'settings' => 'Podešavanja', + 'title' => 'Naslov', + 'new_title' => 'Naslov nove strane', + 'url' => 'URL', + 'filename' => 'Naziv fajla', + 'layout' => 'Plan', + 'description' => 'Opis', + 'preview' => 'Pregled', + 'meta' => 'Meta', + 'meta_title' => 'Meta Naslov', + 'meta_description' => 'Meta Opis', + 'markup' => 'Označavanje', + 'code' => 'Kod', + 'content' => 'Sadržaj', + 'hidden' => 'Skrivena', + 'hidden_comment' => 'Skrivena stranica je dostupna samo korisnicima koji su ulogovani na pozadinski sistem.', + 'enter_fullscreen' => 'Uđite u režim punog ekrana', + 'exit_fullscreen' => 'Izađite iz režima punog ekrana', + 'open_searchbox' => 'Otvori polje za pretragu', + 'close_searchbox' => 'Zatvori polje za pretragu', + 'open_replacebox' => 'Otvori polje za zamenu', + 'close_replacebox' => 'Zatvori polje za zamenu', + 'commit' => 'Izvrši', + 'reset' => 'Resetuj', + 'commit_confirm' => 'Da li zaista želite da izvršite promene nad ovim fajlom? Ovo će pregaziti postojeći', + 'reset_confirm' => 'Da li zaista želite da resetujete ovaj fajl? Ovo će u potpunosti zameniti trenutni sa onim koji je na sistemu', + 'committing' => 'Izvršavanje', + 'resetting' => 'Resetovanje', + 'commit_success' => 'Izvršenje :type je uspešno.', + 'reset_success' => 'Resetovanje :type je uspešno.', + ], + 'asset' => [ + 'menu_label' => 'Sredstva', + 'unsaved_label' => 'Nesačuvano sredstvo(a)', + 'drop_down_add_title' => 'Dodaj...', + 'drop_down_operation_title' => 'Radnja...', + 'upload_files' => 'Otpremi fajl(ove)', + 'create_file' => 'Napravi fajl', + 'create_directory' => 'Napravi direktorijum', + 'directory_popup_title' => 'Novi direktorijum', + 'directory_name' => 'Naziv direktorijuma', + 'rename' => 'Promeni naziv', + 'delete' => 'Izbriši', + 'move' => 'Pomeri', + 'select' => 'Izaberi', + 'new' => 'Novi fajl', + 'rename_popup_title' => 'Promeni naziv', + 'rename_new_name' => 'Novi naziv', + 'invalid_path' => 'Putanja može sadržati samo brojeve, latinska slova, razmake, kao i sledeće simbole: ._-/', + 'error_deleting_file' => 'Greška pri brisanju fajla :name.', + 'error_deleting_dir_not_empty' => 'Greška pri brisanju direktorijuma :name. Direktorijum nije prazan.', + 'error_deleting_dir' => 'Greška pri brisanju direktorijuma :name.', + 'invalid_name' => 'Naziv može sadržati samo brojeve, latinska slova, razmake, kao i sledeće simbole: ._-', + 'original_not_found' => 'Originalni fajl ili direktorijum nije pronađen', + 'already_exists' => 'Fajl ili direktorijum sa ovim nazivom već postoji', + 'error_renaming' => 'Greška pri promeni naziva fajla ili direktorijuma', + 'name_cant_be_empty' => 'Naziv ne može biti prazan', + 'too_large' => 'Otpremljeni fajl je previše velik. Maksimalna dozvoljena veličina je :max_size', + 'type_not_allowed' => 'Samo sledeći tipovi fajla su dozvoljeni: :allowed_types', + 'file_not_valid' => 'Fajl nije validan', + 'error_uploading_file' => "Greška pri otpremanju fajla ':name': :error", + 'move_please_select' => 'Izaberi', + 'move_destination' => 'Odredište direktorijuma', + 'move_popup_title' => 'Pomeri sredstva', + 'move_button' => 'Pomeri', + 'selected_files_not_found' => 'Izabrani fajlovi nisu pronađeni', + 'select_destination_dir' => 'Izaberi odredišni direktorijum', + 'destination_not_found' => 'Odredišni direktorijum nije pronađen', + 'error_moving_file' => 'Greška pri pomeranju fajla :file', + 'error_moving_directory' => 'Greška pri pomeranju direktorijuma :dir', + 'error_deleting_directory' => 'Greška pri brisanju originalnog direktorijuma :dir', + 'no_list_records' => 'Nema pronađenih fajlova', + 'delete_confirm' => 'Izbriši izabrane fajlove ili direktorijume?', + 'path' => 'Putanja', + ], + 'component' => [ + 'menu_label' => 'Komponente', + 'unnamed' => 'Bez naziva', + 'no_description' => 'Opis nije dat', + 'alias' => 'Pseudonim', + 'alias_description' => 'Jedinstven naziv koji je dat komponenti kada se koristi u stranici ili kodu plana.', + 'validation_message' => 'Pseudonimi komponente su neophodni i mogu sadržati samo latinske simbole, brojeve i donje crte. Pseudonimi bi trebalo da počinju latinskim simbolom.', + 'invalid_request' => 'Šablon ne može biti sačuvan zbog podataka koji nisu validni.', + 'no_records' => 'Nema pronađenih komponenti', + 'not_found' => "Komponenta ':name' nije pronađena.", + 'method_not_found' => "Komponenta ':name' ne sadrži ':method'.", + 'soft_component' => 'Opciona komponenta', + 'soft_component_description' => 'Ova komponenta nedostaje ali je opciona.', + ], + 'template' => [ + 'invalid_type' => 'Nepoznati tip šablona.', + 'not_found' => 'Šablon nije pronađen.', + 'saved' => 'Šablon sačuvan.', + 'no_list_records' => 'Zapisi nisu pronađeni', + 'delete_confirm' => 'Izbriši izabrane šablone?', + 'order_by' => 'Sortiraj po', + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Upravljaj sadržajem sajta', + 'manage_assets' => 'Upravljaj slikama, JS i CSS fajlovima sajta', + 'manage_pages' => 'Napravi, modifikuj i izbriši stranice sajta', + 'manage_layouts' => 'Napravi, modifikuj i izbriši planove CMS-a', + 'manage_partials' => 'Napravi, modifikuj i izbriši parcijale CMS-a', + 'manage_themes' => 'Aktiviraj, deaktiviraj i konfiguriši teme CMS-a', + 'manage_theme_options' => 'Konfiguriši opcije izmena za aktivnu temu', + ], + 'theme_log' => [ + 'hint' => 'Ovaj log prikazuje promene načinjene nad temom od strane administratora u pozadinskom delu sistema.', + 'menu_label' => 'Log teme', + 'menu_description' => 'Prikaži promene načinjene nad aktivnom temom.', + 'empty_link' => 'Isprazni log teme', + 'empty_loading' => 'Pražnjenje loga teme...', + 'empty_success' => 'Log teme je ispražnjen', + 'return_link' => 'Vrati se na logove teme', + 'id' => 'ID', + 'id_label' => 'ID loga', + 'created_at' => 'Datum & vreme', + 'user' => 'Korisnik', + 'type' => 'Tip', + 'type_create' => 'Napravi', + 'type_update' => 'Ažuriraj', + 'type_delete' => 'Izbriši', + 'theme_name' => 'Tema', + 'theme_code' => 'Kod teme', + 'old_template' => 'Šablon (Stari)', + 'new_template' => 'Šablon (Novi)', + 'template' => 'Šablon', + 'diff' => 'Izmene', + 'old_value' => 'Stara vrednost', + 'new_value' => 'Nova vrednost', + 'preview_title' => 'Izmene šablona', + 'template_updated' => 'Šablon je ažuriran', + 'template_created' => 'Šablon je napravljen', + 'template_deleted' => 'Šablon je izbrisan', + ], +]; diff --git a/modules/cms/lang/ru/lang.php b/modules/cms/lang/ru/lang.php new file mode 100644 index 0000000..d3cf55c --- /dev/null +++ b/modules/cms/lang/ru/lang.php @@ -0,0 +1,304 @@ + [ + 'invalid_file' => 'Ошибка в имени файла: :name. Имена файлов могут содержать только латинские буквы, цифры, знаки подчеркивания и точки. Пример правильных имен файлов: page.htm, page, subdirectory/page', + 'invalid_property' => "Параметр ':name' нельзя изменить.", + 'file_already_exists' => "Файл ':name' уже существует.", + 'error_saving' => "Ошибка сохранения файла ':name'. Пожалуйста, проверьте права на запись.", + 'error_creating_directory' => 'Ошибка создания директории :name. Пожалуйста, проверьте права на запись.', + 'invalid_file_extension' => 'Указано неправильное расширение файла: :invalid. Разрешенные расширения: :allowed.', + 'error_deleting' => "Невозможно удалить файл шаблона ':name'. Пожалуйста, проверьте права на запись.", + 'delete_success' => 'Шаблоны были успешно удалены: :count.', + 'file_name_required' => 'Пожалуйста, укажите имя файла шаблона.', + 'safe_mode_enabled' => 'В настоящий момент включен безопасный режим.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Веб-сайт', + 'online' => 'Онлайн', + 'maintenance' => 'в разработке', + 'manage_themes' => 'Управление темами', + 'customize_theme' => 'Настройка темы', + ], + ], + 'theme' => [ + 'not_found_name' => "Тема ':name' не найдена.", + 'by_author' => 'Создано :name', + 'active' => [ + 'not_set' => 'Активная тема не установлена.', + 'not_found' => 'Активная тема не найдена.', + ], + 'edit' => [ + 'not_set' => 'Тема для редактирования не установлена.', + 'not_found' => 'Тема для редактирования не найдена.', + 'not_match' => 'Объект, который вы пытаетесь открыть, не принадлежит редактируемой теме. Пожалуйста, обновите страницу.', + ], + 'settings_menu' => 'Фронтенд темы', + 'settings_menu_description' => 'Управление темой интерфейса', + 'default_tab' => 'Свойства', + 'name_label' => 'Название', + 'name_create_placeholder' => 'Название новой темы', + 'author_label' => 'Автор', + 'author_placeholder' => 'Имя автора или название компании', + 'description_label' => 'Описание', + 'description_placeholder' => 'Описание темы', + 'homepage_label' => 'Домашняя страница', + 'homepage_placeholder' => 'Адрес сайта', + 'code_label' => 'Уникальный код', + 'code_placeholder' => 'Уникальный код темы, который используются для её распространения', + 'preview_image_label' => 'Предварительный просмотр', + 'preview_image_placeholder' => 'Путь изображения предварительного просмотра темы.', + 'dir_name_label' => 'Имя директории', + 'dir_name_create_label' => 'Директория темы', + 'theme_label' => 'Тема', + 'theme_title' => 'Темы', + 'activate_button' => 'Активировать', + 'active_button' => 'Активировано', + 'customize_theme' => 'Настройка темы', + 'customize_button' => 'Настроить', + 'duplicate_button' => 'Дублировать', + 'duplicate_title' => 'Дублировать тему', + 'duplicate_theme_success' => 'Дублирование успешно завершено!', + 'manage_button' => 'Управление', + 'manage_title' => 'Управление темой', + 'edit_properties_title' => 'Тема', + 'edit_properties_button' => 'Редактирование свойств', + 'save_properties' => 'Сохранить свойства', + 'import_button' => 'Импортировать', + 'import_title' => 'Импортировать тему', + 'import_theme_success' => 'Импортирование темы успешно завершено!', + 'import_uploaded_file' => 'Файл архива темы', + 'import_overwrite_label' => 'Перезаписывать существующие файлы', + 'import_overwrite_comment' => 'Отключите эту опцию, чтобы импортировать только новые файлы', + 'import_folders_label' => 'Директории', + 'import_folders_comment' => 'Пожалуйста, выберите директории темы, которые вы хотели бы импортировать', + 'export_button' => 'Экспортировать', + 'export_title' => 'Экспортировать тему', + 'export_folders_label' => 'Директории', + 'export_folders_comment' => 'Пожалуйста, выберите директории темы, которые вы хотели бы экспортировать', + 'delete_button' => 'Удалить', + 'delete_confirm' => 'Вы уверены, что хотите удалить эту тему? Это действие необратимо!', + 'delete_active_theme_failed' => 'Невозможно удалить активный тему, попробуйте сделать другую тему активной.', + 'delete_theme_success' => 'Удаление темы успешно завершено!', + 'create_title' => 'Создать тему', + 'create_button' => 'Создать', + 'create_new_blank_theme' => 'Создать новую пустую тему', + 'create_theme_success' => 'Создание темы успешно завершено!', + 'create_theme_required_name' => 'Пожалуйста, укажите имя для темы.', + 'new_directory_name_label' => 'Директория темы', + 'new_directory_name_comment' => 'Укажите новое имя каталога для дубликата темы.', + 'dir_name_invalid' => 'Имя может содержать только цифры, латинские буквы и следующие символы: _ -', + 'dir_name_taken' => 'Указанный каталог уже существует.', + 'find_more_themes' => 'Найти еще темы', + 'saving' => 'Сохранение темы...', + 'return' => 'Вернуться к списку тем', + ], + 'maintenance' => [ + 'settings_menu' => 'Режим обслуживания', + 'settings_menu_description' => 'Управление режимом работы сайта.', + 'is_enabled' => 'Включить режим обслуживания', + 'is_enabled_comment' => 'При активации этого режима посетители сайта увидят страницу выбранную ниже.', + 'hint' => 'Режим обслуживания покажет страницу обслуживания для посетителей, которые не вошли в бэкенд.', + ], + 'page' => [ + 'not_found_name' => "Страница ':name' не найдена", + 'not_found' => [ + 'label' => 'Страница не найдена', + 'help' => 'Запрошенная страница не найдена.', + ], + 'custom_error' => [ + 'label' => 'Ошибка на странице', + 'help' => 'К сожалению, страница не может быть отображена из-за ошибки.', + ], + 'menu_label' => 'Страницы', + 'unsaved_label' => 'Несохранённая(е) страница(ы)', + 'no_list_records' => 'Страницы не найдены', + 'new' => 'Новая страница', + 'invalid_url' => 'Неверный формат адреса. Адрес страницы должен начинаться со знака / и может содержать цифры, латинские буквы, и следующие знаки: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Вы действительно хотите удалить выделенные страницы?', + 'delete_confirm_single' => 'Вы действительно хотите удалить эту страницу?', + 'no_layout' => '-- без шаблона --', + 'cms_page' => 'CMS страница', + 'title' => 'Заголовок страницы', + 'url' => 'Страница URL', + 'file_name' => 'Имя файла страницы', + ], + 'layout' => [ + 'not_found_name' => "Не удалось найти макет с именем :name.", + 'menu_label' => 'Макеты', + 'unsaved_label' => 'Несохранённый(е) макет(ы)', + 'no_list_records' => 'Макет не найдено', + 'new' => 'Новый макет', + 'delete_confirm_multiple' => 'Удалить выделенные макеты?', + 'delete_confirm_single' => 'Удалить этот макет?', + ], + 'partial' => [ + 'not_found_name' => "Не удалось найти фрагмент с именем :name.", + 'invalid_name' => 'Ошибка в имени фрагмента :name.', + 'menu_label' => 'Фрагменты', + 'unsaved_label' => 'Несохранённый(е) фрагмент(ы)', + 'no_list_records' => 'Фрагменты не найдены', + 'delete_confirm_multiple' => 'Удалить выделенные фрагменты?', + 'delete_confirm_single' => 'Удалить этот фрагмент?', + 'new' => 'Новый фрагмент', + ], + 'content' => [ + 'not_found_name' => "Не удалось найти контент-файл: ':name'.", + 'menu_label' => 'Контент', + 'unsaved_label' => 'Несохранённый контент', + 'no_list_records' => 'Контент-файлы не найдены', + 'delete_confirm_multiple' => 'Вы действительно хотите удалить выделенные файлы?', + 'delete_confirm_single' => 'Вы действительно хотите удалить этот файл?', + 'new' => 'Новый контент-файл', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Ошибка в имени обработчика AJAX: :name.', + 'not_found' => "Обработчик AJAX не найден: ':name'.", + ], + 'cms' => [ + 'menu_label' => 'CMS', + ], + 'sidebar' => [ + 'add' => 'Добавить', + 'search' => 'Поиск...', + ], + 'editor' => [ + 'settings' => 'Настройки', + 'title' => 'Заголовок', + 'new_title' => 'Заголовок страницы', + 'url' => 'Адрес', + 'filename' => 'Имя файла', + 'layout' => 'Шаблон', + 'description' => 'Описание', + 'preview' => 'Предпросмотр', + 'meta' => 'Метатеги', + 'meta_title' => 'Заголовок (meta title)', + 'meta_description' => 'Описание (meta description)', + 'markup' => 'Разметка', + 'code' => 'Код', + 'content' => 'Содержание', + 'hidden' => 'Скрытая страница', + 'hidden_comment' => 'Скрытые страницы доступны только для вошедших в систему пользователей.', + 'enter_fullscreen' => 'Войти в полноэкранный режим', + 'exit_fullscreen' => 'Выйти из полноэкранного режима', + 'open_searchbox' => 'Открыть окно поиска', + 'close_searchbox' => 'Закрыть окно поиска', + 'open_replacebox' => 'Открыть поле "Заменить"', + 'close_replacebox' => 'Закрыть поле "Заменить"', + 'commit' => 'Зафиксировать', + 'reset' => 'Сброс', + 'commit_confirm' => 'Вы уверены, что хотите сохранить изменения этого файла в файловой системе? Это перезапишет существующий в файловой системе файл', + 'reset_confirm' => 'Вы уверены, что хотите сбросить этот файл до копии, которая находится в файловой системе? Это полностью заменит его файлом, который находится в файловой системе.', + 'committing' => 'Зафиксировать', + 'resetting' => 'Сбросить', + 'commit_success' => ':type был зафиксирован в файловой системе', + 'reset_success' => ':type был сброшен до версии из файловой системы', + ], + 'asset' => [ + 'menu_label' => 'Ассеты', + 'unsaved_label' => 'Несохранённый(е) файл(ы)', + 'drop_down_add_title' => 'Добавить...', + 'drop_down_operation_title' => 'Действие...', + 'upload_files' => 'Загрузить файл(ы)', + 'create_file' => 'Создать файл', + 'create_directory' => 'Создать директорию', + 'directory_popup_title' => 'Новая директория', + 'directory_name' => 'Имя директории', + 'rename' => 'Переименовать', + 'delete' => 'Удалить', + 'move' => 'Переместить', + 'select' => 'Выбрать', + 'new' => 'Новый файл', + 'rename_popup_title' => 'Переименовать', + 'rename_new_name' => 'Новое имя', + 'invalid_path' => 'Путь может содержать только цифры, латинские буквы, пробелы и следующие символы: ._-/', + 'error_deleting_file' => 'Ошибка удаления файла :name.', + 'error_deleting_dir_not_empty' => 'Невозможно удалить директорию :name. Директория содержит файлы или поддиректории.', + 'error_deleting_dir' => 'Ошибка удаления директории :name.', + 'invalid_name' => 'Имя может содержать только цифры, латинские буквы, пробелы и следующие символы: ._-', + 'original_not_found' => 'Оригинальный файл или директория не найдена', + 'already_exists' => 'Файл или директория с таким именем уже существует', + 'error_renaming' => 'Невозможно переименовать файл или директорию', + 'name_cant_be_empty' => 'Имя не может быть пустым', + 'too_large' => 'Загруженный файл слишком велик. Максимальный допустимый размер файла составляет :max_size', + 'type_not_allowed' => 'Разрешены только файлы следующих типов: :allowed_types', + 'file_not_valid' => 'Файл не может быть сохранен', + 'error_uploading_file' => "Ошибка загрузки файла ':name': :error", + 'move_please_select' => 'пожалуйста, выберите директорию', + 'move_destination' => 'Папка назначения', + 'move_popup_title' => 'Переместить файлы', + 'move_button' => 'Переместить', + 'selected_files_not_found' => 'Выбранные файлы не найдены', + 'select_destination_dir' => 'Пожалуйста, выберите директорию', + 'destination_not_found' => 'Конечная директория не найдена', + 'error_moving_file' => 'Не удалось переместить файл :file', + 'error_moving_directory' => 'Не удалось переместить директорию :dir', + 'error_deleting_directory' => 'Не удалось удалить директорию :dir', + 'no_list_records' => 'Файлы не найдены', + 'delete_confirm' => 'Удалить выбранные файлы или каталоги?', + 'path' => 'Путь', + ], + 'component' => [ + 'menu_label' => 'Компоненты', + 'unnamed' => 'Безымянный', + 'no_description' => 'Без описания', + 'alias' => 'Псевдоним', + 'alias_description' => 'Псевдоним компонента определяет его имя, под которым он доступен в коде страницы или шаблона.', + 'validation_message' => 'Псевдонимы обязательны и могут содержать только латинские буквы, цифры и знаки подчеркивания. Псевдонимы должны начинаться с латинской буквы.', + 'invalid_request' => 'Шаблон не может быть сохранен, так как запрос содержит поврежденную информацию о компонентах.', + 'no_records' => 'Компоненты не найдены', + 'not_found' => "Компонент ':name' не найден.", + 'no_default_partial' => "Этот компонент не имеет 'default' фрагмента (partial)", + 'method_not_found' => "Компонент ':name' не содержит метод ':method'.", + 'soft_component' => 'Мягкий компонент', + 'soft_component_description' => 'Этот компонент отсутствует, но он не является обязательным.', + ], + 'template' => [ + 'invalid_type' => 'Неизвестный тип шаблона.', + 'not_found' => 'Запрошенный шаблон не найден.', + 'saved' => 'Шаблон был успешно сохранен.', + 'no_list_records' => 'Записи не найдены', + 'delete_confirm' => 'Удалить выбранные шаблоны?', + 'order_by' => 'Сортировать по', + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Управление контент-файлами сайта', + 'manage_assets' => 'Управление ассетами сайта - изображениями, JavaScript и CSS файлами', + 'manage_pages' => 'Создание, редактирование и удаление страниц сайта', + 'manage_layouts' => 'Создание, редактирование и удаление CMS макетами', + 'manage_partials' => 'Создание, редактирование и удаление CMS фрагментами', + 'manage_themes' => 'Активация, деактивация и конфигурация CMS тем', + 'manage_theme_options' => 'Настройка параметров для активной темы', + ], + 'theme_log' => [ + 'hint' => 'В этом журнале отображаются изменения, внесенные в тему администраторами во внутренней области CMS.', + 'menu_label' => 'Журнал изменений тем', + 'menu_description' => 'Просмотр изменений, внесенных в активную тему.', + 'empty_link' => 'Очистить журнал', + 'empty_loading' => 'Очистка журнала...', + 'empty_success' => 'Журнал очищен', + 'return_link' => 'Вернуться к журналу', + 'id' => 'ID', + 'id_label' => 'ID записи журнала', + 'created_at' => 'Дата & Время', + 'user' => 'Пользователь', + 'type' => 'Тип', + 'type_create' => 'Создайте', + 'type_update' => 'Обновить', + 'type_delete' => 'Удалить', + 'theme_name' => 'Тема', + 'theme_code' => 'Код темы', + 'old_template' => 'Шаблон (старый)', + 'new_template' => 'Шаблон (новый)', + 'template' => 'Шаблон', + 'diff' => 'Изменения', + 'old_value' => 'Старое значение', + 'new_value' => 'Новое значение', + 'preview_title' => 'Изменение шаблона', + 'template_updated' => 'Шаблон обновлен', + 'template_created' => 'Шаблон был создан', + 'template_deleted' => 'Шаблон был удален', + ], +]; diff --git a/modules/cms/lang/sk/lang.php b/modules/cms/lang/sk/lang.php new file mode 100644 index 0000000..d25dcf6 --- /dev/null +++ b/modules/cms/lang/sk/lang.php @@ -0,0 +1,292 @@ + [ + 'invalid_file' => 'Neplatný názov súboru: :name. Názvy súboru môžu obsahovať iba alfanumerické symboly, podtržítka, pomlčky a bodky. Príklady správnych názvov súborov: stranka.htm, stranka, priecinok/stranka', + 'invalid_property' => "Parameter ':name' meno nie je možné nastaviť", + 'file_already_exists' => "Súbor ':name' už existuje.", + 'error_saving' => "Chyba pri ukladaní súboru ':name'. Skontrolujte oprávnenia na zápis.", + 'error_creating_directory' => 'Chyba pri vytváraní zložky :name. Skontrolujte oprávnenia na zápis.', + 'invalid_file_extension' => 'Chybná prípona súboru: :invalid. Povolené prípony sú: :allowed.', + 'error_deleting' => "Chyba pri mazaní šablony ':name'. kontrolujte oprávnenia na zápis.", + 'delete_success' => 'Šablony zmazané: :count.', + 'file_name_required' => 'Je nutné vyplniť Meno súboru.', + 'safe_mode_enabled' => 'Bezpečný režim (Safe mode) je aktívny.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Webová stránka', + 'online' => 'Online', + 'maintenance' => 'Prebieha údržba', + 'manage_themes' => 'Spravovať témy', + 'customize_theme' => 'Prispôsobiť tému' + ] + ], + 'theme' => [ + 'not_found_name' => "Téma ':name' nebola nájdená.", + 'by_author' => 'Vytvoril :name', + 'active' => [ + 'not_set' => 'Aktívna téma nie je nastavená.', + 'not_found' => 'Aktívna téma nebola nájdená.' + ], + 'edit' => [ + 'not_set' => 'Editovaná téma nie je nastavená.', + 'not_found' => 'Editovaná téma nebola nájdená.', + 'not_match' => "Objekt, ktorý chcete práve zobraziť nepatrí k upravovanej téme. Prosím obnovte stránku." + ], + 'settings_menu' => 'Téma vzhľadu', + 'settings_menu_description' => 'Spravujte témy vzhľadu a možnosti prispôsobenia.', + 'default_tab' => 'Parametre', + 'name_label' => 'Názov', + 'name_create_placeholder' => 'Názov novej témy', + 'author_label' => 'Autor', + 'author_placeholder' => 'Osoba alebo názov spoločnosti', + 'description_label' => 'Popis', + 'description_placeholder' => 'Popis témy', + 'homepage_label' => 'Domovská stránka', + 'homepage_placeholder' => 'URL domovskej stránky', + 'code_label' => 'Kód', + 'code_placeholder' => 'Unikátny kód pre distribúciu tejto témy', + 'preview_image_label' => 'Náhľad', + 'preview_image_placeholder' => 'Cesta k súboru s náhľadom.', + 'dir_name_label' => 'Názov priečinka', + 'dir_name_create_label' => 'Cieľová zložka témy', + 'theme_label' => 'Téma', + 'theme_title' => 'Témy', + 'activate_button' => 'Aktivovať', + 'active_button' => 'Aktívna', + 'customize_theme' => 'Upraviť tému', + 'customize_button' => 'Upraviť', + 'duplicate_button' => 'Duplikovať', + 'duplicate_title' => 'Duplikovať tému', + 'duplicate_theme_success' => 'Téma duplikovaná!', + 'manage_button' => 'Spravovať', + 'manage_title' => 'Spravovať tému', + 'edit_properties_title' => 'Téma', + 'edit_properties_button' => 'Nastaviť', + 'save_properties' => 'Uložiť nastavenia', + 'import_button' => 'Importovať', + 'import_title' => 'Importovať tému', + 'import_theme_success' => 'Téma úspešne importovaná!', + 'import_uploaded_file' => 'Súbor s témou', + 'import_overwrite_label' => 'Prepísať existujúce súbory', + 'import_overwrite_comment' => 'Odškrtnite tento box pokiaľ chcete iba importovať nové súbory', + 'import_folders_label' => 'Priečinky', + 'import_folders_comment' => 'Prosím zvoľte priečinky témy, ktoré chcete importovať', + 'export_button' => 'Exportovať', + 'export_title' => 'Exportovať tému', + 'export_folders_label' => 'Priečinky', + 'export_folders_comment' => 'Prosím zvoľte priečinky témy, ktoré chcete exportovať', + 'delete_button' => 'Zmazať', + 'delete_confirm' => 'Zmazať túto tému? Túto akciu nejde vrátiť späť!', + 'delete_active_theme_failed' => 'Aktívnu tému nie je možné zmazať, aktivujte najprv inú tému.', + 'delete_theme_success' => 'Téma úspešne zmazaná!', + 'create_title' => 'Vytvoriť tému', + 'create_button' => 'Vytvoriť', + 'create_new_blank_theme' => 'Vytvoriť novú prázdnu tému', + 'create_theme_success' => 'Téma úspešne vytvorená!', + 'create_theme_required_name' => 'Prosím zvoľte názov novej témy.', + 'new_directory_name_label' => 'Priečinok témy', + 'new_directory_name_comment' => 'Zadajte nový názov priečinku pre duplikovanú tému.', + 'dir_name_invalid' => 'Názov môže obashovať iba čísla, písmená a nasledujúce znaky: _-', + 'dir_name_taken' => 'Zadaný priečinok s témou už existuje.', + 'find_more_themes' => 'Vyhľadať ďalšie témy', + 'saving' => 'Ukladám tému...', + 'return' => 'Návrat na zoznam tém' + ], + 'maintenance' => [ + 'settings_menu' => 'Režim údržby', + 'settings_menu_description' => 'Nastavte stránku režimu údržby a jej nastavenia.', + 'is_enabled' => 'Aktivovať režim údržby', + 'is_enabled_comment' => 'Zvoľte stránku, ktorá bude zobrazená pri aktivovanom režime údržby.', + 'hint' => 'Režim údržby zobrazí stránku údržby návštevníkom, ktorí nie sú prihlásení do adminstrácie.' + ], + 'page' => [ + 'not_found_name' => "Stránka ':name' nebola nájdená", + 'not_found' => [ + 'label' => 'Stránka nenájdená', + 'help' => 'Požadovaná stránka nebola nájdená.' + ], + 'custom_error' => [ + 'label' => 'Chyba stránky', + 'help' => "Ospravedlňujeme sa, niečo sa pokazilo a stránka nemôže byť zobrazená." + ], + 'menu_label' => 'Stránky', + 'unsaved_label' => 'Neuložené stránky', + 'no_list_records' => 'Žiadne stránky', + 'new' => 'Nová stránka', + 'invalid_url' => 'Neplatný formát URL. URL musí začínať lomítkom a môže obsahovať čísla, písmená a nasledujúce znaky: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Skutočne zmazazať vybrané stránky?', + 'delete_confirm_single' => 'Skutočne zmazať túto stránku?', + 'no_layout' => '-- žiadny layout --', + 'cms_page' => 'CMS stránka', + 'title' => 'Názov stránky', + 'url' => 'URL stránky', + 'file_name' => 'Názov súboru stránky' + ], + 'layout' => [ + 'not_found_name' => "Layout ':name' nebol nájdený", + 'menu_label' => 'Layouty', + 'unsaved_label' => 'Neuložené layouty', + 'no_list_records' => 'Žiadne layouty', + 'new' => 'Nový layout', + 'delete_confirm_multiple' => 'Skutočne zmazať zvolené layouty?', + 'delete_confirm_single' => 'Skutočne zmazať tento layout?' + ], + 'partial' => [ + 'not_found_name' => "Čiastková šablóna ':name' nebola nájdená.", + 'invalid_name' => 'Neplatný názov čiastkovej šablóny: :name.', + 'menu_label' => 'Čiastkové šablóny', + 'unsaved_label' => 'Neuložené čiastkové šablóny', + 'no_list_records' => 'Žiadne čiastkové šablóny', + 'delete_confirm_multiple' => 'Skutočne zmazať zvolené čiastkové šablóny?', + 'delete_confirm_single' => 'Skutočne zmazať túto čiastkovú šablónu?', + 'new' => 'Nová čiastková šablóna' + ], + 'content' => [ + 'not_found_name' => "Obsahový súbor ':name' nebol nájdený.", + 'menu_label' => 'Obsah', + 'unsaved_label' => 'Neuložený obsah', + 'no_list_records' => 'Žiadne obsahové súbory', + 'delete_confirm_multiple' => 'Skutočne zmazať zvolené obsahové súbory alebo priečinky?', + 'delete_confirm_single' => 'Skutočne zmazať tento obsahový súbor?', + 'new' => 'Nový obsahový súbor' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Neplatný názov AJAX handlera: :name.', + 'not_found' => "AJAX handler ':name' nebol nájdený." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Pridať', + 'search' => 'Hľadať...' + ], + 'editor' => [ + 'settings' => 'Nastavenia', + 'title' => 'Názov', + 'new_title' => 'Nový názov stránky', + 'url' => 'URL', + 'filename' => 'Názov súboru', + 'layout' => 'Layout', + 'description' => 'Popis', + 'preview' => 'Náhľad', + 'meta' => 'Meta údaje', + 'meta_title' => 'Meta názov', + 'meta_description' => 'Meta popis', + 'markup' => 'Kód', + 'code' => 'PHP kód', + 'content' => 'Obsah', + 'hidden' => 'Skrytá', + 'hidden_comment' => 'Skryté stránky sú dostupne iba pre užívateľov prihlásených do administrácie.', + 'enter_fullscreen' => 'Zapnúť režim celej obrazovky', + 'exit_fullscreen' => 'Vypnúť režim celej obrazovky', + 'open_searchbox' => 'Otvoriť box hľadania', + 'close_searchbox' => 'Zavrieť box hľadania', + 'open_replacebox' => 'Otvoriť box nahradzovania', + 'close_replacebox' => 'Zavrieť box nahradzovania' + ], + 'asset' => [ + 'menu_label' => 'Súbory', + 'unsaved_label' => 'Neuložené súbory', + 'drop_down_add_title' => 'Pridať...', + 'drop_down_operation_title' => 'Akcia...', + 'upload_files' => 'Nahrať súbor(y)', + 'create_file' => 'Vytvoriť súbor', + 'create_directory' => 'Vytvoriť priečinok', + 'directory_popup_title' => 'Nový priečinok', + 'directory_name' => 'Názov priečinka', + 'rename' => 'Premenovať', + 'delete' => 'Zmazať', + 'move' => 'Presunúť', + 'select' => 'Vybrať', + 'new' => 'Nový súbor', + 'rename_popup_title' => 'Premenovať', + 'rename_new_name' => 'Nový názov', + 'invalid_path' => 'Cesta môže obsahovať iba čísla, písmená, medzery a nasledujúce znaky: ._-/', + 'error_deleting_file' => 'Chyba pri mazaní súboru :name.', + 'error_deleting_dir_not_empty' => 'Chyba pri mazaní priečinka :name. Priečinok nie je prázdny.', + 'error_deleting_dir' => 'Chyba pri mazaní priečinku :name.', + 'invalid_name' => 'Názov môže obsahovať iba čísla, písmená, medzery a nasledujúce znaky: ._-', + 'original_not_found' => 'Pôvodný súbor alebo priečinok nebol nájdený', + 'already_exists' => 'Súbor alebo priečinok s týmto názvom už existuje', + 'error_renaming' => 'Chyba pri premenovávaní súboru alebo priečinka', + 'name_cant_be_empty' => 'Názov nemôže byť prázdny', + 'too_large' => 'Nahrávaný súbor je príliš veľký. Maximálna povolená veľkosť súboru je :max_size', + 'type_not_allowed' => 'Iba nasledovné typy súborov sú povolené: :allowed_types', + 'file_not_valid' => 'Súbor nie je validný', + 'error_uploading_file' => "Chyba pri nahrávaní súboru ':name': :error", + 'move_please_select' => 'prosím vyberte', + 'move_destination' => 'Cieľový priečinok', + 'move_popup_title' => 'Presunúť súbory', + 'move_button' => 'Presunúť', + 'selected_files_not_found' => 'Vybrané súbory neboli nájdené', + 'select_destination_dir' => 'Prosím zvoľte cieľový priečinok', + 'destination_not_found' => 'Cieľový priešinok nebol nájdený', + 'error_moving_file' => 'Chyba pri presúvaní súboru :file', + 'error_moving_directory' => 'Chyba pri presúvaní priečinka :dir', + 'error_deleting_directory' => 'Chyba pri mazaní pôvodného priečinka :dir', + 'no_list_records' => 'Žiadne súbory', + 'delete_confirm' => 'Skutočne zmazať vybrané súbory alebo priečinky?', + 'path' => 'Cesta' + ], + 'component' => [ + 'menu_label' => 'Komponenty', + 'unnamed' => 'Bez názvu', + 'no_description' => 'Nebol poskytnutý žiadny popis', + 'alias' => 'Alias', + 'alias_description' => 'Unikátny názov komponentu pri použití v kóde na stránke alebo layoute.', + 'validation_message' => 'Aliasy komponentov sú povinné a môžu obsahovať iba písmená, čísla a podtržítka. Aliasy by mali začínať písmenom.', + 'invalid_request' => 'Šablóna nemôže byť uložená kvôli neplatným dátam kompentntu.', + 'no_records' => 'Žiadne komponenty', + 'not_found' => "Komponent ':name' nebol nájdený.", + 'method_not_found' => "Komponent ':name' neobsahuje metódu ':method'." + ], + 'template' => [ + 'invalid_type' => 'Neznámy typ šablóny.', + 'not_found' => 'Šablóna nenájdená.', + 'saved' => 'Šablóna uložená.', + 'no_list_records' => 'Žiadne záznamy', + 'delete_confirm' => 'Skutočne zmazať vybrané šablóny?', + 'order_by' => 'Zoradiť podľa' + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Správa obsahu stránky', + 'manage_assets' => 'Správa súborov stránky - obrázky, JavaScript súbory, CSS súbory', + 'manage_pages' => 'Tvorba, úpravy a mazanie stránok', + 'manage_layouts' => 'Tvorba, úpravy a mazanie CMS layoutov', + 'manage_partials' => 'Tvorba, úpravy a mazanie čiastkových súborov CMS', + 'manage_themes' => 'Aktivácia, deaktiácia a nastavenia tém', + 'manage_theme_options' => 'Nsatavenia aktívnej témy', + ], + 'theme_log' => [ + 'hint' => 'Tento záznam zobrazuje všetky zmeny témy urobené adminstrátormi v administrácií.', + 'menu_label' => 'Záznam tém', + 'menu_description' => 'Zobraziť zmeny v aktívnej téme.', + 'empty_link' => 'Vyprázdniť záznam tém', + 'empty_loading' => 'Vyprázdňovnie záznamu tém...', + 'empty_success' => 'Záznam tém vyprázdený', + 'return_link' => 'Návrat na záznam tém', + 'id' => 'ID', + 'id_label' => 'ID záznamu', + 'created_at' => 'Čas a dátum', + 'user' => 'Užívateľ', + 'type' => 'Typ', + 'type_create' => 'Vytvorené', + 'type_update' => 'Upravené', + 'type_delete' => 'Zmazané', + 'theme_name' => 'Téma', + 'theme_code' => 'Kód témy', + 'old_template' => 'Šablóna (Pôvodná)', + 'new_template' => 'Šablóna (Nová)', + 'template' => 'Šablóna', + 'diff' => 'Zmeny', + 'old_value' => 'Pôvodná hodnota', + 'new_value' => 'Nová hodnota', + 'preview_title' => 'Zmeny šablóny', + 'template_updated' => 'Šablóna bola upravená', + 'template_created' => 'Šablóna bola vytvorená', + 'template_deleted' => 'Šablóna bola zmazaná', + ], +]; diff --git a/modules/cms/lang/sl/lang.php b/modules/cms/lang/sl/lang.php new file mode 100644 index 0000000..2bff94d --- /dev/null +++ b/modules/cms/lang/sl/lang.php @@ -0,0 +1,303 @@ + [ + 'invalid_file' => 'Neveljavno ime datoteke :name. Imena datotek lahko vsebujejo le alfa-numerične simbole, podčrtaje, pomišljaje in pike. Nekaj primerov pravilnih imen datotek: page.htm, page, subdirectory/page', + 'invalid_property' => "Lastnost ':name' ne more biti nastavljena", + 'file_already_exists' => "Datoteka ':name' že obstaja", + 'error_saving' => "Napaka pri shranjevanju datoteke ':name'. Prosimo, preverite vaša uporabniška dovoljenja.", + 'error_creating_directory' => 'Napaka pri ustvarjanju mape :name. Prosimo, preverite vaša uporabniška dovoljenja.', + 'invalid_file_extension' => "Neveljaven format datoteke :invalid'. Veljavni formati so :allowed.", + 'error_deleting' => "Napaka pri brisanju predloge ':name'. Prosimo, preverite vaša uporabniška dovoljenja.", + 'delete_success' => 'Izbrisanih predlog: :count.', + 'file_name_required' => 'Obvezno polje: Ime datoteke', + 'safe_mode_enabled' => 'Varnostni način je trenutno vključen.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Spletna stran', + 'online' => 'Aktivna', + 'maintenance' => 'V vzdrževanju', + 'manage_themes' => 'Upravljaj teme', + 'customize_theme' => 'Prilagodi temo', + ], + ], + 'theme' => [ + 'not_found_name' => "Teme ':name' ni bilo mogoče najti.", + 'by_author' => 'od :name', + 'active' => [ + 'not_set' => 'Aktivna tema ni nastavljena.', + 'not_found' => 'Aktivne teme ni mogoče najti.', + ], + 'edit' => [ + 'not_set' => 'Urejana tema ni nastavljena.', + 'not_found' => 'Urejane teme ni mogoče najti.', + 'not_match' => "Objekt, do katerega poskušate dostopati, ne pripada urejani temi. Prosimo, osvežite stran.", + ], + 'settings_menu' => 'Tema spletne strani', + 'settings_menu_description' => 'Upravljanje s temo spletne strani in možnostmi prilagoditve.', + 'default_tab' => 'Lastnosti', + 'name_label' => 'Ime', + 'name_create_placeholder' => 'Novo ime teme', + 'author_label' => 'Avtor', + 'author_placeholder' => 'Oseba ali ime podjetja', + 'description_label' => 'Opis', + 'description_placeholder' => 'Opis teme', + 'homepage_label' => 'Spletna stran', + 'homepage_placeholder' => 'URL spletne strani', + 'code_label' => 'Koda', + 'code_placeholder' => 'Unikatna koda teme, ki se uporablja za distribucijo.', + 'preview_image_label' => 'Slika za predogled', + 'preview_image_placeholder' => 'Lokacija slike za predogled teme.', + 'dir_name_label' => 'Ime mape', + 'dir_name_create_label' => 'Ciljna mapa teme', + 'theme_label' => 'Tema', + 'theme_title' => 'Teme', + 'activate_button' => 'Aktiviraj', + 'active_button' => 'Aktiviraj', + 'customize_theme' => 'Prilagodi temo', + 'customize_button' => 'Prilagodi', + 'duplicate_button' => 'Podvoji', + 'duplicate_title' => 'Podvoji temo', + 'duplicate_theme_success' => 'Tema je podvojena.', + 'manage_button' => 'Upravljanje', + 'manage_title' => 'Upravljanje s temo', + 'edit_properties_title' => 'Tema', + 'edit_properties_button' => 'Uredi lastnosti', + 'save_properties' => 'Shrani lastnosti', + 'import_button' => 'Uvozi', + 'import_title' => 'Uvozi temo', + 'import_theme_success' => 'Tema je uvožena.', + 'import_uploaded_file' => 'Datoteka z arhivom teme', + 'import_overwrite_label' => 'Prepiši obstoječe datoteke', + 'import_overwrite_comment' => 'Odkljukajte to polje, če želite uvoziti le nove datoteke.', + 'import_folders_label' => 'Mape', + 'import_folders_comment' => 'Prosimo, izberite mape teme, ki jih želite uvoziti.', + 'export_button' => 'Izvozi', + 'export_title' => 'Izvozi temo', + 'export_folders_label' => 'Mape', + 'export_folders_comment' => 'Prosimo, izberite mape teme, ki jih želite izvoziti.', + 'delete_button' => 'Izbriši', + 'delete_confirm' => 'Želite izbrisati to temo? Ukaza ni mogoče razveljaviti!', + 'delete_active_theme_failed' => 'Aktivne teme ni mogoče izbrisati. Najprej je potrebno zamenjati aktivno temo.', + 'delete_theme_success' => 'Tema je izbrisana.', + 'create_title' => 'Ustvari temo', + 'create_button' => 'Ustvari', + 'create_new_blank_theme' => 'Ustvari novo prazno temo', + 'create_theme_success' => 'Tema je ustvarjena.', + 'create_theme_required_name' => 'Prosimo, navedite ime teme.', + 'new_directory_name_label' => 'Mapa za temo', + 'new_directory_name_comment' => 'Podajte novo ime mape za podvojeno temo.', + 'dir_name_invalid' => 'Ime lahko vsebuje samo številke, latinične črke in naslednje simbole: _-', + 'dir_name_taken' => 'Želena mapa za temo že obstaja.', + 'find_more_themes' => 'Poišči več tem', + 'saving' => 'Shranjevanje teme...', + 'return' => 'Nazaj na seznam tem', + ], + 'maintenance' => [ + 'settings_menu' => 'Način vzdrževanja', + 'settings_menu_description' => 'Nastavitve načina vzdrževanja in preklop na način vzdrževanja.', + 'is_enabled' => 'Omogoči način vzdrževanja', + 'is_enabled_comment' => 'Izberite stran, ki bo prikazana ob vključenem načinu vzdrževanja.', + 'hint' => 'V načinu vzdrževanja bo stran o vzdrževanju prikazana obiskovalcem, ki niso prijavljeni v administracijo.', + ], + 'page' => [ + 'not_found_name' => "Strani ':name' ni mogoče najti.", + 'not_found' => [ + 'label' => 'Stran ne obstaja', + 'help' => 'Zahtevane strani ni bilo mogoče najti.', + ], + 'custom_error' => [ + 'label' => 'Napaka strani', + 'help' => 'Žal je prišlo do napake in strani ni mogoče prikazati.', + ], + 'menu_label' => 'Strani', + 'unsaved_label' => 'Neshranjene strani', + 'no_list_records' => 'Ni najdenih strani.', + 'new' => 'Nova stran', + 'invalid_url' => 'Neveljavna oblika URL formata. URL se mora začeti z znakom za desno poševnico in lahko vsebuje številke, latinične črke in naslednje znake: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Želite izbrisati izbrane strani?', + 'delete_confirm_single' => 'Želite izbrisati to stran?', + 'no_layout' => '-- brez postavitve --', + 'cms_page' => 'CMS stran', + 'title' => 'Naslov strani', + 'url' => 'URL strani', + 'file_name' => 'Ime datoteke strani', + ], + 'layout' => [ + 'not_found_name' => "Postavitve ':name' ni mogoče najti.", + 'menu_label' => 'Postavitve', + 'unsaved_label' => 'Neshranjene postavitve', + 'no_list_records' => 'Ni najdenih postavitev.', + 'new' => 'Nova postavitev', + 'delete_confirm_multiple' => 'Želite izbrisati izbrane postavitve?', + 'delete_confirm_single' => 'Želite izbrisati to postavitev?', + ], + 'partial' => [ + 'not_found_name' => "Predloge ':name' ni mogoče najti.", + 'invalid_name' => 'Neveljavno ime predloge :name.', + 'menu_label' => 'Predloge', + 'unsaved_label' => 'Neshranjene predloge', + 'no_list_records' => 'Ni najdenih predlog.', + 'delete_confirm_multiple' => 'Želite izbrisati izbrane predloge?', + 'delete_confirm_single' => 'Želite izbrisati to predlogo?', + 'new' => 'Nova predloga', + ], + 'content' => [ + 'not_found_name' => "Datoteke z vsebino ':name' ni mogoče najti.", + 'menu_label' => 'Vsebine', + 'unsaved_label' => 'Neshranjena vsebina', + 'no_list_records' => 'Ni najdenih datotek z vsebino.', + 'delete_confirm_multiple' => 'Ali želite izbrisati izbrane datoteke ali mape z vsebino?', + 'delete_confirm_single' => 'Želite izbrisati to datoteko z vsebino?', + 'new' => 'Nova datoteka z vsebino', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Neveljavno ime AJAX akcije: :name', + 'not_found' => "Ni mogoče najti AJAX akcije ':name'.", + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Dodaj', + 'search' => 'Iskanje...', + ], + 'editor' => [ + 'settings' => 'Nastavitve', + 'title' => 'Naslov', + 'new_title' => 'Nov naslov strani', + 'url' => 'URL', + 'filename' => 'Ime datoteke', + 'layout' => 'Postavitev', + 'description' => 'Opis', + 'preview' => 'Predogled', + 'meta' => 'Meta podatki', + 'meta_title' => 'Meta naslov', + 'meta_description' => 'Meta opis', + 'markup' => 'Označevalni jezik', + 'code' => 'Koda', + 'content' => 'Vsebina', + 'hidden' => 'Skrito', + 'hidden_comment' => 'Skrite strani so dostopne le uporabnikom, ki so prijavljeni v administracijo.', + 'enter_fullscreen' => 'Celozaslonski način', + 'exit_fullscreen' => 'Zapri celozaslonski način', + 'open_searchbox' => 'Odpri iskalnik', + 'close_searchbox' => 'Zapri iskalnik', + 'open_replacebox' => 'Odpri "Najdi in zamenjaj"', + 'close_replacebox' => 'Zapri "Najdi in zamenjaj"', + 'commit' => 'Shrani spremembe', + 'reset' => 'Ponastavi', + 'commit_confirm' => 'Ali ste prepričani, da želite shraniti spremembe datoteke v datotečni sistem? To bo prepisalo obstoječo datoteko v datotečnem sistemu.', + 'reset_confirm' => 'Ali ste prepričani, da želite datoteko ponastaviti na kopijo, ki se nahaja v datotečnem sistemu? To bo datoteko v celoti nadomestilo z datoteko, ki se nahaja v datotečnem sistemu.', + 'committing' => 'Shranjujem spremembe', + 'resetting' => 'Ponastavljam', + 'commit_success' => 'Sprememba :type je bila shranjena v datotečni sistem.', + 'reset_success' => 'Sprememba :type je bila ponastavljena na različico iz datotečnega sistema.', + ], + 'asset' => [ + 'menu_label' => 'Oblikovne datoteke', + 'unsaved_label' => 'Neshranjene datoteke', + 'drop_down_add_title' => 'Dodaj...', + 'drop_down_operation_title' => 'Dejanje...', + 'upload_files' => 'Naloži datoteke', + 'create_file' => 'Ustvari datoteko', + 'create_directory' => 'Ustvari mapo', + 'directory_popup_title' => 'Nova mapa', + 'directory_name' => 'Ime mape', + 'rename' => 'Preimenuj', + 'delete' => 'Izbriši', + 'move' => 'Premakni', + 'select' => 'Izberi', + 'new' => 'Nova datoteka', + 'rename_popup_title' => 'Preimenuj', + 'rename_new_name' => 'Novo ime', + 'invalid_path' => 'Lokacija lahko vsebuje le številke, latinične črke, presledke in naslednje znake: ._-/', + 'error_deleting_file' => 'Napaka pri brisanju datoteke :name.', + 'error_deleting_dir_not_empty' => 'Napaka pri brisanju mape :name. Mapa ni prazna.', + 'error_deleting_dir' => 'Napaka pri brisanju mape :name.', + 'invalid_name' => 'Ime lahko vsebuje le številke, latinične črke, presledke in naslednje znake: ._-', + 'original_not_found' => 'Originalne datoteke oziroma mape ni mogoče najti.', + 'already_exists' => 'Datoteka oziroma mapa s tem imenom že obstaja.', + 'error_renaming' => 'Napaka pri preimenovanju datoteke oziroma mape.', + 'name_cant_be_empty' => 'Ime ne more biti prazno.', + 'too_large' => 'Naložena datoteka je prevelika. Največja dovoljena velikost datoteke je :max_size.', + 'type_not_allowed' => 'Dovoljeni so le formati datotek: :alowed_types', + 'file_not_valid' => 'Neveljavna datoteka', + 'error_uploading_file' => "Napaka pri nalaganju datoteke ':name': :error", + 'move_please_select' => 'izberite', + 'move_destination' => 'Ciljna mapa', + 'move_popup_title' => 'Premakni oblikovne datoteke', + 'move_button' => 'Premakni', + 'selected_files_not_found' => 'Izbranih datotek ni mogoče najti.', + 'select_destination_dir' => 'Prosimo, izberite ciljno mapo.', + 'destination_not_found' => 'Ciljne mape ni mogoče najti.', + 'error_moving_file' => 'Napaka pri premikanju datoteke :file.', + 'error_moving_directory' => 'Napaka pri premikanju mape :dir.', + 'error_deleting_directory' => 'Napaka pri brisanju originalne mape :dir.', + 'no_list_records' => 'Ni najdenih datotek.', + 'delete_confirm' => 'Želite izbrisati izbrane datoteke ali mape?', + 'path' => 'Lokacija', + ], + 'component' => [ + 'menu_label' => 'Komponente', + 'unnamed' => 'Neimenovano', + 'no_description' => 'Opis ni podan', + 'alias' => 'Vzdevek', + 'alias_description' => 'Unikatno ime komponente, ki se uporablja na strani ali v kodi postavitve.', + 'validation_message' => 'Vzdevki komponent so obvezni in lahko vsebujejo le latinične znake, številke in podčrtaje. Vzdevki naj se začnejo z latiničnim znakom.', + 'invalid_request' => 'Predloge ni bilo mogoče shraniti zaradi neveljavnih podatkov komponente.', + 'no_records' => 'Ni najdenih komponent.', + 'not_found' => "Komponente :name ni mogoče najti.", + 'method_not_found' => "Komponenta ':name' ne vsebuje metode ':method'.", + 'soft_component' => 'Mehka komponenta', + 'soft_component_description' => 'Ta komponenta manjka, vendar ni obvezna.', + ], + 'template' => [ + 'invalid_type' => 'Neznan format predloge.', + 'not_found' => 'Predloge ni mogoče najti.', + 'saved' => 'Predloga je shranjena.', + 'no_list_records' => 'Ni najdenih zapisov.', + 'delete_confirm' => 'Želite izbrisati izbrane predloge?', + 'order_by' => 'Razvrsti po', + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Upravljanje datotek z vsebino spletne strani', + 'manage_assets' => 'Upravljanje z oblikovnimi datotekami - slike, JavaScript, CSS datoteke', + 'manage_pages' => 'Ustvarjanje, spreminjanje ali brisanje strani', + 'manage_layouts' => 'Ustvarjanje, spreminjanje ali brisanje CMS postavitev', + 'manage_partials' => 'Ustvarjanje, spreminjanje ali brisanje CMS predlog', + 'manage_themes' => 'Aktiviranje, de-aktiviranje ali konfiguriranje CMS tem', + 'manage_theme_options' => 'Konfiguriranje možnosti prilagajanja za aktivno temo', + ], + 'theme_log' => [ + 'hint' => 'V tem dnevniku so prikazane vse spremembe teme, ki so jih naredili administratorji v administraciji.', + 'menu_label' => 'Dnevnik sprememb teme', + 'menu_description' => 'Pokaži spremembe aktivne teme.', + 'empty_link' => 'Sprazni dnevnik sprememb teme', + 'empty_loading' => 'Praznjenje dnevnika sprememb...', + 'empty_success' => 'Dnevnik sprememb je izpraznjen.', + 'return_link' => 'Vrni se na dnevnik sprememb teme', + 'id' => 'ID', + 'id_label' => 'ID dnevnika', + 'created_at' => 'Čas in datum', + 'user' => 'Uporabnik', + 'type' => 'Tip', + 'type_create' => 'Ustvari', + 'type_update' => 'Posodobi', + 'type_delete' => 'Izbriši', + 'theme_name' => 'Tema', + 'theme_code' => 'Koda teme', + 'old_template' => 'Predloga (stara)', + 'new_template' => 'Predloga (nova)', + 'template' => 'Predloga', + 'diff' => 'Spremembe', + 'old_value' => 'Stara vrednost', + 'new_value' => 'Nova vrednost', + 'preview_title' => 'Spremembe predloge', + 'template_updated' => 'Predloga je posodobljena.', + 'template_created' => 'Predloga je ustvarjena.', + 'template_deleted' => 'Predloga je izbrisana.', + ], +]; diff --git a/modules/cms/lang/sv/lang.php b/modules/cms/lang/sv/lang.php new file mode 100644 index 0000000..30adf25 --- /dev/null +++ b/modules/cms/lang/sv/lang.php @@ -0,0 +1,242 @@ + [ + 'invalid_file' => 'Felaktigt filnamn: :name. Filnamn kan endast innehålla alfanumeriska tecken, understreck, streck och punkter. Några exempel på korrekta filnamn är: sida.htm, sida, undermapp/sida', + 'invalid_property' => 'Egenskapen ":name" kunde inte sättas', + 'file_already_exists' => 'Filen ":name" finns redan', + 'error_saving' => 'Ett fel inträffade när ":name" skulle sparas', + 'error_creating_directory' => 'Ett fel inträffade när mappen :name skulle skapas', + 'invalid_file_extension'=>'Felaktig filändelse: :invalid. Tillåtna filändelser är: :allowed.', + 'error_deleting' => 'Det gick inte att radera mallfilen: ":name".', + 'delete_success' => 'Mallarna är nu raderade: :count.', + 'file_name_required' => 'Filnamnsfältet är obligatoriskt.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'online' => 'online', + 'maintenance' => 'i underhåll', + ] + ], + 'theme' => [ + 'not_found_name' => "Kunde inte hitta temat ':name'.", + 'active' => [ + 'not_set' => "Ett aktivt tema är ej valt", + 'not_found' => 'Kunde inte hitta det aktiva temat.' + ], + 'edit' => [ + 'not_set' => "Redigeringstemat är ej valt", + 'not_found' => "Redigeringstemat kunde ej hittas", + 'not_match' => "Objektet du försöker komma åt tillhör inte det tema som för håller på att redigeras. Var god ladda om sidan", + ], + 'settings_menu' => 'Front-end tema', + 'settings_menu_description' => 'Förhandsgranska listan av installerade teman och välj ett aktivt tema.', + 'default_tab' => 'Egenskaper', + 'name_label' => 'Namn', + 'name_create_placeholder' => 'Nytt tema namn', + 'author_label' => 'Författare', + 'author_placeholder' => 'Person eller företagsnamn', + 'description_label' => 'Beskrivning', + 'description_placeholder' => 'Tema beskrivning', + 'homepage_label' => 'Hemsida', + 'homepage_placeholder' => 'Webbadress', + 'code_label' => 'Kod', + 'code_placeholder' => 'En unik kod för detta tema som används för distribution', + 'dir_name_label' => 'Katalognamn', + 'dir_name_create_label' => 'Destinationen för temakatalogen', + 'theme_label' => 'Tema', + 'theme_title' => 'Teman', + 'activate_button' => 'Aktivera', + 'active_button' => 'Aktivera', + 'customize_theme' => 'Anpassa tema', + 'customize_button' => 'Anpassa', + 'duplicate_button' => 'Duplicera', + 'duplicate_title' => 'Duplicera temat', + 'duplicate_theme_success' => 'Lyckades duplicera temat!', + 'manage_button' => 'Hantera', + 'manage_title' => 'Hantera teman', + 'edit_properties_title' => 'Tema', + 'edit_properties_button' => 'Redigera egenskaper', + 'save_properties' => 'Spara egenskaperna', + 'import_button' => 'Importera', + 'import_title' => 'Importera tema', + 'import_theme_success' => 'Lyckades importera temat!', + 'import_uploaded_file' => 'Tema akrivfil', + 'import_overwrite_label' => 'Skriv över befintliga filer', + 'import_overwrite_comment' => 'Avmarkera rutan för att endast importera nya filer', + 'import_folders_label' => 'Mappar', + 'import_folders_comment' => 'Vänligen ange temamappen som du vill importera', + 'export_button' => 'Exportera', + 'export_title' => 'Exportera tema', + 'export_folders_label' => 'Mappar', + 'export_folders_comment' => 'Vänligen välj temamappen du vill importera', + 'delete_button' => 'Radera', + 'delete_confirm' => 'Är du säker på att du vill readera detta tema?? Det kan inte bli ogjort!', + 'delete_active_theme_failed' => 'Du kan inte att readera det akriva temat, försök markera ett annat tema som aktivt först.', + 'delete_theme_success' => 'Lyckades radera temat!', + 'create_title' => 'Skapa tema', + 'create_button' => 'Skapa', + 'create_new_blank_theme' => 'Skapa ett nytt blankt tema', + 'create_theme_success' => 'Lyckades skapa temat!', + 'create_theme_required_name' => 'Vänligen ange ett namn för temat.', + 'new_directory_name_label' => 'Temamappen', + 'new_directory_name_comment' => 'Ange ett nytt katalognamn för det duplicerade temat.', + 'dir_name_invalid' => 'Namn kan bara innehålla siffror, latinska bokstäver och följande symboler: _-', + 'dir_name_taken' => 'Den önskade temakatalogen finns redan.', + 'find_more_themes' => 'Hitta fler teman på OctoberCMS Theme Marketplace', + 'saving' => 'Sparar tema...', + 'return' => 'Återvänd till temalistan', + ], + 'maintenance' => [ + 'settings_menu' => 'Underhållsläge', + 'settings_menu_description' => 'Konfigurera underhållsläge-sidan och växla inställningen.', + 'is_enabled' => 'Akrivera underhållsläge-läget', + 'is_enabled_comment' => 'När den är aktiverad så kommer besökare att se sidan som väljs nedan.' + ], + 'page' => [ + 'not_found_name' => "The page ':name' is not found", + 'not_found' => [ + 'label' => "Sidan kunde ej hittas", + 'help' => "Den begärda sidan kunde ej hittas", + ], + 'custom_error' => [ + 'label' => "Sidfel", + 'help' => "Tyvärr kan inte sidan visas", + ], + 'menu_label' => 'Sidor', + 'unsaved_label' => 'Osparade sidor', + 'no_list_records' => 'Inga sidor funna', + 'new' => 'Ny sida', + 'invalid_url' => 'Felaktigt URL-format. URLen skall starta med ett / och kan innehålla siffror, bokstäver och följande tecken: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Vill du verkligen radera markerade sidor?', + 'delete_confirm_single' => 'Vill du verkligen radera denna sida?', + 'no_layout' => '-- ingen layout --' + ], + 'layout' => [ + 'not_found_name' => "Layouten ':name' hittades ej", + 'menu_label' => 'Layouter', + 'unsaved_label' => 'Osparade layouter', + 'no_list_records' => 'Inga layouter funna', + 'new' => 'Ny layout', + 'delete_confirm_multiple' => 'Vill du verkligen radera valda layouter?', + 'delete_confirm_single' => 'Vill du verkligen radera denna layouter?' + ], + 'partial' => [ + 'not_found_name' => "En partial med namnet ':name' kunde ej hittas", + 'invalid_name' => "Felaktigt partialnamn: :name", + 'menu_label' => 'Partials', + 'unsaved_label' => 'Osparade partials', + 'no_list_records' => 'Inga partials funna', + 'delete_confirm_multiple' => 'Vill du verkligen radera markerade partials?', + 'delete_confirm_single' => 'Vill du verkligen radera denna partial?', + 'new' => 'Ny partial' + ], + 'content' => [ + 'not_found_name' => "Innehållet ':name' kunde ej hittas", + 'menu_label' => 'Innehåll', + 'unsaved_label' => 'Osparat innehåll', + 'no_list_records' => 'Inga innehållsfiler funna', + 'delete_confirm_multiple' => 'Vill du verkligen radera markerade filer eller mappar?', + 'delete_confirm_single' => 'Vill du verkligen radera detta innehållsfil?', + 'new' => 'Ny innehållsfil' + ], + 'ajax_handler' => [ + 'invalid_name' => "Felaktig AJAX-hanterare: :name", + 'not_found' => "AJAX-hanterare ':name' kunde ej hittas", + ], + 'cms' => [ + 'menu_label' => "CMS" + ], + 'sidebar' => [ + 'add' => 'Lägg till', + 'search' => 'Sök...' + ], + 'editor' => [ + 'settings' => 'Inställningar', + 'title' => 'Titel', + 'new_title' => 'Ny sidtitel', + 'url' => 'URL', + 'filename' => 'Filnamn', + 'layout' => 'Layout', + 'description' => 'Beskrivning', + 'preview' => 'Förhandsgranska', + 'meta' => 'Meta', + 'meta_title' => 'Meta-titel', + 'meta_description' => 'Meta-beskrivning', + 'markup' => 'Markup', + 'code' => 'Kod', + 'content' => 'Innehåll', + 'hidden' => 'Dold', + 'hidden_comment' => 'Dolda sidor är endast tillgängliga genom inloggade back-end användare.', + 'enter_fullscreen' => 'Starta helskärmsläge', + 'exit_fullscreen' => 'Avsluta helskärmsläge' + ], + 'asset' => [ + 'menu_label' => "Filsystem", + 'unsaved_label' => 'Osparade filer', + 'drop_down_add_title' => 'Lägg till...', + 'drop_down_operation_title' => 'Åtgärd...', + 'upload_files' => 'Ladda upp fil(er)', + 'create_file' => 'Skapa fil', + 'create_directory' => 'Skapa mapp', + 'directory_popup_title' => 'Ny mapp', + 'directory_name' => 'Mappnamn', + 'rename' => 'Döp om', + 'delete' => 'Radera', + 'move' => 'Flytta', + 'select' => 'Välj', + 'new' => 'Ny fil', + 'rename_popup_title' => 'Byt namn', + 'rename_new_name' => 'Nytt namn', + 'invalid_path' => 'Sökvägen kan endast innehålla siffror, bokstäver, mellanslag och följande tecken: ._-/', + 'error_deleting_file' => 'Kunde inte radera filen :name.', + 'error_deleting_dir_not_empty' => 'Ett fel uppstod vid försök att radera :name. Mappen är ej tom', + 'error_deleting_dir' => 'Kunde inte radera filen :name.', + 'invalid_name' => 'Namn kan endast innehålla siffror, bokstäver, mellanslag och följande tecken: ._-', + 'original_not_found' => 'Orginalfilen eller mappen kunde ej hittas', + 'already_exists' => 'En fil eller mapp med detta namn finns redan', + 'error_renaming' => 'Ett fel uppstod vid namnbyte på filen eller mappen', + 'name_cant_be_empty' => 'Namn får ej vara tomt', + 'too_large' => 'Den uppladdade filen är för stor. Tillåten filstorlek är :max_size', + 'type_not_allowed' => 'Endast följande filtyper är tillåtna: :allowed_types', + 'file_not_valid' => 'Filen är inte korrekt', + 'error_uploading_file' => 'Ett fel uppstod vid uppladdning av ":name" :error', + 'move_please_select' => 'Var god välj', + 'move_destination' => 'Destionationsmapp', + 'move_popup_title' => 'Flytta objekt', + 'move_button' => 'Flytta', + 'selected_files_not_found' => 'Valda filer kunde ej hittas', + 'select_destination_dir' => 'Var god välj en destinationsmapp', + 'destination_not_found' => 'Destinationsmappen kunde ej hittas', + 'error_moving_file' => 'Ett fel uppstod vid flytt av fil :file', + 'error_moving_directory' => 'Ett fel uppstod vid flytt av mapp :dir', + 'error_deleting_directory' => 'Ett fel uppstod vid radering av orginalmapp :dir', + 'path' => 'Sökväg' + ], + 'component' => [ + 'menu_label' => "Komponenter", + 'unnamed' => "Ej namngiven", + 'no_description' => "Ingen beskrivning", + 'alias' => "Alias", + 'alias_description' => "Ett unikt namn för denna komponent, när den skall användas i sid- eller layoutkod", + 'validation_message' => "Komponentalias är obligatoriska och får endast innehålla bokstäver, siffror, och understreck. De måste börja med en bokstav", + 'invalid_request' => "Mallen kunde inte sparas pga felaktig komponentdata", + 'no_records' => 'Inga komponenter funna', + 'not_found' => "Komponenten ':name' kunde ej hittas", + 'method_not_found' => "Komponenten ':name' saknar metoden ':method'", + ], + 'template' => [ + 'invalid_type' => "Felaktig malltyp", + 'not_found' => "Den angivna mallen kunde ej hittas", + 'saved'=> "Mallen har sparats" + ], + 'permissions' => [ + 'name' => 'Cms', + 'manage_content' => 'Hantera innehåll', + 'manage_assets' => 'Hantera filer', + 'manage_pages' => 'Hantera sidor', + 'manage_layouts' => 'Hantera layouts', + 'manage_partials' => 'Hantera partials', + 'manage_themes' => 'Hantera teman', + ], +]; diff --git a/modules/cms/lang/th/lang.php b/modules/cms/lang/th/lang.php new file mode 100644 index 0000000..c3c4b71 --- /dev/null +++ b/modules/cms/lang/th/lang.php @@ -0,0 +1,296 @@ + [ + 'invalid_file' => 'ชื่อไฟล์ไม่ถูกต้อง: :name ชื่อไฟล์สามารถใส่ ตัวอักษรภาษาอังกฤษ ตัวเลข และสัญลักษณ์ _-. ตัวอย่างชื่อไฟล์ที่ถูกต้อง: page.htm, page, subdirectory/page', + 'invalid_property' => "คุณสมบัติ ':name' ไม่สามารถตั้งค่าได้", + 'file_already_exists' => "ไฟล์ ':name' มีอยู่แล้ว", + 'error_saving' => "การบันทึกไฟล์ผิดพลาด ':name' กรุณาตรวจสอบสิทธิ์การเขียนไฟล์", + 'error_creating_directory' => 'การสร้างโฟลเดอร์ผิดพลาด :name. กรุณาตรวจสอบสิทธิ์การเขียนไฟล์', + 'invalid_file_extension' => 'นามสกุลไฟล์ไม่ถูกต้อง: :invalid นามสกุลที่อนุญาตให้ใช้ได้มีดังนี้: :allowed', + 'error_deleting' => "การลบไฟล์แม่แบบผิดพลาด ':name' กรุณาตรวจสอบสิทธิ์การเขียนไฟล์", + 'delete_success' => 'ลบแม่แบบจำนวน: :count แม่แบบ', + 'file_name_required' => 'ต้องใส่ช่องชื่อไฟล์', + 'safe_mode_enabled' => 'โหมดความปลอดภัยกำลังถูกใช้งาน', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'เว็บไซต์', + 'online' => 'ออนไลน์', + 'maintenance' => 'กำลังปรับปรุง', + 'manage_themes' => 'จัดการธีม', + 'customize_theme' => 'ปรับแก้ธีม', + ], + ], + 'theme' => [ + 'not_found_name' => "ไม่พบธีม ':name'", + 'by_author' => 'โดย :name', + 'active' => [ + 'not_set' => 'ยังไม่ได้เปิดใช้งานธีม', + 'not_found' => 'ไม่พบธีมที่เปิดใช้งาน', + ], + 'edit' => [ + 'not_set' => 'ธีมที่แก้ไขไม่สามารถตั้งค่าได้', + 'not_found' => 'หาธีมที่แก้ไขไม่พบ', + 'not_match' => "สิ่งที่คุณกำลังพยายามเข้าถึงไม่อยู่ในธีมที่กำลังแก้ไขอยู่ กรุณารีโหลดหน้าเว็บ", + ], + 'settings_menu' => 'ธีมหน้าบ้าน (Theme)', + 'settings_menu_description' => 'จัดการธีมหน้าบ้าน และตัวเลือกในการปรับแก้อื่นๆ', + 'default_tab' => 'คุณสมบัติ', + 'name_label' => 'ชื่อ', + 'name_create_placeholder' => 'ชื่อธีมใหม่', + 'author_label' => 'ผู้สร้าง', + 'author_placeholder' => 'ชื่อบุคคลหรือบริษัท', + 'description_label' => 'รายละเอียด', + 'description_placeholder' => 'รายละเอียดธีม', + 'homepage_label' => 'โฮมเพจ', + 'homepage_placeholder' => 'URL ของเว็บไซต์', + 'code_label' => 'รหัส', + 'code_placeholder' => 'รหัสที่ไม่ซ้ำสำหรับเอาธีมไปแจกจ่าย', + 'preview_image_label' => 'ภาพตัวอย่าง', + 'preview_image_placeholder' => 'ชื่อไฟล์และโฟลเดอร์ภาพตัวอย่างของธีม', + 'dir_name_label' => 'ชื่อโฟลเดอร์', + 'dir_name_create_label' => 'ชื่อโฟลเดอร์ของธีม', + 'theme_label' => 'ธีม', + 'theme_title' => 'ธีม', + 'activate_button' => 'เปิดการใช้งาน', + 'active_button' => 'ใช้งานอยู่', + 'customize_theme' => 'ปรับแก้ธีม', + 'customize_button' => 'ปรับแก้', + 'duplicate_button' => 'ทำซ้ำ', + 'duplicate_title' => 'ทำซ้ำธีม', + 'duplicate_theme_success' => 'ทำซ้ำธีมแล้ว!', + 'manage_button' => 'จัดการ', + 'manage_title' => 'จัดการธีม', + 'edit_properties_title' => 'ธีม', + 'edit_properties_button' => 'แก้ไขคุณสมบัติ', + 'save_properties' => 'บันทึกคุณสมบัติ', + 'import_button' => 'อิมพอร์ต', + 'import_title' => 'อิมพอร์ตธีม', + 'import_theme_success' => 'อิมพอร์ดธีมแล้ว!', + 'import_uploaded_file' => 'ไฟล์ธีม', + 'import_overwrite_label' => 'เขียนทับไฟล์ที่มีอยู่แล้ว', + 'import_overwrite_comment' => 'เอาติ๊กออกจะอิมพอร์ทเฉพาะไฟล์ใหม่', + 'import_folders_label' => 'โฟลเดอร์', + 'import_folders_comment' => 'กรุณาเลือกโฟลเดอร์ของธีมที่คุณต้องการอิมพอร์ท', + 'export_button' => 'เอ็กซพอร์ต', + 'export_title' => 'เอ็กซพอร์ตธีม', + 'export_folders_label' => 'โฟลเดอร์', + 'export_folders_comment' => 'กรุณาเลือกโฟลเดอร์ของธีมที่ท่านต้องการเอ็กซพอร์ต', + 'delete_button' => 'ลบ', + 'delete_confirm' => 'ลบธีมนี้? ไม่สามารถย้อนกลับได้!', + 'delete_active_theme_failed' => 'ไม่สามารถลบธีมที่กำลังใช้งานอยู่, เปิดการใช้งานธีมอื่นก่อนลบ', + 'delete_theme_success' => 'ลบธีมแล้ว!', + 'create_title' => 'สร้างธีม', + 'create_button' => 'สร้าง', + 'create_new_blank_theme' => 'สร้างธีมใหม่', + 'create_theme_success' => 'สร้างธีมแล้ว!', + 'create_theme_required_name' => 'กรุณากำหนดชื่อธีม', + 'new_directory_name_label' => 'ชื่อโฟลเดอร์ธีม', + 'new_directory_name_comment' => 'กำหนดโฟลเดอร์ใหม่สำหรับธีมที่จะทำซ้ำ', + 'dir_name_invalid' => 'ชื่อโฟลเดอร์ธีม สามารถใช้ตัวเลข อักษรภาษาอังกฤษและเครื่องหมาย: _-', + 'dir_name_taken' => 'ชื่อโฟลเดอร์ธีมมีอยู่แล้ว', + 'find_more_themes' => 'หาธีมอื่นๆ', + 'saving' => 'กำลังบันทึกธีม...', + 'return' => 'กลับสู่หน้ารายการธีม', + ], + 'maintenance' => [ + 'settings_menu' => 'โหมดการบำรุงรักษา', + 'settings_menu_description' => 'ปรับแก้หน้าโหมดการบำรุงรักษา และเลือกการตั้งค่า', + 'is_enabled' => 'เปิดใช้โหมดการบำรุงรักษา', + 'is_enabled_comment' => 'เลือกหน้าที่ต้องการให้แสดงเมื่อเปิดใช้งานโหมดการบำรุงรักษา', + 'hint' => 'โหลดการบำรุงรักษาจะแสดงหน้าบำรุงรักษาสำหรับผู้เยี่ยมชมที่ไม่ได้ลงชื่อเข้าใช้หน้าเว็บหลังบ้าน', + ], + 'page' => [ + 'not_found_name' => "หาหน้าเว็บ ':name' ไม่พบ", + 'not_found' => [ + 'label' => 'ไม่พบหน้าเว็บ', + 'help' => 'หาหน้าเว็บที่ร้องขอไม่พบ', + ], + 'custom_error' => [ + 'label' => 'หน้าเว็บผิดพลาด', + 'help' => "ขอโทษครับ, มีบางอย่างผิดพลาดและไม่สามารถแสดงหน้าเว็บได้", + ], + 'menu_label' => 'หน้าเว็บ', + 'unsaved_label' => 'หน้าเว็บที่ยังไม่บันทึก', + 'no_list_records' => 'ไม่พบหน้าเว็บ', + 'new' => 'หน้าใหม่', + 'invalid_url' => 'รูปแบบ URL ไม่ถูกต้อง, URL ควรเริ่มต้นด้วยเครื่องหมาย / และสามารถมีตัวเลข, ตัวอักษรภาษาอังกฤษและเครื่องหมาย: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'ลบหน้าที่ถูกเลือกไว้?', + 'delete_confirm_single' => 'ลบหน้านี้?', + 'no_layout' => '-- ไม่มีโครงร่าง --', + 'cms_page' => 'หน้าเว็บ CMS', + 'title' => 'หัวเรื่องหน้าเว็บ', + 'url' => 'URL หน้าเว็บ', + 'file_name' => 'ชื่อไฟล์หน้าเว็บ', + ], + 'layout' => [ + 'not_found_name' => "หาโครงร่าง ':name' ไม่พบ", + 'menu_label' => 'โครงร่าง (Layout)', + 'unsaved_label' => 'โครงร่างที่ยังไม่บันทึก', + 'no_list_records' => 'ไม่พบโครงร่าง', + 'new' => 'โครงร่างใหม่', + 'delete_confirm_multiple' => 'ลบโครงร่างที่เลือกไว้?', + 'delete_confirm_single' => 'ลบโครงร่างนี้?', + ], + 'partial' => [ + 'not_found_name' => "ไม่พบส่วนย่อย ':name'", + 'invalid_name' => 'ส่วนย่อยชื่อ: :name ไม่ถูกต้อง', + 'menu_label' => 'ส่วนย่อย', + 'unsaved_label' => 'ส่วนย่อยที่ยังไม่บันทึก', + 'no_list_records' => 'ไม่พบส่วนย่อย', + 'delete_confirm_multiple' => 'ลบส่วนย่อยที่เลือกไว้?', + 'delete_confirm_single' => 'ลบส่วนย่อยนี้?', + 'new' => 'ส่วนย่อยใหม่', + ], + 'content' => [ + 'not_found_name' => "ไม่พบไฟล์เนื้อหา ':name'", + 'menu_label' => 'เนื้อหา', + 'unsaved_label' => 'เนื้อหาที่ยังไม่ได้บันทึก', + 'no_list_records' => 'หาไฟล์เนื้อหาไม่พบ', + 'delete_confirm_multiple' => 'ลบไฟล์เนื้อหาหรือโฟลเดอร์ที่เลือกไว้?', + 'delete_confirm_single' => 'ลบไฟล์เนื้อหานี้?', + 'new' => 'ไฟล์เนื้อหาใหม่', + ], + 'ajax_handler' => [ + 'invalid_name' => 'ชื่อผู้จัดการ AJAX: :name ไม่ถูกต้อง', + 'not_found' => "หาผู้จัดการ AJAX ':name' ไม่พบ", + ], + 'cms' => [ + 'menu_label' => 'CMS', + ], + 'sidebar' => [ + 'add' => 'เพิ่ม', + 'search' => 'ค้นหา...', + ], + 'editor' => [ + 'settings' => 'การตั้งค่า', + 'title' => 'หัวเรื่อง', + 'new_title' => 'หัวเรื่องหน้าใหม่', + 'url' => 'URL', + 'filename' => 'ชื่อไฟล์', + 'layout' => 'โครงร่าง', + 'description' => 'รายละเอียด', + 'preview' => 'ดูตัวอย่าง', + 'meta' => 'ข้อมูลย่อย', + 'meta_title' => 'หัวเรื่อง', + 'meta_description' => 'รายละเอียด', + 'markup' => 'Markup', + 'code' => 'Code', + 'content' => 'เนื้อหา', + 'hidden' => 'ซ่อน', + 'hidden_comment' => 'เพจที่ถูกซ่อนสามารถเข้าถึงได้โดยผู้ใช้หลังบ้านที่ล็อกอินเท่านั้น', + 'enter_fullscreen' => 'เข้าสู่โหมดเต็มหน้าจอ', + 'exit_fullscreen' => 'ออกโหมดเต็มหน้าจอ', + 'open_searchbox' => 'เปิดกล่องค้นหา', + 'close_searchbox' => 'ปิดกล่องค้นหา', + 'open_replacebox' => 'เปลี่ยนกล่องแทนที่', + 'close_replacebox' => 'ปิดกล่องแทนที่', + 'reset' => 'ตั้งค่าเริ่มต้น', + 'reset_confirm' => 'คุณแน่ใจว่าต้องการตั้งค่าเริ่มต้นไฟล์นี้ตามข้อมูลที่อยู่ในระบบไฟล์? ไฟล์นี้จะถูกเขียนทับด้วยไฟล์ที่อยู่ในระบบไฟล์', + 'resetting' => 'กำลังตั้งค่าเริ่มต้น', + ], + 'asset' => [ + 'menu_label' => 'สินทรัพย์', + 'unsaved_label' => 'สินทรัพย์ที่ยังไม่ได้บันทึก', + 'drop_down_add_title' => 'เพิ่ม...', + 'drop_down_operation_title' => 'การทำงาน...', + 'upload_files' => 'อัพโหลดไฟล์', + 'create_file' => 'สร้างไฟล์', + 'create_directory' => 'สร้างโฟลเดอร์', + 'directory_popup_title' => 'โฟลเดอร์ใหม่', + 'directory_name' => 'ชื่อโฟลเดอร์', + 'rename' => 'เปลี่ยนชื่อ', + 'delete' => 'ลบ', + 'move' => 'ย้าย', + 'select' => 'เลือก', + 'new' => 'ไฟล์ใหม่', + 'rename_popup_title' => 'เปลี่ยนชื่อ', + 'rename_new_name' => 'ชื่อใหม่', + 'invalid_path' => 'path สามารถใส่ได้เฉพาะ ตัวเลข ตัวอักษรภาษาอังกฤษ ช่องว่าง และสัญลักษณ์ต่อไปนี้: ._-/', + 'error_deleting_file' => 'การลบไฟล์ :name ผิดพลาด', + 'error_deleting_dir_not_empty' => 'การลบโฟลเดอร์ผิดพลาด :name โฟลเดอร์นี้ไม่ว่างเปล่า', + 'error_deleting_dir' => 'การลบโฟลเดอร์ :name ผิดพลาด', + 'invalid_name' => 'ชื่อ สามารถใส่ได้เฉพาะ ตัวเลข ตัวอักษรภาษาอังกฤษ ช่องว่าง และสัญลักษณ์ต่อไปนี้: ._-', + 'original_not_found' => 'หาไฟล์หรือโฟลเดอร์ต้นทางไม่พบ', + 'already_exists' => 'ชื่อไฟล์หรือโฟลเดอร์นี้มีอยู่แล้ว', + 'error_renaming' => 'การเปลี่ยนชื่อไฟล์หรือโฟลเดอร์ผิดพลาด', + 'name_cant_be_empty' => 'ให้ชื่อว่างเปล่าไม่ได้', + 'too_large' => 'ไฟล์ที่ต้องการอัพโหลดใหญ่เกินไป ขนาดไฟล์สูงสุดที่อนุญาตคือ :max_size', + 'type_not_allowed' => 'อนุญาตเฉพาะประเภทไฟล์ต่อไปนี้: :allowed_types', + 'file_not_valid' => 'ไฟล์ไม่ถูกต้อง', + 'error_uploading_file' => "อัพโหลดไฟล์ ':name' ผิดพลาด: :error", + 'move_please_select' => 'กรุณาเลือก', + 'move_destination' => 'โฟลเดอร์ปลายทาง', + 'move_popup_title' => 'ย้ายสินทรัพย์', + 'move_button' => 'ย้าย', + 'selected_files_not_found' => 'ไม่พบไฟล์ที่เลือกไว้', + 'select_destination_dir' => 'กรุณาเลือกโฟลเดอร์ปลายทาง', + 'destination_not_found' => 'ไม่พบโฟลเดอร์ปลายทาง', + 'error_moving_file' => 'การย้ายไฟล์ :file ผิดพลาด', + 'error_moving_directory' => 'การย้ายโฟลเดอร์ :dir ผิดพลาด', + 'error_deleting_directory' => 'การลบโฟลเดอร์ต้นทาง :dir ผิดพลาด', + 'no_list_records' => 'ไม่พบไฟล์', + 'delete_confirm' => 'ลบไฟล์หรือโฟลเดอร์ที่เลือกไว้?', + 'path' => 'Path', + ], + 'component' => [ + 'menu_label' => 'ส่วนประกอบ', + 'unnamed' => 'ไม่มีชื่อ', + 'no_description' => 'ไม่มีรายละเอียดมาด้วย', + 'alias' => 'นามแฝง', + 'alias_description' => 'ชื่อที่ไม่ซ้ำที่กำหนดให้กับส่วนประกอบนี้สำหรับใช้ในโค้ดหน้าเว็บหรือโครงร่าง', + 'validation_message' => 'ต้องใส่นามแฝงส่วนประกอบ และสามารถใส่ได้เฉพาะ ตัวอักษรภาษาอังกฤษ ตัวเลข และเครื่องหมาย _ นามแฝงควรเริ่มต้นด้วยตัวอักษรภาษาอังกฤษ', + 'invalid_request' => 'แม่แบบไม่สามารถถูกบันทึกเนื่องจากข้อมูลส่วนประกอบไม่ถูกต้อง', + 'no_records' => 'ไม่พบส่วนประกอบ', + 'not_found' => "หาส่วนประกอบ ':name' ไม่พบ", + 'method_not_found' => "ส่วนประกอบ ':name' ไม่มี method ชื่อ ':method'.", + ], + 'template' => [ + 'invalid_type' => 'ไม่รู้จักประเภทแม่แบบ', + 'not_found' => 'ไม่พบแม่แบบ', + 'saved' => 'บันทึกแม่แบบแล้ว', + 'no_list_records' => 'ไม่พบข้อมูล', + 'delete_confirm' => 'ลบแม่แบบที่เลือกไว้?', + 'order_by' => 'เรียงลำดับโดย', + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'จัดการไฟล์เนื้อหาเว็บไซต์', + 'manage_assets' => 'จัดการสินทรัพย์ของเว็บไซต์ - รูปภาพ, ไฟล์ JavaScript, ไฟล์ CSS', + 'manage_pages' => 'สร้าง, แก้ไข และลบ หน้าเว็บไซต์', + 'manage_layouts' => 'สร้าง, แก้ไข และลบ โครงร่าง', + 'manage_partials' => 'สร้าง, แก้ไข และลบ ส่วนย่อย', + 'manage_themes' => 'เปิด, ปิดการใช้งาน และปรับแต่งค่า ธีม', + 'manage_theme_options' => 'ปรับแต่งค่าตัวเลือกต่างๆ สำหรับธีมที่ใช้งานอยู่', + ], + 'theme_log' => [ + 'hint' => 'บันทึกนี้แสดงการเปลี่ยนแปลงที่เกี่ยวกับธีมโดยผู้ดูแลระบบในส่วนหน้าเว็บหลังบ้าน', + 'menu_label' => 'บันทึกธีม', + 'menu_description' => 'ดูการเปลี่ยนแปลงของธีมที่กำลังใช้งานอยู่', + 'empty_link' => 'ลบบันทึกธีมทั้งหมด', + 'empty_loading' => 'กำลังลบบันทึกธีม...', + 'empty_success' => 'ลบบันทึกธีมเรียบร้อยแล้ว', + 'return_link' => 'กลับสู่หน้าบันทึกธีม', + 'id' => 'ไอดี', + 'id_label' => 'ไอดีบันทึก', + 'created_at' => 'วันเวลา', + 'user' => 'ผู้ใช้', + 'type' => 'ประเภท', + 'type_create' => 'สร้าง', + 'type_update' => 'อัพเดท', + 'type_delete' => 'ลบ', + 'theme_name' => 'ชื่อธีม', + 'theme_code' => 'รหัสธีม', + 'old_template' => 'แม่แบบเก่า', + 'new_template' => 'แม่แบบใหม่', + 'template' => 'แม่แบบ (Template)', + 'diff' => 'การเปลี่ยนแปลง', + 'old_value' => 'ค่าเก่า', + 'new_value' => 'ค่าใหม่', + 'preview_title' => 'Template changes', + 'template_updated' => 'อัพเดทแม่แบบแล้ว', + 'template_created' => 'สร้างแม่แบบแล้ว', + 'template_deleted' => 'ลบแม่แบบแล้ว', + ], +]; diff --git a/modules/cms/lang/tr/lang.php b/modules/cms/lang/tr/lang.php new file mode 100644 index 0000000..8f65424 --- /dev/null +++ b/modules/cms/lang/tr/lang.php @@ -0,0 +1,293 @@ + [ + 'invalid_file' => 'Hatalı dosya adı: :name. Dosya isimleri sadece alfanümerik semboller, alt çizgiler, tire ve nokta içerebilir. Bazı doğru dosya adı örnekleri: sayfa.htm, sayfa, altdizin/sayfa', + 'invalid_property' => '":name" özelliği ayarlanamadı', + 'file_already_exists' => '":name" isimli dosya mevcut.', + 'error_saving' => '":name" kaydedilirken hatayla oluştu.', + 'error_creating_directory' => ':name klasörü oluşturulurken hata oluştu', + 'invalid_file_extension'=>'Hatalı dosya uzantısı: :invalid. İzin verilen uzantılar: :allowed.', + 'error_deleting' => '":name" şablon dosyası silinirken hatayla karşılaşıldı.', + 'delete_success' => ':count şablon başarıyla silindi.', + 'file_name_required' => 'Dosya adı alanı gereklidir.', + 'safe_mode_enabled' => 'Güvenli mod şuan aktif.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Website', + 'online' => 'yayında', + 'maintenance' => 'bakım modunda', + 'manage_themes' => 'Temaları yönet', + 'customize_theme' => 'Tema özelleştir', + ], + ], + 'theme' => [ + 'not_found_name' => "':name' isimli tema bulunamadı.", + 'by_author' => ':name ile filtrele', + 'active' => [ + 'not_set' => "Aktif tema belirtilmedi.", + 'not_found' => 'Aktif tema bulunamadı.', + ], + 'edit' => [ + 'not_set' => "Düzenlenecek tema belirtilmedi.", + 'not_found' => "Düzenlenecek tema bulunamadı.", + 'not_match' => "Ulaşmaya çalıştığınız nesne düzenlenecek temaya ait değil. Lütfen sayfayı yenileyin.", + ], + 'settings_menu' => 'Temalar', + 'settings_menu_description' => 'Yüklü temalar listesini önizleyebilir, bir tema seçip aktifleştirebilirsiniz.', + 'default_tab' => 'Özellikler', + 'name_label' => 'İsim', + 'name_create_placeholder' => 'Yeni tema ismi', + 'author_label' => 'Yazar', + 'author_placeholder' => 'Kişi yada şirket ismi', + 'description_label' => 'Açıklama', + 'description_placeholder' => 'Tema açıklaması', + 'homepage_label' => 'Anasayfa', + 'homepage_placeholder' => 'Anasayfa Adresi(URL)', + 'code_label' => 'Kod', + 'code_placeholder' => 'Temanın dağıtımında kullanılmak üzere benzersiz bir kod.', + 'preview_image_label' => 'Önizleme görseli', + 'preview_image_placeholder' => 'Tema önizleme görselinin yolu.', + 'dir_name_label' => 'Klasör ismi', + 'dir_name_create_label' => 'Hedef tema dizini', + 'theme_label' => 'Tema', + 'theme_title' => 'Temalar', + 'activate_button' => 'Aktifleştir', + 'active_button' => 'Aktifleştir', + 'customize_theme' => 'Temayı Özelleştir', + 'customize_button' => 'Düzenle', + 'duplicate_button' => 'Kopyala', + 'duplicate_title' => 'Temayı kopyala', + 'duplicate_theme_success' => 'Tema başarıyla kopyalandı!', + 'manage_button' => 'Yönet', + 'manage_title' => 'Temayı yönet', + 'edit_properties_title' => 'Tema', + 'edit_properties_button' => 'Özellikleri düzenle', + 'save_properties' => 'Özellikleri kaydet', + 'import_button' => 'İçe aktar', + 'import_title' => 'Temayı içe aktar', + 'import_theme_success' => 'Tema başarıyla içe aktarıldı!', + 'import_uploaded_file' => 'Tema arşiv dosyası', + 'import_overwrite_label' => 'Mevcut dosyaların üstüne yaz', + 'import_overwrite_comment' => 'Sadece yeni dosyaları almak için bu kutucuğu boşaltın', + 'import_folders_label' => 'Klasörler', + 'import_folders_comment' => 'Lütfen içe aktarmak istediğiniz tema klasörlerini seçiniz.', + 'export_button' => 'Dışa aktar', + 'export_title' => 'Temayı dışa aktar', + 'export_folders_label' => 'Klasörler', + 'export_folders_comment' => 'Lütfen dışa aktarmak istediğiniz tema klasörlerini seçiniz', + 'delete_button' => 'Sil', + 'delete_confirm' => 'Bu temayı silmek istediniğize emin misiniz? Bu işlem geri alınamaz!', + 'delete_active_theme_failed' => 'Aktif tema silinemez. Lütfen başka bir temayı aktif tema olarak seçiniz.', + 'delete_theme_success' => 'Tema başarıyla silindi!', + 'create_title' => 'Tema oluştur', + 'create_button' => 'Oluştur', + 'create_new_blank_theme' => 'Yeni boş bir tema oluştur', + 'create_theme_success' => 'Tema başarıyla oluşturuldu!', + 'create_theme_required_name' => 'Please specify a name for the theme.', + 'new_directory_name_label' => 'Tema dizini', + 'new_directory_name_comment' => 'Kopyalanacak tema için yeni bir tema dizini giriniz.', + 'dir_name_invalid' => 'İsim sadece sayı, latin harfleri ve şu sembolleri içerebilir: _- ', + 'dir_name_taken' => 'İstenen tema dizini zaten mevcut.', + 'find_more_themes' => 'Daha fazla tema bulun', + 'saving' => 'Tema kaydediliyor...', + 'return' => 'Tema listesine geri dön', + ], + 'maintenance' => [ + 'settings_menu' => 'Bakım modu', + 'settings_menu_description' => 'Bakım modu ayarlarını düzenleyip bakım sayfasını yapılandırabilirsiniz.', + 'is_enabled' => 'Bakım modunu aktifleştir', + 'is_enabled_comment' => 'Aktifleştirildiğinde, web sitesi ziyaretçileri aşağıdaki seçtiğiniz sayfayı görecektir.', + 'hint' => 'Bakımda sayfası, yönetim paneli girişi yapmamış tüm ziyaretçilere seçilen bakımda sayfasını gösterir.', + ], + 'page' => [ + 'not_found_name' => "':name' sayfası bulunamadı", + 'not_found' => [ + 'label' => "Sayfa bulunamadı", + 'help' => "İstenilen sayfa bulunamadı.", + ], + 'custom_error' => [ + 'label' => "Sayfa hatası", + 'help' => "Üzgünüz, bir şeyler ters gitti ve sayfa görüntülenemiyor.", + ], + 'menu_label' => 'Sayfalar', + 'unsaved_label' => 'Kaydedilmemiş sayfa(lar)', + 'no_list_records' => 'Hiç sayfa yok.', + 'new' => 'Sayfa oluştur', + 'invalid_url' => 'Hatalı URL formatı. URL eğik çizgi ile başlamalı ve sayı, Latin harfleri ve aşağıdaki sembolleri içerebilir: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Seçili sayfaları silmek istediğinize emin misiniz?', + 'delete_confirm_single' => 'Bu sayfayı silmek istediğinize emin misiniz?', + 'no_layout' => '-- şablon yok --', + 'cms_page' => 'CMS sayfa', + 'title' => 'Sayfa başlığı', + 'url' => 'Sayfa URL', + 'file_name' => 'Sayfa dosyası adı', + ], + 'layout' => [ + 'not_found_name' => "':name' isimli şablon bulunamadı", + 'menu_label' => 'Şablonlar', + 'unsaved_label' => 'Kaydedilmemiş şablon(lar)', + 'no_list_records' => 'Şablon bulunamadı', + 'new' => 'Şablon oluştur', + 'delete_confirm_multiple' => 'Seçili şablonları silmek istediğinize emin misiniz?', + 'delete_confirm_single' => 'Seçili şablonu silmek istediğinize emin misiniz?', + ], + 'partial' => [ + 'not_found_name' => "':name' bölümü bulunamadı.", + 'invalid_name' => "Hatalı bölüm adı: :name.", + 'menu_label' => 'Bölümler', + 'unsaved_label' => 'Kaydedilmemiş bölüm(ler)', + 'no_list_records' => 'Bölüm bulunamadı.', + 'delete_confirm_multiple' => 'Seçili bölümleri silmek istediğinize emin misiniz?', + 'delete_confirm_single' => 'Bu bölümü silmek istediğinize emin misiniz?', + 'new' => 'Bölüm Oluştur', + ], + 'content' => [ + 'not_found_name' => "':name' isminde içerik dosyası bulunamadı.", + 'menu_label' => 'İçerik', + 'unsaved_label' => 'Kaydedilmemiş içerik', + 'no_list_records' => 'İçerik dosyası bulunamadı.', + 'delete_confirm_multiple' => 'Seçili içerik dosyaları veya klasörlerini silmek istediğinize emin misiniz?', + 'delete_confirm_single' => 'Bu içerik dosyasını silmek istediğinize emin misiniz?', + 'new' => 'Yeni İçerik', + ], + 'ajax_handler' => [ + 'invalid_name' => "Hatalı AJAX işleyici adı: :name.", + 'not_found' => "':name' isimli AJAX işleyici bulunamadı.", + ], + 'cms' => [ + 'menu_label' => "Tasarım Ayarları", + ], + 'sidebar' => [ + 'add' => 'Ekle', + 'search' => 'Ara...', + ], + 'editor' => [ + 'settings' => 'Ayarlar', + 'title' => 'Başlık', + 'new_title' => 'Yeni sayfa başlığı', + 'url' => 'URL', + 'filename' => 'Dosya Adı', + 'layout' => 'Düzen', + 'description' => 'Tanım', + 'preview' => 'Önizleme', + 'meta' => 'Meta', + 'meta_title' => 'Meta Başlık', + 'meta_description' => 'Meta Tanım', + 'markup' => 'Biçimlendirme', + 'code' => 'Kod', + 'content' => 'İçerik', + 'hidden' => 'Gizli', + 'hidden_comment' => 'Gizli sayfalara yalnızca Yönetim Paneline giriş yapmış kullanıcılar erişilebilir.', + 'enter_fullscreen' => 'Tam Ekran moduna geç', + 'exit_fullscreen' => 'Tam Ekran modundan çık', + 'open_searchbox' => 'Arama kutusunu aç', + 'close_searchbox' => 'Arama kutusunu kapat', + 'open_replacebox' => 'Düzenleme kutusunu aç', + 'close_replacebox' => 'Düzenleme kutusunu kapat', + ], + 'asset' => [ + 'menu_label' => "Dosyalar", + 'unsaved_label' => 'Kaydedilmemiş dosya(lar)', + 'drop_down_add_title' => 'Ekle...', + 'drop_down_operation_title' => 'İşlemler...', + 'upload_files' => 'Dosya(lar) yükle', + 'create_file' => 'Dosya oluştur', + 'create_directory' => 'Klasör oluştur', + 'directory_popup_title' => 'Yeni klasör', + 'directory_name' => 'Klasör ismi', + 'rename' => 'Yeniden isimlendir', + 'delete' => 'Sil', + 'move' => 'Taşı', + 'select' => 'Seç', + 'new' => 'Yeni dosya', + 'rename_popup_title' => 'Yeniden isimlendir', + 'rename_new_name' => 'Yeni isim', + 'invalid_path' => 'Yol sadece sayı, Latin harfleri, boşluk ve şu sembolleri içerebilir: ._-/', + 'error_deleting_file' => ':name dosyası silinirken hatayla karşılaşıldı.', + 'error_deleting_dir_not_empty' => ':name klasörü silinemedi. Klasör boş değil.', + 'error_deleting_dir' => ':name dosyası silinirken hatayla karşılaşıldı.', + 'invalid_name' => 'İsim sadece sayı, Latin harfleri, boşluk ve şu sembolleri içerebilir: ._-', + 'original_not_found' => 'Orjinal dosya veya dizin bulunamadı', + 'already_exists' => 'Bu isimde dosya veya dizin zaten var', + 'error_renaming' => 'Dosya veya dizin ismi düzenlenemedi', + 'name_cant_be_empty' => 'İsim alanı boş bırakılamaz.', + 'too_large' => 'Yüklenen dosya çok büyük. İzin verilen maksimum boyut :max_size', + 'type_not_allowed' => 'İzin verilen dosya tipleri: :allowed_types', + 'file_not_valid' => 'Dosya geçerli değil', + 'error_uploading_file' => '":name" yüklenirken hatayla karşılaşıldı: :error', + 'move_please_select' => 'lütfen seçiniz', + 'move_destination' => 'Hedef klasör', + 'move_popup_title' => 'Assets\'i taşı', + 'move_button' => 'Taşı', + 'selected_files_not_found' => 'Seçilen dosyalar bulunamadı.', + 'select_destination_dir' => 'Lütfen hedef klasör seçiniz', + 'destination_not_found' => 'Hedef klasör bulunamadı', + 'error_moving_file' => ':file dosyası taşınırken hatayla karşılaşıldı', + 'error_moving_directory' => ':dir klasörü taşınırken hatayla karşılaşıldı', + 'error_deleting_directory' => ':dir klasörü silinirken hatayla karşılaşıldı', + 'no_list_records' => 'Dosya bulunamadı', + 'delete_confirm' => 'Seçilen dosyalar veya dizinler silinsin mi?', + 'path' => 'Yol', + ], + 'component' => [ + 'menu_label' => "Bileşenler", + 'unnamed' => "İsimsiz", + 'no_description' => "Açıklama girilmedi.", + 'alias' => "Takma ad", + 'alias_description' => "Bu bileşen için benzersiz bir isim. Sayfa veya şablonda kullanırken bu isim gerekecektir.", + 'validation_message' => "Bileşen isimleri gerkelidir ve sadece Latin semboller, sayılar, ve alt çizgi içerebilir. Bileşen ismi ayrıca Latin harfle başlamalı.", + 'invalid_request' => "Şablonda hatalı bileşen verisi olduğu için kaydedilemedi.", + 'no_records' => 'Bileşen bulunamadı.', + 'not_found' => "':name' isimli bileşen bulunamadı.", + 'method_not_found' => "':name' isimli bileşen ':method'unu içermiyor.", + ], + 'template' => [ + 'invalid_type' => "Hatalı şablon tipi.", + 'not_found' => "İstenilen şablon bulunamadı.", + 'saved'=> "Şablon başarıyla kaydedildi.", + 'no_list_records' => 'Kayıt bulunamadı', + 'delete_confirm' => 'Seçilen şablonlar silinsin mi?', + 'order_by' => 'Sırala', + ], + 'permissions' => [ + 'name' => 'CMS Sistemi', + 'manage_content' => 'İçerikleri düzenleyebilsin', + 'manage_assets' => 'Dosyaları düzenleyebilsin', + 'manage_pages' => 'Sayfaları düzenleyebilsin', + 'manage_layouts' => 'Şablonları düzenleyebilsin', + 'manage_partials' => 'Parça Kodları düzenleyebilsin', + 'manage_themes' => 'Temaları düzenleyebilsin', + 'manage_theme_options' => 'Aktif tema için özelleştirme seçeneklerini yapılandırın', + ], + 'theme_log' => [ + 'hint' => 'Bu kayıtlar, backend yöneticileri tarafından temada yapılan değişiklikleri görüntüler.', + 'menu_label' => 'Tema log', + 'menu_description' => 'Aktif temada yapılan değişiklikleri görüntüleyin.', + 'empty_link' => 'Tema loglarını temizle', + 'empty_loading' => 'Tema logları temizleniyor...', + 'empty_success' => 'Tema log temizlendi', + 'return_link' => 'Tema loglarına dön', + 'id' => 'ID', + 'id_label' => 'Log ID', + 'created_at' => 'Tarih ve Saat', + 'user' => 'Kişi', + 'type' => 'Tipi', + 'type_create' => 'Oluştur', + 'type_update' => 'Güncelle', + 'type_delete' => 'Sil', + 'theme_name' => 'Tema', + 'theme_code' => 'Tema kodu', + 'old_template' => 'Şablon (Eski)', + 'new_template' => 'Şablon (Yeni)', + 'template' => 'Şablon', + 'diff' => 'Değişiklikler', + 'old_value' => 'Eski değer', + 'new_value' => 'Yeni değer', + 'preview_title' => 'Şablon değişiklikleri', + 'template_updated' => 'Şablon güncellendi', + 'template_created' => 'Şablon oluşturuldu', + 'template_deleted' => 'Şablon silindi', + ], +]; diff --git a/modules/cms/lang/uk/lang.php b/modules/cms/lang/uk/lang.php new file mode 100644 index 0000000..7632ea2 --- /dev/null +++ b/modules/cms/lang/uk/lang.php @@ -0,0 +1,293 @@ + [ + 'invalid_file' => 'Помилка в імені файлу: :name. Імена файлів можуть містити тільки латинські букви, цифри, знаки підкреслення і точки. Приклад правильних імен файлів: page.htm, page, subdirectory/page', + 'invalid_property' => "Параметр ':name' не можна змінити.", + 'file_already_exists' => "Файл ':name' вже існує.", + 'error_saving' => "Помилка збереження файлу ':name'. Будь ласка, перевірте права на запис.", + 'error_creating_directory' => 'Помилка створення директорії :name. Будь ласка, перевірте права на запис.', + 'invalid_file_extension' => 'Зазначено неправильне розширення файлу: :invalid. Дозволені розширення: :allowed.', + 'error_deleting' => "Неможливо видалити файл шаблону ':name'. Будь ласка, перевірте права на запис.", + 'delete_success' => 'Шаблони були успішно видалені: :count.', + 'file_name_required' => 'Будь ласка, вкажіть ім\'я файлу шаблону.', + 'safe_mode_enabled' => 'Безпечний режим в даний момент включений.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Веб-сайт', + 'online' => 'Онлайн', + 'maintenance' => 'В розробці', + 'manage_themes' => 'Керування темами', + 'customize_theme' => 'Налаштування теми' + ], + ], + 'theme' => [ + 'not_found_name' => "Тема ':name' не знайдена.", + 'by_author' => 'Автор :name', + 'active' => [ + 'not_set' => 'Активна тема не встановлена.', + 'not_found' => 'Активна тема не знайдена.' + ], + 'edit' => [ + 'not_set' => 'Тема для редагування не встановлена.', + 'not_found' => 'Тема для редагування не знайдена.', + 'not_match' => 'Об\'єкт, який ви намагаєтеся відкрити, не належить редагованої темі. Будь ласка, оновіть сторінку.' + ], + 'settings_menu' => 'Фронтенд теми', + 'settings_menu_description' => 'Керування інтерфейсною темою', + 'default_tab' => 'Властивості', + 'name_label' => 'Назва', + 'name_create_placeholder' => 'Назва нової теми', + 'author_label' => 'Автор', + 'author_placeholder' => 'Ім\'я автора або назва компанії', + 'description_label' => 'Опис', + 'description_placeholder' => 'Опис теми', + 'homepage_label' => 'Домашня сторінка', + 'homepage_placeholder' => 'Адреса сайту', + 'code_label' => 'Унікальний код', + 'code_placeholder' => 'Унікальний код теми, який використовуються для її поширення', + 'preview_image_label' => 'Попередній перегляд', + 'preview_image_placeholder' => 'Шлях до зображення для попереднього перегляду.', + 'dir_name_label' => 'Назва директорії', + 'dir_name_create_label' => 'Директорія теми', + 'theme_label' => 'Тема', + 'theme_title' => 'Теми', + 'activate_button' => 'Активувати', + 'active_button' => 'Активовано', + 'customize_theme' => 'Налаштування теми', + 'customize_button' => 'Налаштувати тему', + 'duplicate_button' => 'Дублювати', + 'duplicate_title' => 'Дублювати тему', + 'duplicate_theme_success' => 'Дублювання успішно завершено!', + 'manage_button' => 'Керування', + 'manage_title' => 'Керування темою', + 'edit_properties_title' => 'Тема', + 'edit_properties_button' => 'Редагування властивостей', + 'save_properties' => 'Зберегти властивості', + 'import_button' => 'Імпортувати', + 'import_title' => 'Імпортувати тему', + 'import_theme_success' => 'Імпорт теми успішно завершено!', + 'import_uploaded_file' => 'Файл архіву теми', + 'import_overwrite_label' => 'Перезаписувати існуючі файли', + 'import_overwrite_comment' => 'Вимкніть цю опцію, щоб імпортувати тільки нові файли', + 'import_folders_label' => 'Директорії', + 'import_folders_comment' => 'Будь ласка, оберіть директорії теми, які ви хотіли б імпортувати', + 'export_button' => 'Експорт', + 'export_title' => 'Експортувати тему', + 'export_folders_label' => 'Директорії', + 'export_folders_comment' => 'Будь ласка, оберіть директорії теми, які ви хотіли б експортувати', + 'delete_button' => 'Видалити', + 'delete_confirm' => 'Ви впевнені, що хочете видалити цю тему? Ця дія є незворотнім!', + 'delete_active_theme_failed' => 'Неможливо видалити активний тему, спробуйте зробити іншу тему активною.', + 'delete_theme_success' => 'Видалення теми успішно завершено!', + 'create_title' => 'Створити тему', + 'create_button' => 'Створити', + 'create_new_blank_theme' => 'Створити нову тему', + 'create_theme_success' => 'Тема була успішно створена', + 'create_theme_required_name' => 'Будь ласка, вкажіть назву для теми.', + 'new_directory_name_label' => 'Директорія теми', + 'new_directory_name_comment' => 'Вкажіть нову назву каталогу дубліката теми.', + 'dir_name_invalid' => 'Назва може містити тільки цифри, латинські літери і такі символи: _ -', + 'dir_name_taken' => 'Зазначений каталог вже існує.', + 'find_more_themes' => 'Знайти нові теми', + 'saving' => 'Збереження теми...', + 'return' => 'Повернутися до списку тем' + ], + 'maintenance' => [ + 'settings_menu' => 'Режим обслуговування', + 'settings_menu_description' => 'Керування режимом роботи сайту.', + 'is_enabled' => 'Увімкнути режим обслуговування', + 'is_enabled_comment' => 'При активації цього режиму відвідувачі сайту побачать сторінку обрану нижче.', + 'hint' => 'Режим обслуговування покаже сторінку обслуговування для відвідувачів, що не авторизувалися в CMS.' + ], + 'page' => [ + 'not_found_name' => "Сторінка ':name' не знайдена", + 'not_found' => [ + 'label' => 'Сторінка не знайдена', + 'help' => 'Запрошення сторінка не знайдена.' + ], + 'custom_error' => [ + 'label' => 'Помилка на сторінці', + 'help' => 'На жаль, сторінка не може бути відображена через помилку.' + ], + 'menu_label' => 'Сторінки', + 'unsaved_label' => 'Незбережена(і) сторінка(и)', + 'no_list_records' => 'Сторінки не знайденi', + 'new' => 'Нова сторінка', + 'invalid_url' => 'Невірний формат адреси. Адреса сторінки повинен починатися зі знака / і може містити цифри, латинські літери, і такі знаки: ._- [] :? | / + * ^ $', + 'delete_confirm_multiple' => 'Ви дійсно хочете видалити виділені сторінки?', + 'delete_confirm_single' => 'Ви дійсно хочете видалити цю сторінку?', + 'no_layout' => '-- без шаблону --', + 'cms_page' => 'CMS сторінка', + 'title' => 'Заголовок сторінки', + 'url' => 'URL сторінки', + 'file_name' => 'Файл сторінки' + ], + 'layout' => [ + 'not_found_name' => "Не вдалося знайти шаблон (layout) з ім'ям :name.", + 'menu_label' => 'Шаблони', + 'unsaved_label' => 'Незбережений(і) макет(и)', + 'no_list_records' => 'Шаблони не знайдені', + 'new' => 'Новий шаблон', + 'delete_confirm_multiple' => 'Ви дійсно хочете видалити виділені шаблони?', + 'delete_confirm_single' => 'Ви дійсно хочете видалити цей шаблон?' + ], + 'partial' => [ + 'not_found_name' => "Не вдалося знайти шаблон (partial) з ім'ям :name.", + 'invalid_name' => 'Помилка в імені шаблону (partial) :name.', + 'menu_label' => 'Фрагменти', + 'unsaved_label' => 'Незбережений(і) фрагмент(и)', + 'no_list_records' => 'Фрагменти не знайдені', + 'delete_confirm_multiple' => 'Ви дійсно хочете видалити виділені фрагменти?', + 'delete_confirm_single' => 'Ви дійсно хочете видалити цей фрагмент?', + 'new' => 'Новий фрагмент' + ], + 'content' => [ + 'not_found_name' => "Не вдалося знайти файл вмісту (content file): ':name'.", + 'menu_label' => 'Вміст', + 'unsaved_label' => 'Незбережені файли', + 'no_list_records' => 'Файли з вмістом не знайдені', + 'delete_confirm_multiple' => 'Ви дійсно хочете видалити виділені файли?', + 'delete_confirm_single' => 'Ви дійсно хочете видалити цей файл?', + 'new' => 'Новий файл вмісту' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Помилка в імені обробника AJAX: :name.', + 'not_found' => "Обробник AJAX не найден: ':name'.", + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Створити', + 'search' => 'Пошук...' + ], + 'editor' => [ + 'settings' => 'Налаштування', + 'title' => 'Заголовок', + 'new_title' => 'Заголовок сторінки', + 'url' => 'Адреса', + 'filename' => 'Ім\'я файлу', + 'layout' => 'Шаблон', + 'description' => 'Опис', + 'preview' => 'Переглянути', + 'meta' => 'Метатеги', + 'meta_title' => 'Заголовок (meta title)', + 'meta_description' => 'Опис (meta description)', + 'markup' => 'Шаблон', + 'code' => 'Код', + 'content' => 'Зміст', + 'hidden' => 'Прихована сторінка', + 'hidden_comment' => 'Приховані сторінки доступні тільки для авторизованих в системі користувачів.', + 'enter_fullscreen' => 'Увійти в повноекранний режим', + 'exit_fullscreen' => 'Вийти з повноекранного режиму', + 'open_searchbox' => 'Відкрити вікно пошуку', + 'close_searchbox' => 'Закрити вікно пошуку', + 'open_replacebox' => 'Відкрито вікно замінити', + 'close_replacebox' => 'Закрити вікно замінити' + ], + 'asset' => [ + 'menu_label' => 'Ресурси', + 'unsaved_label' => 'Незбережений(і) файл(и)', + 'drop_down_add_title' => 'Додати...', + 'drop_down_operation_title' => 'Дія...', + 'upload_files' => 'Завантажити файли', + 'create_file' => 'Створити файл', + 'create_directory' => 'Створити директорію', + 'directory_popup_title' => 'Нова директорія', + 'directory_name' => 'Назва директорії', + 'rename' => 'Перейменувати', + 'delete' => 'Видалити', + 'move' => 'Перемістити', + 'select' => 'Обрати', + 'new' => 'Новий файл', + 'rename_popup_title' => 'Перейменувати', + 'rename_new_name' => 'Нове ім\'я', + 'invalid_path' => 'Шлях може містити тільки цифри, латинські літери, пробіли і наступні символи: ._- /', + 'error_deleting_file' => 'Помилка видалення файлу :name.', + 'error_deleting_dir_not_empty' => 'Неможливо видалити директорію :name. Директорія містить файли або піддиректорії.', + 'error_deleting_dir' => 'Помилка видалення директорії:name.', + 'invalid_name' => 'Назва може містити тільки цифри, латинські літери, пробіли і наступні символи: ._-', + 'original_not_found' => 'Оригінальний файл або директорія не знайдено', + 'already_exists' => 'Файл або директорія з таким ім\'ям вже існує', + 'error_renaming' => 'Неможливо перейменувати файл або директорію', + 'name_cant_be_empty' => 'Назва не може бути порожньою', + 'too_large' => 'Завантажений файл занадто великий. Максимальний допустимий розмір файлу складає :max_size', + 'type_not_allowed' => 'Дозволені файли лише наступних типів: :allowed_types', + 'file_not_valid' => 'Файл не може бути збережений', + 'error_uploading_file' => "Помилка завантаження файлу ':name': :error", + 'move_please_select' => 'будь ласка, оберіть директорію', + 'move_destination' => 'Папка призначення', + 'move_popup_title' => 'Перемістити файли', + 'move_button' => 'Перемістити', + 'selected_files_not_found' => 'Вибрані файли не знайдені', + 'select_destination_dir' => 'Будь ласка, оберіть директорію', + 'destination_not_found' => 'Кінцева директорія не знайдена', + 'error_moving_file' => 'Не вдалося перемістити файл :file', + 'error_moving_directory' => 'Не вдалося перемістити директорію :dir', + 'error_deleting_directory' => 'Не вдалося видалити директорію :dir', + 'no_list_records' => 'Файли не знайдені', + 'delete_confirm' => 'Видалити обрані файли або каталоги?', + 'path' => 'Шлях' + ], + 'component' => [ + 'menu_label' => 'Компоненти', + 'unnamed' => 'Без назви', + 'no_description' => 'Без опису', + 'alias' => 'Назва компонента', + 'alias_description' => 'Назва компонента визначає його ім\'я, під яким він доступний в коді сторінки або шаблону.', + 'validation_message' => 'Псевдонім обов\'язковий і може містити тільки латинські букви, цифри і знаки підкреслення. Псевдоніми повинні починатися з літери.', + 'invalid_request' => 'Шаблон не може бути збережений, так як містить пошкоджену інформацію про компоненти.', + 'no_records' => 'Компоненти не знайдені', + 'not_found' => "Компонент ':name' не знайдено.", + 'method_not_found' => "Компонент ':name' не містить метод ':method'.", + ], + 'template' => [ + 'invalid_type' => 'Невідомий тип шаблону.', + 'not_found' => 'Запитаний шаблон не найден.', + 'saved' => 'Шаблон був успішно збережений.', + 'no_list_records' => 'Записів не знайдено', + 'delete_confirm' => 'Видалити вибрані шаблони?', + 'order_by' => 'Сортувати за' + ], + 'permissions' => [ + 'name' => 'Керування CMS', + 'manage_content' => 'Керування контентом', + 'manage_assets' => 'Керування файлами', + 'manage_pages' => 'Керування сторінками', + 'manage_layouts' => 'Керування шаблонами', + 'manage_partials' => 'Керування фрагментами', + 'manage_themes' => 'Керування темами', + 'manage_theme_options' => 'Налаштувати поточну тему CMS', + ], + 'theme_log' => [ + 'hint' => 'Цей журнал відображає будь-які зміни, внесені до теми адміністраторами в задній частині області CMS.', + 'menu_label' => 'Журнал змін тем', + 'menu_description' => 'Переглянути зміни, внесені до активної теми.', + 'empty_link' => 'Очистити журнал', + 'empty_loading' => 'Очищення журналу...', + 'empty_success' => 'Журнал очищено', + 'return_link' => 'Повернутися до журналу', + 'id' => 'ID', + 'id_label' => 'ID запису журналу', + 'created_at' => 'Дата, час', + 'user' => 'Користувач', + 'type' => 'Тип', + 'type_create' => 'Створити', + 'type_update' => 'Оновити', + 'type_delete' => 'Видалити', + 'theme_name' => 'Тема', + 'theme_code' => 'Код теми', + 'old_template' => 'Шаблон (старий)', + 'new_template' => 'Шаблон (новий)', + 'template' => 'Шаблон', + 'diff' => 'Зміни', + 'old_value' => 'Старе значення', + 'new_value' => 'Нове значення', + 'preview_title' => 'Зміни в шаблоні', + 'template_updated' => 'Шаблон було оновлено', + 'template_created' => 'Шаблон був створений', + 'template_deleted' => 'Шаблон був видалений' + ] +]; diff --git a/modules/cms/lang/vn/lang.php b/modules/cms/lang/vn/lang.php new file mode 100644 index 0000000..b6745ba --- /dev/null +++ b/modules/cms/lang/vn/lang.php @@ -0,0 +1,293 @@ + [ + 'invalid_file' => 'Tên tệp không hợp lệ :name. Tên tệp có thể chứa chỉ các ký tự chữ và số, dấu gạch dưới, dấu gạch ngang và dấu chấm. Ví dụ: page.htm, page, subdirectory/page', + 'invalid_property' => "Khổng thể cài thuộc tính ':name'", + 'file_already_exists' => "Tệp tin ':name' đã tồn tại.", + 'error_saving' => "Lỗi lưu file ':name'. Vui lòng kiểm tra write permission.", + 'error_creating_directory' => 'Không thể tạo thư mục :name. Vui lòng kiểm tra write permission.', + 'invalid_file_extension' => 'Extension không hợp lệ: :invalid. Extensions hợp lệ: :allowed.', + 'error_deleting' => "Không thể xóa template file ':name'. Vui lòng kiểm tra write permission.", + 'delete_success' => 'Đã xóa template: :count.', + 'file_name_required' => 'Tên file là bắt buộc.', + 'safe_mode_enabled' => 'Safe mode đã được bật.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Giao diện web', + 'online' => 'Trực tuyến', + 'maintenance' => 'Đang bảo trì', + 'manage_themes' => 'Quản lý giao diện', + 'customize_theme' => 'Tùy chỉnh giao diện' + ] + ], + 'theme' => [ + 'not_found_name' => "Giao diện ':name' không tồn tại", + 'by_author' => 'Tạo bởi :name', + 'active' => [ + 'not_set' => 'Giao diện đang kích hoạt chưa được cài đặt.', + 'not_found' => 'Không tìm thấy giao diện đang kích hoạt.' + ], + 'edit' => [ + 'not_set' => 'Giao diện chưa được cài đặt.', + 'not_found' => 'Không tìm thấy giao diện.', + 'not_match' => "Giao diện này đang trong chế độ chỉnh sửa. Vui lòng tải lại trang" + ], + 'settings_menu' => 'Giao diện website', + 'settings_menu_description' => 'Cấu hình giao diện website và các tùy chỉnh', + 'default_tab' => 'Các thuộc tính', + 'name_label' => 'Tên', + 'name_create_placeholder' => 'Tên giao diện', + 'author_label' => 'Tác giả', + 'author_placeholder' => 'Tên cá nhân hoặc công ty', + 'description_label' => 'Mô tả', + 'description_placeholder' => 'Mô tả giao diện', + 'homepage_label' => 'Trang chủ', + 'homepage_placeholder' => 'Đường dẫn trang chủ tác giả', + 'code_label' => 'Code', + 'code_placeholder' => 'Tạo mã code duy nhất để phân phối giao diện của bạn', + 'preview_image_label' => 'Hình ảnh xem trước giao diện', + 'preview_image_placeholder' => 'Đường dẫn hình ảnh xem trước của giao diện.', + 'dir_name_label' => 'Tên đường dẫn', + 'dir_name_create_label' => 'Đường dẫn chứa giao diện', + 'theme_label' => 'Giao diện', + 'theme_title' => 'Themes', + 'activate_button' => 'Kích hoạt', + 'active_button' => 'Kích hoạt', + 'customize_theme' => 'Tùy chỉnh giao diện', + 'customize_button' => 'Tùy chỉnh', + 'duplicate_button' => 'Nhân đôi', + 'duplicate_title' => 'Nhân đôi giao diện', + 'duplicate_theme_success' => 'Nhân đôi giao diện thành công!', + 'manage_button' => 'Quản lý', + 'manage_title' => 'Quản lý giao diện', + 'edit_properties_title' => 'giao diện', + 'edit_properties_button' => 'Chỉnh sửa các thuộc tính', + 'save_properties' => 'Lưu lại thuộc tính', + 'import_button' => 'Import', + 'import_title' => 'Import giao diện', + 'import_theme_success' => 'Nhập thành công giao diện!', + 'import_uploaded_file' => 'Tệp tin giao diện', + 'import_overwrite_label' => 'Ghi đè file', + 'import_overwrite_comment' => 'Bỏ check để chỉ nhập tệp mới ( không ghi đè)', + 'import_folders_label' => 'Các thư mục', + 'import_folders_comment' => 'Vuui lòng chọn các thư mục bạn muốn import', + 'export_button' => 'Export', + 'export_title' => 'Xuất giao diện', + 'export_folders_label' => 'Các thư mục', + 'export_folders_comment' => 'Vui lòng chọn các mục bạn muốn export', + 'delete_button' => 'Xóa', + 'delete_confirm' => 'Xóa giao diện. Sau khi xóa không thể khôi phục lại', + 'delete_active_theme_failed' => 'Không thể xóa giao diện đang được kích hoạt. Vui lòng kích hoạt 1 giao diện khác và thử lại', + 'delete_theme_success' => 'Xóa thành công!', + 'create_title' => 'Tạo theme mới', + 'create_button' => 'Tạo mới', + 'create_new_blank_theme' => 'Tạo một giao diện trống', + 'create_theme_success' => 'Giao diện đã được tạo!', + 'create_theme_required_name' => 'Vui lòng điền tên gaio diện', + 'new_directory_name_label' => 'Đường dẫn của giao diện', + 'new_directory_name_comment' => 'Nhập vào đường dẫn cho giao diện mới.', + 'dir_name_invalid' => 'Tên chỉ có thể chứa chữ số, chữ cái Latinh và các ký hiệu sau: _-', + 'dir_name_taken' => 'Đường dẫn này đã tồn tại.', + 'find_more_themes' => 'Tìm kiếm giao diện', + 'saving' => 'Đang lưu giao diện...', + 'return' => 'Quay lại trang quản lý giao diện' + ], + 'maintenance' => [ + 'settings_menu' => 'Chế độ bảo trì', + 'settings_menu_description' => 'Bật chế độ bảo trì và chỉ định trang sẽ hiển thị ở chế độ bảo trì.', + 'is_enabled' => 'Bật chế độ bảo trì', + 'is_enabled_comment' => 'Chọn trang sẽ hiển thị ở chế độ bảo trì.', + 'hint' => 'Chế độ bảo trì sẽ hiển thị trang bảo trì đối với khách truy cập trang' + ], + 'page' => [ + 'not_found_name' => "Trang ':name' không tồn tại", + 'not_found' => [ + 'label' => 'Trang không tồn tại', + 'help' => 'Không tìm thấy trang bạn yêu cầu.' + ], + 'custom_error' => [ + 'label' => 'Lỗi trang', + 'help' => "Có lỗi xảy ra khiến trang này không thể hiển thị" + ], + 'menu_label' => 'Danh sách trang', + 'unsaved_label' => 'Trang chưa được lưu', + 'no_list_records' => 'Không tìm thấy trang', + 'new' => 'Trang mới', + 'invalid_url' => 'Định dạng URL không hợp lệ. URL phải bắt đầu bằng biểu tượng dấu gạch chéo và có thể chứa chữ số, chữ cái Latinh và ký hiệu sau đây: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Xóa các trang đang chọn?', + 'delete_confirm_single' => 'Xóa trang này?', + 'no_layout' => '-- Không chọn --', + 'cms_page' => 'CMS page', + 'title' => 'Tiêu đề trang', + 'url' => 'URL trang', + 'file_name' => 'Tên file của trang' + ], + 'layout' => [ + 'not_found_name' => "Mẫu giao diện ':name' không tìm thấy", + 'menu_label' => 'Các mẫu', + 'unsaved_label' => 'Mẫu giao diện chưa được lưu', + 'no_list_records' => 'Không tìm thấy mẫu giao diện nào', + 'new' => 'Mẫu giao diện mới', + 'delete_confirm_multiple' => 'Xóa các mẫu giao diện đã chọn?', + 'delete_confirm_single' => 'Xóa mẫu giao diện này?' + ], + 'partial' => [ + 'not_found_name' => "Không tìm thấy partial ':name'.", + 'invalid_name' => 'Partial không hợp lệ: :name.', + 'menu_label' => 'Partials', + 'unsaved_label' => 'Chưa lưu partial(s)', + 'no_list_records' => 'Không tìm thấy partial nào', + 'delete_confirm_multiple' => 'Xóa các Partital đã chọn?', + 'delete_confirm_single' => 'Xóa partial này?', + 'new' => 'Partital mới' + ], + 'content' => [ + 'not_found_name' => "Không tìm thấy tệp tin nội dung ':name'.", + 'menu_label' => 'Nội dung', + 'unsaved_label' => 'Chưa lưu nội dung', + 'no_list_records' => 'Không tìm thấy tệp tin nội dung nào', + 'delete_confirm_multiple' => 'Xóa các tệp tin nội dung hoặc đường dẫn đã chọn?', + 'delete_confirm_single' => 'Xóa tệp tin nội dung này?', + 'new' => 'Tẹo tệp mới' + ], + 'ajax_handler' => [ + 'invalid_name' => 'Tên AJAX handler không hợp lệ: :name.', + 'not_found' => "Không tìm thấy AJAX handler ':name'" + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Thêm mới', + 'search' => 'Tìm kiếm...' + ], + 'editor' => [ + 'settings' => 'Cài đặt', + 'title' => 'Tiêu đề', + 'new_title' => 'Tiêu đề trang', + 'url' => 'URL', + 'filename' => 'Tên file', + 'layout' => 'Giao diện mẫu', + 'description' => 'Mô tả', + 'preview' => 'Xem trước', + 'meta' => 'Meta', + 'meta_title' => 'Meta Title', + 'meta_description' => 'Meta Description', + 'markup' => 'Markup', + 'code' => 'Code', + 'content' => 'Nội dung', + 'hidden' => 'Ẩn', + 'hidden_comment' => 'Ẩn trang này, và chỉ hiển thị đối với những người đã đăng nhập trang quản trị', + 'enter_fullscreen' => 'Toàn màn hình', + 'exit_fullscreen' => 'Thoát toàn màn hình', + 'open_searchbox' => 'Mở hộp tìm kiếm', + 'close_searchbox' => 'Đóng hộp tìm kiếm', + 'open_replacebox' => 'Mở hộp Replace', + 'close_replacebox' => 'Đóng hộp Replace' + ], + 'asset' => [ + 'menu_label' => 'Assets', + 'unsaved_label' => 'Chưa lưu asset(s)', + 'drop_down_add_title' => 'Thêm mới...', + 'drop_down_operation_title' => 'Hành động...', + 'upload_files' => 'Upload file(s)', + 'create_file' => 'Tạo mới file', + 'create_directory' => 'Tạo mới thư mục', + 'directory_popup_title' => 'Thư mục mới', + 'directory_name' => 'Tên thư mục', + 'rename' => 'Đổi tên', + 'delete' => 'Xóa', + 'move' => 'Di chuyển ra chỗ khác', + 'select' => 'Lựa chọn', + 'new' => 'Tệp mới', + 'rename_popup_title' => 'Đổi tên', + 'rename_new_name' => 'Tên mới', + 'invalid_path' => 'Đường dẫn chỉ có thể chứa chữ số, chữ cái Latinh, dấu cách và các ký hiệu sau đây: ._-/', + 'error_deleting_file' => 'Lỗi xóa tệp tin :name.', + 'error_deleting_dir_not_empty' => 'Lỗi xóa thư mục :name. Thư mục phải trống mới xóa được.', + 'error_deleting_dir' => 'Lỗi xóa thư mục :name.', + 'invalid_name' => 'Tên chỉ có thể chứa chữ số, chữ cái Latinh, dấu cách và các ký hiệu sau đây: ._-', + 'original_not_found' => 'Tệp gốc hoặc đường dẫn không tồn tại', + 'already_exists' => 'Tên tệp tin hoặc đường dẫn đã tồn tại', + 'error_renaming' => 'Lỗi sửa tên tệp tin hoặc thư mục', + 'name_cant_be_empty' => 'Tên không được để trống', + 'too_large' => 'Kích thước tệp tin quá lớn. Kích thước tệp tin không được vượt quá :max_size', + 'type_not_allowed' => 'Chỉ chấp nhận các loại tệp tin sau: :allowed_types', + 'file_not_valid' => 'File không hợp lệ', + 'error_uploading_file' => "Lỗi upload tệp tin ':name': :error", + 'move_please_select' => 'Vui lòng chọn', + 'move_destination' => 'Thư mục cần chuyển đến', + 'move_popup_title' => 'Di chuyển assets', + 'move_button' => 'Di chuyển', + 'selected_files_not_found' => 'Không tìm thấy tệp tin đã chọn', + 'select_destination_dir' => 'Vui lòng chọn thư mục cần di chuyển đến', + 'destination_not_found' => 'Thư mục cần chuyển đến không tồn tại', + 'error_moving_file' => 'Lỗi di chuyển tệp tin :file', + 'error_moving_directory' => 'Lỗi di chuyển thư mục :dir', + 'error_deleting_directory' => 'Lỗi xóa thư mục gốc :dir', + 'no_list_records' => 'Không tìm thấy tệp tin nào', + 'delete_confirm' => 'Xóa các tệp tin hoặc thư mục đã chọn?', + 'path' => 'Path' + ], + 'component' => [ + 'menu_label' => 'Components', + 'unnamed' => 'Không có tên', + 'no_description' => 'Không có mô tả', + 'alias' => 'Alias', + 'alias_description' => 'Chọn 1 mã duy nhất để phân biệt các component khi được dùng ở front-end.', + 'validation_message' => 'Component aliases là bắt buộc và chỉ có thể chứa các ký hiệu Latin, chữ số và dấu gạch dưới. Các bí danh nên bắt đầu bằng một biểu tượng Latin.', + 'invalid_request' => 'Không thể lưu template vì chứa component không hợp lệ.', + 'no_records' => 'Không tìm thấy components nào', + 'not_found' => "Component ':name' không tồn tại.", + 'method_not_found' => "Component ':name' không có method ':method'." + ], + 'template' => [ + 'invalid_type' => 'Không xác định được định dạng template.', + 'not_found' => 'Không tìm thấy Template.', + 'saved' => 'Đã lưu template.', + 'no_list_records' => 'Không có kết quả', + 'delete_confirm' => 'Xóa các template đã chọn?', + 'order_by' => 'Order by' + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Quản lý các tệp content của website', + 'manage_assets' => 'Quản lý các thư mục và tệp assets - images, JavaScript files, CSS', + 'manage_pages' => 'Tạo mới, chỉnh sửa và xóa các trang của website', + 'manage_layouts' => 'Tạo mới, chỉnh sửa và xóa các CMS layout', + 'manage_partials' => 'Tạo mới, chỉnh sửa và xóa các CMS partial', + 'manage_themes' => 'Kích hoạt, bỏ kích hoạt và cấu hình CMS theme', + 'manage_theme_options' => 'Lựa chọn các cấu hình tùy chỉnh cho theme đang được kích hoạt', + ], + 'theme_log' => [ + 'hint' => 'Bản ghi những thay đổi của giao diện được thực hiện trong trang quản trị', + 'menu_label' => 'Nhật ký giao diện', + 'menu_description' => 'Xem những thay đổi của giao diện đang được kích hoạt.', + 'empty_link' => 'Xóa hết nhật ký về thay đổi giao diện', + 'empty_loading' => 'Đang xóa nhật ký giao diện...', + 'empty_success' => 'Đã xóa hết nhật ký', + 'return_link' => 'Quay lại trang nhật ký giao diện', + 'id' => 'ID', + 'id_label' => 'Log ID', + 'created_at' => 'Thời gian', + 'user' => 'Người dùng', + 'type' => 'Loại', + 'type_create' => 'Ngày tạo', + 'type_update' => 'Ngày cập nhật', + 'type_delete' => 'Ngày xóa', + 'theme_name' => 'Giao diện', + 'theme_code' => 'Mã giao diện', + 'old_template' => 'Giao diện mẫu (Cũ)', + 'new_template' => 'Giao diện mẫu (Mới)', + 'template' => 'Giao diện mẫu', + 'diff' => 'Thay đổi', + 'old_value' => 'Giá trị cũ', + 'new_value' => 'Giá trị mới', + 'preview_title' => 'Thay đổi giao diện mẫu', + 'template_updated' => 'Giao diện mẫu đã được cập nhật', + 'template_created' => 'Giao diện mẫu đã được tạo', + 'template_deleted' => 'Giao diện mẫu đã xóa', + ], +]; diff --git a/modules/cms/lang/zh-cn/lang.php b/modules/cms/lang/zh-cn/lang.php new file mode 100644 index 0000000..074fbe3 --- /dev/null +++ b/modules/cms/lang/zh-cn/lang.php @@ -0,0 +1,301 @@ + [ + 'invalid_file' => '非法文件名: :name。文件名中只能包括字母或数字, _, - 和 .. 正确的文件名: page.htm, page, subdirectory/page', + 'invalid_property' => "无法设置属性 ':name' ", + 'file_already_exists' => "文件 ':name' 已存在.", + 'error_saving' => "保存文件 ':name' 错误。请检查写权限。", + 'error_creating_directory' => '创建文件夹 :name 错误。请检查写权限。', + 'invalid_file_extension'=>'非法文件扩展名: :invalid. 允许的扩展名: :allowed.', + 'error_deleting' => "删除模板文件 ':name' 错误. 请检查写权限.", + 'delete_success' => '成功删除模板: :count.', + 'file_name_required' => '需要文件名字段.', + 'safe_mode_enabled' => '已启用安全模式.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Website', + 'online' => '在线', + 'maintenance' => '维护', + 'manage_themes' => '管理主题', + 'customize_theme' => '自定义主题', + ] + ], + 'theme' => [ + 'not_found_name' => "未找到主题 ':name'", + 'by_author' => '作者 :name', + 'active' => [ + 'not_set' => '未设置活动主题', + 'not_found' => '无法找到活动主题' + ], + 'edit' => [ + 'not_set' => '未设置编辑主题.', + 'not_found' => '无法找到编辑主题', + 'not_match' => "您所尝试访问的对象不属于正在编辑的主题。请重载页面。" + ], + 'settings_menu' => '前端主题', + 'settings_menu_description' => '选择一个活动主题以预览。', + 'default_tab' => '属性', + 'name_label' => '名称', + 'name_create_placeholder' => '新主题名', + 'author_label' => '作者', + 'author_placeholder' => '成员或制作组名', + 'description_label' => '描述', + 'description_placeholder' => '主题描述', + 'homepage_label' => '主页', + 'homepage_placeholder' => '网站地址', + 'code_label' => '代码', + 'code_placeholder' => '主题发行唯一码', + 'preview_image_label' => '预览图', + 'preview_image_placeholder' => '预览图路径.', + 'dir_name_label' => '目录名', + 'dir_name_create_label' => '目标主题目录', + 'theme_label' => '主题', + 'theme_title' => '主题', + 'activate_button' => '激活', + 'active_button' => '激活', + 'customize_theme' => '自定义主题', + 'customize_button' => '自定义', + 'duplicate_button' => '复制', + 'duplicate_title' => '复制主题', + 'duplicate_theme_success' => '复制主题成功!', + 'manage_button' => '管理', + 'manage_title' => '管理主题', + 'edit_properties_title' => '主题', + 'edit_properties_button' => '编辑属性', + 'save_properties' => '保存属性', + 'import_button' => '导入', + 'import_title' => '导入主题', + 'import_theme_success' => '成功导入主题!', + 'import_uploaded_file' => '主题存档文件', + 'import_overwrite_label' => '覆盖已存在的文件', + 'import_overwrite_comment' => '取消勾选以仅导入新文件', + 'import_folders_label' => '文件夹', + 'import_folders_comment' => '请选择你想要导入的主题文件夹', + 'export_button' => '导出', + 'export_title' => '导出主题', + 'export_folders_label' => '文件夹', + 'export_folders_comment' => '请选择你想要导入的主题文件夹', + 'delete_button' => '删除', + 'delete_confirm' => '您确定删除这个主题吗? 此操作不能被撤销!', + 'delete_active_theme_failed' => '无法删除此活动主题, 请先尝试其他主题.', + 'delete_theme_success' => '删除主题成功!', + 'create_title' => '创建主题', + 'create_button' => '创建', + 'create_new_blank_theme' => '创建空白主题', + 'create_theme_success' => '创建主题成功!', + 'create_theme_required_name' => '请指点主题名.', + 'new_directory_name_label' => '主题目录', + 'new_directory_name_comment' => '提供复制主题的新闻目录名.', + 'dir_name_invalid' => '名称只能包含数字, 拉丁字母和以下字符: _-', + 'dir_name_taken' => '主题目录已存在.', + 'find_more_themes' => '在 OctoberCMS 主题商店中查找更多主题', + 'saving' => '保存主题中...', + 'return' => '返回主题列表', + ], + 'maintenance' => [ + 'settings_menu' => '维护模式', + 'settings_menu_description' => '配置维护模式页面和开关设置.', + 'is_enabled' => '启用维护模式', + 'is_enabled_comment' => '当启用时, 网站访问者会看到下述页面.', + 'hint' => '维护模式将对未登陆后台的访客展示维护页面.', + ], + 'page' => [ + 'not_found_name' => "无法找到页面 ':name'", + 'not_found' => [ + 'label' => '无法找到页面', + 'help' => '无法找到所请求的页面' + ], + 'custom_error' => [ + 'label' => '页面错误', + 'help' => "很抱歉,发生了错误导致页面不能显示." + ], + 'menu_label' => '页面', + 'unsaved_label' => '未保存页面', + 'no_list_records' => '找不到页面', + 'new' => '新页面', + 'invalid_url' => '不合法的URL格式. URL可以以正斜杠开头, 包含数字, 拉丁字母和下面的字符: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => '真的想要删除选择的页面吗?', + 'delete_confirm_single' => '真的想要删除这个页面吗?', + 'no_layout' => '-- 无布局 --', + 'cms_page' => 'CMS 页面', + 'title' => '页面标题', + 'url' => '页面URL', + 'file_name' => '页面文件名' + ], + 'layout' => [ + 'not_found_name' => "布局 ':name' 找不到", + 'menu_label' => '布局', + 'unsaved_label' => '未保存布局', + 'no_list_records' => '找不到布局', + 'new' => '新布局', + 'delete_confirm_multiple' => '您真的想要删除选中的布局?', + 'delete_confirm_single' => '您真的想要删除这个布局?' + ], + 'partial' => [ + 'not_found_name' => "部件 ':name' 找不到.", + 'invalid_name' => '非法的部件名: :name.', + 'menu_label' => '部件', + 'unsaved_label' => '未保存的部件', + 'no_list_records' => '无法找到部件', + 'delete_confirm_multiple' => '您真的想要删除选择的部件?', + 'delete_confirm_single' => '您真的想要删除这个部件?', + 'new' => '新部件' + ], + 'content' => [ + 'not_found_name' => "无法找到内容文件 ':name'", + 'menu_label' => '内容', + 'unsaved_label' => '未保存内容', + 'no_list_records' => '无法找到内容文件', + 'delete_confirm_multiple' => '您真的想要删除选中的文件或目录吗?', + 'delete_confirm_single' => '您真的想要删除这个内容文件?', + 'new' => '新内容文件' + ], + 'ajax_handler' => [ + 'invalid_name' => '非法 AJAX 处理器: :name.', + 'not_found' => "无法找到 AJAX 处理器 ':name' " + ], + 'cms' => [ + 'menu_label' => '内容管理系统' + ], + 'sidebar' => [ + 'add' => '增加', + 'search' => '搜索...' + ], + 'editor' => [ + 'settings' => '设置', + 'title' => '标题', + 'new_title' => '新文件标题', + 'url' => 'URL', + 'filename' => '文件名', + 'layout' => '布局', + 'description' => '描述', + 'preview' => '预览', + 'meta' => '元素', + 'meta_title' => '元素标题', + 'meta_description' => '元素描述', + 'markup' => '标记', + 'code' => '代码', + 'content' => '内容', + 'hidden' => '隐藏', + 'hidden_comment' => '隐藏页面只能被已登录的后台用户访问.', + 'enter_fullscreen' => '进入全屏模式', + 'exit_fullscreen' => '退出全屏模式', + 'open_searchbox' => '打开搜索框', + 'close_searchbox' => '关闭搜索框', + 'open_replacebox' => '打开替换框', + 'close_replacebox' => '关闭替换框', + 'commit' => '提交', + 'reset' => '重置', + 'commit_confirm' => '您是否确认保存对文件的修改?这将会对原有的文件内容进行覆盖', + 'reset_confirm' => '您是否确认重置对文件的修改?这将会完全恢复文件到原来的内容', + 'committing' => '提交中...', + 'resetting' => '重置中...', + 'commit_success' => ' :type 保存成功', + 'reset_success' => ' :type 重置成功', + ], + 'asset' => [ + 'menu_label' => '资源', + 'unsaved_label' => '未保存的资源', + 'drop_down_add_title' => '增加...', + 'drop_down_operation_title' => '动作...', + 'upload_files' => '上传文件', + 'create_file' => '新建文件', + 'create_directory' => '新建目录', + 'directory_popup_title' => '新目录', + 'directory_name' => '目录名', + 'rename' => '重命名', + 'delete' => '删除', + 'move' => '移动', + 'select' => '选择', + 'new' => '新文件', + 'rename_popup_title' => '重命名', + 'rename_new_name' => '新名称', + 'invalid_path' => '路径名称只能包含数字, 拉丁字母和以下字符: _-/', + 'error_deleting_file' => '删除文件 :name 错误.', + 'error_deleting_dir_not_empty' => '删除目录 :name 错误. 目录不为空.', + 'error_deleting_dir' => '删除文件 :name 错误.', + 'invalid_name' => '名称只能包含数字, 拉丁字母, 空格和以下字符: _-', + 'original_not_found' => '原始文件或目录找不到', + 'already_exists' => '文件或目录已存在', + 'error_renaming' => '重命名文件或目录错误', + 'name_cant_be_empty' => '名称不能为空', + 'too_large' => '上传的文件太大. 最大文件大小是 :max_size', + 'type_not_allowed' => '只有下面的文件类型是允许的: :allowed_types', + 'file_not_valid' => '文件不合法', + 'error_uploading_file' => "上传文件错误 ':name': :error", + 'move_please_select' => '请选择', + 'move_destination' => '目标目录', + 'move_popup_title' => '移动资源', + 'move_button' => '移动', + 'selected_files_not_found' => '无法找到已选择的文件', + 'select_destination_dir' => '请选择目标目录', + 'destination_not_found' => '无法找到目标目录', + 'error_moving_file' => '移动文件 :file 错误', + 'error_moving_directory' => '移动目录 :dir 错误', + 'error_deleting_directory' => '删除原始目录 :dir 错误', + 'no_list_records' => '资源文件为空', + 'delete_confirm' => '确定删除选中的文件或文件夹?', + 'path' => '路径' + ], + 'component' => [ + 'menu_label' => '组件', + 'unnamed' => '未命名', + 'no_description' => '没有描述', + 'alias' => '别名', + 'alias_description' => '在页面或者布局代码中组件的唯一名称', + 'validation_message' => '需要组件别名, 且只能包含拉丁字符, 数字和下划线. 别名必须以拉丁字符开头.', + 'invalid_request' => '组件数据非法,无法保存', + 'no_records' => '无法找到找不到', + 'not_found' => "无法找到组件 ':name'", + 'method_not_found' => "组件 ':name' 中无方法 ':method'." + ], + 'template' => [ + 'invalid_type' => '未知模板类型.', + 'not_found' => '无法找到所请求的模板', + 'saved'=> '模板保存成功.', + 'no_list_records' => '模板文件为空', + 'delete_confirm' => '确认删除选中的模板?', + 'order_by' => '排序方式' + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => '管理内容', + 'manage_assets' => '管理资源', + 'manage_pages' => '管理页面', + 'manage_layouts' => '管理布局', + 'manage_partials' => '管理部件', + 'manage_themes' => '管理主题', + 'manage_theme_options' => '管理主题的自定义选项', + ], + 'theme_log' => [ + 'hint' => '显示管理员在后台对主题的所有操作日志', + 'menu_label' => '主题操作日志', + 'menu_description' => '查看对激活主题的操作日志.', + 'empty_link' => '清空操作日志', + 'empty_loading' => '清空主题操作日志中...', + 'empty_success' => '主题操作日志清空成功', + 'return_link' => '返回主题操作日志', + 'id' => '序号', + 'id_label' => '日志 序号', + 'created_at' => '日志生成时间', + 'user' => '用户名', + 'type' => '操作类型', + 'type_create' => '创建', + 'type_update' => '更新', + 'type_delete' => '删除', + 'theme_name' => '主题名', + 'theme_code' => '主题code', + 'old_template' => '文件名 (Old)', + 'new_template' => '文件名 (New)', + 'template' => '文件名', + 'diff' => '文件修改对比', + 'old_value' => '文件修改前', + 'new_value' => '文件修改后', + 'preview_title' => '文件修改详情', + 'template_updated' => '文件已更新', + 'template_created' => '文件已创建', + 'template_deleted' => '文件已删除', + ], +]; diff --git a/modules/cms/lang/zh-tw/lang.php b/modules/cms/lang/zh-tw/lang.php new file mode 100644 index 0000000..3c69e44 --- /dev/null +++ b/modules/cms/lang/zh-tw/lang.php @@ -0,0 +1,245 @@ + [ + 'invalid_file' => '不合法的檔案名: :name. 檔案名只能包括字母或數字, _, - 和 .. 一些正確的檔案名: page.htm, page, subdirectory/page', + 'invalid_property' => "屬性 ':name' 不能設定", + 'file_already_exists' => "檔案 ':name' 已經存在.", + 'error_saving' => "保存檔案 ':name' 錯誤. 請檢查寫權限.", + 'error_creating_directory' => '建立檔案夾 :name 錯誤. 請檢查寫權限.', + 'invalid_file_extension'=>'不合法的檔案擴展: :invalid. 允許的擴展: :allowed.', + 'error_deleting' => "刪除模板檔案 ':name' 錯誤. 請檢查寫權限.", + 'delete_success' => '模板成功刪除: :count.', + 'file_name_required' => '需要檔案名字串.' + ], + 'dashboard' => [ + 'active_theme' => [ + 'online' => '在線', + 'maintenance' => '維護中', + ] + ], + 'theme' => [ + 'not_found_name' => "主題 ':name' 沒找到.", + 'active' => [ + 'not_set' => '活動主題沒設定.', + 'not_found' => '活動主題找不到.' + ], + 'edit' => [ + 'not_set' => '編輯主題沒設定.', + 'not_found' => '編輯主題沒找到.', + 'not_match' => "您嘗試訪問的對象不屬於正在編輯的主題. 請重載頁面." + ], + 'settings_menu' => '前端主題', + 'settings_menu_description' => '預覽安裝的主題, 選擇一個活動主題.', + 'default_tab' => '屬性', + 'name_label' => '名稱', + 'name_create_placeholder' => '新主題名稱', + 'author_label' => '作者', + 'author_placeholder' => '人或公司名', + 'description_label' => '描述', + 'description_placeholder' => '主題描述', + 'homepage_label' => '主頁', + 'homepage_placeholder' => '網站地址', + 'code_label' => '代碼', + 'code_placeholder' => '發行主題的唯一碼', + 'dir_name_label' => '目錄名', + 'dir_name_create_label' => '目標主題目錄', + 'theme_label' => '主題', + 'theme_title' => '主題', + 'activate_button' => '啟用', + 'active_button' => '啟用', + 'customize_theme' => '自訂主題', + 'customize_button' => '自訂', + 'duplicate_button' => '複製', + 'duplicate_title' => '複製主題', + 'duplicate_theme_success' => '複製主題成功!', + 'manage_button' => '管理', + 'manage_title' => '管理主題', + 'edit_properties_title' => '主題', + 'edit_properties_button' => '編輯屬性', + 'save_properties' => '保存屬性', + 'import_button' => '導入', + 'import_title' => '導入主題', + 'import_theme_success' => '成功導入主題!', + 'import_uploaded_file' => '主題存檔檔案', + 'import_overwrite_label' => '覆蓋已經存在的檔案', + 'import_overwrite_comment' => '取消勾選, 只導入新檔案', + 'import_folders_label' => '檔案夾', + 'import_folders_comment' => '請選擇您想要導入的主題檔案夾', + 'export_button' => '導出', + 'export_title' => '導出主題', + 'export_folders_label' => '檔案夾', + 'export_folders_comment' => '請選擇您想要導入的主題檔案夾', + 'delete_button' => '刪除', + 'delete_confirm' => '您確定刪除這個主題嗎? 這個操作不能撤銷!', + 'delete_active_theme_failed' => '不能刪除活動主題, 請先嘗試另外一個主題.', + 'delete_theme_success' => '刪除主題成功!', + 'create_title' => '建立主題', + 'create_button' => '建立', + 'create_new_blank_theme' => '建立新的空白主題', + 'create_theme_success' => '建立主題成功!', + 'create_theme_required_name' => '請指點主題名.', + 'new_directory_name_label' => '主題目錄', + 'new_directory_name_comment' => '提供複製主題的新聞目錄名.', + 'dir_name_invalid' => '名稱只能包含數字, 拉丁字母和以下字元: _-', + 'dir_name_taken' => '主題目錄已存在.', + 'find_more_themes' => '在 OctoberCMS 主題商店中搜尋更多主題', + 'saving' => '保存主題...', + 'return' => '返回主題列表', + ], + 'maintenance' => [ + 'settings_menu' => '維護模式', + 'settings_menu_description' => '設定維護模式頁面和開關設定.', + 'is_enabled' => '啟用維護模式', + 'is_enabled_comment' => '當啟用時, 網站訪問者會看到下述頁面.' + ], + 'page' => [ + 'not_found_name' => "頁面 ':name' 找不到", + 'not_found' => [ + 'label' => '頁面找不到', + 'help' => '請求的頁面找不到.' + ], + 'custom_error' => [ + 'label' => '頁面錯誤', + 'help' => "很抱歉, 有一些地方發生了錯誤導致頁面不能顯示." + ], + 'menu_label' => '頁面', + 'unsaved_label' => '未保存頁面', + 'no_list_records' => '找不到頁面', + 'new' => '新頁面', + 'invalid_url' => '不合法的URL格式. URL可以正斜槓開頭, 包含數字, 拉丁字母和下面的字元: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => '真的想要刪除選擇的頁面嗎?', + 'delete_confirm_single' => '真的想要刪除這個頁面嗎?', + 'no_layout' => '-- 沒有佈局 --', + 'title' => '頁面標題', + 'url' => '頁面網址', + 'file_name' => '頁面檔案名稱', + ], + 'layout' => [ + 'not_found_name' => "佈局 ':name' 找不到", + 'menu_label' => '佈局', + 'unsaved_label' => '未保存佈局', + 'no_list_records' => '找不到佈局', + 'new' => '新佈局', + 'delete_confirm_multiple' => '您真的想要刪除選取的佈局?', + 'delete_confirm_single' => '您真的想要刪除這個佈局?' + ], + 'partial' => [ + 'not_found_name' => "部件 ':name' 找不到.", + 'invalid_name' => '不合法的部件名: :name.', + 'menu_label' => '部件', + 'unsaved_label' => '未保存的部件', + 'no_list_records' => '找不到部件', + 'delete_confirm_multiple' => '您真的想要刪除選擇的部件?', + 'delete_confirm_single' => '您真的想要刪除這個部件?', + 'new' => '新部件' + ], + 'content' => [ + 'not_found_name' => "內容檔案 ':name' 找不到.", + 'menu_label' => '內容', + 'unsaved_label' => '未保存內容', + 'no_list_records' => '找不到內容檔案', + 'delete_confirm_multiple' => '您真的想要刪除選取的檔案或目錄嗎?', + 'delete_confirm_single' => '您真的想要刪除這個內容檔案?', + 'new' => '新內容檔案' + ], + 'ajax_handler' => [ + 'invalid_name' => '不合法的 AJAX 處理器: :name.', + 'not_found' => " AJAX 處理器 ':name' 找不到." + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => '增加', + 'search' => '搜尋...' + ], + 'editor' => [ + 'settings' => '設定', + 'title' => '標題', + 'new_title' => '新檔案標題', + 'url' => 'URL', + 'filename' => '檔案名', + 'layout' => '佈局', + 'description' => '描述', + 'preview' => '預覽', + 'meta' => 'Meta', + 'meta_title' => 'Meta 標題', + 'meta_description' => 'Meta 描述', + 'markup' => 'Markup', + 'code' => '代碼', + 'content' => '內容', + 'hidden' => '隱藏', + 'hidden_comment' => '隱藏頁面只能被登錄的後台使用者訪問.', + 'enter_fullscreen' => '進入全螢幕模式', + 'exit_fullscreen' => '退出全螢幕模式', + ], + 'asset' => [ + 'menu_label' => '資源', + 'unsaved_label' => '未保存的資源', + 'drop_down_add_title' => '增加...', + 'drop_down_operation_title' => '動作...', + 'upload_files' => '上傳檔案', + 'create_file' => '新建檔案', + 'create_directory' => '新建目錄', + 'directory_popup_title' => '新目錄', + 'directory_name' => '目錄名', + 'rename' => '重新命名', + 'delete' => '刪除', + 'move' => '移動', + 'select' => '選擇', + 'new' => '新檔案', + 'rename_popup_title' => '重新命名', + 'rename_new_name' => '新名稱', + 'invalid_path' => '路徑名稱只能包含數字, 拉丁字母和以下字元: _-/', + 'error_deleting_file' => '刪除檔案 :name 錯誤.', + 'error_deleting_dir_not_empty' => '刪除目錄 :name 錯誤. 目錄不為空.', + 'error_deleting_dir' => '刪除檔案 :name 錯誤.', + 'invalid_name' => '名稱只能包含數字, 拉丁字母, 空格和以下字元: _-', + 'original_not_found' => '原始檔案或目錄找不到', + 'already_exists' => '檔案或目錄已存在', + 'error_renaming' => '重新命名檔案或目錄錯誤', + 'name_cant_be_empty' => '名稱不能為空', + 'too_large' => '上傳的檔案太大. 最大檔案大小是 :max_size', + 'type_not_allowed' => '只有下面的檔案類型是允許的: :allowed_types', + 'file_not_valid' => '檔案不合法', + 'error_uploading_file' => "上傳檔案錯誤 ':name': :error", + 'move_please_select' => '請選擇', + 'move_destination' => '目標目錄', + 'move_popup_title' => '移動資源', + 'move_button' => '移動', + 'selected_files_not_found' => '選擇的檔案找不到', + 'select_destination_dir' => '請選擇目標目錄', + 'destination_not_found' => '目標目錄找不到', + 'error_moving_file' => '移動檔案 :file 錯誤', + 'error_moving_directory' => '移動目錄 :dir 錯誤', + 'error_deleting_directory' => '刪除原始目錄 :dir 錯誤', + 'path' => '路徑' + ], + 'component' => [ + 'menu_label' => '組件', + 'unnamed' => '未命名的', + 'no_description' => '沒有描述', + 'alias' => '別名', + 'alias_description' => '這個組件的唯一名稱, 在頁面或者佈局代碼中.', + 'validation_message' => '需要組件別名, 且只能包含拉丁字元, 數字和下劃線. 別名必須以拉丁字元開頭.', + 'invalid_request' => '模板不能保存, 因為非法組件數據.', + 'no_records' => '找不到組件', + 'not_found' => "組件 ':name' 找不到.", + 'method_not_found' => "組件 ':name' 不包含方法 ':method'." + ], + 'template' => [ + 'invalid_type' => '未知模板類型.', + 'not_found' => '請求模板找不到.', + 'saved'=> '模板保存成功.' + ], + 'permissions' => [ + 'name' => 'Cms', + 'manage_content' => '管理內容', + 'manage_assets' => '管理資源', + 'manage_pages' => '管理頁面', + 'manage_layouts' => '管理佈局', + 'manage_partials' => '管理部件', + 'manage_themes' => '管理主題' + ], +]; diff --git a/modules/cms/models/MaintenanceSetting.php b/modules/cms/models/MaintenanceSetting.php new file mode 100644 index 0000000..4530b5f --- /dev/null +++ b/modules/cms/models/MaintenanceSetting.php @@ -0,0 +1,92 @@ +is_enabled = false; + } + + public function getCmsPageOptions() + { + if (!$theme = Theme::getEditTheme()) { + throw new ApplicationException('Unable to find the active theme.'); + } + + return Page::listInTheme($theme)->lists('fileName', 'fileName'); + } + + /** + * Ensure each theme has its own CMS page, store it inside a mapping array. + * @return void + */ + public function beforeValidate() + { + if (!$theme = Theme::getEditTheme()) { + throw new ApplicationException('Unable to find the active theme.'); + } + + $themeMap = $this->getSettingsValue('theme_map', []); + $themeMap[$theme->getDirName()] = $this->getSettingsValue('cms_page'); + $this->setSettingsValue('theme_map', $themeMap); + } + + /** + * Restore the CMS page found in the mapping array, or disable the + * maintenance mode. + * @return void + */ + public function afterFetch() + { + if ( + ($theme = Theme::getEditTheme()) + && ($themeMap = array_get($this->attributes, 'theme_map')) + && ($cmsPage = array_get($themeMap, $theme->getDirName())) + ) { + $this->cms_page = $cmsPage; + } + else { + $this->is_enabled = false; + } + } +} diff --git a/modules/cms/models/ThemeData.php b/modules/cms/models/ThemeData.php new file mode 100644 index 0000000..49b7e4c --- /dev/null +++ b/modules/cms/models/ThemeData.php @@ -0,0 +1,262 @@ +getAttributes(), $staticAttributes); + + $this->data = $dynamicAttributes; + $this->setRawAttributes(array_only($this->getAttributes(), $staticAttributes)); + } + + /** + * Clear asset cache after saving to ensure `assetVar` form fields take + * immediate effect. + */ + public function afterSave() + { + try { + CombineAssets::resetCache(); + } + catch (Exception $ex) { + } + } + + /** + * Returns a cached version of this model, based on a Theme object. + * @param $theme Cms\Classes\Theme + * @return self + */ + public static function forTheme($theme) + { + $dirName = $theme->getDirName(); + if ($themeData = array_get(self::$instances, $dirName)) { + return $themeData; + } + + try { + $themeData = self::firstOrCreate(['theme' => $dirName]); + } + catch (Exception $ex) { + // Database failed + $themeData = new self(['theme' => $dirName]); + } + + return self::$instances[$dirName] = $themeData; + } + + /** + * After fetching the model, intiialize model relationships based + * on form field definitions. + * @return void + */ + public function afterFetch() + { + $data = (array) $this->data + $this->getDefaultValues(); + + /* + * Repeater form fields store arrays and must be jsonable. + */ + foreach ($this->getFormFields() as $id => $field) { + if (!isset($field['type'])) { + continue; + } + + if ($field['type'] === 'repeater') { + $this->jsonable[] = $id; + } + elseif ($field['type'] === 'fileupload') { + $this->attachOne[$id] = File::class; + unset($data[$id]); + } + } + + /* + * Fill this model with the jsonable attributes kept in 'data'. + */ + $this->setRawAttributes((array) $this->getAttributes() + $data, true); + } + + /** + * Before model is validated, set the default values. + * @return void + */ + public function beforeValidate() + { + if (!$this->exists) { + $this->setDefaultValues(); + } + } + + /** + * Creates relationships for this model based on form field definitions. + */ + public function initFormFields() + { + } + + /** + * Sets default values on this model based on form field definitions. + */ + public function setDefaultValues() + { + foreach ($this->getDefaultValues() as $attribute => $value) { + $this->{$attribute} = $value; + } + } + + /** + * Gets default values for this model based on form field definitions. + * @return array + */ + public function getDefaultValues() + { + $result = []; + + foreach ($this->getFormFields() as $attribute => $field) { + if (($value = array_get($field, 'default')) === null) { + continue; + } + + $result[$attribute] = $value; + } + + return $result; + } + + /** + * Returns all fields defined for this model, based on form field definitions. + * @return array + */ + public function getFormFields() + { + if (!$theme = CmsTheme::load($this->theme)) { + throw new Exception(Lang::get('Unable to find theme with name :name', $this->theme)); + } + + $config = $theme->getFormConfig(); + + return array_get($config, 'fields', []) + + array_get($config, 'tabs.fields', []) + + array_get($config, 'secondaryTabs.fields', []); + } + + /** + * Returns variables that should be passed to the asset combiner. + * @return array + */ + public function getAssetVariables() + { + $result = []; + + foreach ($this->getFormFields() as $attribute => $field) { + if (!$varName = array_get($field, 'assetVar')) { + continue; + } + + $result[$varName] = $this->{$attribute}; + } + + return $result; + } + + /** + * Applies asset variables to the combiner filters that support it. + * @return void + */ + public static function applyAssetVariablesToCombinerFilters($filters) + { + $theme = CmsTheme::getActiveTheme(); + + if (!$theme) { + return; + } + + if (!$theme->hasCustomData()) { + return; + } + + $assetVars = $theme->getCustomData()->getAssetVariables(); + + foreach ($filters as $filter) { + if (method_exists($filter, 'setPresets')) { + $filter->setPresets($assetVars); + } + } + } + + /** + * Generate a cache key for the combiner, this allows variables to bust the cache. + * @return string + */ + public static function getCombinerCacheKey() + { + $theme = CmsTheme::getActiveTheme(); + if (!$theme->hasCustomData()) { + return ''; + } + + $customData = $theme->getCustomData(); + + return (string) $customData->updated_at ?: ''; + } +} diff --git a/modules/cms/models/ThemeExport.php b/modules/cms/models/ThemeExport.php new file mode 100644 index 0000000..72b9475 --- /dev/null +++ b/modules/cms/models/ThemeExport.php @@ -0,0 +1,155 @@ + null, + 'themeName' => null, + 'dirName' => null, + 'folders' => [ + 'assets' => true, + 'pages' => true, + 'layouts' => true, + 'partials' => true, + 'content' => true, + ] + ]; + + /** + * Import / Export model classes are helpers and are not to write to the database + * + * @return void + */ + public function save(array $options = null, $sessionKey = null) + { + throw new ApplicationException(sprintf("The % model is not intended to be saved, please use %s instead", get_class($this), 'ThemeData')); + } + + public function getFoldersOptions() + { + return [ + 'assets' => 'Assets', + 'pages' => 'Pages', + 'layouts' => 'Layouts', + 'partials' => 'Partials', + 'content' => 'Content', + ]; + } + + public function setThemeAttribute($theme) + { + if (!$theme instanceof CmsTheme) { + return; + } + + $this->attributes['themeName'] = $theme->getConfigValue('name', $theme->getDirName()); + $this->attributes['dirName'] = $theme->getDirName(); + $this->attributes['theme'] = $theme; + } + + public function export($theme, $data = []) + { + $this->theme = $theme; + $this->fill($data); + + try { + $themePath = $this->theme->getPath(); + $tempPath = temp_path() . '/'.uniqid('oc'); + $zipName = uniqid('oc'); + $zipPath = temp_path().'/'.$zipName; + + if (!File::makeDirectory($tempPath)) { + throw new ApplicationException('Unable to create directory '.$tempPath); + } + + if (!File::makeDirectory($metaPath = $tempPath . '/meta')) { + throw new ApplicationException('Unable to create directory '.$metaPath); + } + + File::copy($themePath.'/theme.yaml', $tempPath.'/theme.yaml'); + File::copyDirectory($themePath.'/meta', $metaPath); + + foreach ($this->folders as $folder) { + if (!array_key_exists($folder, $this->getFoldersOptions())) { + continue; + } + + File::copyDirectory($themePath.'/'.$folder, $tempPath.'/'.$folder); + } + + Zip::make($zipPath, $tempPath); + File::deleteDirectory($tempPath); + } + catch (Exception $ex) { + if (strlen($tempPath) && File::isDirectory($tempPath)) { + File::deleteDirectory($tempPath); + } + + if (strlen($zipPath) && File::isFile($zipPath)) { + File::delete($zipPath); + } + + throw $ex; + } + + return $zipName; + } + + public static function download($name, $outputName = null) + { + if (!preg_match('/^oc[0-9a-z]*$/i', $name)) { + throw new ApplicationException('File not found'); + } + + $zipPath = temp_path() . '/' . $name; + if (!file_exists($zipPath)) { + throw new ApplicationException('File not found'); + } + + $headers = Response::download($zipPath, $outputName)->headers->all(); + $result = Response::make(File::get($zipPath), 200, $headers); + + @File::delete($zipPath); + + return $result; + } +} diff --git a/modules/cms/models/ThemeImport.php b/modules/cms/models/ThemeImport.php new file mode 100644 index 0000000..12bb509 --- /dev/null +++ b/modules/cms/models/ThemeImport.php @@ -0,0 +1,200 @@ + \System\Models\File::class + ]; + + /** + * @var array Make the model's attributes public so behaviors can modify them. + */ + public $attributes = [ + 'theme' => null, + 'themeName' => null, + 'dirName' => null, + 'overwrite' => true, + 'folders' => [ + 'assets' => true, + 'pages' => true, + 'layouts' => true, + 'partials' => true, + 'content' => true, + ] + ]; + + /** + * Import / Export model classes are helpers and are not to write to the database + * + * @return void + */ + public function save(array $options = null, $sessionKey = null) + { + throw new ApplicationException(sprintf("The % model is not intended to be saved, please use %s instead", get_class($this), 'ThemeData')); + } + + public function getFoldersOptions() + { + return [ + 'assets' => 'Assets', + 'pages' => 'Pages', + 'layouts' => 'Layouts', + 'partials' => 'Partials', + 'content' => 'Content', + ]; + } + + public function setThemeAttribute($theme) + { + if (!$theme instanceof CmsTheme) { + return; + } + + $this->attributes['themeName'] = $theme->getConfigValue('name', $theme->getDirName()); + $this->attributes['dirName'] = $theme->getDirName(); + $this->attributes['theme'] = $theme; + } + + public function import($theme, $data = [], $sessionKey = null) + { + @set_time_limit(3600); + + $this->theme = $theme; + $this->fill($data); + + try { + $file = $this->uploaded_file()->withDeferred($sessionKey)->first(); + if (!$file) { + throw new ApplicationException('There is no file attached to import!'); + } + + $themePath = $this->theme->getPath(); + $tempPath = temp_path() . '/'.uniqid('oc'); + $zipName = uniqid('oc'); + $zipPath = temp_path().'/'.$zipName; + + File::put($zipPath, $file->getContents()); + + if (!File::makeDirectory($tempPath)) { + throw new ApplicationException('Unable to create directory '.$tempPath); + } + + Zip::extract($zipPath, $tempPath); + + if (File::isDirectory($tempPath.'/meta')) { + $this->copyDirectory($tempPath.'/meta', $themePath.'/meta'); + } + + foreach ($this->folders as $folder) { + if (!array_key_exists($folder, $this->getFoldersOptions())) { + continue; + } + + $this->copyDirectory($tempPath.'/'.$folder, $themePath.'/'.$folder); + } + + File::deleteDirectory($tempPath); + File::delete($zipPath); + $file->delete(); + } + catch (Exception $ex) { + if (!empty($tempPath) && File::isDirectory($tempPath)) { + File::deleteDirectory($tempPath); + } + + if (!empty($zipPath) && File::isFile($zipPath)) { + File::delete($zipPath); + } + + throw $ex; + } + } + + /** + * Helper for copying directories that supports the ability + * to not overwrite existing files. Inherited from File::copyDirectory + * + * @param string $directory + * @param string $destination + * @return bool + */ + protected function copyDirectory($directory, $destination) + { + // Preference is to overwrite existing files + if ($this->overwrite) { + return File::copyDirectory($directory, $destination); + } + + if (!File::isDirectory($directory)) { + return false; + } + + $options = FilesystemIterator::SKIP_DOTS; + + if (!File::isDirectory($destination)) { + File::makeDirectory($destination, 0777, true); + } + + $items = new FilesystemIterator($directory, $options); + + foreach ($items as $item) { + $target = $destination.'/'.$item->getBasename(); + + if ($item->isDir()) { + $path = $item->getPathname(); + + if (!$this->copyDirectory($path, $target)) { + return false; + } + } + else { + // Do not overwrite existing files + if (File::isFile($target)) { + continue; + } + + if (!File::copy($item->getPathname(), $target)) { + return false; + } + } + } + + return true; + } +} diff --git a/modules/cms/models/ThemeLog.php b/modules/cms/models/ThemeLog.php new file mode 100644 index 0000000..6105e31 --- /dev/null +++ b/modules/cms/models/ThemeLog.php @@ -0,0 +1,134 @@ + \Backend\Models\User::class + ]; + + protected $themeCache; + + /** + * Adds observers to the model for logging purposes. + */ + public static function bindEventsToModel(HalcyonModel $template) + { + $template->bindEvent('model.beforeDelete', function () use ($template) { + self::add($template, self::TYPE_DELETE); + }); + + $template->bindEvent('model.beforeSave', function () use ($template) { + self::add($template, $template->exists ? self::TYPE_UPDATE : self::TYPE_CREATE); + }); + } + + /** + * Creates a log record + * @return self + */ + public static function add(HalcyonModel $template, $type = null) + { + if (!App::hasDatabase()) { + return; + } + + if (!LogSetting::get('log_theme')) { + return; + } + + if (!$type) { + $type = self::TYPE_UPDATE; + } + + $isDelete = $type === self::TYPE_DELETE; + $dirName = $template->getObjectTypeDirName(); + $templateName = $template->fileName; + $oldTemplateName = $template->getOriginal('fileName'); + $newContent = $template->toCompiled(); + $oldContent = $template->getOriginal('content'); + + if ($newContent === $oldContent && $templateName === $oldTemplateName && !$isDelete) { + traceLog($newContent, $oldContent); + traceLog('Content not dirty for: '. $template->getObjectTypeDirName().'/'.$template->fileName); + return; + } + + $record = new self; + $record->type = $type; + $record->theme = Theme::getEditThemeCode(); + $record->template = $isDelete ? '' : $dirName.'/'.$templateName; + $record->old_template = $oldTemplateName ? $dirName.'/'.$oldTemplateName : ''; + $record->content = $isDelete ? '' : $newContent; + $record->old_content = $oldContent; + + if ($user = BackendAuth::getUser()) { + $record->user_id = $user->id; + } + + try { + $record->save(); + } + catch (Exception $ex) { + } + + return $record; + } + + public function getThemeNameAttribute() + { + $code = $this->theme; + + if (!isset($this->themeCache[$code])) { + $this->themeCache[$code] = Theme::load($code); + } + + $theme = $this->themeCache[$code]; + + return $theme->getConfigValue('name', $theme->getDirName()); + } + + public function getTypeOptions() + { + return [ + self::TYPE_CREATE => 'cms::lang.theme_log.type_create', + self::TYPE_UPDATE => 'cms::lang.theme_log.type_update', + self::TYPE_DELETE => 'cms::lang.theme_log.type_delete' + ]; + } + + public function getAnyTemplateAttribute() + { + return $this->template ?: $this->old_template; + } + + public function getTypeNameAttribute() + { + return array_get($this->getTypeOptions(), $this->type); + } +} diff --git a/modules/cms/models/maintenancesetting/_hint.htm b/modules/cms/models/maintenancesetting/_hint.htm new file mode 100644 index 0000000..816d79e --- /dev/null +++ b/modules/cms/models/maintenancesetting/_hint.htm @@ -0,0 +1,4 @@ + +

    + +

    diff --git a/modules/cms/models/maintenancesetting/fields.yaml b/modules/cms/models/maintenancesetting/fields.yaml new file mode 100644 index 0000000..6c5e3de --- /dev/null +++ b/modules/cms/models/maintenancesetting/fields.yaml @@ -0,0 +1,18 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + + hint: + type: hint + path: ~/modules/cms/models/maintenancesetting/_hint.htm + + is_enabled: + label: cms::lang.maintenance.is_enabled + comment: cms::lang.maintenance.is_enabled_comment + type: checkbox + + cms_page: + type: dropdown + cssClass: checkbox-align \ No newline at end of file diff --git a/modules/cms/models/themeexport/fields.yaml b/modules/cms/models/themeexport/fields.yaml new file mode 100644 index 0000000..5a9db2c --- /dev/null +++ b/modules/cms/models/themeexport/fields.yaml @@ -0,0 +1,14 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + + themeName: + label: cms::lang.theme.theme_label + disabled: true + + folders: + label: cms::lang.theme.export_folders_label + commentAbove: cms::lang.theme.export_folders_comment + type: checkboxlist diff --git a/modules/cms/models/themeimport/fields.yaml b/modules/cms/models/themeimport/fields.yaml new file mode 100644 index 0000000..bc996eb --- /dev/null +++ b/modules/cms/models/themeimport/fields.yaml @@ -0,0 +1,25 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + + themeName: + label: cms::lang.theme.theme_label + disabled: true + + uploaded_file: + label: cms::lang.theme.import_uploaded_file + type: fileupload + mode: file + fileTypes: zip + + overwrite: + label: cms::lang.theme.import_overwrite_label + comment: cms::lang.theme.import_overwrite_comment + type: checkbox + + folders: + label: cms::lang.theme.import_folders_label + commentAbove: cms::lang.theme.import_folders_comment + type: checkboxlist diff --git a/modules/cms/models/themelog/columns.yaml b/modules/cms/models/themelog/columns.yaml new file mode 100644 index 0000000..26a4e24 --- /dev/null +++ b/modules/cms/models/themelog/columns.yaml @@ -0,0 +1,49 @@ +# =================================== +# Column Definitions +# =================================== + +columns: + id: + label: cms::lang.theme_log.id + searchable: yes + invisible: true + width: 75px + + created_at: + label: cms::lang.theme_log.created_at + searchable: yes + width: 160px + type: timetense + + type: + label: cms::lang.theme_log.type + invisible: true + + any_template: + label: cms::lang.theme_log.template + searchable: false + sortable: false + + template: + label: cms::lang.theme_log.new_template + searchable: true + invisible: true + + old_template: + label: cms::lang.theme_log.old_template + searchable: true + invisible: true + + user: + label: cms::lang.theme_log.user + relation: user + select: concat(first_name, ' ', last_name) + + theme_name: + label: cms::lang.theme_log.theme_name + sortable: false + + theme: + label: cms::lang.theme_log.theme_code + searchable: true + invisible: true diff --git a/modules/cms/models/themelog/fields.yaml b/modules/cms/models/themelog/fields.yaml new file mode 100644 index 0000000..54c840b --- /dev/null +++ b/modules/cms/models/themelog/fields.yaml @@ -0,0 +1,36 @@ +# =================================== +# Field Definitions +# =================================== + +tabs: + fields: + + diff_template: + tab: cms::lang.theme_log.diff + type: partial + path: field_diff_template + + diff_content: + tab: cms::lang.theme_log.diff + type: partial + path: field_diff_content + + template: + tab: cms::lang.theme_log.new_value + type: partial + path: field_template + + content: + tab: cms::lang.theme_log.new_value + type: partial + path: field_content + + old_template: + tab: cms::lang.theme_log.old_value + type: partial + path: field_template + + old_content: + tab: cms::lang.theme_log.old_value + type: partial + path: field_content diff --git a/modules/cms/reportwidgets/ActiveTheme.php b/modules/cms/reportwidgets/ActiveTheme.php new file mode 100644 index 0000000..70668d7 --- /dev/null +++ b/modules/cms/reportwidgets/ActiveTheme.php @@ -0,0 +1,71 @@ +loadData(); + } + catch (Exception $ex) { + $this->vars['error'] = $ex->getMessage(); + } + + return $this->makePartial('widget'); + } + + public function defineProperties() + { + return [ + 'title' => [ + 'title' => 'backend::lang.dashboard.widget_title_label', + 'default' => 'cms::lang.dashboard.active_theme.widget_title_default', + 'type' => 'string', + 'validationPattern' => '^.+$', + 'validationMessage' => 'backend::lang.dashboard.widget_title_error', + ] + ]; + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addCss('css/activetheme.css', 'core'); + } + + protected function loadData() + { + if (!$theme = Theme::getActiveTheme()) { + throw new ApplicationException(Lang::get('cms::lang.theme.not_found_name', ['name'=>Theme::getActiveThemeCode()])); + } + + $this->vars['theme'] = $theme; + $this->vars['inMaintenance'] = MaintenanceSetting::get('is_enabled'); + $this->vars['canManage'] = BackendAuth::getUser()->hasAccess('cms.manage_themes'); + $this->vars['canConfig'] = BackendAuth::getUser()->hasAccess('cms.manage_theme_options'); + } +} diff --git a/modules/cms/reportwidgets/activetheme/assets/css/activetheme.css b/modules/cms/reportwidgets/activetheme/assets/css/activetheme.css new file mode 100644 index 0000000..6449e4f --- /dev/null +++ b/modules/cms/reportwidgets/activetheme/assets/css/activetheme.css @@ -0,0 +1,4 @@ +.widget-activetheme .theme-thumbnail { + margin-top: -15px; + margin-bottom: 15px; +} diff --git a/modules/cms/reportwidgets/activetheme/partials/_widget.htm b/modules/cms/reportwidgets/activetheme/partials/_widget.htm new file mode 100644 index 0000000..599522a --- /dev/null +++ b/modules/cms/reportwidgets/activetheme/partials/_widget.htm @@ -0,0 +1,48 @@ +
    +

    property('title'))) ?>

    + + +
    + +
    + + +
    +
    +
    + +
    diff --git a/modules/cms/routes.php b/modules/cms/routes.php new file mode 100644 index 0000000..1aaf5ec --- /dev/null +++ b/modules/cms/routes.php @@ -0,0 +1,39 @@ +where('slug', '(.*)?')->middleware('web'); + + /** + * @event cms.route + * Fires after cms routes get added + * + * Example usage: + * + * Event::listen('cms.route', function () { + * // your code here + * }); + * + */ + Event::fire('cms.route'); +}); diff --git a/modules/cms/traits/UrlMaker.php b/modules/cms/traits/UrlMaker.php new file mode 100644 index 0000000..ebe0c05 --- /dev/null +++ b/modules/cms/traits/UrlMaker.php @@ -0,0 +1,210 @@ +url` magically + * linking to the component that declares `isPrimary = 1` in configuration. + * + * [blogPost] + * isPrimary = "1" + * + * The parameters passed to the component are supplied when overriding the + * method `getUrlParams` also within the model. + * + * public function getUrlParams() + * { + * return [ + * 'id' => $this->id, + * 'hash' => $this->hash, + * ]; + * } + * + * @package october\cms + * @author Alexey Bobkov, Samuel Georges + */ +trait UrlMaker +{ + // + // Properties to declare + // + + /** + * @var string The component to use for generating URLs. + */ + // protected $urlComponentName = 'testArchive'; + + /** + * @var string The property name to determine a primary component. + */ + // protected $urlComponentProperty = 'isPrimary'; + + /** + * Returns an array of values to use in URL generation. + * @return @array + */ + // public function getUrlParams() + // { + // return [ + // 'id' => $this->id, + // 'slug' => $this->slug + // ]; + // } + + // + // Internal properties + // + + /** + * @var string URL cache + */ + protected $url; + + /** + * @var string Page where detected component is found. + */ + protected static $urlPageName; + + /** + * Changes the component used for generating the URLs dynamically. + * + * @param string $name + * @param string $property + * @return void + */ + public function resetUrlComponent($name, $property = null) + { + $this->urlComponentName = $name; + + if ($property) { + $this->urlComponentProperty = $property; + } + + static::$urlPageName = $this->url = null; + } + + /** + * Mutator for the "url" attribute. Returns the URL detected by the component. + * @return string + */ + public function getUrlAttribute() + { + if ($this->url === null) { + $this->url = $this->makeUrl(); + } + + return $this->url; + } + + /** + * Explicitly set the URL for this model. + * @param string $value + * @return void + */ + public function setUrlAttribute($value) + { + $this->url = $value; + } + + /** + * Explicitly set the CMS Page to link to. + * @param string $pageName + * @return void + */ + public function setUrlPageName($pageName) + { + static::$urlPageName = $pageName; + } + + /** + * Locates the page name where the detected component is found. This method + * uses the Cache service to improve performance. + * @return string + */ + public function getUrlPageName() + { + if (static::$urlPageName !== null) { + return static::$urlPageName; + } + + /* + * Cache + */ + $key = 'urlMaker'.$this->urlComponentName.crc32(get_class($this)); + + $cached = Cache::get($key, false); + if ($cached !== false && ($cached = @unserialize($cached)) !== false) { + $filePath = array_get($cached, 'path'); + $mtime = array_get($cached, 'mtime'); + if (!File::isFile($filePath) || ($mtime != File::lastModified($filePath))) { + $cached = false; + } + } + + if ($cached !== false) { + return static::$urlPageName = array_get($cached, 'fileName'); + } + + /* + * Fallback + */ + $page = null; + $useProperty = property_exists($this, 'urlComponentProperty'); + + if ($useProperty) { + $page = Page::whereComponent($this->urlComponentName, $this->urlComponentProperty, '1')->first(); + } + + if (!$useProperty || !$page) { + $page = Page::withComponent($this->urlComponentName)->first(); + } + + if (!$page) { + throw new ApplicationException(sprintf( + 'Unable to a find a primary component "%s" for generating a URL in %s.', + $this->urlComponentName, + get_class($this) + )); + } + + $baseFileName = $page->getBaseFileName(); + $filePath = $page->getFilePath(); + + $cached = [ + 'path' => $filePath, + 'fileName' => $baseFileName, + 'mtime' => @File::lastModified($filePath) + ]; + + $expiresAt = now()->addMinutes(Config::get('cms.parsedPageCacheTTL', 1440)); + Cache::put($key, serialize($cached), $expiresAt); + + return static::$urlPageName = $baseFileName; + } + + /** + * Generates a real URL based on the page, detected by the primary component. + * The CMS Controller is used for this process passing the declared params. + * @return string + */ + protected function makeUrl() + { + $controller = Controller::getController() ?: new Controller; + + return $controller->pageUrl($this->getUrlPageName(), $this->getUrlParams()); + } +} diff --git a/modules/cms/twig/ComponentNode.php b/modules/cms/twig/ComponentNode.php new file mode 100644 index 0000000..c375d15 --- /dev/null +++ b/modules/cms/twig/ComponentNode.php @@ -0,0 +1,45 @@ + $nodes], ['names' => $paramNames], $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param TwigCompiler $compiler A TwigCompiler instance + */ + public function compile(TwigCompiler $compiler) + { + $compiler->addDebugInfo($this); + + $compiler->write("\$context['__cms_component_params'] = [];\n"); + + for ($i = 1; $i < count($this->getNode('nodes')); $i++) { + $compiler->write("\$context['__cms_component_params']['".$this->getAttribute('names')[$i-1]."'] = "); + $compiler->subcompile($this->getNode('nodes')->getNode($i)); + $compiler->write(";\n"); + } + + $compiler + ->write("echo \$this->env->getExtension('Cms\Twig\Extension')->componentFunction(") + ->subcompile($this->getNode('nodes')->getNode(0)) + ->write(", \$context['__cms_component_params']") + ->write(");\n") + ; + + $compiler->write("unset(\$context['__cms_component_params']);\n"); + } +} diff --git a/modules/cms/twig/ComponentTokenParser.php b/modules/cms/twig/ComponentTokenParser.php new file mode 100644 index 0000000..568721f --- /dev/null +++ b/modules/cms/twig/ComponentTokenParser.php @@ -0,0 +1,70 @@ +getLine(); + $stream = $this->parser->getStream(); + + $name = $this->parser->getExpressionParser()->parseExpression(); + $paramNames = []; + $nodes = [$name]; + + $end = false; + while (!$end) { + $current = $stream->next(); + + switch ($current->getType()) { + case TwigToken::NAME_TYPE: + $paramNames[] = $current->getValue(); + $stream->expect(TwigToken::OPERATOR_TYPE, '='); + $nodes[] = $this->parser->getExpressionParser()->parseExpression(); + break; + + case TwigToken::BLOCK_END_TYPE: + $end = true; + break; + + default: + throw new TwigErrorSyntax( + sprintf('Invalid syntax in the component tag. Line %s', $lineno), + $stream->getCurrent()->getLine(), + $stream->getSourceContext() + ); + break; + } + } + + return new ComponentNode(new TwigNode($nodes), $paramNames, $token->getLine(), $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'component'; + } +} diff --git a/modules/cms/twig/ContentNode.php b/modules/cms/twig/ContentNode.php new file mode 100644 index 0000000..02d8ab1 --- /dev/null +++ b/modules/cms/twig/ContentNode.php @@ -0,0 +1,47 @@ + $nodes], ['names' => $paramNames], $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param TwigCompiler $compiler A TwigCompiler instance + */ + public function compile(TwigCompiler $compiler) + { + $compiler->addDebugInfo($this); + + $compiler->write("\$context['__cms_content_params'] = [];\n"); + + for ($i = 1; $i < count($this->getNode('nodes')); $i++) { + $compiler->write("\$context['__cms_content_params']['".$this->getAttribute('names')[$i-1]."'] = "); + $compiler->write('twig_escape_filter($this->env, '); + $compiler->subcompile($this->getNode('nodes')->getNode($i)); + $compiler->write(")"); + $compiler->write(";\n"); + } + + $compiler + ->write("echo \$this->env->getExtension('Cms\Twig\Extension')->contentFunction(") + ->subcompile($this->getNode('nodes')->getNode(0)) + ->write(", \$context['__cms_content_params']") + ->write(");\n") + ; + + $compiler->write("unset(\$context['__cms_content_params']);\n"); + } +} diff --git a/modules/cms/twig/ContentTokenParser.php b/modules/cms/twig/ContentTokenParser.php new file mode 100644 index 0000000..3bedc57 --- /dev/null +++ b/modules/cms/twig/ContentTokenParser.php @@ -0,0 +1,74 @@ +getLine(); + $stream = $this->parser->getStream(); + + $name = $this->parser->getExpressionParser()->parseExpression(); + $paramNames = []; + $nodes = [$name]; + + $end = false; + while (!$end) { + $current = $stream->next(); + + switch ($current->getType()) { + case TwigToken::NAME_TYPE: + $paramNames[] = $current->getValue(); + $stream->expect(TwigToken::OPERATOR_TYPE, '='); + $nodes[] = $this->parser->getExpressionParser()->parseExpression(); + break; + + case TwigToken::BLOCK_END_TYPE: + $end = true; + break; + + default: + throw new TwigErrorSyntax( + sprintf('Invalid syntax in the content tag. Line %s', $lineno), + $stream->getCurrent()->getLine(), + $stream->getSourceContext() + ); + break; + } + } + + return new ContentNode(new TwigNode($nodes), $paramNames, $token->getLine(), $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'content'; + } +} diff --git a/modules/cms/twig/DebugExtension.php b/modules/cms/twig/DebugExtension.php new file mode 100644 index 0000000..f974bb8 --- /dev/null +++ b/modules/cms/twig/DebugExtension.php @@ -0,0 +1,612 @@ +controller = $controller; + } + + /** + * Returns a list of global functions to add to the existing list. + * @return array An array of global functions + */ + public function getFunctions() + { + return [ + new TwigSimpleFunction('dump', [$this, 'runDump'], [ + 'is_safe' => ['html'], + 'needs_context' => true, + 'needs_environment' => true + ]), + ]; + } + + /** + * Processes the dump variables, if none is supplied, all the twig + * template variables are used + * @param TwigEnvironment $env + * @param array $context + * @return string + */ + public function runDump(TwigEnvironment $env, $context) + { + if (!$env->isDebug()) { + return; + } + + $result = ''; + + $count = func_num_args(); + if ($count == 2) { + $this->variablePrefix = true; + $vars = []; + foreach ($context as $key => $value) { + if (!$value instanceof TwigTemplate) { + $vars[$key] = $value; + } + } + + $result .= $this->dump($vars, static::PAGE_CAPTION); + } + else { + $this->variablePrefix = false; + for ($i = 2; $i < $count; $i++) { + $var = func_get_arg($i); + + if ($var instanceof ComponentBase) { + $caption = [static::COMPONENT_CAPTION, get_class($var)]; + } + elseif (is_array($var)) { + $caption = static::ARRAY_CAPTION; + } + elseif (is_object($var)) { + $caption = [static::OBJECT_CAPTION, get_class($var)]; + } + else { + $caption = [static::OBJECT_CAPTION, gettype($var)]; + } + + $result .= $this->dump($var, $caption); + } + } + return $result; + } + + /** + * Dump information about a variable + * @param mixed $variables Variable to dump + * @param mixed $caption Caption [and subcaption] of the dump + * @return void + */ + public function dump($variables = null, $caption = null) + { + $this->commentMap = []; + $this->zebra = 1; + $info = []; + + if (!is_array($variables)) { + if ($variables instanceof Paginator) { + $variables = $this->paginatorToArray($variables); + } + elseif (is_object($variables)) { + $variables = $this->objectToArray($variables); + } + else { + $variables = [$variables]; + } + } + + $output = []; + $output[] = ''; + + if ($caption) { + $output[] = $this->makeTableHeader($caption); + } + + $output[] = ''; + foreach ($variables as $key => $item) { + $output[] = $this->makeTableRow($key, $item); + } + $output[] = ''; + $output[] = '
    '; + + $html = implode(PHP_EOL, $output); + + return '
    ' . $html . '
    '; + } + + /** + * Builds the HTML used for the table header. + * @param mixed $caption Caption [and subcaption] of the dump + * @return string + */ + protected function makeTableHeader($caption) + { + if (is_array($caption)) { + list($caption, $subcaption) = $caption; + } + + $output = []; + $output[] = ''; + $output[] = ''; + $output[] = ''; + $output[] = $caption; + + if (isset($subcaption)) { + $output[] = '
    '.$subcaption.'
    '; + } + + $output[] = ''; + $output[] = ''; + $output[] = ''; + return implode(PHP_EOL, $output); + } + + /** + * Builds the HTML used for each table row. + * @param mixed $key + * @param mixed $variable + * @return string + */ + protected function makeTableRow($key, $variable) + { + $this->zebra = $this->zebra ? 0 : 1; + $css = $this->getDataCss($variable); + $output = []; + $output[] = ''; + $output[] = ''.$this->evalKeyLabel($key).''; + $output[] = ''.$this->evalVarLabel($variable).''; + $output[] = ''.$this->evalVarDesc($variable, $key).''; + $output[] = ''; + $output[] = ''; + $output[] = ''.$this->evalVarDump($variable).''; + $output[] = ''; + return implode(PHP_EOL, $output); + } + + /** + * Builds JavaScript for toggling the dump container + * @return string + */ + protected function evalToggleDumpOnClick() + { + $output = "var d=this.parentElement.nextElementSibling.getElementsByTagName('div')[0];"; + $output .= "d.style.display=='none'?d.style.display='block':d.style.display='none'"; + return $output; + } + + /** + * Dumps a variable using HTML Dumper, wrapped in a hidden DIV element. + * @param mixed $variable + * @return string + */ + protected function evalVarDump($variable) + { + $dumper = new HtmlDumper; + $cloner = new VarCloner; + + $output = '
    '; + $output .= $dumper->dump($cloner->cloneVar($variable), true); + $output .= '
    '; + + return $output; + } + + /** + * Returns a variable name as HTML friendly. + * @param string $key + * @return string + */ + protected function evalKeyLabel($key) + { + if ($this->variablePrefix === true) { + $output = '{{ %s }}'; + } + elseif (is_array($this->variablePrefix)) { + $prefix = implode('.', $this->variablePrefix); + $output = '{{ '.$prefix.'.%s }}'; + } + elseif ($this->variablePrefix) { + $output = '{{ '.$this->variablePrefix.'.%s }}'; + } + else { + $output = '%s'; + } + + return sprintf($output, $key); + } + + /** + * Evaluate the variable description + * @param mixed $variable + * @return string + */ + protected function evalVarLabel($variable) + { + $type = $this->getType($variable); + switch ($type) { + case 'object': + return $this->evalObjLabel($variable); + + case 'array': + return $type . '('.count($variable).')'; + + default: + return $type; + } + } + + /** + * Evaluate an object type for label + * @param object $variable + * @return string + */ + protected function getType($variable) + { + $type = gettype($variable); + if ($type == 'string' && substr($variable, 0, 12) == '___METHOD___') { + return 'method'; + } + + return $type; + } + + /** + * Evaluate an object type for label + * @param object $variable + * @return string + */ + protected function evalObjLabel($variable) + { + $class = get_class($variable); + $label = class_basename($variable); + + if ($variable instanceof ComponentBase) { + $label = 'Component'; + } + elseif ($variable instanceof Collection) { + $label = 'Collection('.$variable->count().')'; + } + elseif ($variable instanceof Paginator) { + $label = 'Paged Collection('.$variable->count().')'; + } + elseif ($variable instanceof Model) { + $label = 'Model'; + } + + return ''.$label.''; + } + + /** + * Evaluate the variable description + * @param mixed $variable + * @return string + */ + protected function evalVarDesc($variable, $key) + { + $type = $this->getType($variable); + + if ($type == 'method') { + return $this->evalMethodDesc($variable); + } + + if (isset($this->commentMap[$key])) { + return $this->commentMap[$key]; + } + + if ($type == 'array') { + return $this->evalArrDesc($variable); + } + + if ($type == 'object') { + return $this->evalObjDesc($variable); + } + + return ''; + } + + /** + * Evaluate an method type for description + * @param object $variable + * @return string + */ + protected function evalMethodDesc($variable) + { + $parts = explode('|', $variable); + if (count($parts) < 2) { + return null; + } + + $method = $parts[1]; + return $this->commentMap[$method] ?? null; + } + + /** + * Evaluate an array type for description + * @param array $variable + * @return string + */ + protected function evalArrDesc($variable) + { + $output = []; + foreach ($variable as $key => $value) { + $output[] = ''.$key.''; + } + + return implode(', ', $output); + } + + /** + * Evaluate an object type for description + * @param array $variable + * @return string + */ + protected function evalObjDesc($variable) + { + $output = []; + if ($variable instanceof ComponentBase) { + $details = $variable->componentDetails(); + $output[] = ''; + $output[] = array_get($details, 'name'); + $output[] = ''; + } + + return implode('', $output); + } + + // + // Object helpers + // + + /** + * Returns default comment information for a paginator object. + * @param Illuminate\Pagination\Paginator $paginator + * @return array + */ + protected function paginatorToArray(Paginator $paginator) + { + $this->commentMap = [ + 'links()' => 'Renders links for navigating the collection', + 'currentPage' => 'Get the current page for the request.', + 'lastPage' => 'Get the last page that should be available.', + 'perPage' => 'Get the number of items to be displayed per page.', + 'total' => 'Get the total number of items in the complete collection.', + 'from' => 'Get the number of the first item on the paginator.', + 'to' => 'Get the number of the last item on the paginator.', + 'count' => 'Returns the number of items in this collection', + ]; + + return [ + 'links' => '___METHOD___|links()', + 'currentPage' => '___METHOD___|currentPage', + 'lastPage' => '___METHOD___|lastPage', + 'perPage' => '___METHOD___|perPage', + 'total' => '___METHOD___|total', + 'from' => '___METHOD___|from', + 'to' => '___METHOD___|to', + 'count' => '___METHOD___|count', + ]; + } + + /** + * Returns a map of an object as an array, containing methods and properties. + * @param mixed $object + * @return array + */ + protected function objectToArray($object) + { + $class = get_class($object); + $info = new \ReflectionClass($object); + + $this->commentMap[$class] = []; + + $methods = []; + foreach ($info->getMethods() as $method) { + if (!$method->isPublic()) { + continue; // Only public + } + if ($method->class != $class) { + continue; // Only locals + } + $name = $method->getName(); + if (in_array($name, $this->blockMethods)) { + continue; // Blocked methods + } + if (preg_match('/^on[A-Z]{1}[\w+]*$/', $name)) { + continue; // AJAX methods + } + if (preg_match('/^get[A-Z]{1}[\w+]*Options$/', $name)) { + continue; // getSomethingOptions + } + if (substr($name, 0, 1) == '_') { + continue; // Magic/hidden method + } + $name .= '()'; + $methods[$name] = '___METHOD___|'.$name; + $this->commentMap[$name] = $this->evalDocBlock($method); + } + + $vars = []; + foreach ($info->getProperties() as $property) { + if ($property->isStatic()) { + continue; // Only non-static + } + if (!$property->isPublic()) { + continue; // Only public + } + if ($property->class != $class) { + continue; // Only locals + } + $name = $property->getName(); + $vars[$name] = $object->{$name}; + $this->commentMap[$name] = $this->evalDocBlock($property); + } + + return $methods + $vars; + } + + /** + * Extracts the comment from a DocBlock + * @param ReflectionClass $reflectionObj + * @return string + */ + protected function evalDocBlock($reflectionObj) + { + $comment = $reflectionObj->getDocComment(); + $comment = substr($comment, 3, -2); + + $parts = explode('@', $comment); + $comment = array_shift($parts); + $comment = trim(trim($comment), '*'); + $comment = implode(' ', array_map('trim', explode('*', $comment))); + + return $comment; + } + + // + // Style helpers + // + + /** + * Get the CSS string for the output data + * @param mixed $variable + * @return string + */ + protected function getDataCss($variable) + { + $css = [ + 'padding' => '7px', + 'background-color' => $this->zebra ? '#D8D9DB' : '#FFF', + 'color' => '#405261', + ]; + + $type = gettype($variable); + if ($type == 'NULL') { + $css['color'] = '#999'; + } + + return $this->arrayToCss($css); + } + + /** + * Get the CSS string for the output container + * @return string + */ + protected function getContainerCss() + { + return $this->arrayToCss([ + 'background-color' => '#F3F3F3', + 'border' => '1px solid #bbb', + 'border-radius' => '4px', + 'font-size' => '12px', + 'line-height' => '18px', + 'margin' => '20px', + 'padding' => '7px', + 'display' => 'inline-block', + ]); + } + + /** + * Get the CSS string for the output header + * @return string + */ + protected function getHeaderCss() + { + return $this->arrayToCss([ + 'font-size' => '18px', + 'font-weight' => 'normal', + 'margin' => '0', + 'padding' => '10px', + 'background-color' => '#7B8892', + 'color' => '#FFF', + ]); + } + + /** + * Get the CSS string for the output subheader + * @return string + */ + protected function getSubheaderCss() + { + return $this->arrayToCss([ + 'font-size' => '12px', + 'font-weight' => 'normal', + 'font-style' => 'italic', + 'margin' => '0', + 'padding' => '0', + 'background-color' => '#7B8892', + 'color' => '#FFF', + ]); + } + + /** + * Convert a key/value pair array into a CSS string + * @param array $rules List of rules to process + * @return string + */ + protected function arrayToCss(array $rules) + { + $strings = []; + + foreach ($rules as $key => $value) { + $strings[] = $key . ': ' . $value; + } + + return implode('; ', $strings); + } +} diff --git a/modules/cms/twig/DefaultNode.php b/modules/cms/twig/DefaultNode.php new file mode 100644 index 0000000..2cc4efb --- /dev/null +++ b/modules/cms/twig/DefaultNode.php @@ -0,0 +1,31 @@ +addDebugInfo($this) + ->write("echo '';\n") + ; + } +} diff --git a/modules/cms/twig/DefaultTokenParser.php b/modules/cms/twig/DefaultTokenParser.php new file mode 100644 index 0000000..e601c1b --- /dev/null +++ b/modules/cms/twig/DefaultTokenParser.php @@ -0,0 +1,41 @@ + + * {% default %} + * {% endput %} + * + * @package october\cms + * @author Alexey Bobkov, Samuel Georges + */ +class DefaultTokenParser extends TwigTokenParser +{ + /** + * Parses a token and returns a node. + * + * @param TwigToken $token A TwigToken instance + * @return Twig\Node\Node A Twig\Node\Node instance + */ + public function parse(TwigToken $token) + { + $stream = $this->parser->getStream(); + $stream->expect(TwigToken::BLOCK_END_TYPE); + return new DefaultNode($token->getLine(), $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'default'; + } +} diff --git a/modules/cms/twig/Extension.php b/modules/cms/twig/Extension.php new file mode 100644 index 0000000..af95e6b --- /dev/null +++ b/modules/cms/twig/Extension.php @@ -0,0 +1,224 @@ +controller = $controller; + } + + /** + * Returns a list of functions to add to the existing list. + * + * @return array An array of functions + */ + public function getFunctions() + { + return [ + new TwigSimpleFunction('page', [$this, 'pageFunction'], ['is_safe' => ['html']]), + new TwigSimpleFunction('partial', [$this, 'partialFunction'], ['is_safe' => ['html']]), + new TwigSimpleFunction('content', [$this, 'contentFunction'], ['is_safe' => ['html']]), + new TwigSimpleFunction('component', [$this, 'componentFunction'], ['is_safe' => ['html']]), + new TwigSimpleFunction('placeholder', [$this, 'placeholderFunction'], ['is_safe' => ['html']]), + ]; + } + + /** + * Returns a list of filters this extensions provides. + * + * @return array An array of filters + */ + public function getFilters() + { + return [ + new TwigSimpleFilter('page', [$this, 'pageFilter'], ['is_safe' => ['html']]), + new TwigSimpleFilter('theme', [$this, 'themeFilter'], ['is_safe' => ['html']]), + ]; + } + + /** + * Returns a list of token parsers this extensions provides. + * + * @return array An array of token parsers + */ + public function getTokenParsers() + { + return [ + new PageTokenParser, + new PartialTokenParser, + new ContentTokenParser, + new PutTokenParser, + new PlaceholderTokenParser, + new DefaultTokenParser, + new FrameworkTokenParser, + new ComponentTokenParser, + new FlashTokenParser, + new ScriptsTokenParser, + new StylesTokenParser, + ]; + } + + /** + * Renders a page. + * This function should be used in the layout code to output the requested page. + * @return string Returns the page contents. + */ + public function pageFunction() + { + return $this->controller->renderPage(); + } + + /** + * Renders a partial. + * @param string $name Specifies the partial name. + * @param array $parameters A optional list of parameters to pass to the partial. + * @param bool $throwException Throw an exception if the partial is not found. + * @return string Returns the partial contents. + */ + public function partialFunction($name, $parameters = [], $throwException = false) + { + return $this->controller->renderPartial($name, $parameters, $throwException); + } + + /** + * Renders a content file. + * @param string $name Specifies the content block name. + * @param array $parameters A optional list of parameters to pass to the content. + * @return string Returns the file contents. + */ + public function contentFunction($name, $parameters = []) + { + return $this->controller->renderContent($name, $parameters); + } + + /** + * Renders a component's default content. + * @param string $name Specifies the component name. + * @param array $parameters A optional list of parameters to pass to the component. + * @return string Returns the component default contents. + */ + public function componentFunction($name, $parameters = []) + { + return $this->controller->renderComponent($name, $parameters); + } + + /** + * Renders registered assets of a given type + * @return string Returns the component default contents. + */ + public function assetsFunction($type = null) + { + return $this->controller->makeAssets($type); + } + + /** + * Renders a placeholder content, without removing the block, + * must be called before the placeholder tag itself + * @return string Returns the placeholder contents. + */ + public function placeholderFunction($name, $default = null) + { + if (($result = Block::get($name)) === null) { + return null; + } + + $result = str_replace('', trim($default), $result); + return $result; + } + + /** + * Looks up the URL for a supplied page and returns it relative to the website root. + * @param mixed $name Specifies the Cms Page file name. + * @param array $parameters Route parameters to consider in the URL. + * @param bool $routePersistence By default the existing routing parameters will be included + * when creating the URL, set to false to disable this feature. + * @return string + */ + public function pageFilter($name, $parameters = [], $routePersistence = true) + { + return $this->controller->pageUrl($name, $parameters, $routePersistence); + } + + /** + * Converts supplied URL to a theme URL relative to the website root. If the URL provided is an + * array then the files will be combined. + * @param mixed $url Specifies the theme-relative URL + * @return string + */ + public function themeFilter($url) + { + return $this->controller->themeUrl($url); + } + + /** + * Opens a layout block. + * @param string $name Specifies the block name + */ + public function startBlock($name) + { + Block::startBlock($name); + } + + /** + * Returns a layout block contents and removes the block. + * @param string $name Specifies the block name + * @param string $default The default placeholder contents. + * @return mixed Returns the block contents string or null of the block doesn't exist + */ + public function displayBlock($name, $default = null) + { + if (($result = Block::placeholder($name)) === null) { + return $default; + } + + /** + * @event cms.block.render + * Provides an opportunity to modify the rendered block content + * + * Example usage: + * + * Event::listen('cms.block.render', function ((string) $name, (string) $result) { + * if ($name === 'myBlockName') { + * return 'my custom content'; + * } + * }); + * + */ + if ($event = Event::fire('cms.block.render', [$name, $result], true)) { + $result = $event; + } + + $result = str_replace('', trim($default), $result); + return $result; + } + + /** + * Closes a layout block. + */ + public function endBlock($append = true) + { + Block::endBlock($append); + } +} diff --git a/modules/cms/twig/FlashNode.php b/modules/cms/twig/FlashNode.php new file mode 100644 index 0000000..462a538 --- /dev/null +++ b/modules/cms/twig/FlashNode.php @@ -0,0 +1,71 @@ + $body], ['name' => $name], $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param TwigCompiler $compiler A TwigCompiler instance + */ + public function compile(TwigCompiler $compiler) + { + $attrib = $this->getAttribute('name'); + + $compiler + ->write('$_type = isset($context["type"]) ? $context["type"] : null;') + ->write('$_message = isset($context["message"]) ? $context["message"] : null;') + ; + + if ($attrib == 'all') { + $compiler + ->addDebugInfo($this) + ->write('foreach (Flash::getMessages() as $type => $messages) {'.PHP_EOL) + ->indent() + ->write('foreach ($messages as $message) {'.PHP_EOL) + ->indent() + ->write('$context["type"] = $type;') + ->write('$context["message"] = $message;') + ->subcompile($this->getNode('body')) + ->outdent() + ->write('}'.PHP_EOL) + ->outdent() + ->write('}'.PHP_EOL) + ; + } + else { + $compiler + ->addDebugInfo($this) + ->write('$context["type"] = ') + ->string($attrib) + ->write(';') + ->write('foreach (Flash::') + ->raw($attrib) + ->write('() as $message) {'.PHP_EOL) + ->indent() + ->write('$context["message"] = $message;') + ->subcompile($this->getNode('body')) + ->outdent() + ->write('}'.PHP_EOL) + ; + } + + $compiler + ->write('$context["type"] = $_type;') + ->write('$context["message"] = $_message;') + ; + } +} diff --git a/modules/cms/twig/FlashTokenParser.php b/modules/cms/twig/FlashTokenParser.php new file mode 100644 index 0000000..e6f7071 --- /dev/null +++ b/modules/cms/twig/FlashTokenParser.php @@ -0,0 +1,55 @@ +getLine(); + $stream = $this->parser->getStream(); + + if ($token = $stream->nextIf(TwigToken::NAME_TYPE)) { + $name = $token->getValue(); + } + else { + $name = 'all'; + } + $stream->expect(TwigToken::BLOCK_END_TYPE); + + $body = $this->parser->subparse([$this, 'decideIfEnd'], true); + $stream->expect(TwigToken::BLOCK_END_TYPE); + + return new FlashNode($name, $body, $lineno, $this->getTag()); + } + + public function decideIfEnd(TwigToken $token) + { + return $token->test(['endflash']); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'flash'; + } +} diff --git a/modules/cms/twig/FrameworkNode.php b/modules/cms/twig/FrameworkNode.php new file mode 100644 index 0000000..9aa2aa0 --- /dev/null +++ b/modules/cms/twig/FrameworkNode.php @@ -0,0 +1,56 @@ + $name], $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param TwigCompiler $compiler A TwigCompiler instance + */ + public function compile(TwigCompiler $compiler) + { + $attrib = $this->getAttribute('name'); + $includeExtras = strtolower(trim($attrib)) === 'extras'; + + $compiler + ->addDebugInfo($this) + ->write("\$_minify = ".CombineAssets::class."::instance()->useMinify;" . PHP_EOL); + + if ($includeExtras) { + $compiler + ->write("if (\$_minify) {" . PHP_EOL) + ->indent() + ->write("echo ''.PHP_EOL;" . PHP_EOL) + ->outdent() + ->write("}" . PHP_EOL) + ->write("else {" . PHP_EOL) + ->indent() + ->write("echo ''.PHP_EOL;" . PHP_EOL) + ->write("echo ''.PHP_EOL;" . PHP_EOL) + ->outdent() + ->write("}" . PHP_EOL) + ->write("echo ''.PHP_EOL;" . PHP_EOL) + ; + } + else { + $compiler->write("echo ''.PHP_EOL;" . PHP_EOL); + } + + $compiler->write('unset($_minify);' . PHP_EOL); + } +} diff --git a/modules/cms/twig/FrameworkTokenParser.php b/modules/cms/twig/FrameworkTokenParser.php new file mode 100644 index 0000000..cea6aed --- /dev/null +++ b/modules/cms/twig/FrameworkTokenParser.php @@ -0,0 +1,45 @@ +getLine(); + $stream = $this->parser->getStream(); + + $name = null; + if ($token = $stream->nextIf(TwigToken::NAME_TYPE)) { + $name = $token->getValue(); + } + + $stream->expect(TwigToken::BLOCK_END_TYPE); + return new FrameworkNode($name, $lineno, $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'framework'; + } +} diff --git a/modules/cms/twig/Loader.php b/modules/cms/twig/Loader.php new file mode 100644 index 0000000..c0b1dc1 --- /dev/null +++ b/modules/cms/twig/Loader.php @@ -0,0 +1,180 @@ +obj = $obj; + } + + /** + * Returns the Twig content string. + * This step is cached internally by Twig. + * + * @param string $name The template name + * @return TwigSource + */ + public function getSourceContext($name) + { + if (!$this->validateCmsObject($name)) { + return parent::getSourceContext($name); + } + + $content = $this->obj->getTwigContent(); + + /** + * @event cms.template.processTwigContent + * Provides an opportunity to modify Twig content before being processed by Twig. `$dataHolder` = {content: $twigContent} + * + * Example usage: + * + * Event::listen('cms.template.processTwigContent', function ((\Cms\Classes\CmsObject) $thisObject, (object) $dataHolder) { + * $dataHolder->content = "NO CONTENT FOR YOU!"; + * }); + * + */ + $dataHolder = (object) ['content' => $content]; + Event::fire('cms.template.processTwigContent', [$this->obj, $dataHolder]); + + return new TwigSource((string) $dataHolder->content, $name); + } + + /** + * Returns the Twig cache key. + * + * @param string $name The template name + * @return string + */ + public function getCacheKey($name) + { + if (!$this->validateCmsObject($name)) { + return parent::getCacheKey($name); + } + + return $this->obj->getTwigCacheKey(); + } + + /** + * Determines if the content is fresh. + * + * @param string $name The template name + * @param mixed $time The time to check against the template + * @return bool + */ + public function isFresh($name, $time) + { + if (!$this->validateCmsObject($name)) { + return parent::isFresh($name, $time); + } + + return $this->obj->mtime <= $time; + } + + /** + * Returns the file name of the loaded template. + * + * @param string $name The template name + * @return string + */ + public function getFilename($name) + { + if (!$this->validateCmsObject($name)) { + return parent::getFilename($name); + } + + return $this->obj->getFilePath(); + } + + /** + * Checks that the template exists. + * + * @param string $name The template name + * @return bool + */ + public function exists($name) + { + if (!$this->validateCmsObject($name)) { + return parent::exists($name); + } + + return $this->obj->exists; + } + + /** + * Internal method that checks if the template name matches + * the loaded object, with fallback support to partials. + * + * @param string $name The template name to validate + * @return bool + */ + protected function validateCmsObject($name) + { + if ($this->obj && $name === $this->obj->getFilePath()) { + return true; + } + + if ($fallbackObj = $this->findFallbackObject($name)) { + $this->obj = $fallbackObj; + return true; + } + + return false; + } + + /** + * Looks up a fallback CMS partial object. + * + * @param string $name The filename to attempt to load a fallback CMS partial for + * @return Cms\Classes\Partial|bool Returns false if a CMS partial can't be found + */ + protected function findFallbackObject($name) + { + // Ignore Laravel views + if (strpos($name, '::') !== false) { + return false; + } + + // Check the cache + if (array_key_exists($name, $this->fallbackCache)) { + return $this->fallbackCache[$name]; + } + + // Attempt to load the path as a CMS Partial object + try { + $partial = CmsPartial::find($name); + } catch (\Exception $e) { + return false; + } + + return $this->fallbackCache[$name] = $partial; + } +} diff --git a/modules/cms/twig/PageNode.php b/modules/cms/twig/PageNode.php new file mode 100644 index 0000000..32c92f7 --- /dev/null +++ b/modules/cms/twig/PageNode.php @@ -0,0 +1,31 @@ +addDebugInfo($this) + ->write("echo \$this->env->getExtension('Cms\Twig\Extension')->pageFunction();\n") + ; + } +} diff --git a/modules/cms/twig/PageTokenParser.php b/modules/cms/twig/PageTokenParser.php new file mode 100644 index 0000000..1c6b481 --- /dev/null +++ b/modules/cms/twig/PageTokenParser.php @@ -0,0 +1,38 @@ +parser->getStream(); + $stream->expect(TwigToken::BLOCK_END_TYPE); + return new PageNode($token->getLine(), $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'page'; + } +} diff --git a/modules/cms/twig/PartialNode.php b/modules/cms/twig/PartialNode.php new file mode 100644 index 0000000..c6a4842 --- /dev/null +++ b/modules/cms/twig/PartialNode.php @@ -0,0 +1,46 @@ + $nodes], ['names' => $paramNames], $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param TwigCompiler $compiler A TwigCompiler instance + */ + public function compile(TwigCompiler $compiler) + { + $compiler->addDebugInfo($this); + + $compiler->write("\$context['__cms_partial_params'] = [];\n"); + + for ($i = 1; $i < count($this->getNode('nodes')); $i++) { + $compiler->write("\$context['__cms_partial_params']['".$this->getAttribute('names')[$i-1]."'] = "); + $compiler->subcompile($this->getNode('nodes')->getNode($i)); + $compiler->write(";\n"); + } + + $compiler + ->write("echo \$this->env->getExtension('Cms\Twig\Extension')->partialFunction(") + ->subcompile($this->getNode('nodes')->getNode(0)) + ->write(", \$context['__cms_partial_params']") + ->write(", true") + ->write(");\n") + ; + + $compiler->write("unset(\$context['__cms_partial_params']);\n"); + } +} diff --git a/modules/cms/twig/PartialTokenParser.php b/modules/cms/twig/PartialTokenParser.php new file mode 100644 index 0000000..b996252 --- /dev/null +++ b/modules/cms/twig/PartialTokenParser.php @@ -0,0 +1,74 @@ +getLine(); + $stream = $this->parser->getStream(); + + $name = $this->parser->getExpressionParser()->parseExpression(); + $paramNames = []; + $nodes = [$name]; + + $end = false; + while (!$end) { + $current = $stream->next(); + + switch ($current->getType()) { + case TwigToken::NAME_TYPE: + $paramNames[] = $current->getValue(); + $stream->expect(TwigToken::OPERATOR_TYPE, '='); + $nodes[] = $this->parser->getExpressionParser()->parseExpression(); + break; + + case TwigToken::BLOCK_END_TYPE: + $end = true; + break; + + default: + throw new TwigErrorSyntax( + sprintf('Invalid syntax in the partial tag. Line %s', $lineno), + $stream->getCurrent()->getLine(), + $stream->getSourceContext() + ); + break; + } + } + + return new PartialNode(new TwigNode($nodes), $paramNames, $token->getLine(), $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'partial'; + } +} diff --git a/modules/cms/twig/PlaceholderNode.php b/modules/cms/twig/PlaceholderNode.php new file mode 100644 index 0000000..4a40c75 --- /dev/null +++ b/modules/cms/twig/PlaceholderNode.php @@ -0,0 +1,83 @@ +hasNode('default'); + $varId = '__placeholder_'.$this->getAttribute('name').'_default_contents'; + $compiler + ->addDebugInfo($this) + ->write("\$context[") + ->raw("'".$varId."'") + ->raw("] = null;"); + + if ($hasBody) { + $compiler + ->addDebugInfo($this) + ->write('ob_start();') + ->subcompile($this->getNode('default')) + ->write("\$context[") + ->raw("'".$varId."'") + ->raw("] = ob_get_clean();"); + } + + $isText = $this->hasAttribute('type') && $this->getAttribute('type') == 'text'; + + $compiler->addDebugInfo($this); + if (!$isText) { + $compiler->write("echo \$this->env->getExtension('Cms\Twig\Extension')->displayBlock("); + } + else { + $compiler->write("echo twig_escape_filter(\$this->env, \$this->env->getExtension('Cms\Twig\Extension')->displayBlock("); + } + + $compiler + ->raw("'".$this->getAttribute('name')."', ") + ->raw("\$context[") + ->raw("'".$varId."'") + ->raw("]") + ->raw(")"); + + if (!$isText) { + $compiler->raw(";\n"); + } + else { + $compiler->raw(");\n"); + } + + $compiler + ->addDebugInfo($this) + ->write("unset(\$context[") + ->raw("'".$varId."'") + ->raw("]);"); + } +} diff --git a/modules/cms/twig/PlaceholderTokenParser.php b/modules/cms/twig/PlaceholderTokenParser.php new file mode 100644 index 0000000..59d7c3d --- /dev/null +++ b/modules/cms/twig/PlaceholderTokenParser.php @@ -0,0 +1,98 @@ + + * {% endshowblock %} + * + * @package october\cms + * @author Alexey Bobkov, Samuel Georges + */ +class PlaceholderTokenParser extends TwigTokenParser +{ + /** + * Parses a token and returns a node. + * + * @param TwigToken $token A TwigToken instance + * @return TwigNode A TwigNode instance + */ + public function parse(TwigToken $token) + { + $stream = $this->parser->getStream(); + $name = $stream->expect(TwigToken::NAME_TYPE)->getValue(); + $body = null; + $params = []; + + if ($stream->test(TwigToken::NAME_TYPE, 'default')) { + $stream->next(); + $params = $this->loadParams($stream); + + $body = $this->parser->subparse([$this, 'decidePlaceholderEnd'], true); + $stream->expect(TwigToken::BLOCK_END_TYPE); + } + else { + $params = $this->loadParams($stream); + } + + return new PlaceholderNode($name, $params, $body, $token->getLine(), $this->getTag()); + } + + public function decidePlaceholderEnd(TwigToken $token) + { + return $token->test('endplaceholder'); + } + + protected function loadParams($stream) + { + $params = []; + + $end = false; + while (!$end) { + $current = $stream->next(); + + switch ($current->getType()) { + case TwigToken::NAME_TYPE: + $paramName = $current->getValue(); + $stream->expect(TwigToken::OPERATOR_TYPE, '='); + $current = $stream->next(); + $params[$paramName] = $current->getValue(); + break; + + case TwigToken::BLOCK_END_TYPE: + $end = true; + break; + + default: + throw new TwigErrorSyntax( + sprintf('Invalid syntax in the placeholder tag. Line %s', $stream->getCurrent()->getLine()), + $stream->getCurrent()->getLine(), + $stream->getSourceContext() + ); + break; + } + } + + return $params; + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'placeholder'; + } +} diff --git a/modules/cms/twig/PutNode.php b/modules/cms/twig/PutNode.php new file mode 100644 index 0000000..82ff67c --- /dev/null +++ b/modules/cms/twig/PutNode.php @@ -0,0 +1,44 @@ + $body], ['name' => $name, 'endType' => $endType], $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param TwigCompiler $compiler A TwigCompiler instance + */ + public function compile(TwigCompiler $compiler) + { + $compiler + ->addDebugInfo($this) + ->write("echo \$this->env->getExtension('Cms\Twig\Extension')->startBlock(") + ->raw("'".$this->getAttribute('name')."'") + ->write(");\n") + ; + + $isOverwrite = strtolower($this->getAttribute('endType')) == 'overwrite'; + + $compiler->subcompile($this->getNode('body')); + + $compiler + ->addDebugInfo($this) + ->write("echo \$this->env->getExtension('Cms\Twig\Extension')->endBlock(") + ->raw($isOverwrite ? 'false' : 'true') + ->write(");\n") + ; + } +} diff --git a/modules/cms/twig/PutTokenParser.php b/modules/cms/twig/PutTokenParser.php new file mode 100644 index 0000000..ec5572b --- /dev/null +++ b/modules/cms/twig/PutTokenParser.php @@ -0,0 +1,63 @@ + + * {% endput %} + * + * or + * + * {% put head %} + * + * {% default %} + * {% endput %} + * + * @package october\cms + * @author Alexey Bobkov, Samuel Georges + */ +class PutTokenParser extends TwigTokenParser +{ + /** + * Parses a token and returns a node. + * + * @param TwigToken $token A TwigToken instance + * @return Twig\Node\Node A Twig\Node\Node instance + */ + public function parse(TwigToken $token) + { + $lineno = $token->getLine(); + $stream = $this->parser->getStream(); + $name = $stream->expect(TwigToken::NAME_TYPE)->getValue(); + $stream->expect(TwigToken::BLOCK_END_TYPE); + $body = $this->parser->subparse([$this, 'decidePutEnd'], true); + + $endType = null; + if ($token = $stream->nextIf(TwigToken::NAME_TYPE)) { + $endType = $token->getValue(); + } + + $stream->expect(TwigToken::BLOCK_END_TYPE); + + return new PutNode($body, $name, $endType, $lineno, $this->getTag()); + } + + public function decidePutEnd(TwigToken $token) + { + return $token->test('endput'); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'put'; + } +} diff --git a/modules/cms/twig/ScriptsNode.php b/modules/cms/twig/ScriptsNode.php new file mode 100644 index 0000000..96c71b6 --- /dev/null +++ b/modules/cms/twig/ScriptsNode.php @@ -0,0 +1,32 @@ +addDebugInfo($this) + ->write("echo \$this->env->getExtension('Cms\Twig\Extension')->assetsFunction('js');\n") + ->write("echo \$this->env->getExtension('Cms\Twig\Extension')->displayBlock('scripts');\n") + ; + } +} diff --git a/modules/cms/twig/ScriptsTokenParser.php b/modules/cms/twig/ScriptsTokenParser.php new file mode 100644 index 0000000..8965aee --- /dev/null +++ b/modules/cms/twig/ScriptsTokenParser.php @@ -0,0 +1,38 @@ +parser->getStream(); + $stream->expect(TwigToken::BLOCK_END_TYPE); + return new ScriptsNode($token->getLine(), $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'scripts'; + } +} diff --git a/modules/cms/twig/StylesNode.php b/modules/cms/twig/StylesNode.php new file mode 100644 index 0000000..e3ad91a --- /dev/null +++ b/modules/cms/twig/StylesNode.php @@ -0,0 +1,32 @@ +addDebugInfo($this) + ->write("echo \$this->env->getExtension('Cms\Twig\Extension')->assetsFunction('css');\n") + ->write("echo \$this->env->getExtension('Cms\Twig\Extension')->displayBlock('styles');\n") + ; + } +} diff --git a/modules/cms/twig/StylesTokenParser.php b/modules/cms/twig/StylesTokenParser.php new file mode 100644 index 0000000..eaa9346 --- /dev/null +++ b/modules/cms/twig/StylesTokenParser.php @@ -0,0 +1,38 @@ +parser->getStream(); + $stream->expect(TwigToken::BLOCK_END_TYPE); + return new StylesNode($token->getLine(), $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'styles'; + } +} diff --git a/modules/cms/views/404.php b/modules/cms/views/404.php new file mode 100644 index 0000000..2e8414e --- /dev/null +++ b/modules/cms/views/404.php @@ -0,0 +1,14 @@ + + + + + <?= Lang::get('cms::lang.page.not_found.label') ?> + + + +
    +

    +

    +
    + + \ No newline at end of file diff --git a/modules/cms/views/error.php b/modules/cms/views/error.php new file mode 100644 index 0000000..efd9b3e --- /dev/null +++ b/modules/cms/views/error.php @@ -0,0 +1,14 @@ + + + + + <?= Lang::get('cms::lang.page.custom_error.label') ?> + + + +
    +

    +

    +
    + + diff --git a/modules/cms/widgets/AssetList.php b/modules/cms/widgets/AssetList.php new file mode 100644 index 0000000..a376435 --- /dev/null +++ b/modules/cms/widgets/AssetList.php @@ -0,0 +1,746 @@ +alias = $alias; + $this->theme = Theme::getEditTheme(); + $this->selectionInputName = 'file'; + $this->assetExtensions = FileDefinitions::get('assetExtensions'); + + parent::__construct($controller, []); + + $this->bindToController(); + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addCss('css/assetlist.css', 'core'); + $this->addJs('js/assetlist.js', 'core'); + } + + /** + * Renders the widget. + * @return string + */ + public function render() + { + return $this->makePartial('body', [ + 'data' => $this->getData() + ]); + } + + // + // Event handlers + // + + public function onOpenDirectory() + { + $path = Input::get('path'); + if (!$this->validatePath($path)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + $delay = Input::get('delay'); + if ($delay) { + usleep(1000000*$delay); + } + + $this->putSession('currentPath', $path); + + return [ + '#'.$this->getId('asset-list') => $this->makePartial('items', ['items' => $this->getData()]) + ]; + } + + public function onRefresh() + { + return [ + '#'.$this->getId('asset-list') => $this->makePartial('items', ['items' => $this->getData()]) + ]; + } + + public function onUpdate() + { + $this->extendSelection(); + + return $this->onRefresh(); + } + + public function onDeleteFiles() + { + $this->validateRequestTheme(); + + $fileList = Request::input('file'); + $error = null; + $deleted = []; + + try { + $assetsPath = $this->getAssetsPath(); + + foreach ($fileList as $path => $selected) { + if ($selected) { + if (!$this->validatePath($path)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + $fullPath = $assetsPath.'/'.$path; + if (File::exists($fullPath)) { + if (!File::isDirectory($fullPath)) { + if (!@File::delete($fullPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_deleting_file', + ['name' => $path] + )); + } + } + else { + $empty = File::isDirectoryEmpty($fullPath); + if ($empty === false) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_deleting_dir_not_empty', + ['name' => $path] + )); + } + + if (!@rmdir($fullPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_deleting_dir', + ['name' => $path] + )); + } + } + + $deleted[] = $path; + $this->removeSelection($path); + } + } + } + } + catch (Exception $ex) { + $error = $ex->getMessage(); + } + + return [ + 'deleted' => $deleted, + 'error' => $error, + 'theme' => Request::input('theme') + ]; + } + + public function onLoadRenamePopup() + { + $this->validateRequestTheme(); + + $path = Input::get('renamePath'); + if (!$this->validatePath($path)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + $this->vars['originalPath'] = $path; + $this->vars['name'] = basename($path); + + return $this->makePartial('rename_form'); + } + + public function onApplyName() + { + $this->validateRequestTheme(); + + $newName = trim(Input::get('name')); + if (!strlen($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.name_cant_be_empty')); + } + + if (!$this->validatePath($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + if (!$this->validateName($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_name')); + } + + $originalPath = Input::get('originalPath'); + if (!$this->validatePath($originalPath)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + $originalFullPath = $this->getFullPath($originalPath); + if (!file_exists($originalFullPath)) { + throw new ApplicationException(Lang::get('cms::lang.asset.original_not_found')); + } + + if (!is_dir($originalFullPath) && !$this->validateFileType($newName)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.type_not_allowed', + ['allowed_types' => implode(', ', $this->assetExtensions)] + )); + } + + $newFullPath = $this->getFullPath(dirname($originalPath).'/'.$newName); + if (file_exists($newFullPath) && $newFullPath !== $originalFullPath) { + throw new ApplicationException(Lang::get('cms::lang.asset.already_exists')); + } + + if (!@rename($originalFullPath, $newFullPath)) { + throw new ApplicationException(Lang::get('cms::lang.asset.error_renaming')); + } + + return [ + '#'.$this->getId('asset-list') => $this->makePartial('items', ['items' => $this->getData()]) + ]; + } + + public function onLoadNewDirPopup() + { + $this->validateRequestTheme(); + + return $this->makePartial('new_dir_form'); + } + + public function onNewDirectory() + { + $this->validateRequestTheme(); + + $newName = trim(Input::get('name')); + if (!strlen($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.name_cant_be_empty')); + } + + if (!$this->validatePath($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + if (!$this->validateName($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_name')); + } + + $newFullPath = $this->getCurrentPath().'/'.$newName; + if (file_exists($newFullPath)) { + throw new ApplicationException(Lang::get('cms::lang.asset.already_exists')); + } + + if (!File::makeDirectory($newFullPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.cms_object.error_creating_directory', + ['name' => $newName] + )); + } + + return [ + '#'.$this->getId('asset-list') => $this->makePartial('items', ['items' => $this->getData()]) + ]; + } + + public function onLoadMovePopup() + { + $this->validateRequestTheme(); + + $fileList = Request::input('file'); + $directories = []; + + $selectedList = array_filter($fileList, function ($value) { + return $value == 1; + }); + + $this->listDestinationDirectories($directories, $selectedList); + + $this->vars['directories'] = $directories; + $this->vars['selectedList'] = base64_encode(json_encode(array_keys($selectedList))); + + return $this->makePartial('move_form'); + } + + public function onMove() + { + $this->validateRequestTheme(); + + $selectedList = Input::get('selectedList'); + if (!strlen($selectedList)) { + throw new ApplicationException(Lang::get('cms::lang.asset.selected_files_not_found')); + } + + $destinationDir = Input::get('dest'); + if (!strlen($destinationDir)) { + throw new ApplicationException(Lang::get('cms::lang.asset.select_destination_dir')); + } + + $destinationFullPath = $this->getFullPath($destinationDir); + if (!file_exists($destinationFullPath) || !is_dir($destinationFullPath)) { + throw new ApplicationException(Lang::get('cms::lang.asset.destination_not_found')); + } + + $list = @json_decode(@base64_decode($selectedList)); + if ($list === false) { + throw new ApplicationException(Lang::get('cms::lang.asset.selected_files_not_found')); + } + + foreach ($list as $path) { + if (!$this->validatePath($path)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + $basename = basename($path); + $originalFullPath = $this->getFullPath($path); + $newFullPath = realpath(rtrim($destinationFullPath, '/')) . '/' . $basename; + $safeDir = $this->getAssetsPath(); + + if ($originalFullPath == $newFullPath) { + continue; + } + + if (!starts_with($newFullPath, $safeDir)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_moving_file', + ['file' => $basename] + )); + } + + if (is_file($originalFullPath)) { + if (!@File::move($originalFullPath, $newFullPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_moving_file', + ['file' => $basename] + )); + } + } + elseif (is_dir($originalFullPath)) { + if (!@File::copyDirectory($originalFullPath, $newFullPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_moving_directory', + ['dir' => $basename] + )); + } + + if (strpos($originalFullPath, '../') !== false) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_deleting_directory', + ['dir' => $basename] + )); + } + + if (strpos($originalFullPath, $safeDir) !== 0) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_deleting_directory', + ['dir' => $basename] + )); + } + + if (!@File::deleteDirectory($originalFullPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_deleting_directory', + ['dir' => $basename] + )); + } + } + } + + return [ + '#'.$this->getId('asset-list') => $this->makePartial('items', ['items' => $this->getData()]) + ]; + } + + public function onSearch() + { + $this->setSearchTerm(Input::get('search')); + $this->extendSelection(); + + return $this->onRefresh(); + } + + /* + * Methods for the internal use + */ + + protected function getData() + { + $assetsPath = $this->getAssetsPath(); + + if (!file_exists($assetsPath) || !is_dir($assetsPath)) { + if (!File::makeDirectory($assetsPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.cms_object.error_creating_directory', + ['name' => $assetsPath] + )); + } + } + + $searchTerm = Str::lower($this->getSearchTerm()); + + if (!strlen($searchTerm)) { + $currentPath = $this->getCurrentPath(); + return $this->getDirectoryContents( + new DirectoryIterator($currentPath) + ); + } + + return $this->findFiles(); + } + + protected function getAssetsPath() + { + return $this->theme->getPath().'/assets'; + } + + protected function getThemeFileUrl($path) + { + return Url::to('themes/'.$this->theme->getDirName().'/assets'.$path); + } + + public function getCurrentRelativePath() + { + $path = $this->getSession('currentPath', '/'); + + if (!$this->validatePath($path)) { + return null; + } + + if ($path == '.') { + return null; + } + + return ltrim($path, '/'); + } + + protected function getCurrentPath() + { + $assetsPath = $this->getAssetsPath(); + + $path = $assetsPath.'/'.$this->getCurrentRelativePath(); + if (!is_dir($path)) { + return $assetsPath; + } + + return $path; + } + + protected function getRelativePath($path) + { + $prefix = $this->getAssetsPath(); + + if (substr($path, 0, strlen($prefix)) == $prefix) { + $path = substr($path, strlen($prefix)); + } + + return $path; + } + + protected function getFullPath($path) + { + return $this->getAssetsPath().'/'.ltrim($path, '/'); + } + + protected function validatePath($path) + { + if (!preg_match('/^[0-9a-z\.\s_\-\/]+$/i', $path)) { + return false; + } + + if (strpos($path, '..') !== false || strpos($path, './') !== false) { + return false; + } + + return true; + } + + protected function validateName($name) + { + if (!preg_match('/^[0-9a-z\.\s_\-]+$/i', $name)) { + return false; + } + + if (strpos($name, '..') !== false) { + return false; + } + + return true; + } + + protected function getDirectoryContents($dir) + { + $editableAssetTypes = Asset::getEditableExtensions(); + + $result = []; + $files = []; + + foreach ($dir as $node) { + if (substr($node->getFileName(), 0, 1) == '.') { + continue; + } + + if ($node->isDir() && !$node->isDot()) { + $result[$node->getFilename()] = (object)[ + 'type' => 'directory', + 'path' => File::normalizePath($this->getRelativePath($node->getPathname())), + 'name' => $node->getFilename(), + 'editable' => false + ]; + } + elseif ($node->isFile()) { + $files[] = (object)[ + 'type' => 'file', + 'path' => File::normalizePath($this->getRelativePath($node->getPathname())), + 'name' => $node->getFilename(), + 'editable' => in_array(strtolower($node->getExtension()), $editableAssetTypes) + ]; + } + } + + foreach ($files as $file) { + $result[] = $file; + } + + return $result; + } + + protected function listDestinationDirectories(&$result, $excludeList, $startDir = null, $level = 0) + { + if ($startDir === null) { + $startDir = $this->getAssetsPath(); + + $result['/'] = 'assets'; + $level = 1; + } + + $dirs = new DirectoryIterator($startDir); + foreach ($dirs as $node) { + if (substr($node->getFileName(), 0, 1) == '.') { + continue; + } + + if ($node->isDir() && !$node->isDot()) { + $fullPath = $node->getPathname(); + $relativePath = $this->getRelativePath($fullPath); + if (array_key_exists($relativePath, $excludeList)) { + continue; + } + + $result[$relativePath] = str_repeat(' ', $level*4).$node->getFilename(); + + $this->listDestinationDirectories($result, $excludeList, $fullPath, $level+1); + } + } + } + + protected function getSearchTerm() + { + return $this->searchTerm !== false ? $this->searchTerm : $this->getSession('search'); + } + + protected function isSearchMode() + { + return strlen($this->getSearchTerm()); + } + + protected function getThemeSessionKey($prefix) + { + return $prefix.$this->theme->getDirName(); + } + + protected function getUpPath() + { + $path = $this->getCurrentRelativePath(); + if (!strlen(rtrim(ltrim($path, '/'), '/'))) { + return null; + } + + return dirname($path); + } + + protected function validateRequestTheme() + { + if ($this->theme->getDirName() != Request::input('theme')) { + throw new ApplicationException(trans('cms::lang.theme.edit.not_match')); + } + } + + /** + * Check for valid asset file extension + * @param string + * @return bool + */ + protected function validateFileType($name) + { + $extension = strtolower(File::extension($name)); + + if (!in_array($extension, $this->assetExtensions)) { + return false; + } + + return true; + } + + /** + * Process file uploads submitted via AJAX + * + * @return void + * @throws ApplicationException If the file "file_data" wasn't detected in the request or if the file failed to pass validation / security checks + */ + public function onUpload() + { + $fileName = null; + + try { + $uploadedFile = Input::file('file_data'); + + if (!is_object($uploadedFile)) { + return; + } + + $fileName = $uploadedFile->getClientOriginalName(); + + /* + * Check valid upload + */ + if (!$uploadedFile->isValid()) { + throw new ApplicationException(Lang::get('cms::lang.asset.file_not_valid')); + } + + /* + * Check file size + */ + $maxSize = UploadedFile::getMaxFilesize(); + if ($uploadedFile->getSize() > $maxSize) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.too_large', + ['max_size' => File::sizeToString($maxSize)] + )); + } + + /* + * Check for valid file extensions + */ + if (!$this->validateFileType($fileName)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.type_not_allowed', + ['allowed_types' => implode(', ', $this->assetExtensions)] + )); + } + + /* + * Accept the uploaded file + */ + $uploadedFile = $uploadedFile->move($this->getCurrentPath(), $uploadedFile->getClientOriginalName()); + + File::chmod($uploadedFile->getRealPath()); + + $response = Response::make('success'); + } + catch (Exception $ex) { + $message = $fileName !== null + ? Lang::get('cms::lang.asset.error_uploading_file', ['name' => $fileName, 'error' => $ex->getMessage()]) + : $ex->getMessage(); + + $response = Response::make($message); + } + + // Override the controller response + $this->controller->setResponse($response); + } + + protected function setSearchTerm($term) + { + $this->searchTerm = trim($term); + $this->putSession('search', $this->searchTerm); + } + + protected function findFiles() + { + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($this->getAssetsPath(), RecursiveDirectoryIterator::SKIP_DOTS), + RecursiveIteratorIterator::SELF_FIRST, + RecursiveIteratorIterator::CATCH_GET_CHILD + ); + + $editableAssetTypes = Asset::getEditableExtensions(); + $searchTerm = Str::lower($this->getSearchTerm()); + $words = explode(' ', $searchTerm); + + $result = []; + foreach ($iterator as $item) { + if (!$item->isDir()) { + if (substr($item->getFileName(), 0, 1) == '.') { + continue; + } + + $path = $this->getRelativePath($item->getPathname()); + + if ($this->pathMatchesSearch($words, $path)) { + $result[] = (object)[ + 'type' => 'file', + 'path' => File::normalizePath($path), + 'name' => $item->getFilename(), + 'editable' => in_array(strtolower($item->getExtension()), $editableAssetTypes) + ]; + } + } + } + + return $result; + } + + protected function pathMatchesSearch(&$words, $path) + { + foreach ($words as $word) { + $word = trim($word); + if (!strlen($word)) { + continue; + } + + if (!Str::contains(Str::lower($path), $word)) { + return false; + } + } + + return true; + } +} diff --git a/modules/cms/widgets/ComponentList.php b/modules/cms/widgets/ComponentList.php new file mode 100644 index 0000000..0e2b8f6 --- /dev/null +++ b/modules/cms/widgets/ComponentList.php @@ -0,0 +1,247 @@ +alias = $alias; + + parent::__construct($controller, []); + $this->bindToController(); + } + + /** + * Renders the widget. + * @return string + */ + public function render() + { + return $this->makePartial('body', [ + 'data' => $this->getData() + ]); + } + + /* + * Event handlers + */ + + public function onSearch() + { + $this->setSearchTerm(Input::get('search')); + + return $this->updateList(); + } + + /* + * Methods for th internal use + */ + + protected function getData() + { + $searchTerm = Str::lower($this->getSearchTerm()); + $searchWords = []; + if (strlen($searchTerm)) { + $searchWords = explode(' ', $searchTerm); + } + + $pluginManager = PluginManager::instance(); + $plugins = $pluginManager->getPlugins(); + + $this->prepareComponentList(); + + $items = []; + foreach ($plugins as $plugin) { + $components = $this->getPluginComponents($plugin); + if (!is_array($components)) { + continue; + } + + $pluginDetails = $plugin->pluginDetails(); + + $pluginName = $pluginDetails['name'] ?? Lang::get('system::lang.plugin.unnamed'); + $pluginIcon = $pluginDetails['icon'] ?? 'icon-puzzle-piece'; + $pluginDescription = $pluginDetails['description'] ?? null; + + $pluginClass = get_class($plugin); + + $pluginItems = []; + foreach ($components as $componentInfo) { + $className = $componentInfo->className; + $alias = $componentInfo->alias; + $component = App::make($className, [null, []]); + + if ($component->isHidden) { + continue; + } + + $componentDetails = $component->componentDetails(); + $component->alias = '--alias--'; + + $item = (object)[ + 'title' => ComponentHelpers::getComponentName($component), + 'description' => ComponentHelpers::getComponentDescription($component), + 'plugin' => $pluginName, + 'propertyConfig' => ComponentHelpers::getComponentsPropertyConfig($component), + 'propertyValues' => ComponentHelpers::getComponentPropertyValues($component, $alias), + 'className' => get_class($component), + 'pluginIcon' => $pluginIcon, + 'alias' => $alias, + 'name' => $componentInfo->duplicateAlias + ? $componentInfo->className + : $componentInfo->alias + ]; + + if ($searchWords && !$this->itemMatchesSearch($searchWords, $item)) { + continue; + } + + if (!array_key_exists($pluginClass, $items)) { + $group = (object)[ + 'title' => $pluginName, + 'description' => $pluginDescription, + 'pluginClass' => $pluginClass, + 'icon' => $pluginIcon, + 'items' => [] + ]; + + $items[$pluginClass] = $group; + } + + $pluginItems[] = $item; + } + + usort($pluginItems, function ($a, $b) { + return strcmp($a->title, $b->title); + }); + + if (isset($items[$pluginClass])) { + $items[$pluginClass]->items = $pluginItems; + } + } + + uasort($items, function ($a, $b) { + return strcmp($a->title, $b->title); + }); + + return $items; + } + + protected function prepareComponentList() + { + $pluginManager = PluginManager::instance(); + $plugins = $pluginManager->getPlugins(); + + $componentList = []; + foreach ($plugins as $plugin) { + $components = $plugin->registerComponents(); + if (!is_array($components)) { + continue; + } + + foreach ($components as $className => $alias) { + $duplicateAlias = false; + foreach ($componentList as $componentInfo) { + if ($componentInfo->alias == $alias) { + $componentInfo->duplicateAlias = true; + $duplicateAlias = true; + } + } + + $componentList[] = (object)[ + 'className' => $className, + 'alias' => $alias, + 'duplicateAlias' => $duplicateAlias, + 'pluginClass' => get_class($plugin) + ]; + } + } + + $this->pluginComponentList = $componentList; + } + + protected function getPluginComponents($plugin) + { + $result = []; + $pluginClass = get_class($plugin); + foreach ($this->pluginComponentList as $componentInfo) { + if ($componentInfo->pluginClass == $pluginClass) { + $result[] = $componentInfo; + } + } + + return $result; + } + + protected function getSearchTerm() + { + return $this->searchTerm !== false ? $this->searchTerm : $this->getSession('search'); + } + + protected function setSearchTerm($term) + { + $this->searchTerm = trim($term); + $this->putSession('search', $this->searchTerm); + } + + protected function updateList() + { + return [ + '#' . $this->getId('component-list') => $this->makePartial('items', [ + 'items' => $this->getData() + ]) + ]; + } + + protected function itemMatchesSearch(&$words, $item) + { + foreach ($words as $word) { + $word = trim($word); + if (!strlen($word)) { + continue; + } + + if (!$this->itemContainsWord($word, $item)) { + return false; + } + } + + return true; + } + + protected function itemContainsWord($word, $item) + { + if (Str::contains(Str::lower($item->title), $word)) { + return true; + } + + if (Str::contains(Str::lower($item->description), $word) && strlen($item->description)) { + return true; + } + + if (Str::contains(Str::lower($item->plugin), $word) && strlen($item->plugin)) { + return true; + } + + return false; + } +} diff --git a/modules/cms/widgets/MediaManager.php b/modules/cms/widgets/MediaManager.php new file mode 100644 index 0000000..4161d62 --- /dev/null +++ b/modules/cms/widgets/MediaManager.php @@ -0,0 +1,26 @@ += 2020. + */ +class MediaManager extends BackendMediaManager +{ + /** + * Constructor. + */ + public function __construct() + { + traceLog('Widget Cms\Widgets\MediaManager has been deprecated, use ' . BackendMediaManager::class . ' instead.'); + + $this->assetPath = '/modules/backend/widgets/mediamanager/assets'; + $this->viewPath = base_path('/modules/backend/widgets/mediamanager/partials'); + + parent::__construct(...func_get_args()); + } +} diff --git a/modules/cms/widgets/TemplateList.php b/modules/cms/widgets/TemplateList.php new file mode 100644 index 0000000..40386ce --- /dev/null +++ b/modules/cms/widgets/TemplateList.php @@ -0,0 +1,415 @@ +'URL'] + */ + public $descriptionProperties = []; + + /** + * @var string object property to use as a description. + */ + public $descriptionProperty; + + /** + * @var string Message to display when there are no records in the list. + */ + public $noRecordsMessage = 'cms::lang.template.no_list_records'; + + /** + * @var string Message to display when the Delete button is clicked. + */ + public $deleteConfirmation = 'cms::lang.template.delete_confirm'; + + /** + * @var string Specifies the item type. + */ + public $itemType; + + /** + * @var string Extra CSS class name to apply to the control. + */ + public $controlClass; + + /** + * @var string A list of file name patterns to suppress / hide. + */ + public $ignoreDirectories = []; + + /** + * @var boolean Defines sorting properties. + * The sorting feature is disabled if there are no sorting properties defined. + */ + public $sortingProperties = []; + + /* + * Public methods + */ + + public function __construct($controller, $alias, callable $dataSource) + { + $this->alias = $alias; + $this->dataSource = $dataSource; + $this->theme = Theme::getEditTheme(); + $this->selectionInputName = 'template'; + $this->collapseSessionKey = $this->getThemeSessionKey('groups'); + + parent::__construct($controller, []); + + if (!Request::isXmlHttpRequest()) { + $this->resetSelection(); + } + + $configFile = 'config_' . snake_case($alias) .'.yaml'; + $config = $this->makeConfig($configFile); + + foreach ($config as $field => $value) { + if (property_exists($this, $field)) { + $this->$field = $value; + } + } + + $this->bindToController(); + } + + /** + * Renders the widget. + * @return string + */ + public function render() + { + $toolbarClass = Str::contains($this->controlClass, 'hero') ? 'separator' : null; + + $this->vars['toolbarClass'] = $toolbarClass; + + return $this->makePartial('body', [ + 'data' => $this->getData() + ]); + } + + /* + * Event handlers + */ + + public function onSearch() + { + $this->setSearchTerm(Input::get('search')); + $this->extendSelection(); + + return $this->updateList(); + } + + public function onUpdate() + { + $this->extendSelection(); + + return $this->updateList(); + } + + public function onApplySorting() + { + $this->setSortingProperty(Input::get('sortProperty')); + + $result = $this->updateList(); + $result['#'.$this->getId('sorting-options')] = $this->makePartial('sorting-options'); + + return $result; + } + + // + // Methods for the internal use + // + + protected function getData() + { + /* + * Load the data + */ + $items = call_user_func($this->dataSource); + + if ($items instanceof \October\Rain\Support\Collection) { + $items = $items->all(); + } + + $items = $this->removeIgnoredDirectories($items); + + $items = array_map([$this, 'normalizeItem'], $items); + + $this->sortItems($items); + + /* + * Apply the search + */ + $filteredItems = []; + $searchTerm = Str::lower($this->getSearchTerm()); + + if (strlen($searchTerm)) { + /* + * Exact + */ + foreach ($items as $index => $item) { + if ($this->itemContainsWord($searchTerm, $item, true)) { + $filteredItems[] = $item; + unset($items[$index]); + } + } + + /* + * Fuzzy + */ + $words = explode(' ', $searchTerm); + foreach ($items as $item) { + if ($this->itemMatchesSearch($words, $item)) { + $filteredItems[] = $item; + } + } + } + else { + $filteredItems = $items; + } + + /* + * Group the items + */ + $result = []; + $foundGroups = []; + foreach ($filteredItems as $itemData) { + $pos = strpos($itemData->fileName, '/'); + + if ($pos !== false) { + $group = substr($itemData->fileName, 0, $pos); + if (!array_key_exists($group, $foundGroups)) { + $newGroup = (object)[ + 'title' => $group, + 'items' => [] + ]; + + $foundGroups[$group] = $newGroup; + } + + $foundGroups[$group]->items[] = $itemData; + } + else { + $result[] = $itemData; + } + } + + // Sort folders by name regardless of the + // selected sorting options. + ksort($foundGroups); + + foreach ($foundGroups as $group) { + $result[] = $group; + } + + return $result; + } + + protected function sortItems(&$items) + { + $sortingProperty = $this->getSortingProperty(); + + usort($items, function ($a, $b) use ($sortingProperty) { + return strcmp($a->$sortingProperty, $b->$sortingProperty); + }); + } + + protected function removeIgnoredDirectories($items) + { + if (!$this->ignoreDirectories) { + return $items; + } + + $ignoreCache = []; + + $items = array_filter($items, function ($item) use (&$ignoreCache) { + $fileName = $item->getBaseFileName(); + $dirName = dirname($fileName); + + if (isset($ignoreCache[$dirName])) { + return false; + } + + foreach ($this->ignoreDirectories as $ignoreDir) { + if (File::fileNameMatch($dirName, $ignoreDir)) { + $ignoreCache[$dirName] = true; + return false; + } + } + + return true; + }); + + return $items; + } + + protected function normalizeItem($item) + { + $description = null; + if ($descriptionProperty = $this->descriptionProperty) { + $description = $item->$descriptionProperty; + } + + $descriptions = []; + foreach ($this->descriptionProperties as $property => $title) { + if ($item->$property) { + $descriptions[$title] = $item->$property; + } + } + + $result = [ + 'title' => $this->getItemTitle($item), + 'fileName' => $item->getFileName(), + 'description' => $description, + 'descriptions' => $descriptions, + 'dragValue' => $this->getItemDragValue($item) + ]; + + foreach ($this->sortingProperties as $property => $name) { + $result[$property] = $item->$property; + } + + return (object) $result; + } + + protected function getItemDragValue($item) + { + if ($item instanceof \Cms\Classes\Partial) { + return "{% partial '".$item->getBaseFileName()."' %}"; + } + + if ($item instanceof \Cms\Classes\Content) { + return "{% content '".$item->getBaseFileName()."' %}"; + } + + if ($item instanceof \Cms\Classes\Page) { + return "{{ '".$item->getBaseFileName()."'|page }}"; + } + + return ''; + } + + protected function getItemTitle($item) + { + $titleProperty = $this->titleProperty; + + if ($titleProperty) { + return $item->$titleProperty ?: basename($item->getFileName()); + } + + return basename($item->getFileName()); + } + + protected function setSearchTerm($term) + { + $this->searchTerm = trim($term); + $this->putSession('search', $this->searchTerm); + } + + protected function getSearchTerm() + { + return $this->searchTerm !== false ? $this->searchTerm : $this->getSession('search'); + } + + protected function updateList() + { + return [ + '#'.$this->getId('template-list') => $this->makePartial('items', ['items' => $this->getData()]) + ]; + } + + protected function itemMatchesSearch($words, $item) + { + foreach ($words as $word) { + $word = trim($word); + if (!strlen($word)) { + continue; + } + + if (!$this->itemContainsWord($word, $item)) { + return false; + } + } + + return true; + } + + protected function itemContainsWord($word, $item, $exact = false) + { + $operator = $exact ? 'is' : 'contains'; + + if (strlen($item->title) && Str::$operator(Str::lower($item->title), $word)) { + return true; + } + + if (Str::$operator(Str::lower($item->fileName), $word)) { + return true; + } + + if (Str::$operator(Str::lower($item->description), $word) && strlen($item->description)) { + return true; + } + + foreach ($item->descriptions as $value) { + if (Str::$operator(Str::lower($value), $word) && strlen($value)) { + return true; + } + } + + return false; + } + + protected function getThemeSessionKey($prefix) + { + return $prefix.$this->theme->getDirName(); + } + + protected function getSortingProperty() + { + $property = $this->getSession($this->getThemeSessionKey('sorting_property'), self::SORTING_FILENAME); + + if (!array_key_exists($property, $this->sortingProperties)) { + return self::SORTING_FILENAME; + } + + return $property; + } + + protected function setSortingProperty($property) + { + $this->putSession($this->getThemeSessionKey('sorting_property'), $property); + } +} diff --git a/modules/cms/widgets/assetlist/assets/css/assetlist.css b/modules/cms/widgets/assetlist/assets/css/assetlist.css new file mode 100644 index 0000000..c748bb3 --- /dev/null +++ b/modules/cms/widgets/assetlist/assets/css/assetlist.css @@ -0,0 +1,244 @@ +.control-assetlist p.no-data { + padding: 22px; + margin: 0; + color: #666666; + font-size: 14px; + text-align: center; + font-weight: 400; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.control-assetlist p.parent, +.control-assetlist ul li { + font-weight: 300; + line-height: 150%; + margin-bottom: 0; +} +.control-assetlist p.parent.active a, +.control-assetlist ul li.active a { + background: #dddddd; + position: relative; +} +.control-assetlist p.parent.active a:after, +.control-assetlist ul li.active a:after { + position: absolute; + height: 100%; + width: 4px; + left: 0; + top: 0; + background: #e67e22; + display: block; + content: ' '; +} +.control-assetlist p.parent a.link, +.control-assetlist ul li a.link { + display: block; + position: relative; + word-wrap: break-word; + padding: 10px 50px 10px 20px; + outline: none; + font-weight: 400; + color: #405261; + font-size: 14px; +} +.control-assetlist p.parent a.link:hover, +.control-assetlist ul li a.link:hover, +.control-assetlist p.parent a.link:focus, +.control-assetlist ul li a.link:focus, +.control-assetlist p.parent a.link:active, +.control-assetlist ul li a.link:active { + text-decoration: none; +} +.control-assetlist p.parent a.link span, +.control-assetlist ul li a.link span { + display: block; +} +.control-assetlist p.parent a.link span.description, +.control-assetlist ul li a.link span.description { + color: #8f8f8f; + font-size: 12px; + font-weight: 400; + word-wrap: break-word; +} +.control-assetlist p.parent a.link span.description strong, +.control-assetlist ul li a.link span.description strong { + color: #405261; + font-weight: 400; +} +.control-assetlist p.parent.directory a.link, +.control-assetlist ul li.directory a.link, +.control-assetlist p.parent.parent a.link, +.control-assetlist ul li.parent a.link { + padding-left: 40px; +} +.control-assetlist p.parent.directory a.link:after, +.control-assetlist ul li.directory a.link:after, +.control-assetlist p.parent.parent a.link:after, +.control-assetlist ul li.parent a.link:after { + display: block; + position: absolute; + width: 10px; + height: 10px; + top: 10px; + left: 20px; + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + content: "\f07b"; + color: #a1aab1; + font-size: 14px; +} +.control-assetlist p.parent.parent a.link, +.control-assetlist ul li.parent a.link { + padding-left: 41px; + background-color: #ffffff; + word-wrap: break-word; +} +.control-assetlist p.parent.parent a.link:before, +.control-assetlist ul li.parent a.link:before { + content: ''; + display: block; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 1px; + background: #ecf0f1; +} +.control-assetlist p.parent.parent a.link:after, +.control-assetlist ul li.parent a.link:after { + font-size: 13px; + color: #34495e; + width: 18px; + height: 18px; + top: 11px; + left: 22px; + opacity: 0.5; + filter: alpha(opacity=50); + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + content: "\f053"; +} +.control-assetlist p.parent a.link:hover { + background: #dddddd !important; +} +.control-assetlist p.parent a.link:hover:after { + opacity: 1; + filter: alpha(opacity=100); +} +.control-assetlist p.parent a.link:hover:before { + display: none; +} +.control-assetlist ul { + padding: 0; + margin: 0; +} +.control-assetlist ul li { + font-weight: 300; + line-height: 150%; + position: relative; + list-style: none; +} +.control-assetlist ul li.active a.link, +.control-assetlist ul li a.link:hover { + background: #dddddd; +} +.control-assetlist ul li.active a.link { + position: relative; +} +.control-assetlist ul li.active a.link:after { + position: absolute; + height: 100%; + width: 4px; + left: 0; + top: 0; + background: #e67e22; + display: block; + content: ' '; +} +.control-assetlist ul li div.controls { + position: absolute; + right: 45px; + top: 10px; +} +.control-assetlist ul li div.controls .dropdown { + width: 14px; + height: 21px; +} +.control-assetlist ul li div.controls .dropdown.open a.control { + display: block!important; +} +.control-assetlist ul li div.controls .dropdown.open a.control:before { + visibility: visible; + display: block; +} +.control-assetlist ul li div.controls a.control { + color: #405261; + font-size: 14px; + visibility: hidden; + overflow: hidden; + width: 14px; + height: 21px; + display: none; + text-decoration: none; + cursor: pointer; + opacity: 0.5; + filter: alpha(opacity=50); +} +.control-assetlist ul li div.controls a.control:before { + visibility: visible; + display: block; + margin-right: 0; +} +.control-assetlist ul li div.controls a.control:hover { + opacity: 1; + filter: alpha(opacity=100); +} +.control-assetlist ul li:hover { + background: #dddddd; +} +.control-assetlist ul li:hover div.controls, +.control-assetlist ul li:hover a.control { + display: block!important; +} +.control-assetlist ul li:hover div.controls > a.control, +.control-assetlist ul li:hover a.control > a.control { + display: block!important; +} +.control-assetlist ul li .checkbox { + position: absolute; + top: -5px; + right: -5px; +} +.control-assetlist ul li .checkbox label { + margin-right: 0; +} +.control-assetlist ul li .checkbox label:before { + border-color: #cccccc; +} +.control-assetlist div.list-container { + position: relative; + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); +} +.control-assetlist div.list-container.animate ul { + -webkit-transition: all 0.2s ease; + transition: all 0.2s ease; +} +.control-assetlist div.list-container.goForward ul { + -webkit-transform: translate(-350px, 0); + -ms-transform: translate(-350px, 0); + transform: translate(-350px, 0); +} +.control-assetlist div.list-container.goBackward ul { + -webkit-transform: translate(350px, 0); + -ms-transform: translate(350px, 0); + transform: translate(350px, 0); +} diff --git a/modules/cms/widgets/assetlist/assets/js/assetlist.js b/modules/cms/widgets/assetlist/assets/js/assetlist.js new file mode 100644 index 0000000..4fb3d41 --- /dev/null +++ b/modules/cms/widgets/assetlist/assets/js/assetlist.js @@ -0,0 +1,184 @@ +/* + * Asset list + */ ++function ($) { "use strict"; + + var AssetList = function (form, alias) { + this.$form = $(form) + this.alias = alias + + + this.$form.on('ajaxSuccess', $.proxy(this.onAjaxSuccess, this)) + this.$form.on('click', 'ul.list > li.directory > a', $.proxy(this.onDirectoryClick, this)) + this.$form.on('click', 'ul.list > li.file > a', $.proxy(this.onFileClick, this)) + this.$form.on('click', 'p.parent > a', $.proxy(this.onDirectoryClick, this)) + this.$form.on('click', 'a[data-control=delete-asset]', $.proxy(this.onDeleteClick, this)) + this.$form.on('oc.list.setActiveItem', $.proxy(this.onSetActiveItem, this)) + + this.setupUploader() + } + + // Event handlers + // ================= + + AssetList.prototype.onDirectoryClick = function(e) { + this.gotoDirectory( + $(e.currentTarget).data('path'), + $(e.currentTarget).parent().hasClass('parent') + ) + + return false; + } + + AssetList.prototype.gotoDirectory = function(path, gotoParent) { + var $container = $('div.list-container', this.$form), + self = this + + if (gotoParent !== undefined && gotoParent) + $container.addClass('goBackward') + else + $container.addClass('goForward') + + $.oc.stripeLoadIndicator.show() + this.$form.request(this.alias+'::onOpenDirectory', { + data: { + path: path, + d: 0.2 + }, + complete: function() { + self.updateUi() + $container.trigger('oc.scrollbar.gotoStart') + }, + error: function(jqXHR, textStatus, errorThrown) { + $container.removeClass('goForward goBackward') + alert(jqXHR.responseText.length ? jqXHR.responseText : jqXHR.statusText) + } + }).always(function(){ + $.oc.stripeLoadIndicator.hide() + }) + } + + AssetList.prototype.onDeleteClick = function(e) { + var $el = $(e.currentTarget), + self = this + + if (!confirm($el.data('confirmation'))) + return false + + this.$form.request(this.alias+'::onDeleteFiles', { + success: function(data) { + if (data.error !== undefined && $.type(data.error) === 'string' && data.error.length) + $.oc.flashMsg({text: data.error, 'class': 'error'}) + }, + complete: function() { + self.refresh() + } + }) + + return false + } + + AssetList.prototype.onAjaxSuccess = function() { + this.updateUi() + } + + AssetList.prototype.onUploadFail = function(file, message) { + if (file.xhr.status === 413) { + message = 'Server rejected the file because it was too large, try increasing post_max_size'; + } + if (!message) { + message = 'Error uploading file' + } + + $.oc.alert(message) + + this.refresh() + } + + AssetList.prototype.onUploadSuccess = function(file, data) { + if (data !== 'success') { + $.oc.alert(data) + } + } + + AssetList.prototype.onUploadComplete = function(file, data) { + $.oc.stripeLoadIndicator.hide() + this.refresh() + } + + AssetList.prototype.onUploadStart = function() { + $.oc.stripeLoadIndicator.show() + } + + AssetList.prototype.onFileClick = function(event) { + var $link = $(event.currentTarget), + $li = $link.parent() + + var e = $.Event('open.oc.list', {relatedTarget: $li.get(0), clickEvent: event}) + this.$form.trigger(e, this) + + if (e.isDefaultPrevented()) + return false; + } + + AssetList.prototype.onSetActiveItem = function(event, dataId) { + $('ul li.file', this.$form).removeClass('active') + if (dataId) + $('ul li.file[data-id="'+dataId+'"]', this.$form).addClass('active') + } + + // Service functions + // ================= + + AssetList.prototype.updateUi = function() { + $('button[data-control=asset-tools]', self.$form).trigger('oc.triggerOn.update') + } + + AssetList.prototype.refresh = function() { + var self = this; + + this.$form.request(this.alias+'::onRefresh', { + complete: function() { + self.updateUi() + } + }) + } + + AssetList.prototype.setupUploader = function() { + var self = this, + $link = $('[data-control="upload-assets"]', this.$form), + uploaderOptions = { + method: 'POST', + url: window.location, + paramName: 'file_data', + previewsContainer: $('
    ').get(0), + clickable: $link.get(0), + timeout: 0, + headers: {} + } + + /* + * Add CSRF token to headers + */ + var token = $('meta[name="csrf-token"]').attr('content') + if (token) { + uploaderOptions.headers['X-CSRF-TOKEN'] = token + } + + var dropzone = new Dropzone($('
    ').get(0), uploaderOptions) + dropzone.on('error', $.proxy(self.onUploadFail, self)) + dropzone.on('success', $.proxy(self.onUploadSuccess, self)) + dropzone.on('complete', $.proxy(self.onUploadComplete, self)) + dropzone.on('sending', function(file, xhr, formData) { + $.each(self.$form.serializeArray(), function (index, field) { + formData.append(field.name, field.value) + }) + xhr.setRequestHeader('X-OCTOBER-REQUEST-HANDLER', self.alias + '::onUpload') + self.onUploadStart() + }) + } + + $(document).ready(function(){ + new AssetList($('#asset-list-container').closest('form'), $('#asset-list-container').data('alias')) + }) +}(window.jQuery); diff --git a/modules/cms/widgets/assetlist/assets/less/assetlist.less b/modules/cms/widgets/assetlist/assets/less/assetlist.less new file mode 100644 index 0000000..a8070d3 --- /dev/null +++ b/modules/cms/widgets/assetlist/assets/less/assetlist.less @@ -0,0 +1,236 @@ +@import "../../../../../backend/assets/less/core/boot.less"; + +.control-assetlist { + p.no-data { + padding: 22px; + margin: 0; + color: @color-filelist-norecords-text; + font-size: 14px; + text-align: center; + font-weight: 400; + .border-radius(@border-radius-base); + } + + p.parent, ul li { + font-weight: 300; + line-height: 150%; + margin-bottom: 0; + + &.active a { + background: @color-list-active; + position: relative; + &:after { + position: absolute; + height: 100%; + width: 4px; + left: 0; + top: 0; + background: @color-list-active-border; + display: block; + content: ' '; + } + } + + a.link { + display: block; + position: relative; + word-wrap: break-word; + padding: 10px 50px 10px 20px; + outline: none; + font-weight: 400; + color: @color-text-title; + font-size: 14px; + + &:hover, &:focus, &:active {text-decoration: none;} + + span { + display: block; + + &.description { + color: @color-text-description; + font-size: 12px; + font-weight: 400; + word-wrap: break-word; + + strong { + color: @color-text-title; + font-weight: 400; + } + } + } + } + + &.directory, &.parent { + a.link { + padding-left: 40px; + + &:after { + display: block; + position: absolute; + width: 10px; + height: 10px; + top: 10px; + left: 20px; + .icon(@folder); + color: @color-list-icon; + font-size: 14px; + } + } + } + + &.parent { + a.link { + padding-left: 41px; + background-color: @color-list-parent-bg; + word-wrap: break-word; + + &:before { + content: ''; + height: 1px; + display: block; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 1px; + background: #ecf0f1; + } + + + &:after { + font-size: 13px; + color: @color-list-nav-arrow; + width: 18px; + height: 18px; + top: 11px; + left: 22px; + .opacity(0.5); + .icon(@chevron-left); + } + } + } + } + + p.parent a.link:hover { + background: @color-list-active!important; + + &:after { + .opacity(1); + } + + &:before { + display: none; + } + } + + ul { + padding: 0; + margin: 0; + + li { + font-weight: 300; + line-height: 150%; + position: relative; + list-style: none; + + &.active a.link, a.link:hover {background: @color-list-active;} + &.active a.link { + position: relative; + &:after { + position: absolute; + height: 100%; + width: 4px; + left: 0; + top: 0; + background: @color-list-active-border; + display: block; + content: ' '; + } + } + + div.controls { + position: absolute; + right: 45px; + top: 10px; + + .dropdown { + width: 14px; + height: 21px; + + &.open a.control { + display: block!important; + &:before { + visibility: visible; + display: block; + } + } + } + + a.control { + color: @color-text-title; + font-size: 14px; + visibility: hidden; + overflow: hidden; + width: 14px; + height: 21px; + display: none; + text-decoration: none; + cursor: pointer; + .opacity(0.5); + &:before { + visibility: visible; + display: block; + margin-right: 0; + } + + &:hover { + .opacity(1); + } + } + } + + &:hover { + background: @color-list-active; + div.controls, a.control { + display: block!important; + + > a.control { + display: block!important; + } + } + } + + .checkbox { + position: absolute; + top: -5px; + right: -5px; + + label { + margin-right: 0; + + &:before { + border-color: @color-filelist-cb-border; + } + } + } + } + } + + div.list-container { + position: relative; + .translate(0, 0); + + &.animate ul { + .transition(all 0.2s ease); + } + + &.goForward ul { + .translate(-350px, 0); + } + + &.goBackward ul { + .translate(350px, 0); + } + + } +} diff --git a/modules/cms/widgets/assetlist/partials/_body.htm b/modules/cms/widgets/assetlist/partials/_body.htm new file mode 100644 index 0000000..27ca4f6 --- /dev/null +++ b/modules/cms/widgets/assetlist/partials/_body.htm @@ -0,0 +1,9 @@ +makePartial('toolbar') ?> +
    +
    +
    + makePartial('files', ['data'=>$data]) ?> +
    +
    +
    + diff --git a/modules/cms/widgets/assetlist/partials/_files.htm b/modules/cms/widgets/assetlist/partials/_files.htm new file mode 100644 index 0000000..2462542 --- /dev/null +++ b/modules/cms/widgets/assetlist/partials/_files.htm @@ -0,0 +1,7 @@ +
    +
    +
    + makePartial('items', ['items'=>$data]) ?> +
    +
    +
    \ No newline at end of file diff --git a/modules/cms/widgets/assetlist/partials/_items.htm b/modules/cms/widgets/assetlist/partials/_items.htm new file mode 100644 index 0000000..72fd066 --- /dev/null +++ b/modules/cms/widgets/assetlist/partials/_items.htm @@ -0,0 +1,61 @@ +isSearchMode(); + + if (($upPath = $this->getUpPath()) !== null && !$searchMode): +?> +

    + getCurrentRelativePath() ?> +

    + +
    + +
      + theme->getDirName().'-'.ltrim($item->path, '/'); + ?> +
    • editable): ?>data-editable data-item-path="path, '/')) ?>" data-item-theme="theme->getDirName()) ?>" data-item-type="asset" data-id=""> + + name) ?> + + + + path)) ?> + + + + +
      + +
      + + +
      + path) ?> + isItemSelected($item->path) ? 'checked' : null ?> + data-request="getEventHandler('onSelect') ?>" + value="1"> + +
      + +
    • + +
    + +

    noRecordsMessage)) ?>

    + +
    + + + + diff --git a/modules/cms/widgets/assetlist/partials/_move_form.htm b/modules/cms/widgets/assetlist/partials/_move_form.htm new file mode 100644 index 0000000..37cbcc7 --- /dev/null +++ b/modules/cms/widgets/assetlist/partials/_move_form.htm @@ -0,0 +1,41 @@ +$this->getEventHandler('onMove'), + 'data-request-success'=>"\$(this).trigger('close.oc.popup')", + 'data-stripe-load-indicator'=>1, + 'id'=>'asset-move-popup-form' +]) ?> + + + + \ No newline at end of file diff --git a/modules/cms/widgets/assetlist/partials/_new_dir_form.htm b/modules/cms/widgets/assetlist/partials/_new_dir_form.htm new file mode 100644 index 0000000..027c574 --- /dev/null +++ b/modules/cms/widgets/assetlist/partials/_new_dir_form.htm @@ -0,0 +1,43 @@ +$this->getEventHandler('onNewDirectory'), + 'data-request-success'=>"\$(this).trigger('close.oc.popup')", + 'data-stripe-load-indicator'=>1, + 'id'=>'asset-new-dir-popup-form' +]) ?> + + + + + \ No newline at end of file diff --git a/modules/cms/widgets/assetlist/partials/_rename_form.htm b/modules/cms/widgets/assetlist/partials/_rename_form.htm new file mode 100644 index 0000000..2a23302 --- /dev/null +++ b/modules/cms/widgets/assetlist/partials/_rename_form.htm @@ -0,0 +1,43 @@ +getEventHandler('onApplyName'), [ + 'success' => "\$el.trigger('close.oc.popup');", + 'data-stripe-load-indicator' => 1, + 'id' => 'asset-rename-popup-form' +]) ?> + + + + + \ No newline at end of file diff --git a/modules/cms/widgets/assetlist/partials/_toolbar.htm b/modules/cms/widgets/assetlist/partials/_toolbar.htm new file mode 100644 index 0000000..e0d44f2 --- /dev/null +++ b/modules/cms/widgets/assetlist/partials/_toolbar.htm @@ -0,0 +1,78 @@ +
    +
    + + +
    +
    + + + +
    +
    + + +
    + +
    + +
    +
    \ No newline at end of file diff --git a/modules/cms/widgets/componentlist/partials/_body.htm b/modules/cms/widgets/componentlist/partials/_body.htm new file mode 100644 index 0000000..d917426 --- /dev/null +++ b/modules/cms/widgets/componentlist/partials/_body.htm @@ -0,0 +1,8 @@ +makePartial('toolbar') ?> +
    +
    +
    + makePartial('components', ['data'=>$data]) ?> +
    +
    +
    diff --git a/modules/cms/widgets/componentlist/partials/_component_list.htm b/modules/cms/widgets/componentlist/partials/_component_list.htm new file mode 100644 index 0000000..f95cd29 --- /dev/null +++ b/modules/cms/widgets/componentlist/partials/_component_list.htm @@ -0,0 +1,39 @@ +
    +
    +
    + + $component): ?> + 0 && ($index % 2) == 0): ?> +
    + + +
    +
    + + +
    + +
    +
    + title) ?> + description) ?> + alias) ?> + + + + + + + + + + + × +
    +
    + +
    +
    +
    \ No newline at end of file diff --git a/modules/cms/widgets/componentlist/partials/_components.htm b/modules/cms/widgets/componentlist/partials/_components.htm new file mode 100644 index 0000000..cf7a601 --- /dev/null +++ b/modules/cms/widgets/componentlist/partials/_components.htm @@ -0,0 +1,11 @@ +
    +
    +
    + makePartial('items', ['items'=>$data]) ?> +
    +
    +
    \ No newline at end of file diff --git a/modules/cms/widgets/componentlist/partials/_items.htm b/modules/cms/widgets/componentlist/partials/_items.htm new file mode 100644 index 0000000..8abe913 --- /dev/null +++ b/modules/cms/widgets/componentlist/partials/_items.htm @@ -0,0 +1,16 @@ + +
      + +
    • +
      +

      title)) ?>

      + + description)) ?> +
      + makePartial('component_list', ['components'=>$item->items]) ?> +
    • + +
    + +

    + \ No newline at end of file diff --git a/modules/cms/widgets/componentlist/partials/_toolbar.htm b/modules/cms/widgets/componentlist/partials/_toolbar.htm new file mode 100644 index 0000000..66c1ef7 --- /dev/null +++ b/modules/cms/widgets/componentlist/partials/_toolbar.htm @@ -0,0 +1,16 @@ +
    +
    + + +
    + +
    + +
    +
    diff --git a/modules/cms/widgets/templatelist/partials/_body.htm b/modules/cms/widgets/templatelist/partials/_body.htm new file mode 100644 index 0000000..a4273cb --- /dev/null +++ b/modules/cms/widgets/templatelist/partials/_body.htm @@ -0,0 +1,8 @@ +makePartial('toolbar') ?> +
    +
    +
    + makePartial('templates', ['data' => $data]) ?> +
    +
    +
    diff --git a/modules/cms/widgets/templatelist/partials/_items.htm b/modules/cms/widgets/templatelist/partials/_items.htm new file mode 100644 index 0000000..60f5d90 --- /dev/null +++ b/modules/cms/widgets/templatelist/partials/_items.htm @@ -0,0 +1,59 @@ + + + +

    noRecordsMessage)) ?>

    + + + + + \ No newline at end of file diff --git a/modules/cms/widgets/templatelist/partials/_sorting-options.htm b/modules/cms/widgets/templatelist/partials/_sorting-options.htm new file mode 100644 index 0000000..4aacc07 --- /dev/null +++ b/modules/cms/widgets/templatelist/partials/_sorting-options.htm @@ -0,0 +1,7 @@ +sortingProperties as $propertyName=>$propertyTitle): ?> +
  • getSortingProperty() == $propertyName): ?>class="active"> + + + +
  • + diff --git a/modules/cms/widgets/templatelist/partials/_templates.htm b/modules/cms/widgets/templatelist/partials/_templates.htm new file mode 100644 index 0000000..e1f0b86 --- /dev/null +++ b/modules/cms/widgets/templatelist/partials/_templates.htm @@ -0,0 +1,11 @@ +
    +
    +
    + makePartial('items', ['items' => $data]) ?> +
    +
    +
    diff --git a/modules/cms/widgets/templatelist/partials/_toolbar.htm b/modules/cms/widgets/templatelist/partials/_toolbar.htm new file mode 100644 index 0000000..8371b23 --- /dev/null +++ b/modules/cms/widgets/templatelist/partials/_toolbar.htm @@ -0,0 +1,51 @@ +
    +
    + + +
    +
    + + + sortingProperties): ?> + + + + +
    +
    + + +
    + +
    + +
    +
    diff --git a/modules/system/ServiceProvider.php b/modules/system/ServiceProvider.php new file mode 100644 index 0000000..3b4f504 --- /dev/null +++ b/modules/system/ServiceProvider.php @@ -0,0 +1,605 @@ +registerSingletons(); + $this->registerPrivilegedActions(); + + /* + * Register all plugins + */ + PluginManager::instance()->registerAll(); + + $this->registerConsole(); + $this->registerErrorHandler(); + $this->registerLogging(); + $this->registerTwigParser(); + $this->registerMailer(); + $this->registerMarkupTags(); + $this->registerAssetBundles(); + $this->registerValidator(); + $this->registerGlobalViewVars(); + + /* + * Register other module providers + */ + foreach (Config::get('cms.loadModules', []) as $module) { + if (strtolower(trim($module)) != 'system') { + App::register('\\' . $module . '\ServiceProvider'); + } + } + + /* + * Backend specific + */ + if (App::runningInBackend()) { + $this->registerBackendNavigation(); + $this->registerBackendReportWidgets(); + $this->registerBackendPermissions(); + $this->registerBackendSettings(); + } + } + + /** + * Bootstrap the module events. + * + * @return void + */ + public function boot() + { + // Fix UTF8MB4 support for MariaDB < 10.2 and MySQL < 5.7 + $this->applyDatabaseDefaultStringLength(); + + // Fix use of Storage::url() for local disks that haven't been configured correctly + foreach (Config::get('filesystems.disks') as $key => $config) { + if ($config['driver'] === 'local' && ends_with($config['root'], '/storage/app') && empty($config['url'])) { + Config::set("filesystems.disks.$key.url", '/storage/app'); + } + } + + /* + * Set a default samesite config value for invalid values + */ + if (!in_array(strtolower(Config::get('session.same_site')), ['lax', 'strict', 'none'])) { + Config::set('session.same_site', 'Lax'); + } + + Paginator::useBootstrapThree(); + Paginator::defaultSimpleView('system::pagination.simple-default'); + + /* + * Boot plugins + */ + PluginManager::instance()->bootAll(); + + parent::boot('system'); + } + + /** + * Register singletons + */ + protected function registerSingletons() + { + App::singleton('cms.helper', function () { + return new \Cms\Helpers\Cms; + }); + + App::singleton('backend.helper', function () { + return new \Backend\Helpers\Backend; + }); + + App::singleton('backend.menu', function () { + return \Backend\Classes\NavigationManager::instance(); + }); + + App::singleton('backend.auth', function () { + return \Backend\Classes\AuthManager::instance(); + }); + } + + /** + * Check for CLI or system/updates route and disable any plugin initialization + */ + protected function registerPrivilegedActions() + { + $requests = ['/combine/', '@/system/updates', '@/system/install', '@/backend/auth']; + $commands = ['october:up', 'october:update', 'october:env', 'october:version']; + + /* + * Requests + */ + $path = RouterHelper::normalizeUrl(Request::path()); + $backendUri = RouterHelper::normalizeUrl(Config::get('cms.backendUri', 'backend')); + foreach ($requests as $request) { + if (substr($request, 0, 1) == '@') { + $request = $backendUri . substr($request, 1); + } + + if (stripos($path, $request) === 0) { + PluginManager::$noInit = true; + } + } + + /* + * CLI + */ + if (App::runningInConsole() && count(array_intersect($commands, Request::server('argv', []))) > 0) { + PluginManager::$noInit = true; + } + } + + /* + * Register markup tags + */ + protected function registerMarkupTags() + { + MarkupManager::instance()->registerCallback(function ($manager) { + $manager->registerFunctions([ + // Functions + 'input' => 'input', + 'post' => 'post', + 'get' => 'get', + 'link_to' => 'link_to', + 'link_to_asset' => 'link_to_asset', + 'link_to_route' => 'link_to_route', + 'link_to_action' => 'link_to_action', + 'asset' => 'asset', + 'action' => 'action', + 'url' => 'url', + 'route' => 'route', + 'secure_url' => 'secure_url', + 'secure_asset' => 'secure_asset', + + // Classes + 'str_*' => ['Str', '*'], + 'url_*' => ['Url', '*'], + 'html_*' => ['Html', '*'], + 'form_*' => ['Form', '*'], + 'form_macro' => ['Form', '__call'] + ]); + + $manager->registerFilters([ + // Classes + 'slug' => ['Str', 'slug'], + 'plural' => ['Str', 'plural'], + 'singular' => ['Str', 'singular'], + 'finish' => ['Str', 'finish'], + 'snake' => ['Str', 'snake'], + 'camel' => ['Str', 'camel'], + 'studly' => ['Str', 'studly'], + 'trans' => ['Lang', 'get'], + 'transchoice' => ['Lang', 'choice'], + 'md' => ['Markdown', 'parse'], + 'md_safe' => ['Markdown', 'parseSafe'], + 'time_since' => ['System\Helpers\DateTime', 'timeSince'], + 'time_tense' => ['System\Helpers\DateTime', 'timeTense'], + ]); + }); + } + + /** + * Register command line specifics + */ + protected function registerConsole() + { + /* + * Allow plugins to use the scheduler + */ + Event::listen('console.schedule', function ($schedule) { + // Fix initial system migration with plugins that use settings for scheduling - see #3208 + if (App::hasDatabase() && !Schema::hasTable(UpdateManager::instance()->getMigrationTableName())) { + return; + } + + $plugins = PluginManager::instance()->getPlugins(); + foreach ($plugins as $plugin) { + if (method_exists($plugin, 'registerSchedule')) { + $plugin->registerSchedule($schedule); + } + } + }); + + /* + * Add CMS based cache clearing to native command + */ + Event::listen('cache:cleared', function () { + \System\Helpers\Cache::clearInternal(); + }); + + /* + * Register console commands + */ + $this->registerConsoleCommand('october.up', 'System\Console\OctoberUp'); + $this->registerConsoleCommand('october.down', 'System\Console\OctoberDown'); + $this->registerConsoleCommand('october.update', 'System\Console\OctoberUpdate'); + $this->registerConsoleCommand('october.util', 'System\Console\OctoberUtil'); + $this->registerConsoleCommand('october.mirror', 'System\Console\OctoberMirror'); + $this->registerConsoleCommand('october.fresh', 'System\Console\OctoberFresh'); + $this->registerConsoleCommand('october.env', 'System\Console\OctoberEnv'); + $this->registerConsoleCommand('october.install', 'System\Console\OctoberInstall'); + $this->registerConsoleCommand('october.passwd', 'System\Console\OctoberPasswd'); + $this->registerConsoleCommand('october.version', 'System\Console\OctoberVersion'); + $this->registerConsoleCommand('october.manifest', 'System\Console\OctoberManifest'); + + $this->registerConsoleCommand('plugin.install', 'System\Console\PluginInstall'); + $this->registerConsoleCommand('plugin.remove', 'System\Console\PluginRemove'); + $this->registerConsoleCommand('plugin.disable', 'System\Console\PluginDisable'); + $this->registerConsoleCommand('plugin.enable', 'System\Console\PluginEnable'); + $this->registerConsoleCommand('plugin.refresh', 'System\Console\PluginRefresh'); + $this->registerConsoleCommand('plugin.rollback', 'System\Console\PluginRollback'); + $this->registerConsoleCommand('plugin.list', 'System\Console\PluginList'); + + $this->registerConsoleCommand('theme.install', 'System\Console\ThemeInstall'); + $this->registerConsoleCommand('theme.remove', 'System\Console\ThemeRemove'); + $this->registerConsoleCommand('theme.list', 'System\Console\ThemeList'); + $this->registerConsoleCommand('theme.use', 'System\Console\ThemeUse'); + $this->registerConsoleCommand('theme.sync', 'System\Console\ThemeSync'); + } + + /* + * Error handling for uncaught Exceptions + */ + protected function registerErrorHandler() + { + Event::listen('exception.beforeRender', function ($exception, $httpCode, $request) { + $handler = new ErrorHandler; + return $handler->handleException($exception); + }); + } + + /* + * Write all log events to the database + */ + protected function registerLogging() + { + Event::listen(\Illuminate\Log\Events\MessageLogged::class, function ($event) { + if (EventLog::useLogging()) { + EventLog::add($event->message, $event->level, $event->context); + } + }); + } + + /* + * Register text twig parser + */ + protected function registerTwigParser() + { + /* + * Register system Twig environment + */ + App::singleton('twig.environment', function ($app) { + $twig = new TwigEnvironment(new TwigLoader, ['auto_reload' => true]); + $twig->addExtension(new TwigExtension); + $twig->addExtension(new SandboxExtension(new TwigSecurityPolicy, true)); + return $twig; + }); + + /* + * Register .htm extension for Twig views + */ + App::make('view')->addExtension('htm', 'twig', function () { + return new TwigEngine(App::make('twig.environment')); + }); + } + + /** + * Register mail templating and settings override. + */ + protected function registerMailer() + { + /* + * Register system layouts + */ + MailManager::instance()->registerCallback(function ($manager) { + $manager->registerMailLayouts([ + 'default' => 'system::mail.layout-default', + 'system' => 'system::mail.layout-system', + ]); + + $manager->registerMailPartials([ + 'header' => 'system::mail.partial-header', + 'footer' => 'system::mail.partial-footer', + 'button' => 'system::mail.partial-button', + 'panel' => 'system::mail.partial-panel', + 'table' => 'system::mail.partial-table', + 'subcopy' => 'system::mail.partial-subcopy', + 'promotion' => 'system::mail.partial-promotion', + ]); + }); + + /* + * Override system mailer with mail settings + */ + Event::listen('mailer.beforeRegister', function () { + if (MailSetting::isConfigured()) { + MailSetting::applyConfigValues(); + } + }); + + /* + * Override standard Mailer content with template + */ + Event::listen('mailer.beforeAddContent', function ($mailer, $message, $view, $data, $raw, $plain) { + $method = $raw === null ? 'addContentToMailer' : 'addRawContentToMailer'; + $plainOnly = $view === null; // When "plain-text only" email is sent, $view is null, this sets the flag appropriately + return !MailManager::instance()->$method($message, $raw ?: $view ?: $plain, $data, $plainOnly); + }); + } + + /* + * Register navigation + */ + protected function registerBackendNavigation() + { + BackendMenu::registerCallback(function ($manager) { + $manager->registerMenuItems('October.System', [ + 'system' => [ + 'label' => 'system::lang.settings.menu_label', + 'icon' => 'icon-cog', + 'iconSvg' => 'modules/system/assets/images/cog-icon.svg', + 'url' => Backend::url('system/settings'), + 'permissions' => [], + 'order' => 1000 + ] + ]); + }); + + /* + * Register the sidebar for the System main menu + */ + BackendMenu::registerContextSidenavPartial( + 'October.System', + 'system', + '~/modules/system/partials/_system_sidebar.htm' + ); + + /* + * Remove the October.System.system main menu item if there is no subpages to display + */ + Event::listen('backend.menu.extendItems', function ($manager) { + $systemSettingItems = SettingsManager::instance()->listItems('system'); + $systemMenuItems = $manager->listSideMenuItems('October.System', 'system'); + + if (empty($systemSettingItems) && empty($systemMenuItems)) { + $manager->removeMainMenuItem('October.System', 'system'); + } + }, -9999); + } + + /* + * Register report widgets + */ + protected function registerBackendReportWidgets() + { + WidgetManager::instance()->registerReportWidgets(function ($manager) { + $manager->registerReportWidget(\System\ReportWidgets\Status::class, [ + 'label' => 'backend::lang.dashboard.status.widget_title_default', + 'context' => 'dashboard' + ]); + }); + } + + /* + * Register permissions + */ + protected function registerBackendPermissions() + { + BackendAuth::registerCallback(function ($manager) { + $manager->registerPermissions('October.System', [ + 'system.manage_updates' => [ + 'label' => 'system::lang.permissions.manage_software_updates', + 'tab' => 'system::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + ], + 'system.access_logs' => [ + 'label' => 'system::lang.permissions.access_logs', + 'tab' => 'system::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + ], + 'system.manage_mail_settings' => [ + 'label' => 'system::lang.permissions.manage_mail_settings', + 'tab' => 'system::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + ], + 'system.manage_mail_templates' => [ + 'label' => 'system::lang.permissions.manage_mail_templates', + 'tab' => 'system::lang.permissions.name', + 'roles' => UserRole::CODE_DEVELOPER, + ] + ]); + }); + } + + /* + * Register settings + */ + protected function registerBackendSettings() + { + Event::listen('system.settings.extendItems', function ($manager) { + \System\Models\LogSetting::filterSettingItems($manager); + }); + + SettingsManager::instance()->registerCallback(function ($manager) { + $manager->registerSettingItems('October.System', [ + 'updates' => [ + 'label' => 'system::lang.updates.menu_label', + 'description' => 'system::lang.updates.menu_description', + 'category' => SettingsManager::CATEGORY_SYSTEM, + 'icon' => 'icon-cloud-download', + 'url' => Backend::url('system/updates'), + 'permissions' => ['system.manage_updates'], + 'order' => 300 + ], + 'administrators' => [ + 'label' => 'backend::lang.user.menu_label', + 'description' => 'backend::lang.user.menu_description', + 'category' => SettingsManager::CATEGORY_SYSTEM, + 'icon' => 'icon-users', + 'url' => Backend::url('backend/users'), + 'permissions' => ['backend.manage_users'], + 'order' => 400 + ], + 'mail_templates' => [ + 'label' => 'system::lang.mail_templates.menu_label', + 'description' => 'system::lang.mail_templates.menu_description', + 'category' => SettingsManager::CATEGORY_MAIL, + 'icon' => 'icon-envelope-square', + 'url' => Backend::url('system/mailtemplates'), + 'permissions' => ['system.manage_mail_templates'], + 'order' => 610 + ], + 'mail_settings' => [ + 'label' => 'system::lang.mail.menu_label', + 'description' => 'system::lang.mail.menu_description', + 'category' => SettingsManager::CATEGORY_MAIL, + 'icon' => 'icon-envelope', + 'class' => 'System\Models\MailSetting', + 'permissions' => ['system.manage_mail_settings'], + 'order' => 620 + ], + 'mail_brand_settings' => [ + 'label' => 'system::lang.mail_brand.menu_label', + 'description' => 'system::lang.mail_brand.menu_description', + 'category' => SettingsManager::CATEGORY_MAIL, + 'icon' => 'icon-paint-brush', + 'url' => Backend::url('system/mailbrandsettings'), + 'permissions' => ['system.manage_mail_templates'], + 'order' => 630 + ], + 'event_logs' => [ + 'label' => 'system::lang.event_log.menu_label', + 'description' => 'system::lang.event_log.menu_description', + 'category' => SettingsManager::CATEGORY_LOGS, + 'icon' => 'icon-exclamation-triangle', + 'url' => Backend::url('system/eventlogs'), + 'permissions' => ['system.access_logs'], + 'order' => 900, + 'keywords' => 'error exception' + ], + 'request_logs' => [ + 'label' => 'system::lang.request_log.menu_label', + 'description' => 'system::lang.request_log.menu_description', + 'category' => SettingsManager::CATEGORY_LOGS, + 'icon' => 'icon-file-o', + 'url' => Backend::url('system/requestlogs'), + 'permissions' => ['system.access_logs'], + 'order' => 910, + 'keywords' => '404 error' + ], + 'log_settings' => [ + 'label' => 'system::lang.log.menu_label', + 'description' => 'system::lang.log.menu_description', + 'category' => SettingsManager::CATEGORY_LOGS, + 'icon' => 'icon-dot-circle-o', + 'class' => 'System\Models\LogSetting', + 'permissions' => ['system.manage_logs'], + 'order' => 990 + ], + ]); + }); + } + + /** + * Register asset bundles + */ + protected function registerAssetBundles() + { + /* + * Register asset bundles + */ + CombineAssets::registerCallback(function ($combiner) { + $combiner->registerBundle('~/modules/system/assets/less/styles.less'); + $combiner->registerBundle('~/modules/system/assets/ui/storm.less'); + $combiner->registerBundle('~/modules/system/assets/ui/storm.js'); + $combiner->registerBundle('~/modules/system/assets/js/framework.js'); + $combiner->registerBundle('~/modules/system/assets/js/framework.combined.js'); + $combiner->registerBundle('~/modules/system/assets/css/framework.extras.css'); + }); + } + + /** + * Extends the validator with custom rules + */ + protected function registerValidator() + { + $this->app->resolving('validator', function ($validator) { + /* + * Allowed file extensions, as opposed to mime types. + * - extensions: png,jpg,txt + */ + $validator->extend('extensions', function ($attribute, $value, $parameters) { + $extension = strtolower($value->getClientOriginalExtension()); + return in_array($extension, $parameters); + }); + + $validator->replacer('extensions', function ($message, $attribute, $rule, $parameters) { + return strtr($message, [':values' => implode(', ', $parameters)]); + }); + }); + } + + protected function registerGlobalViewVars() + { + View::share('appName', Config::get('app.name')); + } + + /** + * Fix UTF8MB4 support for old versions of MariaDB (<10.2) and MySQL (<5.7) + */ + protected function applyDatabaseDefaultStringLength() + { + if (Db::getDriverName() !== 'mysql') { + return; + } + + $defaultStrLen = Db::getConfig('varcharmax'); + + if ($defaultStrLen === null && Db::getConfig('charset') === 'utf8mb4') { + $defaultStrLen = 191; + } + + if ($defaultStrLen !== null) { + Schema::defaultStringLength((int) $defaultStrLen); + } + } +} diff --git a/modules/system/aliases.php b/modules/system/aliases.php new file mode 100644 index 0000000..0318eb6 --- /dev/null +++ b/modules/system/aliases.php @@ -0,0 +1,72 @@ + Illuminate\Support\Facades\App::class, + 'Artisan' => Illuminate\Support\Facades\Artisan::class, + 'Bus' => Illuminate\Support\Facades\Bus::class, + 'Cache' => Illuminate\Support\Facades\Cache::class, + 'Cookie' => Illuminate\Support\Facades\Cookie::class, + 'Crypt' => Illuminate\Support\Facades\Crypt::class, + 'Db' => Illuminate\Support\Facades\DB::class, // Preferred + 'DB' => Illuminate\Support\Facades\DB::class, + 'Eloquent' => Illuminate\Database\Eloquent\Model::class, + 'Event' => Illuminate\Support\Facades\Event::class, + 'Hash' => Illuminate\Support\Facades\Hash::class, + 'Lang' => Illuminate\Support\Facades\Lang::class, + 'Log' => Illuminate\Support\Facades\Log::class, + 'Queue' => Illuminate\Support\Facades\Queue::class, + 'Redirect' => Illuminate\Support\Facades\Redirect::class, + 'Redis' => Illuminate\Support\Facades\Redis::class, + 'Request' => Illuminate\Support\Facades\Request::class, + 'Response' => Illuminate\Support\Facades\Response::class, + 'Route' => Illuminate\Support\Facades\Route::class, + 'Session' => Illuminate\Support\Facades\Session::class, + 'Storage' => Illuminate\Support\Facades\Storage::class, + 'Url' => Illuminate\Support\Facades\URL::class, // Preferred + 'URL' => Illuminate\Support\Facades\URL::class, + 'View' => Illuminate\Support\Facades\View::class, + + /* + * October aliases + */ + 'AjaxException' => October\Rain\Exception\AjaxException::class, + 'ApplicationException' => October\Rain\Exception\ApplicationException::class, + 'BackendAuth' => Backend\Facades\BackendAuth::class, + 'Backend' => Backend\Facades\Backend::class, + 'BackendMenu' => Backend\Facades\BackendMenu::class, + 'Block' => October\Rain\Support\Facades\Block::class, + 'Cms' => Cms\Facades\Cms::class, + 'Config' => October\Rain\Support\Facades\Config::class, + 'DbDongle' => October\Rain\Support\Facades\DbDongle::class, + 'File' => October\Rain\Support\Facades\File::class, + 'Flash' => October\Rain\Support\Facades\Flash::class, + 'Form' => October\Rain\Support\Facades\Form::class, + 'Html' => October\Rain\Support\Facades\Html::class, + 'Http' => October\Rain\Support\Facades\Http::class, + 'Ini' => October\Rain\Support\Facades\Ini::class, + 'Input' => October\Rain\Support\Facades\Input::class, + 'Mail' => October\Rain\Support\Facades\Mail::class, + 'Markdown' => October\Rain\Support\Facades\Markdown::class, + 'Model' => October\Rain\Database\Model::class, + 'Schema' => October\Rain\Support\Facades\Schema::class, + 'Seeder' => October\Rain\Database\Updates\Seeder::class, + 'Str' => October\Rain\Support\Facades\Str::class, + 'SystemException' => October\Rain\Exception\SystemException::class, + 'Twig' => October\Rain\Support\Facades\Twig::class, + 'ValidationException' => October\Rain\Exception\ValidationException::class, + 'Validator' => October\Rain\Support\Facades\Validator::class, + 'Yaml' => October\Rain\Support\Facades\Yaml::class, + + /* + * Fallback aliases + */ + // Input facade was removed in Laravel 6 - we are keeping it in the Rain library for backwards compatibility. + 'Illuminate\Support\Facades\Input' => October\Rain\Support\Facades\Input::class, + + // Illuminate's HtmlDumper was "dumped" in Laravel 6 - we'll route this to Symfony's HtmlDumper as Laravel have done. + 'Illuminate\Support\Debug\HtmlDumper' => Symfony\Component\VarDumper\Dumper\HtmlDumper::class, +]; diff --git a/modules/system/assets/css/eventlogs/exception-beautifier.css b/modules/system/assets/css/eventlogs/exception-beautifier.css new file mode 100644 index 0000000..0307ffb --- /dev/null +++ b/modules/system/assets/css/eventlogs/exception-beautifier.css @@ -0,0 +1,135 @@ +.plugin-exception-beautifier .beautifier-message-container { + display: block; + padding: 20px; + background: #fff; +} + +.plugin-exception-beautifier .beautifier-message { + display: block; + font-size: 1.1em; + word-wrap: break-word; + word-break: break-word; +} + +.plugin-exception-beautifier .beautifier-toggle-stacktrace { + background: #ecf0f1; + color: #2b3e50; + text-decoration: none; + display: block; + padding: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + margin-top: 20px; +} + +.plugin-exception-beautifier .beautifier-toggle-stacktrace:hover { + background: #0181b9; + color: white; +} + +.plugin-exception-beautifier .beautifier-stacktrace-line { + display: block; + padding: 10px 0; + word-wrap: break-word; + word-break: break-word; +} + +.plugin-exception-beautifier .beautifier-stacktrace-line:nth-child(even) { + background-color: #ffffff; +} + +.plugin-exception-beautifier .beautifier-stacktrace-line:nth-child(odd) { + background-color: #f2f2f2; +} + +.plugin-exception-beautifier .beautifier-stacktrace-line > * { + margin-left: 55px; + display: block; +} + +.plugin-exception-beautifier .beautifier-stacktrace-line-number { + float: left; + width: 40px; + margin-left: 0; + margin-right: 15px; + text-align: right; + color: #000000; +} + +.plugin-exception-beautifier .beautifier-stacktrace-line-internal { + color: #2C3E50; +} + +.plugin-exception-beautifier .beautifier-stacktrace-line-function { + display: block; + margin-left: 55px; +} + +.plugin-exception-beautifier .beautifier-file { + color: #204bff; + word-wrap: break-word; + word-break: break-word; +} + +.plugin-exception-beautifier .beautifier-line-number { + color: #af0016; +} + +.plugin-exception-beautifier .beautifier-string, +.plugin-exception-beautifier .beautifier-number, +.plugin-exception-beautifier .beautifier-class, +.plugin-exception-beautifier .beautifier-code, +.plugin-exception-beautifier .beautifier-function, +.plugin-exception-beautifier .beautifier-system-function { + font-family: monospace; +} + +.plugin-exception-beautifier .beautifier-class, +.plugin-exception-beautifier .beautifier-function, +.plugin-exception-beautifier .beautifier-system-function { + font-weight: bold; +} + +.plugin-exception-beautifier .beautifier-class { + color: #252623; +} + +.plugin-exception-beautifier .beautifier-function { + color: #cc204d; +} + +.plugin-exception-beautifier .beautifier-system-function { + color: #e33a37; +} + +.plugin-exception-beautifier .beautifier-code { + color: #736b88; +} + +.plugin-exception-beautifier .beautifier-string { + color: #0EA804; +} + +.plugin-exception-beautifier .beautifier-number { + color: #2196F3; +} + +.plugin-exception-beautifier .beautifier-formatted-content, +.plugin-exception-beautifier .beautifier-raw-content { + background: #fff; + padding: 20px; +} + +.plugin-exception-beautifier .beautifier-raw-content { + font-family: monospace; + white-space: nowrap; + overflow: auto; + width: 100%; +} + +.plugin-exception-beautifier .beautifier-raw-content br { + content: ''; + display: block; + margin-bottom: 15px; +} diff --git a/modules/system/assets/css/framework.extras-min.css b/modules/system/assets/css/framework.extras-min.css new file mode 100644 index 0000000..71c327f --- /dev/null +++ b/modules/system/assets/css/framework.extras-min.css @@ -0,0 +1,37 @@ +body.oc-loading, +body.oc-loading * {cursor:wait !important} +.stripe-loading-indicator {height:5px;background:transparent;position:fixed;top:0;left:0;width:100%;overflow:hidden;z-index:2000} +.stripe-loading-indicator .stripe, +.stripe-loading-indicator .stripe-loaded {height:5px;display:block;background:#0090c0;position:absolute;-webkit-box-shadow:inset 0 1px 1px -1px #FFF,inset 0 -1px 1px -1px #FFF;box-shadow:inset 0 1px 1px -1px #FFF,inset 0 -1px 1px -1px #FFF} +.stripe-loading-indicator .stripe {width:100%;-webkit-animation:oc-infinite-loader 60s linear;animation:oc-infinite-loader 60s linear} +.stripe-loading-indicator .stripe-loaded {width:100%;transform:translate3d(-100%,0,0);opacity:0;filter:alpha(opacity=0)} +.stripe-loading-indicator.loaded {opacity:0;filter:alpha(opacity=0);-webkit-transition:opacity 0.4s linear;transition:opacity 0.4s linear;-webkit-transition-delay:0.3s;transition-delay:0.3s} +.stripe-loading-indicator.loaded .stripe {animation-play-state:paused} +.stripe-loading-indicator.loaded .stripe-loaded {opacity:1;filter:alpha(opacity=100);transform:translate3d(0,0,0);-webkit-transition:transform 0.3s linear;transition:transform 0.3s linear} +.stripe-loading-indicator.hide {display:none} +body >p.flash-message {position:fixed;width:500px;left:50%;top:13px;margin-left:-250px;color:#fff;font-size:14px;padding:10px 30px 10px 15px;z-index:10300;word-wrap:break-word;text-shadow:0 -1px 0 rgba(0,0,0,0.15);text-align:center;-webkit-box-shadow:0 1px 6px rgba(0,0,0,0.12),0 1px 4px rgba(0,0,0,0.24);box-shadow:0 1px 6px rgba(0,0,0,0.12),0 1px 4px rgba(0,0,0,0.24);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +body >p.flash-message.fade {opacity:0;filter:alpha(opacity=0);-webkit-transition:all 0.5s,width 0s;transition:all 0.5s,width 0s;-webkit-transform:scale(0.9);-ms-transform:scale(0.9);transform:scale(0.9)} +body >p.flash-message.fade.in {opacity:1;filter:alpha(opacity=100);-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)} +body >p.flash-message.success {background:#8da85e} +body >p.flash-message.error {background:#c30} +body >p.flash-message.warning {background:#f0ad4e} +body >p.flash-message.info {background:#5fb6f5} +body >p.flash-message button.close {float:none;position:absolute;right:10px;top:8px;color:white;font-size:21px;line-height:1;font-weight:bold;opacity:0.2;filter:alpha(opacity=20);padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;outline:none} +body >p.flash-message button.close:hover, +body >p.flash-message button.close:focus {color:white;text-decoration:none;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)} +@media (max-width:768px) {body >p.flash-message {left:10px;right:10px;top:10px;margin-left:0;width:auto }} +[data-request][data-request-validate] [data-validate-for]:not(.visible), +[data-request][data-request-validate] [data-validate-error]:not(.visible) {display:none} +a.oc-loading:after, +button.oc-loading:after, +span.oc-loading:after {content:'';display:inline-block;vertical-align:middle;margin-left:.4em;height:1em;width:1em;animation:oc-rotate-loader 0.8s infinite linear;border:.2em solid currentColor;border-right-color:transparent;border-radius:50%;opacity:0.5;filter:alpha(opacity=50)} +@-moz-keyframes oc-rotate-loader {0% {-moz-transform:rotate(0deg) }100% {-moz-transform:rotate(360deg) }} +@-webkit-keyframes oc-rotate-loader {0% {-webkit-transform:rotate(0deg) }100% {-webkit-transform:rotate(360deg) }} +@-o-keyframes oc-rotate-loader {0% {-o-transform:rotate(0deg) }100% {-o-transform:rotate(360deg) }} +@-ms-keyframes oc-rotate-loader {0% {-ms-transform:rotate(0deg) }100% {-ms-transform:rotate(360deg) }} +@keyframes oc-rotate-loader {0% {transform:rotate(0deg) }100% {transform:rotate(360deg) }} +@-moz-keyframes oc-infinite-loader {0% {transform:translateX(-100%) }10% {transform:translateX(-50%) }20% {transform:translateX(-25%) }30% {transform:translateX(-12.5%) }40% {transform:translateX(-6.25%) }50% {transform:translateX(-3.125%) }60% {transform:translateX(-1.5625%) }70% {transform:translateX(-0.78125%) }80% {transform:translateX(-0.390625%) }90% {transform:translateX(-0.1953125%) }100% {transform:translateX(-0.09765625%) }} +@-webkit-keyframes oc-infinite-loader {0% {transform:translateX(-100%) }10% {transform:translateX(-50%) }20% {transform:translateX(-25%) }30% {transform:translateX(-12.5%) }40% {transform:translateX(-6.25%) }50% {transform:translateX(-3.125%) }60% {transform:translateX(-1.5625%) }70% {transform:translateX(-0.78125%) }80% {transform:translateX(-0.390625%) }90% {transform:translateX(-0.1953125%) }100% {transform:translateX(-0.09765625%) }} +@-o-keyframes oc-infinite-loader {0% {transform:translateX(-100%) }10% {transform:translateX(-50%) }20% {transform:translateX(-25%) }30% {transform:translateX(-12.5%) }40% {transform:translateX(-6.25%) }50% {transform:translateX(-3.125%) }60% {transform:translateX(-1.5625%) }70% {transform:translateX(-0.78125%) }80% {transform:translateX(-0.390625%) }90% {transform:translateX(-0.1953125%) }100% {transform:translateX(-0.09765625%) }} +@-ms-keyframes oc-infinite-loader {0% {transform:translateX(-100%) }10% {transform:translateX(-50%) }20% {transform:translateX(-25%) }30% {transform:translateX(-12.5%) }40% {transform:translateX(-6.25%) }50% {transform:translateX(-3.125%) }60% {transform:translateX(-1.5625%) }70% {transform:translateX(-0.78125%) }80% {transform:translateX(-0.390625%) }90% {transform:translateX(-0.1953125%) }100% {transform:translateX(-0.09765625%) }} +@keyframes oc-infinite-loader {0% {transform:translateX(-100%) }10% {transform:translateX(-50%) }20% {transform:translateX(-25%) }30% {transform:translateX(-12.5%) }40% {transform:translateX(-6.25%) }50% {transform:translateX(-3.125%) }60% {transform:translateX(-1.5625%) }70% {transform:translateX(-0.78125%) }80% {transform:translateX(-0.390625%) }90% {transform:translateX(-0.1953125%) }100% {transform:translateX(-0.09765625%) }} \ No newline at end of file diff --git a/modules/system/assets/css/framework.extras.css b/modules/system/assets/css/framework.extras.css new file mode 100644 index 0000000..71c327f --- /dev/null +++ b/modules/system/assets/css/framework.extras.css @@ -0,0 +1,37 @@ +body.oc-loading, +body.oc-loading * {cursor:wait !important} +.stripe-loading-indicator {height:5px;background:transparent;position:fixed;top:0;left:0;width:100%;overflow:hidden;z-index:2000} +.stripe-loading-indicator .stripe, +.stripe-loading-indicator .stripe-loaded {height:5px;display:block;background:#0090c0;position:absolute;-webkit-box-shadow:inset 0 1px 1px -1px #FFF,inset 0 -1px 1px -1px #FFF;box-shadow:inset 0 1px 1px -1px #FFF,inset 0 -1px 1px -1px #FFF} +.stripe-loading-indicator .stripe {width:100%;-webkit-animation:oc-infinite-loader 60s linear;animation:oc-infinite-loader 60s linear} +.stripe-loading-indicator .stripe-loaded {width:100%;transform:translate3d(-100%,0,0);opacity:0;filter:alpha(opacity=0)} +.stripe-loading-indicator.loaded {opacity:0;filter:alpha(opacity=0);-webkit-transition:opacity 0.4s linear;transition:opacity 0.4s linear;-webkit-transition-delay:0.3s;transition-delay:0.3s} +.stripe-loading-indicator.loaded .stripe {animation-play-state:paused} +.stripe-loading-indicator.loaded .stripe-loaded {opacity:1;filter:alpha(opacity=100);transform:translate3d(0,0,0);-webkit-transition:transform 0.3s linear;transition:transform 0.3s linear} +.stripe-loading-indicator.hide {display:none} +body >p.flash-message {position:fixed;width:500px;left:50%;top:13px;margin-left:-250px;color:#fff;font-size:14px;padding:10px 30px 10px 15px;z-index:10300;word-wrap:break-word;text-shadow:0 -1px 0 rgba(0,0,0,0.15);text-align:center;-webkit-box-shadow:0 1px 6px rgba(0,0,0,0.12),0 1px 4px rgba(0,0,0,0.24);box-shadow:0 1px 6px rgba(0,0,0,0.12),0 1px 4px rgba(0,0,0,0.24);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +body >p.flash-message.fade {opacity:0;filter:alpha(opacity=0);-webkit-transition:all 0.5s,width 0s;transition:all 0.5s,width 0s;-webkit-transform:scale(0.9);-ms-transform:scale(0.9);transform:scale(0.9)} +body >p.flash-message.fade.in {opacity:1;filter:alpha(opacity=100);-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)} +body >p.flash-message.success {background:#8da85e} +body >p.flash-message.error {background:#c30} +body >p.flash-message.warning {background:#f0ad4e} +body >p.flash-message.info {background:#5fb6f5} +body >p.flash-message button.close {float:none;position:absolute;right:10px;top:8px;color:white;font-size:21px;line-height:1;font-weight:bold;opacity:0.2;filter:alpha(opacity=20);padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;outline:none} +body >p.flash-message button.close:hover, +body >p.flash-message button.close:focus {color:white;text-decoration:none;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)} +@media (max-width:768px) {body >p.flash-message {left:10px;right:10px;top:10px;margin-left:0;width:auto }} +[data-request][data-request-validate] [data-validate-for]:not(.visible), +[data-request][data-request-validate] [data-validate-error]:not(.visible) {display:none} +a.oc-loading:after, +button.oc-loading:after, +span.oc-loading:after {content:'';display:inline-block;vertical-align:middle;margin-left:.4em;height:1em;width:1em;animation:oc-rotate-loader 0.8s infinite linear;border:.2em solid currentColor;border-right-color:transparent;border-radius:50%;opacity:0.5;filter:alpha(opacity=50)} +@-moz-keyframes oc-rotate-loader {0% {-moz-transform:rotate(0deg) }100% {-moz-transform:rotate(360deg) }} +@-webkit-keyframes oc-rotate-loader {0% {-webkit-transform:rotate(0deg) }100% {-webkit-transform:rotate(360deg) }} +@-o-keyframes oc-rotate-loader {0% {-o-transform:rotate(0deg) }100% {-o-transform:rotate(360deg) }} +@-ms-keyframes oc-rotate-loader {0% {-ms-transform:rotate(0deg) }100% {-ms-transform:rotate(360deg) }} +@keyframes oc-rotate-loader {0% {transform:rotate(0deg) }100% {transform:rotate(360deg) }} +@-moz-keyframes oc-infinite-loader {0% {transform:translateX(-100%) }10% {transform:translateX(-50%) }20% {transform:translateX(-25%) }30% {transform:translateX(-12.5%) }40% {transform:translateX(-6.25%) }50% {transform:translateX(-3.125%) }60% {transform:translateX(-1.5625%) }70% {transform:translateX(-0.78125%) }80% {transform:translateX(-0.390625%) }90% {transform:translateX(-0.1953125%) }100% {transform:translateX(-0.09765625%) }} +@-webkit-keyframes oc-infinite-loader {0% {transform:translateX(-100%) }10% {transform:translateX(-50%) }20% {transform:translateX(-25%) }30% {transform:translateX(-12.5%) }40% {transform:translateX(-6.25%) }50% {transform:translateX(-3.125%) }60% {transform:translateX(-1.5625%) }70% {transform:translateX(-0.78125%) }80% {transform:translateX(-0.390625%) }90% {transform:translateX(-0.1953125%) }100% {transform:translateX(-0.09765625%) }} +@-o-keyframes oc-infinite-loader {0% {transform:translateX(-100%) }10% {transform:translateX(-50%) }20% {transform:translateX(-25%) }30% {transform:translateX(-12.5%) }40% {transform:translateX(-6.25%) }50% {transform:translateX(-3.125%) }60% {transform:translateX(-1.5625%) }70% {transform:translateX(-0.78125%) }80% {transform:translateX(-0.390625%) }90% {transform:translateX(-0.1953125%) }100% {transform:translateX(-0.09765625%) }} +@-ms-keyframes oc-infinite-loader {0% {transform:translateX(-100%) }10% {transform:translateX(-50%) }20% {transform:translateX(-25%) }30% {transform:translateX(-12.5%) }40% {transform:translateX(-6.25%) }50% {transform:translateX(-3.125%) }60% {transform:translateX(-1.5625%) }70% {transform:translateX(-0.78125%) }80% {transform:translateX(-0.390625%) }90% {transform:translateX(-0.1953125%) }100% {transform:translateX(-0.09765625%) }} +@keyframes oc-infinite-loader {0% {transform:translateX(-100%) }10% {transform:translateX(-50%) }20% {transform:translateX(-25%) }30% {transform:translateX(-12.5%) }40% {transform:translateX(-6.25%) }50% {transform:translateX(-3.125%) }60% {transform:translateX(-1.5625%) }70% {transform:translateX(-0.78125%) }80% {transform:translateX(-0.390625%) }90% {transform:translateX(-0.1953125%) }100% {transform:translateX(-0.09765625%) }} \ No newline at end of file diff --git a/modules/system/assets/css/mailbrandsettings/mailbrandsettings.css b/modules/system/assets/css/mailbrandsettings/mailbrandsettings.css new file mode 100644 index 0000000..042ea75 --- /dev/null +++ b/modules/system/assets/css/mailbrandsettings/mailbrandsettings.css @@ -0,0 +1,4 @@ +.field-colorpicker { + float: right; + margin-top: -10px; +} diff --git a/modules/system/assets/css/settings/settings.css b/modules/system/assets/css/settings/settings.css new file mode 100644 index 0000000..12ad137 --- /dev/null +++ b/modules/system/assets/css/settings/settings.css @@ -0,0 +1,72 @@ +.control-settings .settings-category { + padding: 20px; + background-color: #ecf0f1; +} +.control-settings .settings-category h3 { + margin: 0; + font-weight: 100; + color: #293e50; +} +.control-settings .settings-items { + padding: 20px; + margin: 0; +} +.control-settings .settings-items.row { + font-size: 0; +} +.control-settings .settings-items.row > .settings-item { + float: none; + vertical-align: top; + display: inline-block; +} +.control-settings .settings-items .settings-item > a { + display: block; + position: relative; + padding-left: 72px; + padding-top: 10px; + text-decoration: none; + margin-bottom: 20px; + line-height: 150%; +} +.control-settings .settings-items .settings-item > a h5 { + margin-top: 0; + color: #333333; + font-size: 18px; + line-height: 150%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.control-settings .settings-items .settings-item > a p { + color: #777; + font-size: 12px; + line-height: 150%; +} +.control-settings .settings-items .settings-item > a .item-icon { + position: absolute; + left: 0; + top: 0; + background: #f0f0f0; + -webkit-border-radius: 999px; + -moz-border-radius: 999px; + border-radius: 999px; + width: 64px; + height: 64px; + display: block; + text-align: center; + color: #555; +} +.control-settings .settings-items .settings-item > a .item-icon i { + font-size: 52px; + line-height: 64px; +} +.control-settings .settings-items .settings-item > a:hover h5 { + color: #063f68; +} +.control-settings .settings-items .settings-item > a:hover p { + color: #063f68; +} +.control-settings .settings-items .settings-item > a:hover .item-icon { + background: #e0e0e0; + color: #063f68; +} diff --git a/modules/system/assets/css/styles.css b/modules/system/assets/css/styles.css new file mode 100644 index 0000000..9363978 --- /dev/null +++ b/modules/system/assets/css/styles.css @@ -0,0 +1,2016 @@ +html {font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} +body {margin:0} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section, +summary {display:block} +audio, +canvas, +progress, +video {display:inline-block;vertical-align:baseline} +audio:not([controls]) {display:none;height:0} +[hidden], +template {display:none} +a {background:transparent} +a:active, +a:hover {outline:0} +abbr[title] {border-bottom:1px dotted} +b, +strong {font-weight:bold} +dfn {font-style:italic} +h1 {font-size:2em;margin:0.67em 0} +mark {background:#ff0;color:#000} +small {font-size:80%} +sub, +sup {font-size:75%;line-height:0;position:relative;vertical-align:baseline} +sup {top:-0.5em} +sub {bottom:-0.25em} +img {border:0} +svg:not(:root) {overflow:hidden} +figure {margin:1em 40px} +hr {-moz-box-sizing:content-box;box-sizing:content-box;height:0} +pre {overflow:auto} +code, +kbd, +pre, +samp {font-family:monospace,monospace;font-size:1em} +button, +input, +optgroup, +select, +textarea {color:inherit;font:inherit;margin:0} +button {overflow:visible} +button, +select {text-transform:none} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] {-webkit-appearance:button;cursor:pointer} +button[disabled], +html input[disabled] {cursor:default} +button::-moz-focus-inner, +input::-moz-focus-inner {border:0;padding:0} +input {line-height:normal} +input[type="checkbox"], +input[type="radio"] {box-sizing:border-box;padding:0} +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button {height:auto} +input[type="number"]:focus::-webkit-input-placeholder {margin-right:20px} +input[type="number"]:focus::-moz-placeholder {margin-right:20px} +input[type="number"]:focus:-ms-input-placeholder {margin-right:20px} +input[type="number"]:focus::placeholder {margin-right:20px} +input[type="number"]:hover::-webkit-input-placeholder {margin-right:20px} +input[type="number"]:hover::-moz-placeholder {margin-right:20px} +input[type="number"]:hover:-ms-input-placeholder {margin-right:20px} +input[type="number"]:hover::placeholder {margin-right:20px} +input[type="search"] {-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration {-webkit-appearance:none} +fieldset {border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em} +legend {border:0;padding:0} +textarea {overflow:auto} +optgroup {font-weight:bold} +table {border-collapse:collapse;border-spacing:0;table-layout:auto} +td, +th {padding:0} +*, +*:before, +*:after {-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} +html {font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)} +body {font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px;line-height:1.42857143;color:#333;background-color:#f9f9f9} +input, +button, +select, +textarea {font-family:inherit;font-size:inherit;line-height:inherit} +button, +input, +select[multiple], +textarea {background-image:none} +a {color:#0181b9;text-decoration:none} +a:hover, +a:focus {color:#001721;text-decoration:underline} +a:focus {outline:thin dotted;outline-offset:0;outline:4px auto Highlight;outline:4px auto -webkit-focus-ring-color} +img {vertical-align:middle} +.img-responsive {display:block;max-width:100%;height:auto} +.img-rounded {-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px} +.img-circle {border-radius:50%} +hr {margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee} +.sr-only {position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);border:0} +@media print {* {text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important }a,a:visited {text-decoration:underline }a[href]:after {content:" (" attr(href) ")" }abbr[title]:after {content:" (" attr(title) ")" }a[href^="javascript:"]:after,a[href^="#"]:after {content:"" }pre,blockquote {border:1px solid #999;page-break-inside:avoid }thead {display:table-header-group }tr,img {page-break-inside:avoid }img {max-width:100% !important }p,h2,h3 {orphans:3;widows:3 }h2,h3 {page-break-after:avoid }select {background:#fff !important }.navbar {display:none }.table td,.table th {background-color:#fff !important }.btn >.caret,.dropup >.btn >.caret {border-top-color:#000 !important }.label {border:1px solid #000 }.table {border-collapse:collapse !important }.table-bordered th,.table-bordered td {border:1px solid #ddd !important }} +.container {margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px} +@media (min-width:768px) {.container {width:750px }} +@media (min-width:992px) {.container {width:970px }} +@media (min-width:1200px) {.container {width:1170px }} +.container-fluid {margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px} +.row {margin-left:-15px;margin-right:-15px} +.row-flush {margin-left:0;margin-right:0} +.row-flush [class*="col-"] {padding-left:0 !important;padding-right:0 !important} +.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12 {position:relative;min-height:1px;padding-left:15px;padding-right:15px} +.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12 {float:left} +.col-xs-12 {width:100%} +.col-xs-11 {width:91.66666667%} +.col-xs-10 {width:83.33333333%} +.col-xs-9 {width:75%} +.col-xs-8 {width:66.66666667%} +.col-xs-7 {width:58.33333333%} +.col-xs-6 {width:50%} +.col-xs-5 {width:41.66666667%} +.col-xs-4 {width:33.33333333%} +.col-xs-3 {width:25%} +.col-xs-2 {width:16.66666667%} +.col-xs-1 {width:8.33333333%} +.col-xs-pull-12 {right:100%} +.col-xs-pull-11 {right:91.66666667%} +.col-xs-pull-10 {right:83.33333333%} +.col-xs-pull-9 {right:75%} +.col-xs-pull-8 {right:66.66666667%} +.col-xs-pull-7 {right:58.33333333%} +.col-xs-pull-6 {right:50%} +.col-xs-pull-5 {right:41.66666667%} +.col-xs-pull-4 {right:33.33333333%} +.col-xs-pull-3 {right:25%} +.col-xs-pull-2 {right:16.66666667%} +.col-xs-pull-1 {right:8.33333333%} +.col-xs-pull-0 {right:0%} +.col-xs-push-12 {left:100%} +.col-xs-push-11 {left:91.66666667%} +.col-xs-push-10 {left:83.33333333%} +.col-xs-push-9 {left:75%} +.col-xs-push-8 {left:66.66666667%} +.col-xs-push-7 {left:58.33333333%} +.col-xs-push-6 {left:50%} +.col-xs-push-5 {left:41.66666667%} +.col-xs-push-4 {left:33.33333333%} +.col-xs-push-3 {left:25%} +.col-xs-push-2 {left:16.66666667%} +.col-xs-push-1 {left:8.33333333%} +.col-xs-push-0 {left:0%} +.col-xs-offset-12 {margin-left:100%} +.col-xs-offset-11 {margin-left:91.66666667%} +.col-xs-offset-10 {margin-left:83.33333333%} +.col-xs-offset-9 {margin-left:75%} +.col-xs-offset-8 {margin-left:66.66666667%} +.col-xs-offset-7 {margin-left:58.33333333%} +.col-xs-offset-6 {margin-left:50%} +.col-xs-offset-5 {margin-left:41.66666667%} +.col-xs-offset-4 {margin-left:33.33333333%} +.col-xs-offset-3 {margin-left:25%} +.col-xs-offset-2 {margin-left:16.66666667%} +.col-xs-offset-1 {margin-left:8.33333333%} +.col-xs-offset-0 {margin-left:0%} +@media (min-width:768px) {.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12 {float:left }.col-sm-12 {width:100% }.col-sm-11 {width:91.66666667% }.col-sm-10 {width:83.33333333% }.col-sm-9 {width:75% }.col-sm-8 {width:66.66666667% }.col-sm-7 {width:58.33333333% }.col-sm-6 {width:50% }.col-sm-5 {width:41.66666667% }.col-sm-4 {width:33.33333333% }.col-sm-3 {width:25% }.col-sm-2 {width:16.66666667% }.col-sm-1 {width:8.33333333% }.col-sm-pull-12 {right:100% }.col-sm-pull-11 {right:91.66666667% }.col-sm-pull-10 {right:83.33333333% }.col-sm-pull-9 {right:75% }.col-sm-pull-8 {right:66.66666667% }.col-sm-pull-7 {right:58.33333333% }.col-sm-pull-6 {right:50% }.col-sm-pull-5 {right:41.66666667% }.col-sm-pull-4 {right:33.33333333% }.col-sm-pull-3 {right:25% }.col-sm-pull-2 {right:16.66666667% }.col-sm-pull-1 {right:8.33333333% }.col-sm-pull-0 {right:0% }.col-sm-push-12 {left:100% }.col-sm-push-11 {left:91.66666667% }.col-sm-push-10 {left:83.33333333% }.col-sm-push-9 {left:75% }.col-sm-push-8 {left:66.66666667% }.col-sm-push-7 {left:58.33333333% }.col-sm-push-6 {left:50% }.col-sm-push-5 {left:41.66666667% }.col-sm-push-4 {left:33.33333333% }.col-sm-push-3 {left:25% }.col-sm-push-2 {left:16.66666667% }.col-sm-push-1 {left:8.33333333% }.col-sm-push-0 {left:0% }.col-sm-offset-12 {margin-left:100% }.col-sm-offset-11 {margin-left:91.66666667% }.col-sm-offset-10 {margin-left:83.33333333% }.col-sm-offset-9 {margin-left:75% }.col-sm-offset-8 {margin-left:66.66666667% }.col-sm-offset-7 {margin-left:58.33333333% }.col-sm-offset-6 {margin-left:50% }.col-sm-offset-5 {margin-left:41.66666667% }.col-sm-offset-4 {margin-left:33.33333333% }.col-sm-offset-3 {margin-left:25% }.col-sm-offset-2 {margin-left:16.66666667% }.col-sm-offset-1 {margin-left:8.33333333% }.col-sm-offset-0 {margin-left:0% }} +@media (min-width:992px) {.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12 {float:left }.col-md-12 {width:100% }.col-md-11 {width:91.66666667% }.col-md-10 {width:83.33333333% }.col-md-9 {width:75% }.col-md-8 {width:66.66666667% }.col-md-7 {width:58.33333333% }.col-md-6 {width:50% }.col-md-5 {width:41.66666667% }.col-md-4 {width:33.33333333% }.col-md-3 {width:25% }.col-md-2 {width:16.66666667% }.col-md-1 {width:8.33333333% }.col-md-pull-12 {right:100% }.col-md-pull-11 {right:91.66666667% }.col-md-pull-10 {right:83.33333333% }.col-md-pull-9 {right:75% }.col-md-pull-8 {right:66.66666667% }.col-md-pull-7 {right:58.33333333% }.col-md-pull-6 {right:50% }.col-md-pull-5 {right:41.66666667% }.col-md-pull-4 {right:33.33333333% }.col-md-pull-3 {right:25% }.col-md-pull-2 {right:16.66666667% }.col-md-pull-1 {right:8.33333333% }.col-md-pull-0 {right:0% }.col-md-push-12 {left:100% }.col-md-push-11 {left:91.66666667% }.col-md-push-10 {left:83.33333333% }.col-md-push-9 {left:75% }.col-md-push-8 {left:66.66666667% }.col-md-push-7 {left:58.33333333% }.col-md-push-6 {left:50% }.col-md-push-5 {left:41.66666667% }.col-md-push-4 {left:33.33333333% }.col-md-push-3 {left:25% }.col-md-push-2 {left:16.66666667% }.col-md-push-1 {left:8.33333333% }.col-md-push-0 {left:0% }.col-md-offset-12 {margin-left:100% }.col-md-offset-11 {margin-left:91.66666667% }.col-md-offset-10 {margin-left:83.33333333% }.col-md-offset-9 {margin-left:75% }.col-md-offset-8 {margin-left:66.66666667% }.col-md-offset-7 {margin-left:58.33333333% }.col-md-offset-6 {margin-left:50% }.col-md-offset-5 {margin-left:41.66666667% }.col-md-offset-4 {margin-left:33.33333333% }.col-md-offset-3 {margin-left:25% }.col-md-offset-2 {margin-left:16.66666667% }.col-md-offset-1 {margin-left:8.33333333% }.col-md-offset-0 {margin-left:0% }} +@media (min-width:1200px) {.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12 {float:left }.col-lg-12 {width:100% }.col-lg-11 {width:91.66666667% }.col-lg-10 {width:83.33333333% }.col-lg-9 {width:75% }.col-lg-8 {width:66.66666667% }.col-lg-7 {width:58.33333333% }.col-lg-6 {width:50% }.col-lg-5 {width:41.66666667% }.col-lg-4 {width:33.33333333% }.col-lg-3 {width:25% }.col-lg-2 {width:16.66666667% }.col-lg-1 {width:8.33333333% }.col-lg-pull-12 {right:100% }.col-lg-pull-11 {right:91.66666667% }.col-lg-pull-10 {right:83.33333333% }.col-lg-pull-9 {right:75% }.col-lg-pull-8 {right:66.66666667% }.col-lg-pull-7 {right:58.33333333% }.col-lg-pull-6 {right:50% }.col-lg-pull-5 {right:41.66666667% }.col-lg-pull-4 {right:33.33333333% }.col-lg-pull-3 {right:25% }.col-lg-pull-2 {right:16.66666667% }.col-lg-pull-1 {right:8.33333333% }.col-lg-pull-0 {right:0% }.col-lg-push-12 {left:100% }.col-lg-push-11 {left:91.66666667% }.col-lg-push-10 {left:83.33333333% }.col-lg-push-9 {left:75% }.col-lg-push-8 {left:66.66666667% }.col-lg-push-7 {left:58.33333333% }.col-lg-push-6 {left:50% }.col-lg-push-5 {left:41.66666667% }.col-lg-push-4 {left:33.33333333% }.col-lg-push-3 {left:25% }.col-lg-push-2 {left:16.66666667% }.col-lg-push-1 {left:8.33333333% }.col-lg-push-0 {left:0% }.col-lg-offset-12 {margin-left:100% }.col-lg-offset-11 {margin-left:91.66666667% }.col-lg-offset-10 {margin-left:83.33333333% }.col-lg-offset-9 {margin-left:75% }.col-lg-offset-8 {margin-left:66.66666667% }.col-lg-offset-7 {margin-left:58.33333333% }.col-lg-offset-6 {margin-left:50% }.col-lg-offset-5 {margin-left:41.66666667% }.col-lg-offset-4 {margin-left:33.33333333% }.col-lg-offset-3 {margin-left:25% }.col-lg-offset-2 {margin-left:16.66666667% }.col-lg-offset-1 {margin-left:8.33333333% }.col-lg-offset-0 {margin-left:0% }} +.clearfix:before, +.clearfix:after, +.container:before, +.container:after, +.container-fluid:before, +.container-fluid:after, +.row:before, +.row:after {content:" ";display:table} +.clearfix:after, +.container:after, +.container-fluid:after, +.row:after {clear:both} +.center-block {display:block;margin-left:auto;margin-right:auto} +.pull-right {float:right !important} +.pull-left {float:left !important} +.hide {display:none !important} +.show {display:block !important} +.invisible {visibility:hidden} +.text-hide {font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0} +.hidden {display:none !important;visibility:hidden !important} +.affix {position:fixed} +@-ms-viewport {width:device-width} +.visible-xs, +.visible-sm, +.visible-md, +.visible-lg {display:none !important} +@media (max-width:767px) {.visible-xs {display:block !important }table.visible-xs {display:table }tr.visible-xs {display:table-row !important }th.visible-xs,td.visible-xs {display:table-cell !important }} +@media (min-width:768px) and (max-width:991px) {.visible-sm {display:block !important }table.visible-sm {display:table }tr.visible-sm {display:table-row !important }th.visible-sm,td.visible-sm {display:table-cell !important }} +@media (min-width:992px) and (max-width:1199px) {.visible-md {display:block !important }table.visible-md {display:table }tr.visible-md {display:table-row !important }th.visible-md,td.visible-md {display:table-cell !important }} +@media (min-width:1200px) {.visible-lg {display:block !important }table.visible-lg {display:table }tr.visible-lg {display:table-row !important }th.visible-lg,td.visible-lg {display:table-cell !important }} +@media (max-width:767px) {.hidden-xs {display:none !important }} +@media (min-width:768px) and (max-width:991px) {.hidden-sm {display:none !important }} +@media (min-width:992px) and (max-width:1199px) {.hidden-md {display:none !important }} +@media (min-width:1200px) {.hidden-lg {display:none !important }} +.visible-print {display:none !important} +@media print {.visible-print {display:block !important }table.visible-print {display:table }tr.visible-print {display:table-row !important }th.visible-print,td.visible-print {display:table-cell !important }} +@media print {.hidden-print {display:none !important }} +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 {font-family:inherit;font-weight:400;line-height:1.1;color:inherit} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small, +.h1 small, +.h2 small, +.h3 small, +.h4 small, +.h5 small, +.h6 small, +h1 .small, +h2 .small, +h3 .small, +h4 .small, +h5 .small, +h6 .small, +.h1 .small, +.h2 .small, +.h3 .small, +.h4 .small, +.h5 .small, +.h6 .small {font-weight:normal;line-height:1;color:#999} +h1, +.h1, +h2, +.h2, +h3, +.h3 {margin-top:20px;margin-bottom:10px} +h1 small, +.h1 small, +h2 small, +.h2 small, +h3 small, +.h3 small, +h1 .small, +.h1 .small, +h2 .small, +.h2 .small, +h3 .small, +.h3 .small {font-size:65%} +h4, +.h4, +h5, +.h5, +h6, +.h6 {margin-top:10px;margin-bottom:10px} +h4 small, +.h4 small, +h5 small, +.h5 small, +h6 small, +.h6 small, +h4 .small, +.h4 .small, +h5 .small, +.h5 .small, +h6 .small, +.h6 .small {font-size:75%} +h1, +.h1 {font-size:36px} +h2, +.h2 {font-size:30px} +h3, +.h3 {font-size:24px} +h4, +.h4 {font-size:18px} +h5, +.h5 {font-size:14px} +h6, +.h6 {font-size:12px} +p {margin:0 0 10px} +.lead {margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4} +@media (min-width:768px) {.lead {font-size:21px }} +small, +.small {font-size:85%} +cite {font-style:normal} +.text-left {text-align:left} +.text-right {text-align:right} +.text-center {text-align:center} +.text-justify {text-align:justify} +.text-muted {color:#999} +.text-primary {color:#34495e} +a.text-primary:hover {color:#222f3d} +.text-success {color:#3c763d} +a.text-success:hover {color:#2b542c} +.text-info {color:#31708f} +a.text-info:hover {color:#245269} +.text-warning {color:#8a6d3b} +a.text-warning:hover {color:#66512c} +.text-danger {color:#a94442} +a.text-danger:hover {color:#843534} +.bg-primary {color:#fff;background-color:#34495e} +a.bg-primary:hover {background-color:#222f3d} +.bg-success {background-color:#dff0d8} +a.bg-success:hover {background-color:#c1e2b3} +.bg-info {background-color:#d9edf7} +a.bg-info:hover {background-color:#afd9ee} +.bg-warning {background-color:#fcf8e3} +a.bg-warning:hover {background-color:#f7ecb5} +.bg-danger {background-color:#f2dede} +a.bg-danger:hover {background-color:#e4b9b9} +.page-header {padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee} +ul, +ol {margin-top:0;margin-bottom:10px} +ul ul, +ol ul, +ul ol, +ol ol {margin-bottom:0} +.list-unstyled {padding-left:0;list-style:none} +.list-inline {padding-left:0;list-style:none;margin-left:-5px} +.list-inline >li {display:inline-block;padding-left:5px;padding-right:5px} +dl {margin-top:0;margin-bottom:20px} +dt, +dd {line-height:1.42857143} +dt {font-weight:bold} +dd {margin-left:0} +@media (min-width:768px) {.dl-horizontal dt {float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap }.dl-horizontal dd {margin-left:180px }} +abbr[title], +abbr[data-original-title] {cursor:help;border-bottom:1px dotted #999} +.initialism {font-size:90%;text-transform:uppercase} +blockquote {padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee} +blockquote p:last-child, +blockquote ul:last-child, +blockquote ol:last-child {margin-bottom:0} +blockquote footer, +blockquote small, +blockquote .small {display:block;font-size:80%;line-height:1.42857143;color:#999} +blockquote footer:before, +blockquote small:before, +blockquote .small:before {content:'\2014 \00A0'} +.blockquote-reverse, +blockquote.pull-right {padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right} +.blockquote-reverse footer:before, +blockquote.pull-right footer:before, +.blockquote-reverse small:before, +blockquote.pull-right small:before, +.blockquote-reverse .small:before, +blockquote.pull-right .small:before {content:''} +.blockquote-reverse footer:after, +blockquote.pull-right footer:after, +.blockquote-reverse small:after, +blockquote.pull-right small:after, +.blockquote-reverse .small:after, +blockquote.pull-right .small:after {content:'\00A0 \2014'} +blockquote:before, +blockquote:after {content:""} +address {margin-bottom:20px;font-style:normal;line-height:1.42857143} +.oc-icon-glass:before, +.icon-glass:before {content:"\f000"} +.oc-icon-music:before, +.icon-music:before {content:"\f001"} +.oc-icon-search:before, +.icon-search:before {content:"\f002"} +.oc-icon-envelope-o:before, +.icon-envelope-o:before {content:"\f003"} +.oc-icon-heart:before, +.icon-heart:before {content:"\f004"} +.oc-icon-star:before, +.icon-star:before {content:"\f005"} +.oc-icon-star-o:before, +.icon-star-o:before {content:"\f006"} +.oc-icon-user:before, +.icon-user:before {content:"\f007"} +.oc-icon-film:before, +.icon-film:before {content:"\f008"} +.oc-icon-th-large:before, +.icon-th-large:before {content:"\f009"} +.oc-icon-th:before, +.icon-th:before {content:"\f00a"} +.oc-icon-th-list:before, +.icon-th-list:before {content:"\f00b"} +.oc-icon-check:before, +.icon-check:before {content:"\f00c"} +.oc-icon-remove:before, +.icon-remove:before, +.oc-icon-close:before, +.icon-close:before, +.oc-icon-times:before, +.icon-times:before {content:"\f00d"} +.oc-icon-search-plus:before, +.icon-search-plus:before {content:"\f00e"} +.oc-icon-search-minus:before, +.icon-search-minus:before {content:"\f010"} +.oc-icon-power-off:before, +.icon-power-off:before {content:"\f011"} +.oc-icon-signal:before, +.icon-signal:before {content:"\f012"} +.oc-icon-gear:before, +.icon-gear:before, +.oc-icon-cog:before, +.icon-cog:before {content:"\f013"} +.oc-icon-trash-o:before, +.icon-trash-o:before {content:"\f014"} +.oc-icon-home:before, +.icon-home:before {content:"\f015"} +.oc-icon-file-o:before, +.icon-file-o:before {content:"\f016"} +.oc-icon-clock-o:before, +.icon-clock-o:before {content:"\f017"} +.oc-icon-road:before, +.icon-road:before {content:"\f018"} +.oc-icon-download:before, +.icon-download:before {content:"\f019"} +.oc-icon-arrow-circle-o-down:before, +.icon-arrow-circle-o-down:before {content:"\f01a"} +.oc-icon-arrow-circle-o-up:before, +.icon-arrow-circle-o-up:before {content:"\f01b"} +.oc-icon-inbox:before, +.icon-inbox:before {content:"\f01c"} +.oc-icon-play-circle-o:before, +.icon-play-circle-o:before {content:"\f01d"} +.oc-icon-rotate-right:before, +.icon-rotate-right:before, +.oc-icon-repeat:before, +.icon-repeat:before {content:"\f01e"} +.oc-icon-refresh:before, +.icon-refresh:before {content:"\f021"} +.oc-icon-list-alt:before, +.icon-list-alt:before {content:"\f022"} +.oc-icon-lock:before, +.icon-lock:before {content:"\f023"} +.oc-icon-flag:before, +.icon-flag:before {content:"\f024"} +.oc-icon-headphones:before, +.icon-headphones:before {content:"\f025"} +.oc-icon-volume-off:before, +.icon-volume-off:before {content:"\f026"} +.oc-icon-volume-down:before, +.icon-volume-down:before {content:"\f027"} +.oc-icon-volume-up:before, +.icon-volume-up:before {content:"\f028"} +.oc-icon-qrcode:before, +.icon-qrcode:before {content:"\f029"} +.oc-icon-barcode:before, +.icon-barcode:before {content:"\f02a"} +.oc-icon-tag:before, +.icon-tag:before {content:"\f02b"} +.oc-icon-tags:before, +.icon-tags:before {content:"\f02c"} +.oc-icon-book:before, +.icon-book:before {content:"\f02d"} +.oc-icon-bookmark:before, +.icon-bookmark:before {content:"\f02e"} +.oc-icon-print:before, +.icon-print:before {content:"\f02f"} +.oc-icon-camera:before, +.icon-camera:before {content:"\f030"} +.oc-icon-font:before, +.icon-font:before {content:"\f031"} +.oc-icon-bold:before, +.icon-bold:before {content:"\f032"} +.oc-icon-italic:before, +.icon-italic:before {content:"\f033"} +.oc-icon-text-height:before, +.icon-text-height:before {content:"\f034"} +.oc-icon-text-width:before, +.icon-text-width:before {content:"\f035"} +.oc-icon-align-left:before, +.icon-align-left:before {content:"\f036"} +.oc-icon-align-center:before, +.icon-align-center:before {content:"\f037"} +.oc-icon-align-right:before, +.icon-align-right:before {content:"\f038"} +.oc-icon-align-justify:before, +.icon-align-justify:before {content:"\f039"} +.oc-icon-list:before, +.icon-list:before {content:"\f03a"} +.oc-icon-dedent:before, +.icon-dedent:before, +.oc-icon-outdent:before, +.icon-outdent:before {content:"\f03b"} +.oc-icon-indent:before, +.icon-indent:before {content:"\f03c"} +.oc-icon-video-camera:before, +.icon-video-camera:before {content:"\f03d"} +.oc-icon-photo:before, +.icon-photo:before, +.oc-icon-image:before, +.icon-image:before, +.oc-icon-picture-o:before, +.icon-picture-o:before {content:"\f03e"} +.oc-icon-pencil:before, +.icon-pencil:before {content:"\f040"} +.oc-icon-map-marker:before, +.icon-map-marker:before {content:"\f041"} +.oc-icon-adjust:before, +.icon-adjust:before {content:"\f042"} +.oc-icon-tint:before, +.icon-tint:before {content:"\f043"} +.oc-icon-edit:before, +.icon-edit:before, +.oc-icon-pencil-square-o:before, +.icon-pencil-square-o:before {content:"\f044"} +.oc-icon-share-square-o:before, +.icon-share-square-o:before {content:"\f045"} +.oc-icon-check-square-o:before, +.icon-check-square-o:before {content:"\f046"} +.oc-icon-arrows:before, +.icon-arrows:before {content:"\f047"} +.oc-icon-step-backward:before, +.icon-step-backward:before {content:"\f048"} +.oc-icon-fast-backward:before, +.icon-fast-backward:before {content:"\f049"} +.oc-icon-backward:before, +.icon-backward:before {content:"\f04a"} +.oc-icon-play:before, +.icon-play:before {content:"\f04b"} +.oc-icon-pause:before, +.icon-pause:before {content:"\f04c"} +.oc-icon-stop:before, +.icon-stop:before {content:"\f04d"} +.oc-icon-forward:before, +.icon-forward:before {content:"\f04e"} +.oc-icon-fast-forward:before, +.icon-fast-forward:before {content:"\f050"} +.oc-icon-step-forward:before, +.icon-step-forward:before {content:"\f051"} +.oc-icon-eject:before, +.icon-eject:before {content:"\f052"} +.oc-icon-chevron-left:before, +.icon-chevron-left:before {content:"\f053"} +.oc-icon-chevron-right:before, +.icon-chevron-right:before {content:"\f054"} +.oc-icon-plus-circle:before, +.icon-plus-circle:before {content:"\f055"} +.oc-icon-minus-circle:before, +.icon-minus-circle:before {content:"\f056"} +.oc-icon-times-circle:before, +.icon-times-circle:before {content:"\f057"} +.oc-icon-check-circle:before, +.icon-check-circle:before {content:"\f058"} +.oc-icon-question-circle:before, +.icon-question-circle:before {content:"\f059"} +.oc-icon-info-circle:before, +.icon-info-circle:before {content:"\f05a"} +.oc-icon-crosshairs:before, +.icon-crosshairs:before {content:"\f05b"} +.oc-icon-times-circle-o:before, +.icon-times-circle-o:before {content:"\f05c"} +.oc-icon-check-circle-o:before, +.icon-check-circle-o:before {content:"\f05d"} +.oc-icon-ban:before, +.icon-ban:before {content:"\f05e"} +.oc-icon-arrow-left:before, +.icon-arrow-left:before {content:"\f060"} +.oc-icon-arrow-right:before, +.icon-arrow-right:before {content:"\f061"} +.oc-icon-arrow-up:before, +.icon-arrow-up:before {content:"\f062"} +.oc-icon-arrow-down:before, +.icon-arrow-down:before {content:"\f063"} +.oc-icon-mail-forward:before, +.icon-mail-forward:before, +.oc-icon-share:before, +.icon-share:before {content:"\f064"} +.oc-icon-expand:before, +.icon-expand:before {content:"\f065"} +.oc-icon-compress:before, +.icon-compress:before {content:"\f066"} +.oc-icon-plus:before, +.icon-plus:before {content:"\f067"} +.oc-icon-minus:before, +.icon-minus:before {content:"\f068"} +.oc-icon-asterisk:before, +.icon-asterisk:before {content:"\f069"} +.oc-icon-exclamation-circle:before, +.icon-exclamation-circle:before {content:"\f06a"} +.oc-icon-gift:before, +.icon-gift:before {content:"\f06b"} +.oc-icon-leaf:before, +.icon-leaf:before {content:"\f06c"} +.oc-icon-fire:before, +.icon-fire:before {content:"\f06d"} +.oc-icon-eye:before, +.icon-eye:before {content:"\f06e"} +.oc-icon-eye-slash:before, +.icon-eye-slash:before {content:"\f070"} +.oc-icon-warning:before, +.icon-warning:before, +.oc-icon-exclamation-triangle:before, +.icon-exclamation-triangle:before {content:"\f071"} +.oc-icon-plane:before, +.icon-plane:before {content:"\f072"} +.oc-icon-calendar:before, +.icon-calendar:before {content:"\f073"} +.oc-icon-random:before, +.icon-random:before {content:"\f074"} +.oc-icon-comment:before, +.icon-comment:before {content:"\f075"} +.oc-icon-magnet:before, +.icon-magnet:before {content:"\f076"} +.oc-icon-chevron-up:before, +.icon-chevron-up:before {content:"\f077"} +.oc-icon-chevron-down:before, +.icon-chevron-down:before {content:"\f078"} +.oc-icon-retweet:before, +.icon-retweet:before {content:"\f079"} +.oc-icon-shopping-cart:before, +.icon-shopping-cart:before {content:"\f07a"} +.oc-icon-folder:before, +.icon-folder:before {content:"\f07b"} +.oc-icon-folder-open:before, +.icon-folder-open:before {content:"\f07c"} +.oc-icon-arrows-v:before, +.icon-arrows-v:before {content:"\f07d"} +.oc-icon-arrows-h:before, +.icon-arrows-h:before {content:"\f07e"} +.oc-icon-bar-chart-o:before, +.icon-bar-chart-o:before, +.oc-icon-bar-chart:before, +.icon-bar-chart:before {content:"\f080"} +.oc-icon-twitter-square:before, +.icon-twitter-square:before {content:"\f081"} +.oc-icon-facebook-square:before, +.icon-facebook-square:before {content:"\f082"} +.oc-icon-camera-retro:before, +.icon-camera-retro:before {content:"\f083"} +.oc-icon-key:before, +.icon-key:before {content:"\f084"} +.oc-icon-gears:before, +.icon-gears:before, +.oc-icon-cogs:before, +.icon-cogs:before {content:"\f085"} +.oc-icon-comments:before, +.icon-comments:before {content:"\f086"} +.oc-icon-thumbs-o-up:before, +.icon-thumbs-o-up:before {content:"\f087"} +.oc-icon-thumbs-o-down:before, +.icon-thumbs-o-down:before {content:"\f088"} +.oc-icon-star-half:before, +.icon-star-half:before {content:"\f089"} +.oc-icon-heart-o:before, +.icon-heart-o:before {content:"\f08a"} +.oc-icon-sign-out:before, +.icon-sign-out:before {content:"\f08b"} +.oc-icon-linkedin-square:before, +.icon-linkedin-square:before {content:"\f08c"} +.oc-icon-thumb-tack:before, +.icon-thumb-tack:before {content:"\f08d"} +.oc-icon-external-link:before, +.icon-external-link:before {content:"\f08e"} +.oc-icon-sign-in:before, +.icon-sign-in:before {content:"\f090"} +.oc-icon-trophy:before, +.icon-trophy:before {content:"\f091"} +.oc-icon-github-square:before, +.icon-github-square:before {content:"\f092"} +.oc-icon-upload:before, +.icon-upload:before {content:"\f093"} +.oc-icon-lemon-o:before, +.icon-lemon-o:before {content:"\f094"} +.oc-icon-phone:before, +.icon-phone:before {content:"\f095"} +.oc-icon-square-o:before, +.icon-square-o:before {content:"\f096"} +.oc-icon-bookmark-o:before, +.icon-bookmark-o:before {content:"\f097"} +.oc-icon-phone-square:before, +.icon-phone-square:before {content:"\f098"} +.oc-icon-twitter:before, +.icon-twitter:before {content:"\f099"} +.oc-icon-facebook-f:before, +.icon-facebook-f:before, +.oc-icon-facebook:before, +.icon-facebook:before {content:"\f09a"} +.oc-icon-github:before, +.icon-github:before {content:"\f09b"} +.oc-icon-unlock:before, +.icon-unlock:before {content:"\f09c"} +.oc-icon-credit-card:before, +.icon-credit-card:before {content:"\f09d"} +.oc-icon-feed:before, +.icon-feed:before, +.oc-icon-rss:before, +.icon-rss:before {content:"\f09e"} +.oc-icon-hdd-o:before, +.icon-hdd-o:before {content:"\f0a0"} +.oc-icon-bullhorn:before, +.icon-bullhorn:before {content:"\f0a1"} +.oc-icon-bell:before, +.icon-bell:before {content:"\f0f3"} +.oc-icon-certificate:before, +.icon-certificate:before {content:"\f0a3"} +.oc-icon-hand-o-right:before, +.icon-hand-o-right:before {content:"\f0a4"} +.oc-icon-hand-o-left:before, +.icon-hand-o-left:before {content:"\f0a5"} +.oc-icon-hand-o-up:before, +.icon-hand-o-up:before {content:"\f0a6"} +.oc-icon-hand-o-down:before, +.icon-hand-o-down:before {content:"\f0a7"} +.oc-icon-arrow-circle-left:before, +.icon-arrow-circle-left:before {content:"\f0a8"} +.oc-icon-arrow-circle-right:before, +.icon-arrow-circle-right:before {content:"\f0a9"} +.oc-icon-arrow-circle-up:before, +.icon-arrow-circle-up:before {content:"\f0aa"} +.oc-icon-arrow-circle-down:before, +.icon-arrow-circle-down:before {content:"\f0ab"} +.oc-icon-globe:before, +.icon-globe:before {content:"\f0ac"} +.oc-icon-wrench:before, +.icon-wrench:before {content:"\f0ad"} +.oc-icon-tasks:before, +.icon-tasks:before {content:"\f0ae"} +.oc-icon-filter:before, +.icon-filter:before {content:"\f0b0"} +.oc-icon-briefcase:before, +.icon-briefcase:before {content:"\f0b1"} +.oc-icon-arrows-alt:before, +.icon-arrows-alt:before {content:"\f0b2"} +.oc-icon-group:before, +.icon-group:before, +.oc-icon-users:before, +.icon-users:before {content:"\f0c0"} +.oc-icon-chain:before, +.icon-chain:before, +.oc-icon-link:before, +.icon-link:before {content:"\f0c1"} +.oc-icon-cloud:before, +.icon-cloud:before {content:"\f0c2"} +.oc-icon-flask:before, +.icon-flask:before {content:"\f0c3"} +.oc-icon-cut:before, +.icon-cut:before, +.oc-icon-scissors:before, +.icon-scissors:before {content:"\f0c4"} +.oc-icon-copy:before, +.icon-copy:before, +.oc-icon-files-o:before, +.icon-files-o:before {content:"\f0c5"} +.oc-icon-paperclip:before, +.icon-paperclip:before {content:"\f0c6"} +.oc-icon-save:before, +.icon-save:before, +.oc-icon-floppy-o:before, +.icon-floppy-o:before {content:"\f0c7"} +.oc-icon-square:before, +.icon-square:before {content:"\f0c8"} +.oc-icon-navicon:before, +.icon-navicon:before, +.oc-icon-reorder:before, +.icon-reorder:before, +.oc-icon-bars:before, +.icon-bars:before {content:"\f0c9"} +.oc-icon-list-ul:before, +.icon-list-ul:before {content:"\f0ca"} +.oc-icon-list-ol:before, +.icon-list-ol:before {content:"\f0cb"} +.oc-icon-strikethrough:before, +.icon-strikethrough:before {content:"\f0cc"} +.oc-icon-underline:before, +.icon-underline:before {content:"\f0cd"} +.oc-icon-table:before, +.icon-table:before {content:"\f0ce"} +.oc-icon-magic:before, +.icon-magic:before {content:"\f0d0"} +.oc-icon-truck:before, +.icon-truck:before {content:"\f0d1"} +.oc-icon-pinterest:before, +.icon-pinterest:before {content:"\f0d2"} +.oc-icon-pinterest-square:before, +.icon-pinterest-square:before {content:"\f0d3"} +.oc-icon-google-plus-square:before, +.icon-google-plus-square:before {content:"\f0d4"} +.oc-icon-google-plus:before, +.icon-google-plus:before {content:"\f0d5"} +.oc-icon-money:before, +.icon-money:before {content:"\f0d6"} +.oc-icon-caret-down:before, +.icon-caret-down:before {content:"\f0d7"} +.oc-icon-caret-up:before, +.icon-caret-up:before {content:"\f0d8"} +.oc-icon-caret-left:before, +.icon-caret-left:before {content:"\f0d9"} +.oc-icon-caret-right:before, +.icon-caret-right:before {content:"\f0da"} +.oc-icon-columns:before, +.icon-columns:before {content:"\f0db"} +.oc-icon-unsorted:before, +.icon-unsorted:before, +.oc-icon-sort:before, +.icon-sort:before {content:"\f0dc"} +.oc-icon-sort-down:before, +.icon-sort-down:before, +.oc-icon-sort-desc:before, +.icon-sort-desc:before {content:"\f0dd"} +.oc-icon-sort-up:before, +.icon-sort-up:before, +.oc-icon-sort-asc:before, +.icon-sort-asc:before {content:"\f0de"} +.oc-icon-envelope:before, +.icon-envelope:before {content:"\f0e0"} +.oc-icon-linkedin:before, +.icon-linkedin:before {content:"\f0e1"} +.oc-icon-rotate-left:before, +.icon-rotate-left:before, +.oc-icon-undo:before, +.icon-undo:before {content:"\f0e2"} +.oc-icon-legal:before, +.icon-legal:before, +.oc-icon-gavel:before, +.icon-gavel:before {content:"\f0e3"} +.oc-icon-dashboard:before, +.icon-dashboard:before, +.oc-icon-tachometer:before, +.icon-tachometer:before {content:"\f0e4"} +.oc-icon-comment-o:before, +.icon-comment-o:before {content:"\f0e5"} +.oc-icon-comments-o:before, +.icon-comments-o:before {content:"\f0e6"} +.oc-icon-flash:before, +.icon-flash:before, +.oc-icon-bolt:before, +.icon-bolt:before {content:"\f0e7"} +.oc-icon-sitemap:before, +.icon-sitemap:before {content:"\f0e8"} +.oc-icon-umbrella:before, +.icon-umbrella:before {content:"\f0e9"} +.oc-icon-paste:before, +.icon-paste:before, +.oc-icon-clipboard:before, +.icon-clipboard:before {content:"\f0ea"} +.oc-icon-lightbulb-o:before, +.icon-lightbulb-o:before {content:"\f0eb"} +.oc-icon-exchange:before, +.icon-exchange:before {content:"\f0ec"} +.oc-icon-cloud-download:before, +.icon-cloud-download:before {content:"\f0ed"} +.oc-icon-cloud-upload:before, +.icon-cloud-upload:before {content:"\f0ee"} +.oc-icon-user-md:before, +.icon-user-md:before {content:"\f0f0"} +.oc-icon-stethoscope:before, +.icon-stethoscope:before {content:"\f0f1"} +.oc-icon-suitcase:before, +.icon-suitcase:before {content:"\f0f2"} +.oc-icon-bell-o:before, +.icon-bell-o:before {content:"\f0a2"} +.oc-icon-coffee:before, +.icon-coffee:before {content:"\f0f4"} +.oc-icon-cutlery:before, +.icon-cutlery:before {content:"\f0f5"} +.oc-icon-file-text-o:before, +.icon-file-text-o:before {content:"\f0f6"} +.oc-icon-building-o:before, +.icon-building-o:before {content:"\f0f7"} +.oc-icon-hospital-o:before, +.icon-hospital-o:before {content:"\f0f8"} +.oc-icon-ambulance:before, +.icon-ambulance:before {content:"\f0f9"} +.oc-icon-medkit:before, +.icon-medkit:before {content:"\f0fa"} +.oc-icon-fighter-jet:before, +.icon-fighter-jet:before {content:"\f0fb"} +.oc-icon-beer:before, +.icon-beer:before {content:"\f0fc"} +.oc-icon-h-square:before, +.icon-h-square:before {content:"\f0fd"} +.oc-icon-plus-square:before, +.icon-plus-square:before {content:"\f0fe"} +.oc-icon-angle-double-left:before, +.icon-angle-double-left:before {content:"\f100"} +.oc-icon-angle-double-right:before, +.icon-angle-double-right:before {content:"\f101"} +.oc-icon-angle-double-up:before, +.icon-angle-double-up:before {content:"\f102"} +.oc-icon-angle-double-down:before, +.icon-angle-double-down:before {content:"\f103"} +.oc-icon-angle-left:before, +.icon-angle-left:before {content:"\f104"} +.oc-icon-angle-right:before, +.icon-angle-right:before {content:"\f105"} +.oc-icon-angle-up:before, +.icon-angle-up:before {content:"\f106"} +.oc-icon-angle-down:before, +.icon-angle-down:before {content:"\f107"} +.oc-icon-desktop:before, +.icon-desktop:before {content:"\f108"} +.oc-icon-laptop:before, +.icon-laptop:before {content:"\f109"} +.oc-icon-tablet:before, +.icon-tablet:before {content:"\f10a"} +.oc-icon-mobile-phone:before, +.icon-mobile-phone:before, +.oc-icon-mobile:before, +.icon-mobile:before {content:"\f10b"} +.oc-icon-circle-o:before, +.icon-circle-o:before {content:"\f10c"} +.oc-icon-quote-left:before, +.icon-quote-left:before {content:"\f10d"} +.oc-icon-quote-right:before, +.icon-quote-right:before {content:"\f10e"} +.oc-icon-spinner:before, +.icon-spinner:before {content:"\f110"} +.oc-icon-circle:before, +.icon-circle:before {content:"\f111"} +.oc-icon-mail-reply:before, +.icon-mail-reply:before, +.oc-icon-reply:before, +.icon-reply:before {content:"\f112"} +.oc-icon-github-alt:before, +.icon-github-alt:before {content:"\f113"} +.oc-icon-folder-o:before, +.icon-folder-o:before {content:"\f114"} +.oc-icon-folder-open-o:before, +.icon-folder-open-o:before {content:"\f115"} +.oc-icon-smile-o:before, +.icon-smile-o:before {content:"\f118"} +.oc-icon-frown-o:before, +.icon-frown-o:before {content:"\f119"} +.oc-icon-meh-o:before, +.icon-meh-o:before {content:"\f11a"} +.oc-icon-gamepad:before, +.icon-gamepad:before {content:"\f11b"} +.oc-icon-keyboard-o:before, +.icon-keyboard-o:before {content:"\f11c"} +.oc-icon-flag-o:before, +.icon-flag-o:before {content:"\f11d"} +.oc-icon-flag-checkered:before, +.icon-flag-checkered:before {content:"\f11e"} +.oc-icon-terminal:before, +.icon-terminal:before {content:"\f120"} +.oc-icon-code:before, +.icon-code:before {content:"\f121"} +.oc-icon-mail-reply-all:before, +.icon-mail-reply-all:before, +.oc-icon-reply-all:before, +.icon-reply-all:before {content:"\f122"} +.oc-icon-star-half-empty:before, +.icon-star-half-empty:before, +.oc-icon-star-half-full:before, +.icon-star-half-full:before, +.oc-icon-star-half-o:before, +.icon-star-half-o:before {content:"\f123"} +.oc-icon-location-arrow:before, +.icon-location-arrow:before {content:"\f124"} +.oc-icon-crop:before, +.icon-crop:before {content:"\f125"} +.oc-icon-code-fork:before, +.icon-code-fork:before {content:"\f126"} +.oc-icon-unlink:before, +.icon-unlink:before, +.oc-icon-chain-broken:before, +.icon-chain-broken:before {content:"\f127"} +.oc-icon-question:before, +.icon-question:before {content:"\f128"} +.oc-icon-info:before, +.icon-info:before {content:"\f129"} +.oc-icon-exclamation:before, +.icon-exclamation:before {content:"\f12a"} +.oc-icon-superscript:before, +.icon-superscript:before {content:"\f12b"} +.oc-icon-subscript:before, +.icon-subscript:before {content:"\f12c"} +.oc-icon-eraser:before, +.icon-eraser:before {content:"\f12d"} +.oc-icon-puzzle-piece:before, +.icon-puzzle-piece:before {content:"\f12e"} +.oc-icon-microphone:before, +.icon-microphone:before {content:"\f130"} +.oc-icon-microphone-slash:before, +.icon-microphone-slash:before {content:"\f131"} +.oc-icon-shield:before, +.icon-shield:before {content:"\f132"} +.oc-icon-calendar-o:before, +.icon-calendar-o:before {content:"\f133"} +.oc-icon-fire-extinguisher:before, +.icon-fire-extinguisher:before {content:"\f134"} +.oc-icon-rocket:before, +.icon-rocket:before {content:"\f135"} +.oc-icon-maxcdn:before, +.icon-maxcdn:before {content:"\f136"} +.oc-icon-chevron-circle-left:before, +.icon-chevron-circle-left:before {content:"\f137"} +.oc-icon-chevron-circle-right:before, +.icon-chevron-circle-right:before {content:"\f138"} +.oc-icon-chevron-circle-up:before, +.icon-chevron-circle-up:before {content:"\f139"} +.oc-icon-chevron-circle-down:before, +.icon-chevron-circle-down:before {content:"\f13a"} +.oc-icon-html5:before, +.icon-html5:before {content:"\f13b"} +.oc-icon-css3:before, +.icon-css3:before {content:"\f13c"} +.oc-icon-anchor:before, +.icon-anchor:before {content:"\f13d"} +.oc-icon-unlock-alt:before, +.icon-unlock-alt:before {content:"\f13e"} +.oc-icon-bullseye:before, +.icon-bullseye:before {content:"\f140"} +.oc-icon-ellipsis-h:before, +.icon-ellipsis-h:before {content:"\f141"} +.oc-icon-ellipsis-v:before, +.icon-ellipsis-v:before {content:"\f142"} +.oc-icon-rss-square:before, +.icon-rss-square:before {content:"\f143"} +.oc-icon-play-circle:before, +.icon-play-circle:before {content:"\f144"} +.oc-icon-ticket:before, +.icon-ticket:before {content:"\f145"} +.oc-icon-minus-square:before, +.icon-minus-square:before {content:"\f146"} +.oc-icon-minus-square-o:before, +.icon-minus-square-o:before {content:"\f147"} +.oc-icon-level-up:before, +.icon-level-up:before {content:"\f148"} +.oc-icon-level-down:before, +.icon-level-down:before {content:"\f149"} +.oc-icon-check-square:before, +.icon-check-square:before {content:"\f14a"} +.oc-icon-pencil-square:before, +.icon-pencil-square:before {content:"\f14b"} +.oc-icon-external-link-square:before, +.icon-external-link-square:before {content:"\f14c"} +.oc-icon-share-square:before, +.icon-share-square:before {content:"\f14d"} +.oc-icon-compass:before, +.icon-compass:before {content:"\f14e"} +.oc-icon-toggle-down:before, +.icon-toggle-down:before, +.oc-icon-caret-square-o-down:before, +.icon-caret-square-o-down:before {content:"\f150"} +.oc-icon-toggle-up:before, +.icon-toggle-up:before, +.oc-icon-caret-square-o-up:before, +.icon-caret-square-o-up:before {content:"\f151"} +.oc-icon-toggle-right:before, +.icon-toggle-right:before, +.oc-icon-caret-square-o-right:before, +.icon-caret-square-o-right:before {content:"\f152"} +.oc-icon-euro:before, +.icon-euro:before, +.oc-icon-eur:before, +.icon-eur:before {content:"\f153"} +.oc-icon-gbp:before, +.icon-gbp:before {content:"\f154"} +.oc-icon-dollar:before, +.icon-dollar:before, +.oc-icon-usd:before, +.icon-usd:before {content:"\f155"} +.oc-icon-rupee:before, +.icon-rupee:before, +.oc-icon-inr:before, +.icon-inr:before {content:"\f156"} +.oc-icon-cny:before, +.icon-cny:before, +.oc-icon-rmb:before, +.icon-rmb:before, +.oc-icon-yen:before, +.icon-yen:before, +.oc-icon-jpy:before, +.icon-jpy:before {content:"\f157"} +.oc-icon-ruble:before, +.icon-ruble:before, +.oc-icon-rouble:before, +.icon-rouble:before, +.oc-icon-rub:before, +.icon-rub:before {content:"\f158"} +.oc-icon-won:before, +.icon-won:before, +.oc-icon-krw:before, +.icon-krw:before {content:"\f159"} +.oc-icon-bitcoin:before, +.icon-bitcoin:before, +.oc-icon-btc:before, +.icon-btc:before {content:"\f15a"} +.oc-icon-file:before, +.icon-file:before {content:"\f15b"} +.oc-icon-file-text:before, +.icon-file-text:before {content:"\f15c"} +.oc-icon-sort-alpha-asc:before, +.icon-sort-alpha-asc:before {content:"\f15d"} +.oc-icon-sort-alpha-desc:before, +.icon-sort-alpha-desc:before {content:"\f15e"} +.oc-icon-sort-amount-asc:before, +.icon-sort-amount-asc:before {content:"\f160"} +.oc-icon-sort-amount-desc:before, +.icon-sort-amount-desc:before {content:"\f161"} +.oc-icon-sort-numeric-asc:before, +.icon-sort-numeric-asc:before {content:"\f162"} +.oc-icon-sort-numeric-desc:before, +.icon-sort-numeric-desc:before {content:"\f163"} +.oc-icon-thumbs-up:before, +.icon-thumbs-up:before {content:"\f164"} +.oc-icon-thumbs-down:before, +.icon-thumbs-down:before {content:"\f165"} +.oc-icon-youtube-square:before, +.icon-youtube-square:before {content:"\f166"} +.oc-icon-youtube:before, +.icon-youtube:before {content:"\f167"} +.oc-icon-xing:before, +.icon-xing:before {content:"\f168"} +.oc-icon-xing-square:before, +.icon-xing-square:before {content:"\f169"} +.oc-icon-youtube-play:before, +.icon-youtube-play:before {content:"\f16a"} +.oc-icon-dropbox:before, +.icon-dropbox:before {content:"\f16b"} +.oc-icon-stack-overflow:before, +.icon-stack-overflow:before {content:"\f16c"} +.oc-icon-instagram:before, +.icon-instagram:before {content:"\f16d"} +.oc-icon-flickr:before, +.icon-flickr:before {content:"\f16e"} +.oc-icon-adn:before, +.icon-adn:before {content:"\f170"} +.oc-icon-bitbucket:before, +.icon-bitbucket:before {content:"\f171"} +.oc-icon-bitbucket-square:before, +.icon-bitbucket-square:before {content:"\f172"} +.oc-icon-tumblr:before, +.icon-tumblr:before {content:"\f173"} +.oc-icon-tumblr-square:before, +.icon-tumblr-square:before {content:"\f174"} +.oc-icon-long-arrow-down:before, +.icon-long-arrow-down:before {content:"\f175"} +.oc-icon-long-arrow-up:before, +.icon-long-arrow-up:before {content:"\f176"} +.oc-icon-long-arrow-left:before, +.icon-long-arrow-left:before {content:"\f177"} +.oc-icon-long-arrow-right:before, +.icon-long-arrow-right:before {content:"\f178"} +.oc-icon-apple:before, +.icon-apple:before {content:"\f179"} +.oc-icon-windows:before, +.icon-windows:before {content:"\f17a"} +.oc-icon-android:before, +.icon-android:before {content:"\f17b"} +.oc-icon-linux:before, +.icon-linux:before {content:"\f17c"} +.oc-icon-dribbble:before, +.icon-dribbble:before {content:"\f17d"} +.oc-icon-skype:before, +.icon-skype:before {content:"\f17e"} +.oc-icon-foursquare:before, +.icon-foursquare:before {content:"\f180"} +.oc-icon-trello:before, +.icon-trello:before {content:"\f181"} +.oc-icon-female:before, +.icon-female:before {content:"\f182"} +.oc-icon-male:before, +.icon-male:before {content:"\f183"} +.oc-icon-gittip:before, +.icon-gittip:before, +.oc-icon-gratipay:before, +.icon-gratipay:before {content:"\f184"} +.oc-icon-sun-o:before, +.icon-sun-o:before {content:"\f185"} +.oc-icon-moon-o:before, +.icon-moon-o:before {content:"\f186"} +.oc-icon-archive:before, +.icon-archive:before {content:"\f187"} +.oc-icon-bug:before, +.icon-bug:before {content:"\f188"} +.oc-icon-vk:before, +.icon-vk:before {content:"\f189"} +.oc-icon-weibo:before, +.icon-weibo:before {content:"\f18a"} +.oc-icon-renren:before, +.icon-renren:before {content:"\f18b"} +.oc-icon-pagelines:before, +.icon-pagelines:before {content:"\f18c"} +.oc-icon-stack-exchange:before, +.icon-stack-exchange:before {content:"\f18d"} +.oc-icon-arrow-circle-o-right:before, +.icon-arrow-circle-o-right:before {content:"\f18e"} +.oc-icon-arrow-circle-o-left:before, +.icon-arrow-circle-o-left:before {content:"\f190"} +.oc-icon-toggle-left:before, +.icon-toggle-left:before, +.oc-icon-caret-square-o-left:before, +.icon-caret-square-o-left:before {content:"\f191"} +.oc-icon-dot-circle-o:before, +.icon-dot-circle-o:before {content:"\f192"} +.oc-icon-wheelchair:before, +.icon-wheelchair:before {content:"\f193"} +.oc-icon-vimeo-square:before, +.icon-vimeo-square:before {content:"\f194"} +.oc-icon-turkish-lira:before, +.icon-turkish-lira:before, +.oc-icon-try:before, +.icon-try:before {content:"\f195"} +.oc-icon-plus-square-o:before, +.icon-plus-square-o:before {content:"\f196"} +.oc-icon-space-shuttle:before, +.icon-space-shuttle:before {content:"\f197"} +.oc-icon-slack:before, +.icon-slack:before {content:"\f198"} +.oc-icon-envelope-square:before, +.icon-envelope-square:before {content:"\f199"} +.oc-icon-wordpress:before, +.icon-wordpress:before {content:"\f19a"} +.oc-icon-openid:before, +.icon-openid:before {content:"\f19b"} +.oc-icon-institution:before, +.icon-institution:before, +.oc-icon-bank:before, +.icon-bank:before, +.oc-icon-university:before, +.icon-university:before {content:"\f19c"} +.oc-icon-mortar-board:before, +.icon-mortar-board:before, +.oc-icon-graduation-cap:before, +.icon-graduation-cap:before {content:"\f19d"} +.oc-icon-yahoo:before, +.icon-yahoo:before {content:"\f19e"} +.oc-icon-google:before, +.icon-google:before {content:"\f1a0"} +.oc-icon-reddit:before, +.icon-reddit:before {content:"\f1a1"} +.oc-icon-reddit-square:before, +.icon-reddit-square:before {content:"\f1a2"} +.oc-icon-stumbleupon-circle:before, +.icon-stumbleupon-circle:before {content:"\f1a3"} +.oc-icon-stumbleupon:before, +.icon-stumbleupon:before {content:"\f1a4"} +.oc-icon-delicious:before, +.icon-delicious:before {content:"\f1a5"} +.oc-icon-digg:before, +.icon-digg:before {content:"\f1a6"} +.oc-icon-pied-piper-pp:before, +.icon-pied-piper-pp:before {content:"\f1a7"} +.oc-icon-pied-piper-alt:before, +.icon-pied-piper-alt:before {content:"\f1a8"} +.oc-icon-drupal:before, +.icon-drupal:before {content:"\f1a9"} +.oc-icon-joomla:before, +.icon-joomla:before {content:"\f1aa"} +.oc-icon-language:before, +.icon-language:before {content:"\f1ab"} +.oc-icon-fax:before, +.icon-fax:before {content:"\f1ac"} +.oc-icon-building:before, +.icon-building:before {content:"\f1ad"} +.oc-icon-child:before, +.icon-child:before {content:"\f1ae"} +.oc-icon-paw:before, +.icon-paw:before {content:"\f1b0"} +.oc-icon-spoon:before, +.icon-spoon:before {content:"\f1b1"} +.oc-icon-cube:before, +.icon-cube:before {content:"\f1b2"} +.oc-icon-cubes:before, +.icon-cubes:before {content:"\f1b3"} +.oc-icon-behance:before, +.icon-behance:before {content:"\f1b4"} +.oc-icon-behance-square:before, +.icon-behance-square:before {content:"\f1b5"} +.oc-icon-steam:before, +.icon-steam:before {content:"\f1b6"} +.oc-icon-steam-square:before, +.icon-steam-square:before {content:"\f1b7"} +.oc-icon-recycle:before, +.icon-recycle:before {content:"\f1b8"} +.oc-icon-automobile:before, +.icon-automobile:before, +.oc-icon-car:before, +.icon-car:before {content:"\f1b9"} +.oc-icon-cab:before, +.icon-cab:before, +.oc-icon-taxi:before, +.icon-taxi:before {content:"\f1ba"} +.oc-icon-tree:before, +.icon-tree:before {content:"\f1bb"} +.oc-icon-spotify:before, +.icon-spotify:before {content:"\f1bc"} +.oc-icon-deviantart:before, +.icon-deviantart:before {content:"\f1bd"} +.oc-icon-soundcloud:before, +.icon-soundcloud:before {content:"\f1be"} +.oc-icon-database:before, +.icon-database:before {content:"\f1c0"} +.oc-icon-file-pdf-o:before, +.icon-file-pdf-o:before {content:"\f1c1"} +.oc-icon-file-word-o:before, +.icon-file-word-o:before {content:"\f1c2"} +.oc-icon-file-excel-o:before, +.icon-file-excel-o:before {content:"\f1c3"} +.oc-icon-file-powerpoint-o:before, +.icon-file-powerpoint-o:before {content:"\f1c4"} +.oc-icon-file-photo-o:before, +.icon-file-photo-o:before, +.oc-icon-file-picture-o:before, +.icon-file-picture-o:before, +.oc-icon-file-image-o:before, +.icon-file-image-o:before {content:"\f1c5"} +.oc-icon-file-zip-o:before, +.icon-file-zip-o:before, +.oc-icon-file-archive-o:before, +.icon-file-archive-o:before {content:"\f1c6"} +.oc-icon-file-sound-o:before, +.icon-file-sound-o:before, +.oc-icon-file-audio-o:before, +.icon-file-audio-o:before {content:"\f1c7"} +.oc-icon-file-movie-o:before, +.icon-file-movie-o:before, +.oc-icon-file-video-o:before, +.icon-file-video-o:before {content:"\f1c8"} +.oc-icon-file-code-o:before, +.icon-file-code-o:before {content:"\f1c9"} +.oc-icon-vine:before, +.icon-vine:before {content:"\f1ca"} +.oc-icon-codepen:before, +.icon-codepen:before {content:"\f1cb"} +.oc-icon-jsfiddle:before, +.icon-jsfiddle:before {content:"\f1cc"} +.oc-icon-life-bouy:before, +.icon-life-bouy:before, +.oc-icon-life-buoy:before, +.icon-life-buoy:before, +.oc-icon-life-saver:before, +.icon-life-saver:before, +.oc-icon-support:before, +.icon-support:before, +.oc-icon-life-ring:before, +.icon-life-ring:before {content:"\f1cd"} +.oc-icon-circle-o-notch:before, +.icon-circle-o-notch:before {content:"\f1ce"} +.oc-icon-ra:before, +.icon-ra:before, +.oc-icon-resistance:before, +.icon-resistance:before, +.oc-icon-rebel:before, +.icon-rebel:before {content:"\f1d0"} +.oc-icon-ge:before, +.icon-ge:before, +.oc-icon-empire:before, +.icon-empire:before {content:"\f1d1"} +.oc-icon-git-square:before, +.icon-git-square:before {content:"\f1d2"} +.oc-icon-git:before, +.icon-git:before {content:"\f1d3"} +.oc-icon-y-combinator-square:before, +.icon-y-combinator-square:before, +.oc-icon-yc-square:before, +.icon-yc-square:before, +.oc-icon-hacker-news:before, +.icon-hacker-news:before {content:"\f1d4"} +.oc-icon-tencent-weibo:before, +.icon-tencent-weibo:before {content:"\f1d5"} +.oc-icon-qq:before, +.icon-qq:before {content:"\f1d6"} +.oc-icon-wechat:before, +.icon-wechat:before, +.oc-icon-weixin:before, +.icon-weixin:before {content:"\f1d7"} +.oc-icon-send:before, +.icon-send:before, +.oc-icon-paper-plane:before, +.icon-paper-plane:before {content:"\f1d8"} +.oc-icon-send-o:before, +.icon-send-o:before, +.oc-icon-paper-plane-o:before, +.icon-paper-plane-o:before {content:"\f1d9"} +.oc-icon-history:before, +.icon-history:before {content:"\f1da"} +.oc-icon-circle-thin:before, +.icon-circle-thin:before {content:"\f1db"} +.oc-icon-header:before, +.icon-header:before {content:"\f1dc"} +.oc-icon-paragraph:before, +.icon-paragraph:before {content:"\f1dd"} +.oc-icon-sliders:before, +.icon-sliders:before {content:"\f1de"} +.oc-icon-share-alt:before, +.icon-share-alt:before {content:"\f1e0"} +.oc-icon-share-alt-square:before, +.icon-share-alt-square:before {content:"\f1e1"} +.oc-icon-bomb:before, +.icon-bomb:before {content:"\f1e2"} +.oc-icon-soccer-ball-o:before, +.icon-soccer-ball-o:before, +.oc-icon-futbol-o:before, +.icon-futbol-o:before {content:"\f1e3"} +.oc-icon-tty:before, +.icon-tty:before {content:"\f1e4"} +.oc-icon-binoculars:before, +.icon-binoculars:before {content:"\f1e5"} +.oc-icon-plug:before, +.icon-plug:before {content:"\f1e6"} +.oc-icon-slideshare:before, +.icon-slideshare:before {content:"\f1e7"} +.oc-icon-twitch:before, +.icon-twitch:before {content:"\f1e8"} +.oc-icon-yelp:before, +.icon-yelp:before {content:"\f1e9"} +.oc-icon-newspaper-o:before, +.icon-newspaper-o:before {content:"\f1ea"} +.oc-icon-wifi:before, +.icon-wifi:before {content:"\f1eb"} +.oc-icon-calculator:before, +.icon-calculator:before {content:"\f1ec"} +.oc-icon-paypal:before, +.icon-paypal:before {content:"\f1ed"} +.oc-icon-google-wallet:before, +.icon-google-wallet:before {content:"\f1ee"} +.oc-icon-cc-visa:before, +.icon-cc-visa:before {content:"\f1f0"} +.oc-icon-cc-mastercard:before, +.icon-cc-mastercard:before {content:"\f1f1"} +.oc-icon-cc-discover:before, +.icon-cc-discover:before {content:"\f1f2"} +.oc-icon-cc-amex:before, +.icon-cc-amex:before {content:"\f1f3"} +.oc-icon-cc-paypal:before, +.icon-cc-paypal:before {content:"\f1f4"} +.oc-icon-cc-stripe:before, +.icon-cc-stripe:before {content:"\f1f5"} +.oc-icon-bell-slash:before, +.icon-bell-slash:before {content:"\f1f6"} +.oc-icon-bell-slash-o:before, +.icon-bell-slash-o:before {content:"\f1f7"} +.oc-icon-trash:before, +.icon-trash:before {content:"\f1f8"} +.oc-icon-copyright:before, +.icon-copyright:before {content:"\f1f9"} +.oc-icon-at:before, +.icon-at:before {content:"\f1fa"} +.oc-icon-eyedropper:before, +.icon-eyedropper:before {content:"\f1fb"} +.oc-icon-paint-brush:before, +.icon-paint-brush:before {content:"\f1fc"} +.oc-icon-birthday-cake:before, +.icon-birthday-cake:before {content:"\f1fd"} +.oc-icon-area-chart:before, +.icon-area-chart:before {content:"\f1fe"} +.oc-icon-pie-chart:before, +.icon-pie-chart:before {content:"\f200"} +.oc-icon-line-chart:before, +.icon-line-chart:before {content:"\f201"} +.oc-icon-lastfm:before, +.icon-lastfm:before {content:"\f202"} +.oc-icon-lastfm-square:before, +.icon-lastfm-square:before {content:"\f203"} +.oc-icon-toggle-off:before, +.icon-toggle-off:before {content:"\f204"} +.oc-icon-toggle-on:before, +.icon-toggle-on:before {content:"\f205"} +.oc-icon-bicycle:before, +.icon-bicycle:before {content:"\f206"} +.oc-icon-bus:before, +.icon-bus:before {content:"\f207"} +.oc-icon-ioxhost:before, +.icon-ioxhost:before {content:"\f208"} +.oc-icon-angellist:before, +.icon-angellist:before {content:"\f209"} +.oc-icon-cc:before, +.icon-cc:before {content:"\f20a"} +.oc-icon-shekel:before, +.icon-shekel:before, +.oc-icon-sheqel:before, +.icon-sheqel:before, +.oc-icon-ils:before, +.icon-ils:before {content:"\f20b"} +.oc-icon-meanpath:before, +.icon-meanpath:before {content:"\f20c"} +.oc-icon-buysellads:before, +.icon-buysellads:before {content:"\f20d"} +.oc-icon-connectdevelop:before, +.icon-connectdevelop:before {content:"\f20e"} +.oc-icon-dashcube:before, +.icon-dashcube:before {content:"\f210"} +.oc-icon-forumbee:before, +.icon-forumbee:before {content:"\f211"} +.oc-icon-leanpub:before, +.icon-leanpub:before {content:"\f212"} +.oc-icon-sellsy:before, +.icon-sellsy:before {content:"\f213"} +.oc-icon-shirtsinbulk:before, +.icon-shirtsinbulk:before {content:"\f214"} +.oc-icon-simplybuilt:before, +.icon-simplybuilt:before {content:"\f215"} +.oc-icon-skyatlas:before, +.icon-skyatlas:before {content:"\f216"} +.oc-icon-cart-plus:before, +.icon-cart-plus:before {content:"\f217"} +.oc-icon-cart-arrow-down:before, +.icon-cart-arrow-down:before {content:"\f218"} +.oc-icon-diamond:before, +.icon-diamond:before {content:"\f219"} +.oc-icon-ship:before, +.icon-ship:before {content:"\f21a"} +.oc-icon-user-secret:before, +.icon-user-secret:before {content:"\f21b"} +.oc-icon-motorcycle:before, +.icon-motorcycle:before {content:"\f21c"} +.oc-icon-street-view:before, +.icon-street-view:before {content:"\f21d"} +.oc-icon-heartbeat:before, +.icon-heartbeat:before {content:"\f21e"} +.oc-icon-venus:before, +.icon-venus:before {content:"\f221"} +.oc-icon-mars:before, +.icon-mars:before {content:"\f222"} +.oc-icon-mercury:before, +.icon-mercury:before {content:"\f223"} +.oc-icon-intersex:before, +.icon-intersex:before, +.oc-icon-transgender:before, +.icon-transgender:before {content:"\f224"} +.oc-icon-transgender-alt:before, +.icon-transgender-alt:before {content:"\f225"} +.oc-icon-venus-double:before, +.icon-venus-double:before {content:"\f226"} +.oc-icon-mars-double:before, +.icon-mars-double:before {content:"\f227"} +.oc-icon-venus-mars:before, +.icon-venus-mars:before {content:"\f228"} +.oc-icon-mars-stroke:before, +.icon-mars-stroke:before {content:"\f229"} +.oc-icon-mars-stroke-v:before, +.icon-mars-stroke-v:before {content:"\f22a"} +.oc-icon-mars-stroke-h:before, +.icon-mars-stroke-h:before {content:"\f22b"} +.oc-icon-neuter:before, +.icon-neuter:before {content:"\f22c"} +.oc-icon-genderless:before, +.icon-genderless:before {content:"\f22d"} +.oc-icon-facebook-official:before, +.icon-facebook-official:before {content:"\f230"} +.oc-icon-pinterest-p:before, +.icon-pinterest-p:before {content:"\f231"} +.oc-icon-whatsapp:before, +.icon-whatsapp:before {content:"\f232"} +.oc-icon-server:before, +.icon-server:before {content:"\f233"} +.oc-icon-user-plus:before, +.icon-user-plus:before {content:"\f234"} +.oc-icon-user-times:before, +.icon-user-times:before {content:"\f235"} +.oc-icon-hotel:before, +.icon-hotel:before, +.oc-icon-bed:before, +.icon-bed:before {content:"\f236"} +.oc-icon-viacoin:before, +.icon-viacoin:before {content:"\f237"} +.oc-icon-train:before, +.icon-train:before {content:"\f238"} +.oc-icon-subway:before, +.icon-subway:before {content:"\f239"} +.oc-icon-medium:before, +.icon-medium:before {content:"\f23a"} +.oc-icon-yc:before, +.icon-yc:before, +.oc-icon-y-combinator:before, +.icon-y-combinator:before {content:"\f23b"} +.oc-icon-optin-monster:before, +.icon-optin-monster:before {content:"\f23c"} +.oc-icon-opencart:before, +.icon-opencart:before {content:"\f23d"} +.oc-icon-expeditedssl:before, +.icon-expeditedssl:before {content:"\f23e"} +.oc-icon-battery-4:before, +.icon-battery-4:before, +.oc-icon-battery:before, +.icon-battery:before, +.oc-icon-battery-full:before, +.icon-battery-full:before {content:"\f240"} +.oc-icon-battery-3:before, +.icon-battery-3:before, +.oc-icon-battery-three-quarters:before, +.icon-battery-three-quarters:before {content:"\f241"} +.oc-icon-battery-2:before, +.icon-battery-2:before, +.oc-icon-battery-half:before, +.icon-battery-half:before {content:"\f242"} +.oc-icon-battery-1:before, +.icon-battery-1:before, +.oc-icon-battery-quarter:before, +.icon-battery-quarter:before {content:"\f243"} +.oc-icon-battery-0:before, +.icon-battery-0:before, +.oc-icon-battery-empty:before, +.icon-battery-empty:before {content:"\f244"} +.oc-icon-mouse-pointer:before, +.icon-mouse-pointer:before {content:"\f245"} +.oc-icon-i-cursor:before, +.icon-i-cursor:before {content:"\f246"} +.oc-icon-object-group:before, +.icon-object-group:before {content:"\f247"} +.oc-icon-object-ungroup:before, +.icon-object-ungroup:before {content:"\f248"} +.oc-icon-sticky-note:before, +.icon-sticky-note:before {content:"\f249"} +.oc-icon-sticky-note-o:before, +.icon-sticky-note-o:before {content:"\f24a"} +.oc-icon-cc-jcb:before, +.icon-cc-jcb:before {content:"\f24b"} +.oc-icon-cc-diners-club:before, +.icon-cc-diners-club:before {content:"\f24c"} +.oc-icon-clone:before, +.icon-clone:before {content:"\f24d"} +.oc-icon-balance-scale:before, +.icon-balance-scale:before {content:"\f24e"} +.oc-icon-hourglass-o:before, +.icon-hourglass-o:before {content:"\f250"} +.oc-icon-hourglass-1:before, +.icon-hourglass-1:before, +.oc-icon-hourglass-start:before, +.icon-hourglass-start:before {content:"\f251"} +.oc-icon-hourglass-2:before, +.icon-hourglass-2:before, +.oc-icon-hourglass-half:before, +.icon-hourglass-half:before {content:"\f252"} +.oc-icon-hourglass-3:before, +.icon-hourglass-3:before, +.oc-icon-hourglass-end:before, +.icon-hourglass-end:before {content:"\f253"} +.oc-icon-hourglass:before, +.icon-hourglass:before {content:"\f254"} +.oc-icon-hand-grab-o:before, +.icon-hand-grab-o:before, +.oc-icon-hand-rock-o:before, +.icon-hand-rock-o:before {content:"\f255"} +.oc-icon-hand-stop-o:before, +.icon-hand-stop-o:before, +.oc-icon-hand-paper-o:before, +.icon-hand-paper-o:before {content:"\f256"} +.oc-icon-hand-scissors-o:before, +.icon-hand-scissors-o:before {content:"\f257"} +.oc-icon-hand-lizard-o:before, +.icon-hand-lizard-o:before {content:"\f258"} +.oc-icon-hand-spock-o:before, +.icon-hand-spock-o:before {content:"\f259"} +.oc-icon-hand-pointer-o:before, +.icon-hand-pointer-o:before {content:"\f25a"} +.oc-icon-hand-peace-o:before, +.icon-hand-peace-o:before {content:"\f25b"} +.oc-icon-trademark:before, +.icon-trademark:before {content:"\f25c"} +.oc-icon-registered:before, +.icon-registered:before {content:"\f25d"} +.oc-icon-creative-commons:before, +.icon-creative-commons:before {content:"\f25e"} +.oc-icon-gg:before, +.icon-gg:before {content:"\f260"} +.oc-icon-gg-circle:before, +.icon-gg-circle:before {content:"\f261"} +.oc-icon-tripadvisor:before, +.icon-tripadvisor:before {content:"\f262"} +.oc-icon-odnoklassniki:before, +.icon-odnoklassniki:before {content:"\f263"} +.oc-icon-odnoklassniki-square:before, +.icon-odnoklassniki-square:before {content:"\f264"} +.oc-icon-get-pocket:before, +.icon-get-pocket:before {content:"\f265"} +.oc-icon-wikipedia-w:before, +.icon-wikipedia-w:before {content:"\f266"} +.oc-icon-safari:before, +.icon-safari:before {content:"\f267"} +.oc-icon-chrome:before, +.icon-chrome:before {content:"\f268"} +.oc-icon-firefox:before, +.icon-firefox:before {content:"\f269"} +.oc-icon-opera:before, +.icon-opera:before {content:"\f26a"} +.oc-icon-internet-explorer:before, +.icon-internet-explorer:before {content:"\f26b"} +.oc-icon-tv:before, +.icon-tv:before, +.oc-icon-television:before, +.icon-television:before {content:"\f26c"} +.oc-icon-contao:before, +.icon-contao:before {content:"\f26d"} +.oc-icon-500px:before, +.icon-500px:before {content:"\f26e"} +.oc-icon-amazon:before, +.icon-amazon:before {content:"\f270"} +.oc-icon-calendar-plus-o:before, +.icon-calendar-plus-o:before {content:"\f271"} +.oc-icon-calendar-minus-o:before, +.icon-calendar-minus-o:before {content:"\f272"} +.oc-icon-calendar-times-o:before, +.icon-calendar-times-o:before {content:"\f273"} +.oc-icon-calendar-check-o:before, +.icon-calendar-check-o:before {content:"\f274"} +.oc-icon-industry:before, +.icon-industry:before {content:"\f275"} +.oc-icon-map-pin:before, +.icon-map-pin:before {content:"\f276"} +.oc-icon-map-signs:before, +.icon-map-signs:before {content:"\f277"} +.oc-icon-map-o:before, +.icon-map-o:before {content:"\f278"} +.oc-icon-map:before, +.icon-map:before {content:"\f279"} +.oc-icon-commenting:before, +.icon-commenting:before {content:"\f27a"} +.oc-icon-commenting-o:before, +.icon-commenting-o:before {content:"\f27b"} +.oc-icon-houzz:before, +.icon-houzz:before {content:"\f27c"} +.oc-icon-vimeo:before, +.icon-vimeo:before {content:"\f27d"} +.oc-icon-black-tie:before, +.icon-black-tie:before {content:"\f27e"} +.oc-icon-fonticons:before, +.icon-fonticons:before {content:"\f280"} +.oc-icon-reddit-alien:before, +.icon-reddit-alien:before {content:"\f281"} +.oc-icon-edge:before, +.icon-edge:before {content:"\f282"} +.oc-icon-credit-card-alt:before, +.icon-credit-card-alt:before {content:"\f283"} +.oc-icon-codiepie:before, +.icon-codiepie:before {content:"\f284"} +.oc-icon-modx:before, +.icon-modx:before {content:"\f285"} +.oc-icon-fort-awesome:before, +.icon-fort-awesome:before {content:"\f286"} +.oc-icon-usb:before, +.icon-usb:before {content:"\f287"} +.oc-icon-product-hunt:before, +.icon-product-hunt:before {content:"\f288"} +.oc-icon-mixcloud:before, +.icon-mixcloud:before {content:"\f289"} +.oc-icon-scribd:before, +.icon-scribd:before {content:"\f28a"} +.oc-icon-pause-circle:before, +.icon-pause-circle:before {content:"\f28b"} +.oc-icon-pause-circle-o:before, +.icon-pause-circle-o:before {content:"\f28c"} +.oc-icon-stop-circle:before, +.icon-stop-circle:before {content:"\f28d"} +.oc-icon-stop-circle-o:before, +.icon-stop-circle-o:before {content:"\f28e"} +.oc-icon-shopping-bag:before, +.icon-shopping-bag:before {content:"\f290"} +.oc-icon-shopping-basket:before, +.icon-shopping-basket:before {content:"\f291"} +.oc-icon-hashtag:before, +.icon-hashtag:before {content:"\f292"} +.oc-icon-bluetooth:before, +.icon-bluetooth:before {content:"\f293"} +.oc-icon-bluetooth-b:before, +.icon-bluetooth-b:before {content:"\f294"} +.oc-icon-percent:before, +.icon-percent:before {content:"\f295"} +.oc-icon-gitlab:before, +.icon-gitlab:before {content:"\f296"} +.oc-icon-wpbeginner:before, +.icon-wpbeginner:before {content:"\f297"} +.oc-icon-wpforms:before, +.icon-wpforms:before {content:"\f298"} +.oc-icon-envira:before, +.icon-envira:before {content:"\f299"} +.oc-icon-universal-access:before, +.icon-universal-access:before {content:"\f29a"} +.oc-icon-wheelchair-alt:before, +.icon-wheelchair-alt:before {content:"\f29b"} +.oc-icon-question-circle-o:before, +.icon-question-circle-o:before {content:"\f29c"} +.oc-icon-blind:before, +.icon-blind:before {content:"\f29d"} +.oc-icon-audio-description:before, +.icon-audio-description:before {content:"\f29e"} +.oc-icon-volume-control-phone:before, +.icon-volume-control-phone:before {content:"\f2a0"} +.oc-icon-braille:before, +.icon-braille:before {content:"\f2a1"} +.oc-icon-assistive-listening-systems:before, +.icon-assistive-listening-systems:before {content:"\f2a2"} +.oc-icon-asl-interpreting:before, +.icon-asl-interpreting:before, +.oc-icon-american-sign-language-interpreting:before, +.icon-american-sign-language-interpreting:before {content:"\f2a3"} +.oc-icon-deafness:before, +.icon-deafness:before, +.oc-icon-hard-of-hearing:before, +.icon-hard-of-hearing:before, +.oc-icon-deaf:before, +.icon-deaf:before {content:"\f2a4"} +.oc-icon-glide:before, +.icon-glide:before {content:"\f2a5"} +.oc-icon-glide-g:before, +.icon-glide-g:before {content:"\f2a6"} +.oc-icon-signing:before, +.icon-signing:before, +.oc-icon-sign-language:before, +.icon-sign-language:before {content:"\f2a7"} +.oc-icon-low-vision:before, +.icon-low-vision:before {content:"\f2a8"} +.oc-icon-viadeo:before, +.icon-viadeo:before {content:"\f2a9"} +.oc-icon-viadeo-square:before, +.icon-viadeo-square:before {content:"\f2aa"} +.oc-icon-snapchat:before, +.icon-snapchat:before {content:"\f2ab"} +.oc-icon-snapchat-ghost:before, +.icon-snapchat-ghost:before {content:"\f2ac"} +.oc-icon-snapchat-square:before, +.icon-snapchat-square:before {content:"\f2ad"} +.oc-icon-pied-piper:before, +.icon-pied-piper:before {content:"\f2ae"} +.oc-icon-first-order:before, +.icon-first-order:before {content:"\f2b0"} +.oc-icon-yoast:before, +.icon-yoast:before {content:"\f2b1"} +.oc-icon-themeisle:before, +.icon-themeisle:before {content:"\f2b2"} +.oc-icon-google-plus-circle:before, +.icon-google-plus-circle:before, +.oc-icon-google-plus-official:before, +.icon-google-plus-official:before {content:"\f2b3"} +.oc-icon-fa:before, +.icon-fa:before, +.oc-icon-font-awesome:before, +.icon-font-awesome:before {content:"\f2b4"} +.oc-icon-handshake-o:before, +.icon-handshake-o:before {content:"\f2b5"} +.oc-icon-envelope-open:before, +.icon-envelope-open:before {content:"\f2b6"} +.oc-icon-envelope-open-o:before, +.icon-envelope-open-o:before {content:"\f2b7"} +.oc-icon-linode:before, +.icon-linode:before {content:"\f2b8"} +.oc-icon-address-book:before, +.icon-address-book:before {content:"\f2b9"} +.oc-icon-address-book-o:before, +.icon-address-book-o:before {content:"\f2ba"} +.oc-icon-vcard:before, +.icon-vcard:before, +.oc-icon-address-card:before, +.icon-address-card:before {content:"\f2bb"} +.oc-icon-vcard-o:before, +.icon-vcard-o:before, +.oc-icon-address-card-o:before, +.icon-address-card-o:before {content:"\f2bc"} +.oc-icon-user-circle:before, +.icon-user-circle:before {content:"\f2bd"} +.oc-icon-user-circle-o:before, +.icon-user-circle-o:before {content:"\f2be"} +.oc-icon-user-o:before, +.icon-user-o:before {content:"\f2c0"} +.oc-icon-id-badge:before, +.icon-id-badge:before {content:"\f2c1"} +.oc-icon-drivers-license:before, +.icon-drivers-license:before, +.oc-icon-id-card:before, +.icon-id-card:before {content:"\f2c2"} +.oc-icon-drivers-license-o:before, +.icon-drivers-license-o:before, +.oc-icon-id-card-o:before, +.icon-id-card-o:before {content:"\f2c3"} +.oc-icon-quora:before, +.icon-quora:before {content:"\f2c4"} +.oc-icon-free-code-camp:before, +.icon-free-code-camp:before {content:"\f2c5"} +.oc-icon-telegram:before, +.icon-telegram:before {content:"\f2c6"} +.oc-icon-thermometer-4:before, +.icon-thermometer-4:before, +.oc-icon-thermometer:before, +.icon-thermometer:before, +.oc-icon-thermometer-full:before, +.icon-thermometer-full:before {content:"\f2c7"} +.oc-icon-thermometer-3:before, +.icon-thermometer-3:before, +.oc-icon-thermometer-three-quarters:before, +.icon-thermometer-three-quarters:before {content:"\f2c8"} +.oc-icon-thermometer-2:before, +.icon-thermometer-2:before, +.oc-icon-thermometer-half:before, +.icon-thermometer-half:before {content:"\f2c9"} +.oc-icon-thermometer-1:before, +.icon-thermometer-1:before, +.oc-icon-thermometer-quarter:before, +.icon-thermometer-quarter:before {content:"\f2ca"} +.oc-icon-thermometer-0:before, +.icon-thermometer-0:before, +.oc-icon-thermometer-empty:before, +.icon-thermometer-empty:before {content:"\f2cb"} +.oc-icon-shower:before, +.icon-shower:before {content:"\f2cc"} +.oc-icon-bathtub:before, +.icon-bathtub:before, +.oc-icon-s15:before, +.icon-s15:before, +.oc-icon-bath:before, +.icon-bath:before {content:"\f2cd"} +.oc-icon-podcast:before, +.icon-podcast:before {content:"\f2ce"} +.oc-icon-window-maximize:before, +.icon-window-maximize:before {content:"\f2d0"} +.oc-icon-window-minimize:before, +.icon-window-minimize:before {content:"\f2d1"} +.oc-icon-window-restore:before, +.icon-window-restore:before {content:"\f2d2"} +.oc-icon-times-rectangle:before, +.icon-times-rectangle:before, +.oc-icon-window-close:before, +.icon-window-close:before {content:"\f2d3"} +.oc-icon-times-rectangle-o:before, +.icon-times-rectangle-o:before, +.oc-icon-window-close-o:before, +.icon-window-close-o:before {content:"\f2d4"} +.oc-icon-bandcamp:before, +.icon-bandcamp:before {content:"\f2d5"} +.oc-icon-grav:before, +.icon-grav:before {content:"\f2d6"} +.oc-icon-etsy:before, +.icon-etsy:before {content:"\f2d7"} +.oc-icon-imdb:before, +.icon-imdb:before {content:"\f2d8"} +.oc-icon-ravelry:before, +.icon-ravelry:before {content:"\f2d9"} +.oc-icon-eercast:before, +.icon-eercast:before {content:"\f2da"} +.oc-icon-microchip:before, +.icon-microchip:before {content:"\f2db"} +.oc-icon-snowflake-o:before, +.icon-snowflake-o:before {content:"\f2dc"} +.oc-icon-superpowers:before, +.icon-superpowers:before {content:"\f2dd"} +.oc-icon-wpexplorer:before, +.icon-wpexplorer:before {content:"\f2de"} +.oc-icon-meetup:before, +.icon-meetup:before {content:"\f2e0"} +.close {float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;font-family:sans-serif;opacity:0.2;filter:alpha(opacity=20)} +.close:hover, +.close:focus {color:#000;text-decoration:none;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)} +button.close {padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none} +@font-face {font-family:'FontAwesome';src:url('../ui/font/fontawesome-webfont.eot?v=1.0.1');src:url('../ui/font/fontawesome-webfont.eot?#iefix&v=1.0.1') format('embedded-opentype'),url('../ui/font/fontawesome-webfont.woff?v=1.0.1') format('woff'),url('../ui/font/fontawesome-webfont.ttf?v=1.0.1') format('truetype'),url('../ui/font/fontawesome-webfont.svg#fontawesomeregular?v=1.0.1') format('svg');font-weight:normal;font-style:normal} +[class^="icon-"], +[class*=" icon-"] {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0% 0%;background-repeat:repeat;margin-top:0} +[class^="icon-"]:before, +[class*=" icon-"]:before {text-decoration:inherit;display:inline-block;speak:none} +[class^="icon-"].pull-left, +[class*=" icon-"].pull-left {margin-right:.3em} +[class^="icon-"].pull-right, +[class*=" icon-"].pull-right {margin-left:.3em} +[class^="oc-icon-"]:before, +[class*=" oc-icon-"]:before {display:inline-block;margin-right:8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;vertical-align:baseline} +[class^="oc-icon-"].empty:before, +[class*=" oc-icon-"].empty:before {margin-right:0} +.icon-lg {font-size:1.33333333em;line-height:0.75em;vertical-align:-15%} +.icon-2x {font-size:2em} +.icon-3x {font-size:3em} +.icon-4x {font-size:4em} +.icon-5x {font-size:5em} +body {padding-top:20px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";background:#f3f3f3;color:#405261} +h1, +h2, +h3, +h4, +h5 {font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";text-transform:uppercase} +h1 {font-weight:300;font-size:50px;margin-bottom:15px} +h1 i[class^="icon-"]:before {font-size:46px} +i[class^="icon-"].warning {color:#c84530} +h3 {font-size:24px;font-weight:300} +p.lead {font-size:16px;font-weight:300} +ul.indicators {list-style:none;padding:0;margin:0} +ul.indicators:before, +ul.indicators:after {content:" ";display:table} +ul.indicators:after {clear:both} +ul.indicators:before, +ul.indicators:after {content:" ";display:table} +ul.indicators:after {clear:both} +ul.indicators li {float:left;margin-right:50px} +ul.indicators li:last-child {margin-right:0} +ul.indicators li h3 {font-weight:300;font-size:12px;line-height:100%;margin-bottom:7px} +ul.indicators li p {font-size:20px;font-weight:600;word-wrap:break-word}table.data-table {width:100%;font-size:12px;border-collapse:collapse;margin-bottom:20px} +table.data-table tr:first-child th {border-top:0} +table.data-table tr:last-child td {border-bottom:0} +table.data-table tr td:first-child, +table.data-table tr th:first-child {border-left:0} +table.data-table tr td:last-child, +table.data-table tr th:last-child {border-right:0} +table.data-table td, +table.data-table th {vertical-align:top;text-align:left;font-weight:300;border:1px solid #fff;padding:6px 8px} +table.data-table td.right, +table.data-table th.right {text-align:right} +table.data-table thead th, +table.data-table thead th {text-transform:uppercase;background:#7b8892;color:white} +table.data-table tbody td, +table.data-table tbody th {background-color:white} +table.data-table tbody tr:nth-child(2n) td, +table.data-table tbody tr:nth-child(2n) th {background-color:#d8d9db}.exception-name-block {margin-bottom:15px} +.exception-name-block div, +.exception-name-block p {font-weight:300;padding:10px 15px} +.exception-name-block div {background:#c84530;color:white;position:relative} +.exception-name-block div:after {position:absolute;display:block;content:" ";bottom:-6px;left:20px;width:0;height:0;border-style:solid;border-width:8px 8px 0 8px;border-color:#c84530 transparent transparent transparent} +.exception-name-block p {background:#ebebeb;margin-bottom:0} +.exception-name-block p span {color:#899fb1} +.syntaxhighlighter {margin-bottom:30px;background:white;font:12px/170% Monaco,Menlo,'Ubuntu Mono','Droid Sans Mono','Courier New',monospace !important} +.syntaxhighlighter table {width:100%;table-layout:fixed} +.syntaxhighlighter table td {padding:5px 0} +.syntaxhighlighter table td.gutter {padding:5px 10px;width:35px;background:#7b8892;color:white} +.syntaxhighlighter table td.code {overflow-x:auto;width:100% !important} +.syntaxhighlighter table td.code .container {width:100% !important;padding:0} +.syntaxhighlighter table td.code .container div.line {white-space:nowrap;padding-left:10px} +.syntaxhighlighter table td.code .container div.line.highlighted {background:#c84530;color:white} +.syntaxhighlighter table td.code .container div.line code {font:12px/170% Monaco,Menlo,'Ubuntu Mono','Droid Sans Mono','Courier New',monospace !important} \ No newline at end of file diff --git a/modules/system/assets/css/updates/details.css b/modules/system/assets/css/updates/details.css new file mode 100644 index 0000000..06ee5c4 --- /dev/null +++ b/modules/system/assets/css/updates/details.css @@ -0,0 +1,84 @@ +.plugin-details-content { + padding: 0 0; +} +.plugin-details-content > *:first-child { + margin-top: 0; +} +.plugin-details-content h1 { + font-size: 28px; +} +.plugin-details-content h2 { + font-size: 24px; +} +.plugin-details-content h3 { + font-size: 20px; +} +.plugin-details-content h4 { + font-size: 17px; +} +.plugin-details-content h1, +.plugin-details-content h2 { + padding-bottom: 10px; + border-bottom: 1px solid #ccc; +} +.plugin-details-content img { + max-width: 100%; +} +.plugin-details-content ul, +.plugin-details-content ol { + padding-left: 20px; +} +.plugin-details-content pre { + display: block; + border: none; + margin: 10px -20px 20px; + padding: 10px 10px 10px 20px; + font-size: 13px; + word-break: break-all; + word-wrap: break-word; + color: #fff; + background-color: #333; +} +.plugin-details-content pre code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; +} +.plugin-details-content ul pre, +.plugin-details-content ol pre { + margin-left: -40px; + padding-left: 40px; +} +.plugin-details-content table th { + font-weight: bold; +} +.plugin-details-content table th, +.plugin-details-content table td { + padding: 6px 13px; + border: 1px solid #ddd; +} +.plugin-details-content table tr { + background-color: #fff; + border-top: 1px solid #ccc; +} +.plugin-details-content table tr:nth-child(2n) { + background-color: #f8f8f8; +} +.plugin-details-content dl dt, +.plugin-details-content dl dd { + margin-bottom: 10px; +} +.plugin-details-content dl dt { + width: 75px; + float: left; + text-align: right; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} +.plugin-details-content dl dd { + margin-left: 85px; +} diff --git a/modules/system/assets/css/updates/install.css b/modules/system/assets/css/updates/install.css new file mode 100644 index 0000000..7f51a61 --- /dev/null +++ b/modules/system/assets/css/updates/install.css @@ -0,0 +1,297 @@ +.product-list-empty { + padding: 5px 0; + font-size: 16px; + color: #999; +} +.product-list { + margin: 0; + padding: 10px 0; + overflow: hidden; + /* clearfix */ +} +.product-list li button { + position: absolute; + top: 0; + right: 0; + width: 20px; + height: 20px; + opacity: 0; + outline: none; +} +.product-list li button, +.product-list li .image, +.product-list li .details { + -webkit-transition: opacity .2s linear; + -moz-transition: opacity .2s linear; + transition: opacity .2s linear; +} +.product-list li:hover button { + opacity: .3; +} +.product-list li:hover button:hover { + opacity: .8; +} +.plugin-list li { + list-style: none; + position: relative; + border-bottom: 1px solid #E6E9E9; + margin-bottom: 10px; + padding-bottom: 10px; + overflow: hidden; +} +.plugin-list li .image { + float: left; + margin-right: 15px; + margin-left: 5px; +} +.plugin-list li .image img { + width: 50px; + height: 50px; +} +.plugin-list li .details p { + padding: 0; + margin: 3px 0 0 0; + color: #808C8D; +} +.plugin-list li h4 { + padding: 5px 0 0; + margin: 0; + color: #C03F31; + font-weight: 400; +} +.plugin-list li:last-child { + border-bottom: none; +} +.theme-list li { + float: left; + padding: 0; + margin: 0 10px 10px 0; + list-style: none; + border: 1px solid #E6E9E9; + background: #fff; + position: relative; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-transition: border .2s linear; + -moz-transition: border .2s linear; + transition: border .2s linear; +} +.theme-list li .image { + padding: 5px; +} +.theme-list li .image img { + width: 210px; + height: 140px; +} +.theme-list li .details { + position: absolute; + bottom: 0; + left: 0; + opacity: 0; + padding: 10px; + overflow: hidden; +} +.theme-list li h4 { + padding: 15px 0 0; + margin: 0; +} +.theme-list li p { + padding: 0; + margin: 0; + color: #999; + text-transform: uppercase; + font-size: 12px; +} +.theme-list li:hover { + border-color: transparent; +} +.theme-list li:hover .image { + opacity: 0; +} +.theme-list li:hover .details { + opacity: 1; +} +.suggested-products { + padding: 0; +} +.suggested-products .product { + padding: 0; +} +.suggested-products .image { + float: left; + position: relative; +} +.suggested-products .image img { + width: 40px; + height: 40px; + margin-top: 10px; +} +.suggested-products .details { + margin-left: 50px; + padding: 10px 0; +} +.suggested-products .details h5 { + margin: 0 0 3px; + font-size: 14px; + color: #C03F31; + font-weight: 400; +} +.suggested-products .details p { + font-size: 12px; +} +.suggested-products a { + color: #777; + background: #fff; + padding: 5px; + text-decoration: none; + display: block; + overflow: hidden; + border-bottom: 1px solid #E6E9E9; +} +.suggested-products a:hover { + color: #333; + background: #f9f9f9; +} +.suggested-products a:hover .image:after { + content: "+"; + color: #999; + font-size: 32px; + display: block; + width: 40px; + height: 40px; + text-align: center; + line-height: 40px; + position: absolute; + top: 7px; + left: 0; +} +.suggested-products a:hover .image img { + opacity: .5; +} +.suggested-themes .image img { + width: 60px; + height: 40px; +} +.suggested-themes .details { + margin-left: 70px; +} +/*! + * Typeahead + */ +.product-search { + position: relative; + width: 100%; + margin: 0 auto 0 auto; + text-align: left; + padding-bottom: 15px; +} +.product-search > i.icon { + position: absolute; + top: 50%; + right: 15px; + font-size: 24px; + margin-top: -20px; + color: rgba(0, 0, 0, 0.35); +} +.product-search > i.icon.loading { + display: block; + width: 24px; + height: 24px; + background: url('../../../../system/assets/ui/images/loader-transparent.svg') 50% 50%; + background-size: 24px 24px; + -webkit-animation: spin 1s linear infinite; + animation: spin 1s linear infinite; +} +.twitter-typeahead { + width: 100%; +} +.typeahead, +.tt-hint { + width: 100%; + height: 46px; + padding: 8px 12px; + font-size: 24px; + line-height: 30px; + border: 1px solid #024e6a; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + outline: none; +} +.typeahead { + background-color: #fff; + border-color: #e0e0e0; +} +.tt-input { + font-weight: 200; +} +.tt-input:focus { + border-color: #E6E9E9; +} +.tt-hint { + color: #999; + font-weight: 200; +} +.tt-dropdown-menu { + width: 100%; + margin-top: 0; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); +} +.tt-suggestion { + font-size: 14px; + line-height: 18px; +} +.tt-suggestion + .tt-suggestion { + font-size: 14px; + border-top: 1px solid #ccc; +} +.tt-suggestions .product-details { + padding: 5px; + overflow: hidden; + position: relative; +} +.tt-suggestions .product-image { + float: left; + margin-right: 10px; +} +.tt-suggestions .product-image img { + height: 45px; + width: 45px; +} +.tt-suggestions .product-name { + font-size: 20px; + padding-top: 5px; +} +.tt-suggestion.tt-cursor { + cursor: pointer; +} +.tt-suggestion.tt-cursor .product-details { + color: #333; + background: #f9f9f9; + border-color: #f0f0f0; +} +.tt-suggestion.tt-cursor .product-details .product-image:after { + content: "+"; + color: #999; + font-size: 38px; + display: block; + width: 45px; + height: 45px; + text-align: center; + line-height: 45px; + position: absolute; + top: 5px; + left: 5px; +} +.tt-suggestion.tt-cursor .product-details .product-image img { + opacity: .5; +} diff --git a/modules/system/assets/css/updates/updates.css b/modules/system/assets/css/updates/updates.css new file mode 100644 index 0000000..3de4192 --- /dev/null +++ b/modules/system/assets/css/updates/updates.css @@ -0,0 +1,116 @@ +.important-update-label { + margin: 7px 0; +} +.control-updatelist { + border: 1px solid #ccc; + margin-bottom: 20px; +} +.control-updatelist .update-item { + border-bottom: 1px solid #ccc; +} +.control-updatelist .update-item .item-header { + background-color: #f5f5f5; + border-bottom: 1px solid #ccc; + padding: 0 10px; +} +.control-updatelist .update-item .item-header h5 { + margin: 0; + padding: 15px 0; + text-transform: uppercase; + font-size: 13px; +} +.control-updatelist .update-item .item-header h5 i { + margin-right: 7px; + color: #405261; +} +.control-updatelist .update-item .item-header h5 small { + text-transform: none; + float: right; + line-height: 13px; + margin-right: 5px; +} +.control-updatelist .update-item .item-header .important-update { + padding: 7px 0 0 0; + float: right; + width: 200px; +} +.control-updatelist .update-item dl { + padding: 10px; + margin-bottom: 0; +} +.control-updatelist .update-item dl:before, +.control-updatelist .update-item dl:after { + content: " "; + display: table; +} +.control-updatelist .update-item dl:after { + clear: both; +} +.control-updatelist .update-item dl dt, +.control-updatelist .update-item dl dd { + float: left; + padding: 5px 0; + line-height: 20px; +} +.control-updatelist .update-item dl dt.text-muted, +.control-updatelist .update-item dl dd.text-muted { + color: #999 !important; +} +.control-updatelist .update-item dl dt { + width: 15%; + clear: left; + font-size: 14px; + font-weight: 400; + color: #2b3e50; +} +.control-updatelist .update-item dl dd { + width: 85%; + font-size: 12px; + color: #455152; +} +.control-updatelist .update-item dl .important-update-label { + position: relative; + top: -1px; + background-color: #ab2a1c; + color: #fff; + display: inline-block; + padding: .2em .6em .3em; + font-size: 75%; + line-height: 1; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + -webkit-border-radius: 0.25em; + -moz-border-radius: 0.25em; + border-radius: 0.25em; +} +.control-updatelist .update-item:last-child { + border-bottom: none; +} +.control-updatelist .update-item.item-danger .item-header { + background-color: #f2dede; +} +.control-updatelist .update-item.item-danger .item-header h5, +.control-updatelist .update-item.item-danger .item-header i, +.control-updatelist .update-item.item-danger .item-header { + color: #a94442; +} +.control-updatelist .update-item.item-success .item-header { + background-color: #dff0d8; +} +.control-updatelist .update-item.item-success .item-header h5, +.control-updatelist .update-item.item-success .item-header i, +.control-updatelist .update-item.item-success .item-header { + color: #3c763d; +} +.control-updatelist .update-item.item-muted { + border-bottom: none; +} +.control-updatelist .update-item.item-muted .item-header h5, +.control-updatelist .update-item.item-muted .item-header i, +.control-updatelist .update-item.item-muted .item-header { + color: rgba(0, 0, 0, 0.35); +} +.control-updatelist .update-item.item-muted dl { + display: none; +} diff --git a/modules/system/assets/images/cog-icon.svg b/modules/system/assets/images/cog-icon.svg new file mode 100644 index 0000000..a79be22 --- /dev/null +++ b/modules/system/assets/images/cog-icon.svg @@ -0,0 +1,13 @@ + + + + cog-icon + Created with Sketch. + + + + + + + + \ No newline at end of file diff --git a/modules/system/assets/js/eventlogs/exception-beautifier.js b/modules/system/assets/js/eventlogs/exception-beautifier.js new file mode 100644 index 0000000..f8d876d --- /dev/null +++ b/modules/system/assets/js/eventlogs/exception-beautifier.js @@ -0,0 +1,393 @@ +/* + * Exception Beautifier plugin + */ ++function ($) { + "use strict"; + + var ExceptionBeautifier = function (el, options) { + var self = this + + self.$el = $(el) + self.options = options || {} + + // Init + self.init() + } + + ExceptionBeautifier.DEFAULTS = {} + + ExceptionBeautifier.REGEX = { + phpline: /^(#[0-9]+)\s+(.+\.php)(?:\(([0-9]+)\))?\s*:(.*)/, + artisan: /^(#[0-9]+)\s+(.+artisan)(?:\(([0-9]+)\))?\s*:(.*)/, + internalLine: /^(#[0-9]+)\s+(\[internal function\]\s*:)(.*)/, + defaultLine: /^(#[0-9]+)\s*(.*)/, + className: /([a-z0-9]+\\[a-z0-9\\]+(?:\.\.\.)?)/gi, + filePath: /((?:[A-Z]:)?(?:[\\\/][\w\.-_~@%]+)\.(?:php|js|css|less|yaml|txt|ini))(\(([0-9]+)\)|:([0-9]+)|\s|$)/gi, + staticCall: /::([^( ]+)\(([^()]*|(?:[^(]*\(.+\)[^)]*))\)/, + functionCall: /->([^(]+)\(([^()]*|(?:[^(]*\(.+\)[^)]*))\)/, + closureCall: /\{closure\}\(([^()]*|(?:[^(]*\(.+\)[^)]*))\)/ + } + + ExceptionBeautifier.extensions = [] + + ExceptionBeautifier.prototype.init = function () { + var self = this, + markup + + ExceptionBeautifier.extensions.forEach(function (extension) { + if (typeof extension.onInit === 'function') { + extension.onInit(self) + } + }) + + markup = self.parseSource(self.$el.html()) + + self.$el + .addClass('plugin-exception-beautifier') + .empty() + .append(markup) + } + + ExceptionBeautifier.prototype.parseSource = function (raw) { + var self = this, + source = raw, + markup = {lines: []}, + start = 0, + end + + /* + * We only heavily parse stacktrace messages. + * Standard messages are only applied a simple transform : newline to
    and tab/spaces indentation to   + */ + if (source.indexOf('Stack trace:') < 0) { + source = '{exception-beautifier-message-container}{exception-beautifier-message}' + self.formatMessage(source) + '{/exception-beautifier-message}{/exception-beautifier-message-container}' + } + else { + end = source.indexOf('Stack trace:', start) + markup.message = source.substring(start, end) + + start = source.indexOf('#', end) + while ((end = source.indexOf('#', start + 1)) > 0) { + markup.lines.push(self.parseLine(source.substring(start, end))) + start = end + } + + markup.lines.push(self.parseLine(source.substring(start))) + + source = '{exception-beautifier-message-container}' + + '{exception-beautifier-message}' + self.formatMessage(markup.message) + '{/exception-beautifier-message}' + + '{/exception-beautifier-message-container}' + + '{exception-beautifier-stacktrace#div}' + + markup.lines.forEach(function (line) { + source += '{exception-beautifier-stacktrace-line}' + self.formatStackTraceLine(line) + '{/exception-beautifier-stacktrace-line}' + }) + + source += '{/exception-beautifier-stacktrace#div}' + + ExceptionBeautifier.extensions.forEach(function (extension) { + if (typeof extension.onParse === 'function') { + extension.onParse(self) + } + }) + } + + markup = $(self.buildMarkup('{exception-beautifier-container}' + source + '{/exception-beautifier-container}')) + + return self.finalizeMarkup(markup, raw) + } + + ExceptionBeautifier.prototype.parseLine = function (str) { + var line = {}, + matches + + if ((matches = str.match(ExceptionBeautifier.REGEX.phpline)) || (matches = str.match(ExceptionBeautifier.REGEX.artisan))) { + line.type = 'phpline' + line.number = $.trim(matches[1]) + line.file = $.trim(matches[2]) + line.lineNumber = $.trim(matches[3]) + line.function = $.trim(matches[4]) + } + else if (matches = str.match(ExceptionBeautifier.REGEX.internalLine)) { + line.type = 'internal' + line.number = $.trim(matches[1]) + line.internal = $.trim(matches[2]) + line.function = $.trim(matches[3]) + } + else if (matches = str.match(ExceptionBeautifier.REGEX.defaultLine)) { + line.type = 'default' + line.number = $.trim(matches[1]) + line.function = $.trim(matches[2]) + } + + return line + } + + + ExceptionBeautifier.prototype.formatMessage = function (str) { + var self = this + + return self.formatLineCode( + str + .replace(/^\s+/, '') + .replace(/\r\n|\r|\n/g, '{x-newline}') + .replace(/\t| {2}/g, '{x-tabulation}') + ) + } + + ExceptionBeautifier.prototype.formatFilePath = function (path, line) { + return '{exception-beautifier-file}' + path + '{/exception-beautifier-file}' + } + + ExceptionBeautifier.prototype.formatStackTraceLine = function (line) { + var self = this + + if (line.function) { + line.function = self.formatLineCode(line.function) + } + + switch (line.type) { + case 'phpline': + return '{exception-beautifier-stacktrace-line-number}' + line.number + '{/exception-beautifier-stacktrace-line-number}' + + self.formatFilePath(line.file, line.lineNumber) + + '{exception-beautifier-line-number}(' + line.lineNumber + '):{/exception-beautifier-line-number} ' + + '{exception-beautifier-stacktrace-line-function}' + line.function + '{/exception-beautifier-stacktrace-line-function}' + + case 'internal': + return '{exception-beautifier-stacktrace-line-number}' + line.number + '{/exception-beautifier-stacktrace-line-number}' + + '{exception-beautifier-stacktrace-line-internal}' + line.internal + '{/exception-beautifier-stacktrace-line-internal}' + + '{exception-beautifier-stacktrace-line-function}' + line.function + '{/exception-beautifier-stacktrace-line-function}' + + case 'default': + return '{exception-beautifier-stacktrace-line-number}' + line.number + '{/exception-beautifier-stacktrace-line-number}' + + '{exception-beautifier-stacktrace-line-function}' + line.function + '{/exception-beautifier-stacktrace-line-function}' + } + + return '' + } + + ExceptionBeautifier.prototype.formatLineCode = function (str) { + var self = this + + if (str.match(/^\s*(call_user_func|spl_autoload_call)/)) { + str = str.replace(/^\s*(?:call_user_func|spl_autoload_call)([^(]*)\((.*)\)/, function (str, suffix, parameters) { + return '{exception-beautifier-system-function}call_user_func' + suffix + '({/exception-beautifier-system-function}' + + self.formatFunctionParameters(parameters) + + '{exception-beautifier-system-function}){/exception-beautifier-system-function}' + }) + } + else if (str.match(ExceptionBeautifier.REGEX.closureCall)) { + str = str.replace(ExceptionBeautifier.REGEX.closureCall, function (str, parameters) { + return '{exception-beautifier-function}{closure}({/exception-beautifier-function}' + + self.formatFunctionParameters(parameters) + + '{exception-beautifier-function}){/exception-beautifier-function}' + }) + } + else if (str.match(ExceptionBeautifier.REGEX.functionCall)) { + str = str.replace(ExceptionBeautifier.REGEX.functionCall, function (str, functionName, parameters) { + return '{exception-beautifier-function}→' + functionName + '({/exception-beautifier-function}' + + self.formatFunctionParameters(parameters) + + '{exception-beautifier-function}){/exception-beautifier-function}' + }) + } + else if (str.match(ExceptionBeautifier.REGEX.staticCall)) { + str = str.replace(ExceptionBeautifier.REGEX.staticCall, function (str, functionName, parameters) { + return '{exception-beautifier-function}::' + functionName + '({/exception-beautifier-function}' + + self.formatFunctionParameters(parameters) + + '{exception-beautifier-function}){/exception-beautifier-function}' + }) + } + + str = str.replace(ExceptionBeautifier.REGEX.filePath, function (str, path, line, lineNumber, altLineNumber) { + return self.formatFilePath(path, (lineNumber || '') + (altLineNumber || '')) + + ($.trim(line).length > 0 ? ('{exception-beautifier-line-number}' + line + '{/exception-beautifier-line-number}') : ' ') + }) + + str = str.replace(ExceptionBeautifier.REGEX.className, function (str, name) { + return '{exception-beautifier-class}' + name + '{/exception-beautifier-class}' + }) + + return str + } + + ExceptionBeautifier.prototype.formatFunctionParameters = function (parameters) { + return parameters + .replace(/^([0-9]+)|([^a-z\\])([0-9]+)$|^([0-9]+)([^a-z\\])|([^a-z\\])([0-9]+)([^a-z\\])/g, '$2$6{exception-beautifier-number}$1$3$4$7{/exception-beautifier-number}$5$8') + .replace(/^Array$|([^a-z\\])Array$|^Array([^a-z\\])|([^a-z\\])Array([^a-z\\])/g, '$1$3{exception-beautifier-code}Array{/exception-beautifier-code}$2$4') + .replace(/^Closure$|(\()Closure(\))/g, '$1{exception-beautifier-code}Closure{/exception-beautifier-code}$2') + .replace(/Object\(([^)]+)\)/g, '{exception-beautifier-code}Object({/exception-beautifier-code}$1{exception-beautifier-code}){/exception-beautifier-code}') + .replace(/"((?:\\.|[^"])*)"/g, '{exception-beautifier-string}"$1"{/exception-beautifier-string}') + .replace(/'((?:\\.|[^'])*)'/g, '{exception-beautifier-string}\'$1\'{/exception-beautifier-string}') + } + + ExceptionBeautifier.prototype.buildMarkup = function (str) { + var self = this, + start = str.indexOf('{exception-beautifier-'), + cssOffset = 'exception-beautifier-'.length, + end, endtag, tmp, matches, tag, html, css, attrs, markup = '' + + if (start >= 0) { + if (start > 0) { + markup += self.buildMarkup(str.substring(0, start)) + } + + while (start >= 0) { + end = endtag = str.indexOf('}', start) + + if ((tmp = str.indexOf(' ', start)) >= 0) { + end = Math.min(end, tmp) + } + + tag = str.substring(start + 1, end) + end = str.indexOf('{/' + tag + '}', start) + start = str.indexOf('}', start) + + if (end < 0) { + throw 'Markup error tag {' + tag + '} not closed' + } + + html = 'span' + attrs = '' + css = tag + + if (matches = tag.match(/(.+)#([a-z]+)$/)) { + css = matches[1] + html = matches[2] + } + + css = 'beautifier-' + css.substr(cssOffset) + + if (tmp >= 0 && tmp < endtag) { + attrs = str.substring(tmp, endtag) + } + + markup += '<' + html + ' class="' + css + '"' + attrs + '>' + markup += self.buildMarkup(str.substring(start + 1, end)) + markup += '' + + end = end + ('{/' + tag + '}').length + start = str.indexOf('{exception-beautifier-', end) + + if (start > end || start < 0) { + markup += self.buildMarkup(str.substring(end, start < 0 ? undefined : start)) + } + } + } + else { + // Allow HTML entities + str = str.replace(/&([^\s&;]+?);/g, '&$1;') + + markup += str + .replace(/\{x-newline\}/g, '
    ') + .replace(/\{x-tabulation\}/g, '  ') + } + + return markup + } + + ExceptionBeautifier.prototype.finalizeMarkup = function (markup, source) { + var stacktrace, + messageContainer, + tabs, + iframe + + markup.find('.beautifier-file').each(function () { + $(this).find('.beautifier-class').each(function () { + var $el = $(this) + $el.replaceWith($el.text()) + }) + }) + + markup.find('.beautifier-file+.beautifier-line-number').each(function () { + var $el = $(this) + $el.appendTo($el.prev()) + }) + + messageContainer = markup.find('.beautifier-message-container') + stacktrace = markup.find('.beautifier-stacktrace').addClass('hidden') + + if (!!stacktrace.length) { + $('' + $.oc.lang.get('eventlog.show_stacktrace') + '') + .appendTo(messageContainer) + .on('click', function (event) { + event.preventDefault() + event.stopPropagation() + + var $el = $(this) + $('.beautifier-stacktrace', markup).toggleClass('hidden') + $el.hide() + }) + } + + tabs = $('') + + if (source.indexOf('Message-ID:') > 0) { + markup = source.trim().replace(/(?:^|<\/html>)[^]*?(?:').replace(/ {2}/g, '  ') + }) + iframe = $('') + } + + /* + * Build tab content + */ + if (iframe) { + tabs.find('#beautifier-tab-formatted').append(iframe) + iframe.wrap('
    ') + iframe.on('load', function() { + var $html = iframe.contents().find('html') + $html.html(markup) + $html.css({ + 'font-family': '-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"', + 'font-size': '14px', + 'color': '#74787e' + }) + iframe.height($html.height() + 1) + }) + } + else { + tabs.find('#beautifier-tab-formatted').append(markup) + } + + tabs.find('#beautifier-tab-raw').append('
    ' + source.trim().replace(/\r\n|\r|\n/g, '
    ').replace(/ {2}/g, '  ') + '
    ') + + tabs.ocTab({ + closable: false + }) + + return tabs + } + + // EXCEPTION BEAUTIFIER PLUGIN DEFINITION + // ============================ + + $.fn.exceptionBeautifier = function (option) { + var args = arguments, + result + + this.each(function () { + var $this = $(this) + var data = $this.data('oc.exceptionBeautifier') + var options = $.extend({}, ExceptionBeautifier.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.exceptionBeautifier', (data = new ExceptionBeautifier(this, options))) + if (typeof option == 'string') result = data[option].call($this) + if (typeof result != 'undefined') return false + }) + + return result ? result : this + } + + $.fn.exceptionBeautifier.Constructor = ExceptionBeautifier + + $(document).render(function () { + $('[data-plugin="exception-beautifier"]').exceptionBeautifier() + }) + +}(window.jQuery) diff --git a/modules/system/assets/js/eventlogs/exception-beautifier.links.js b/modules/system/assets/js/eventlogs/exception-beautifier.links.js new file mode 100644 index 0000000..d3773d0 --- /dev/null +++ b/modules/system/assets/js/eventlogs/exception-beautifier.links.js @@ -0,0 +1,136 @@ +/* + * Exception Beautifier plugin - Links extension + */ ++function ($) { + "use strict"; + + var ExceptionBeautifier = $.fn.exceptionBeautifier.Constructor + + ExceptionBeautifier.EDITORS = { + subl: {scheme: 'subl://open?url=file://%file&line=%line', name: 'Sublime (subl://)'}, + txmt: {scheme: 'txmt://open/?url=file://%file&line=%line', name: 'TextMate (txmt://)'}, + mvim: {scheme: 'mvim://open/?url=file://%file&line=%line', name: 'MacVim (mvim://)'}, + phpstorm: {scheme: 'phpstorm://open?file=%file&line=%line', name: 'PhpStorm (phpstorm://)'}, + editor: {scheme: 'editor://open/?file=%file&line=%line', name: 'Custom (editor://)'} + } + + ExceptionBeautifier.REGEX.editor = /idelink:\/\/([^#]+)&([0-9]+)?/ + ExceptionBeautifier.LINKER_POPUP_CONTENT = null + + ExceptionBeautifier.extensions.push({ + onInit: function (exceptionBeautfier) { + exceptionBeautfier.initEditorPopup() + }, + onParse: function (exceptionBeautfier) { + exceptionBeautfier.$el.on('click', 'a[data-href]', function () { + exceptionBeautfier.openWithEditor($(this).data('href')) + }) + } + }) + + ExceptionBeautifier.prototype.initEditorPopup = function () { + if (!ExceptionBeautifier.LINKER_POPUP_CONTENT) { + var title = $.oc.lang.get('eventlog.editor.title'), + description = $.oc.lang.get('eventlog.editor.description'), + openWith = $.oc.lang.get('eventlog.editor.openWith'), + rememberChoice = $.oc.lang.get('eventlog.editor.remember_choice'), + open = $.oc.lang.get('eventlog.editor.open'), + cancel = $.oc.lang.get('eventlog.editor.cancel'), + popup = $(' \ +
    \ + \ + \ + \ +
    ' + ), + select = $('select', popup) + + for (var key in ExceptionBeautifier.EDITORS) { + if (ExceptionBeautifier.EDITORS.hasOwnProperty(key)) { + select.append('') + } + } + + ExceptionBeautifier.LINKER_POPUP_CONTENT = popup.html() + } + } + + ExceptionBeautifier.prototype.openWithEditor = function (link) { + var self = this, + matches, + open = function (value) { + window.open(link.replace( + ExceptionBeautifier.REGEX.editor, + ExceptionBeautifier.EDITORS[value].scheme + .replace(/%file/, matches[1]) + .replace(/%line/, matches[2]) + ), '_self') + } + + if (matches = link.match(ExceptionBeautifier.REGEX.editor)) { + if (window.sessionStorage && window.sessionStorage['oc-exception-beautifier-editor']) { + open(window.sessionStorage['oc-exception-beautifier-editor']) + } else { + $.popup({content: ExceptionBeautifier.LINKER_POPUP_CONTENT}) + .on('shown.oc.popup', function (event, source, popup) { + var select = $('select', popup) + + self.initCustomSelect(select) + + $('[data-action="submit"]', popup).on('click', function () { + if ($('#editor-remember-choice').prop('checked') && window.sessionStorage) { + window.sessionStorage['oc-exception-beautifier-editor'] = select.val() + } + + open(select.val()) + }) + }) + .on('hide.oc.popup', function (event, source, popup) { + $('[data-action]', popup).off('click') + }) + } + } + } + + ExceptionBeautifier.prototype.formatFilePath = function (path, line) { + var self = this + + return '{exception-beautifier-file#a href="javascript:" data-href="idelink://' + encodeURIComponent(self.rewritePath(path)) + '&' + line + '"}' + path + '{/exception-beautifier-file#a}' + } + + ExceptionBeautifier.prototype.rewritePath = function (path) { + return path.replace(/\\/g, '/') + } + + ExceptionBeautifier.prototype.initCustomSelect = function (select) { + if (Modernizr.touchevents) { + return + } + + var options = { + minimumResultsForSearch: Infinity, + escapeMarkup: function (m) { + return m + } + } + + select.select2(options) + } + +}(window.jQuery) \ No newline at end of file diff --git a/modules/system/assets/js/framework-min.js b/modules/system/assets/js/framework-min.js new file mode 100644 index 0000000..a75e431 --- /dev/null +++ b/modules/system/assets/js/framework-min.js @@ -0,0 +1,190 @@ + +if(window.jQuery===undefined){throw new Error('The jQuery library is not loaded. The OctoberCMS framework cannot be initialized.');} +if(window.jQuery.request!==undefined){throw new Error('The OctoberCMS framework is already loaded.');} ++function($){"use strict";var Request=function(element,handler,options){var $el=this.$el=$(element);this.options=options||{};if(handler===undefined){throw new Error('The request handler name is not specified.')} +if(!handler.match(/^(?:\w+\:{2})?on*/)){throw new Error('Invalid handler name. The correct handler name format is: "onEvent".')} +var $form=options.form?$(options.form):$el.closest('form'),$triggerEl=!!$form.length?$form:$el,context={handler:handler,options:options} +if((options.browserValidate!==undefined)&&typeof document.createElement('input').reportValidity=='function'&&$form&&$form[0]&&!$form[0].checkValidity()){$form[0].reportValidity();return false;} +$el.trigger('ajaxSetup',[context]) +var _event=jQuery.Event('oc.beforeRequest') +$triggerEl.trigger(_event,context) +if(_event.isDefaultPrevented())return +var loading=options.loading!==undefined?options.loading:null,url=options.url!==undefined?options.url:window.location.href,isRedirect=options.redirect!==undefined&&options.redirect.length,useFlash=options.flash!==undefined,useFiles=options.files!==undefined +if(useFiles&&typeof FormData==='undefined'){console.warn('This browser does not support file uploads via FormData') +useFiles=false} +if($.type(loading)=='string'){loading=$(loading)} +var requestHeaders={'X-OCTOBER-REQUEST-HANDLER':handler,'X-OCTOBER-REQUEST-PARTIALS':this.extractPartials(options.update)} +if(useFlash){requestHeaders['X-OCTOBER-REQUEST-FLASH']=1} +var csrfToken=getXSRFToken() +if(csrfToken){requestHeaders['X-XSRF-TOKEN']=csrfToken} +var requestData,inputName,data={} +$.each($el.parents('[data-request-data]').toArray().reverse(),function extendRequest(){$.extend(data,paramToObj('data-request-data',$(this).data('request-data')))}) +if($el.is(':input')&&!$form.length){inputName=$el.attr('name') +if(inputName!==undefined&&options.data[inputName]===undefined){options.data[inputName]=$el.val()}} +if(options.data!==undefined&&!$.isEmptyObject(options.data)){$.extend(data,options.data)} +if(useFiles){requestData=new FormData($form.length?$form.get(0):undefined) +if($el.is(':file')&&inputName){$.each($el.prop('files'),function(){requestData.append(inputName,this)}) +delete data[inputName]} +$.each(data,function(key){if(typeof Blob!=="undefined"&&this instanceof Blob&&this.filename){requestData.append(key,this,this.filename)}else{requestData.append(key,this)}})} +else{requestData=[$form.serialize(),$.param(data)].filter(Boolean).join('&')} +var requestOptions={url:url,crossDomain:false,global:options.ajaxGlobal,context:context,headers:requestHeaders,success:function(data,textStatus,jqXHR){if(this.options.beforeUpdate.apply(this,[data,textStatus,jqXHR])===false)return +if(options.evalBeforeUpdate&&eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalBeforeUpdate+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))')===false)return +var _event=jQuery.Event('ajaxBeforeUpdate') +$triggerEl.trigger(_event,[context,data,textStatus,jqXHR]) +if(_event.isDefaultPrevented())return +if(useFlash&&data['X_OCTOBER_FLASH_MESSAGES']){$.each(data['X_OCTOBER_FLASH_MESSAGES'],function(type,message){requestOptions.handleFlashMessage(message,type)})} +var updatePromise=requestOptions.handleUpdateResponse(data,textStatus,jqXHR) +updatePromise.done(function(){$triggerEl.trigger('ajaxSuccess',[context,data,textStatus,jqXHR]) +options.evalSuccess&&eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalSuccess+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))')}) +return updatePromise},error:function(jqXHR,textStatus,errorThrown){var errorMsg,updatePromise=$.Deferred() +if((window.ocUnloading!==undefined&&window.ocUnloading)||errorThrown=='abort') +return +isRedirect=false +options.redirect=null +if(jqXHR.status==406&&jqXHR.responseJSON){errorMsg=jqXHR.responseJSON['X_OCTOBER_ERROR_MESSAGE'] +updatePromise=requestOptions.handleUpdateResponse(jqXHR.responseJSON,textStatus,jqXHR)} +else{errorMsg=jqXHR.responseText?jqXHR.responseText:jqXHR.statusText +updatePromise.resolve()} +updatePromise.done(function(){$el.data('error-message',errorMsg) +var _event=jQuery.Event('ajaxError') +$triggerEl.trigger(_event,[context,errorMsg,textStatus,jqXHR]) +if(_event.isDefaultPrevented())return +if(options.evalError&&eval('(function($el, context, errorMsg, textStatus, jqXHR) {'+options.evalError+'}.call($el.get(0), $el, context, errorMsg, textStatus, jqXHR))')===false) +return +requestOptions.handleErrorMessage(errorMsg)}) +return updatePromise},complete:function(data,textStatus,jqXHR){$triggerEl.trigger('ajaxComplete',[context,data,textStatus,jqXHR]) +options.evalComplete&&eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalComplete+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))')},handleConfirmMessage:function(message){var _event=jQuery.Event('ajaxConfirmMessage') +_event.promise=$.Deferred() +if($(window).triggerHandler(_event,[message])!==undefined){_event.promise.done(function(){options.confirm=null +new Request(element,handler,options)}) +return false} +if(_event.isDefaultPrevented())return +if(message)return confirm(message)},handleErrorMessage:function(message){var _event=jQuery.Event('ajaxErrorMessage') +$(window).trigger(_event,[message]) +if(_event.isDefaultPrevented())return +if(message)alert(message)},handleValidationMessage:function(message,fields){$triggerEl.trigger('ajaxValidation',[context,message,fields]) +var isFirstInvalidField=true +$.each(fields,function focusErrorField(fieldName,fieldMessages){fieldName=fieldName.replace(/\.(\w+)/g,'[$1]') +var fieldElement=$form.find('[name="'+fieldName+'"], [name="'+fieldName+'[]"], [name$="['+fieldName+']"], [name$="['+fieldName+'][]"]').filter(':enabled').first() +if(fieldElement.length>0){var _event=jQuery.Event('ajaxInvalidField') +$(window).trigger(_event,[fieldElement.get(0),fieldName,fieldMessages,isFirstInvalidField]) +if(isFirstInvalidField){if(!_event.isDefaultPrevented())fieldElement.focus() +isFirstInvalidField=false}}})},handleFlashMessage:function(message,type){},handleRedirectResponse:function(url){window.location.assign(url)},handleUpdateResponse:function(data,textStatus,jqXHR){var updatePromise=$.Deferred().done(function(){for(var partial in data){var selector=(options.update[partial])?options.update[partial]:partial +if($.type(selector)=='string'&&selector.charAt(0)=='@'){$(selector.substring(1)).append(data[partial]).trigger('ajaxUpdate',[context,data,textStatus,jqXHR])} +else if($.type(selector)=='string'&&selector.charAt(0)=='^'){$(selector.substring(1)).prepend(data[partial]).trigger('ajaxUpdate',[context,data,textStatus,jqXHR])} +else{$(selector).trigger('ajaxBeforeReplace') +$(selector).html(data[partial]).trigger('ajaxUpdate',[context,data,textStatus,jqXHR])}} +setTimeout(function(){$(window).trigger('ajaxUpdateComplete',[context,data,textStatus,jqXHR]).trigger('resize')},0)}) +if(data['X_OCTOBER_REDIRECT']){options.redirect=data['X_OCTOBER_REDIRECT'] +isRedirect=true} +if(isRedirect){requestOptions.handleRedirectResponse(options.redirect)} +if(data['X_OCTOBER_ERROR_FIELDS']){requestOptions.handleValidationMessage(data['X_OCTOBER_ERROR_MESSAGE'],data['X_OCTOBER_ERROR_FIELDS'])} +if(data['X_OCTOBER_ASSETS']){assetManager.load(data['X_OCTOBER_ASSETS'],$.proxy(updatePromise.resolve,updatePromise))} +else{updatePromise.resolve()} +return updatePromise}} +if(useFiles){requestOptions.processData=requestOptions.contentType=false} +context.success=requestOptions.success +context.error=requestOptions.error +context.complete=requestOptions.complete +requestOptions=$.extend(requestOptions,options) +requestOptions.data=requestData +if(options.confirm&&!requestOptions.handleConfirmMessage(options.confirm)){return} +if(loading)loading.show() +$(window).trigger('ajaxBeforeSend',[context]) +$el.trigger('ajaxPromise',[context]) +return $.ajax(requestOptions).fail(function(jqXHR,textStatus,errorThrown){if(!isRedirect){$el.trigger('ajaxFail',[context,textStatus,jqXHR])} +if(loading)loading.hide()}).done(function(data,textStatus,jqXHR){if(!isRedirect){$el.trigger('ajaxDone',[context,data,textStatus,jqXHR])} +if(loading)loading.hide()}).always(function(dataOrXhr,textStatus,xhrOrError){$el.trigger('ajaxAlways',[context,dataOrXhr,textStatus,xhrOrError])})} +Request.DEFAULTS={update:{},type:'POST',beforeUpdate:function(data,textStatus,jqXHR){},evalBeforeUpdate:null,evalSuccess:null,evalError:null,evalComplete:null,ajaxGlobal:false} +Request.prototype.extractPartials=function(update){var result=[] +for(var partial in update) +result.push(partial) +return result.join('&')} +var old=$.fn.request +$.fn.request=function(handler,option){var args=arguments +var $this=$(this).first() +var data={evalBeforeUpdate:$this.data('request-before-update'),evalSuccess:$this.data('request-success'),evalError:$this.data('request-error'),evalComplete:$this.data('request-complete'),ajaxGlobal:$this.data('request-ajax-global'),confirm:$this.data('request-confirm'),redirect:$this.data('request-redirect'),loading:$this.data('request-loading'),flash:$this.data('request-flash'),files:$this.data('request-files'),browserValidate:$this.data('browser-validate'),form:$this.data('request-form'),url:$this.data('request-url'),update:paramToObj('data-request-update',$this.data('request-update')),data:paramToObj('data-request-data',$this.data('request-data'))} +if(!handler)handler=$this.data('request') +var options=$.extend(true,{},Request.DEFAULTS,data,typeof option=='object'&&option) +return new Request($this,handler,options)} +$.fn.request.Constructor=Request +$.request=function(handler,option){return $(document).request(handler,option)} +$.fn.request.noConflict=function(){$.fn.request=old +return this} +function paramToObj(name,value){if(value===undefined)value='' +if(typeof value=='object')return value +try{return ocJSON("{"+value+"}")} +catch(e){throw new Error('Error parsing the '+name+' attribute value. '+e)}} +function getXSRFToken(){var cookieValue=null +if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';') +for(var i=0;i="0"&&str[pos]<="9")){var body="";for(var i=pos;i="0"&&str[i]<="9")){body+=str[i];}else{return{originLength:body.length,body:body};}} +throw new Error("Broken JSON number body near "+body);} +if(str[pos]==="{"||str[pos]==="["){var stack=[str[pos]];var body=str[pos];for(var i=pos+1;i=0)?pos-5:0,50));} +function canBeKeyHead(ch){if(ch[0]==="\\")return false;if((ch[0]>='a'&&ch[0]<='z')||(ch[0]>='A'&&ch[0]<='Z')||ch[0]==='_')return true;if(ch[0]>='0'&&ch[0]<='9')return true;if(ch[0]==='$')return true;if(ch.charCodeAt(0)>255)return true;return false;} +function isBlankChar(ch){return ch===" "||ch==="\n"||ch==="\t";} +function parse(str){str=str.trim();if(!str.length)throw new Error("Broken JSON object.");var result="";while(str&&str[0]===","){str=str.substr(1);} +if(str[0]==="\""||str[0]==="'"){if(str[str.length-1]!==str[0]){throw new Error("Invalid string JSON object.");} +var body="\"";for(var i=1;i'+html+'
    ',null,false));output.find('*').each(function(){trimAttributes(this);});return output.html();} +window.ocSanitize=function(html){return sanitize(html)};}(window); \ No newline at end of file diff --git a/modules/system/assets/js/framework.combined-min.js b/modules/system/assets/js/framework.combined-min.js new file mode 100644 index 0000000..382a869 --- /dev/null +++ b/modules/system/assets/js/framework.combined-min.js @@ -0,0 +1,252 @@ + +if(window.jQuery===undefined){throw new Error('The jQuery library is not loaded. The OctoberCMS framework cannot be initialized.');} +if(window.jQuery.request!==undefined){throw new Error('The OctoberCMS framework is already loaded.');} ++function($){"use strict";var Request=function(element,handler,options){var $el=this.$el=$(element);this.options=options||{};if(handler===undefined){throw new Error('The request handler name is not specified.')} +if(!handler.match(/^(?:\w+\:{2})?on*/)){throw new Error('Invalid handler name. The correct handler name format is: "onEvent".')} +var $form=options.form?$(options.form):$el.closest('form'),$triggerEl=!!$form.length?$form:$el,context={handler:handler,options:options} +if((options.browserValidate!==undefined)&&typeof document.createElement('input').reportValidity=='function'&&$form&&$form[0]&&!$form[0].checkValidity()){$form[0].reportValidity();return false;} +$el.trigger('ajaxSetup',[context]) +var _event=jQuery.Event('oc.beforeRequest') +$triggerEl.trigger(_event,context) +if(_event.isDefaultPrevented())return +var loading=options.loading!==undefined?options.loading:null,url=options.url!==undefined?options.url:window.location.href,isRedirect=options.redirect!==undefined&&options.redirect.length,useFlash=options.flash!==undefined,useFiles=options.files!==undefined +if(useFiles&&typeof FormData==='undefined'){console.warn('This browser does not support file uploads via FormData') +useFiles=false} +if($.type(loading)=='string'){loading=$(loading)} +var requestHeaders={'X-OCTOBER-REQUEST-HANDLER':handler,'X-OCTOBER-REQUEST-PARTIALS':this.extractPartials(options.update)} +if(useFlash){requestHeaders['X-OCTOBER-REQUEST-FLASH']=1} +var csrfToken=getXSRFToken() +if(csrfToken){requestHeaders['X-XSRF-TOKEN']=csrfToken} +var requestData,inputName,data={} +$.each($el.parents('[data-request-data]').toArray().reverse(),function extendRequest(){$.extend(data,paramToObj('data-request-data',$(this).data('request-data')))}) +if($el.is(':input')&&!$form.length){inputName=$el.attr('name') +if(inputName!==undefined&&options.data[inputName]===undefined){options.data[inputName]=$el.val()}} +if(options.data!==undefined&&!$.isEmptyObject(options.data)){$.extend(data,options.data)} +if(useFiles){requestData=new FormData($form.length?$form.get(0):undefined) +if($el.is(':file')&&inputName){$.each($el.prop('files'),function(){requestData.append(inputName,this)}) +delete data[inputName]} +$.each(data,function(key){if(typeof Blob!=="undefined"&&this instanceof Blob&&this.filename){requestData.append(key,this,this.filename)}else{requestData.append(key,this)}})} +else{requestData=[$form.serialize(),$.param(data)].filter(Boolean).join('&')} +var requestOptions={url:url,crossDomain:false,global:options.ajaxGlobal,context:context,headers:requestHeaders,success:function(data,textStatus,jqXHR){if(this.options.beforeUpdate.apply(this,[data,textStatus,jqXHR])===false)return +if(options.evalBeforeUpdate&&eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalBeforeUpdate+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))')===false)return +var _event=jQuery.Event('ajaxBeforeUpdate') +$triggerEl.trigger(_event,[context,data,textStatus,jqXHR]) +if(_event.isDefaultPrevented())return +if(useFlash&&data['X_OCTOBER_FLASH_MESSAGES']){$.each(data['X_OCTOBER_FLASH_MESSAGES'],function(type,message){requestOptions.handleFlashMessage(message,type)})} +var updatePromise=requestOptions.handleUpdateResponse(data,textStatus,jqXHR) +updatePromise.done(function(){$triggerEl.trigger('ajaxSuccess',[context,data,textStatus,jqXHR]) +options.evalSuccess&&eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalSuccess+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))')}) +return updatePromise},error:function(jqXHR,textStatus,errorThrown){var errorMsg,updatePromise=$.Deferred() +if((window.ocUnloading!==undefined&&window.ocUnloading)||errorThrown=='abort') +return +isRedirect=false +options.redirect=null +if(jqXHR.status==406&&jqXHR.responseJSON){errorMsg=jqXHR.responseJSON['X_OCTOBER_ERROR_MESSAGE'] +updatePromise=requestOptions.handleUpdateResponse(jqXHR.responseJSON,textStatus,jqXHR)} +else{errorMsg=jqXHR.responseText?jqXHR.responseText:jqXHR.statusText +updatePromise.resolve()} +updatePromise.done(function(){$el.data('error-message',errorMsg) +var _event=jQuery.Event('ajaxError') +$triggerEl.trigger(_event,[context,errorMsg,textStatus,jqXHR]) +if(_event.isDefaultPrevented())return +if(options.evalError&&eval('(function($el, context, errorMsg, textStatus, jqXHR) {'+options.evalError+'}.call($el.get(0), $el, context, errorMsg, textStatus, jqXHR))')===false) +return +requestOptions.handleErrorMessage(errorMsg)}) +return updatePromise},complete:function(data,textStatus,jqXHR){$triggerEl.trigger('ajaxComplete',[context,data,textStatus,jqXHR]) +options.evalComplete&&eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalComplete+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))')},handleConfirmMessage:function(message){var _event=jQuery.Event('ajaxConfirmMessage') +_event.promise=$.Deferred() +if($(window).triggerHandler(_event,[message])!==undefined){_event.promise.done(function(){options.confirm=null +new Request(element,handler,options)}) +return false} +if(_event.isDefaultPrevented())return +if(message)return confirm(message)},handleErrorMessage:function(message){var _event=jQuery.Event('ajaxErrorMessage') +$(window).trigger(_event,[message]) +if(_event.isDefaultPrevented())return +if(message)alert(message)},handleValidationMessage:function(message,fields){$triggerEl.trigger('ajaxValidation',[context,message,fields]) +var isFirstInvalidField=true +$.each(fields,function focusErrorField(fieldName,fieldMessages){fieldName=fieldName.replace(/\.(\w+)/g,'[$1]') +var fieldElement=$form.find('[name="'+fieldName+'"], [name="'+fieldName+'[]"], [name$="['+fieldName+']"], [name$="['+fieldName+'][]"]').filter(':enabled').first() +if(fieldElement.length>0){var _event=jQuery.Event('ajaxInvalidField') +$(window).trigger(_event,[fieldElement.get(0),fieldName,fieldMessages,isFirstInvalidField]) +if(isFirstInvalidField){if(!_event.isDefaultPrevented())fieldElement.focus() +isFirstInvalidField=false}}})},handleFlashMessage:function(message,type){},handleRedirectResponse:function(url){window.location.assign(url)},handleUpdateResponse:function(data,textStatus,jqXHR){var updatePromise=$.Deferred().done(function(){for(var partial in data){var selector=(options.update[partial])?options.update[partial]:partial +if($.type(selector)=='string'&&selector.charAt(0)=='@'){$(selector.substring(1)).append(data[partial]).trigger('ajaxUpdate',[context,data,textStatus,jqXHR])} +else if($.type(selector)=='string'&&selector.charAt(0)=='^'){$(selector.substring(1)).prepend(data[partial]).trigger('ajaxUpdate',[context,data,textStatus,jqXHR])} +else{$(selector).trigger('ajaxBeforeReplace') +$(selector).html(data[partial]).trigger('ajaxUpdate',[context,data,textStatus,jqXHR])}} +setTimeout(function(){$(window).trigger('ajaxUpdateComplete',[context,data,textStatus,jqXHR]).trigger('resize')},0)}) +if(data['X_OCTOBER_REDIRECT']){options.redirect=data['X_OCTOBER_REDIRECT'] +isRedirect=true} +if(isRedirect){requestOptions.handleRedirectResponse(options.redirect)} +if(data['X_OCTOBER_ERROR_FIELDS']){requestOptions.handleValidationMessage(data['X_OCTOBER_ERROR_MESSAGE'],data['X_OCTOBER_ERROR_FIELDS'])} +if(data['X_OCTOBER_ASSETS']){assetManager.load(data['X_OCTOBER_ASSETS'],$.proxy(updatePromise.resolve,updatePromise))} +else{updatePromise.resolve()} +return updatePromise}} +if(useFiles){requestOptions.processData=requestOptions.contentType=false} +context.success=requestOptions.success +context.error=requestOptions.error +context.complete=requestOptions.complete +requestOptions=$.extend(requestOptions,options) +requestOptions.data=requestData +if(options.confirm&&!requestOptions.handleConfirmMessage(options.confirm)){return} +if(loading)loading.show() +$(window).trigger('ajaxBeforeSend',[context]) +$el.trigger('ajaxPromise',[context]) +return $.ajax(requestOptions).fail(function(jqXHR,textStatus,errorThrown){if(!isRedirect){$el.trigger('ajaxFail',[context,textStatus,jqXHR])} +if(loading)loading.hide()}).done(function(data,textStatus,jqXHR){if(!isRedirect){$el.trigger('ajaxDone',[context,data,textStatus,jqXHR])} +if(loading)loading.hide()}).always(function(dataOrXhr,textStatus,xhrOrError){$el.trigger('ajaxAlways',[context,dataOrXhr,textStatus,xhrOrError])})} +Request.DEFAULTS={update:{},type:'POST',beforeUpdate:function(data,textStatus,jqXHR){},evalBeforeUpdate:null,evalSuccess:null,evalError:null,evalComplete:null,ajaxGlobal:false} +Request.prototype.extractPartials=function(update){var result=[] +for(var partial in update) +result.push(partial) +return result.join('&')} +var old=$.fn.request +$.fn.request=function(handler,option){var args=arguments +var $this=$(this).first() +var data={evalBeforeUpdate:$this.data('request-before-update'),evalSuccess:$this.data('request-success'),evalError:$this.data('request-error'),evalComplete:$this.data('request-complete'),ajaxGlobal:$this.data('request-ajax-global'),confirm:$this.data('request-confirm'),redirect:$this.data('request-redirect'),loading:$this.data('request-loading'),flash:$this.data('request-flash'),files:$this.data('request-files'),browserValidate:$this.data('browser-validate'),form:$this.data('request-form'),url:$this.data('request-url'),update:paramToObj('data-request-update',$this.data('request-update')),data:paramToObj('data-request-data',$this.data('request-data'))} +if(!handler)handler=$this.data('request') +var options=$.extend(true,{},Request.DEFAULTS,data,typeof option=='object'&&option) +return new Request($this,handler,options)} +$.fn.request.Constructor=Request +$.request=function(handler,option){return $(document).request(handler,option)} +$.fn.request.noConflict=function(){$.fn.request=old +return this} +function paramToObj(name,value){if(value===undefined)value='' +if(typeof value=='object')return value +try{return ocJSON("{"+value+"}")} +catch(e){throw new Error('Error parsing the '+name+' attribute value. '+e)}} +function getXSRFToken(){var cookieValue=null +if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';') +for(var i=0;i="0"&&str[pos]<="9")){var body="";for(var i=pos;i="0"&&str[i]<="9")){body+=str[i];}else{return{originLength:body.length,body:body};}} +throw new Error("Broken JSON number body near "+body);} +if(str[pos]==="{"||str[pos]==="["){var stack=[str[pos]];var body=str[pos];for(var i=pos+1;i=0)?pos-5:0,50));} +function canBeKeyHead(ch){if(ch[0]==="\\")return false;if((ch[0]>='a'&&ch[0]<='z')||(ch[0]>='A'&&ch[0]<='Z')||ch[0]==='_')return true;if(ch[0]>='0'&&ch[0]<='9')return true;if(ch[0]==='$')return true;if(ch.charCodeAt(0)>255)return true;return false;} +function isBlankChar(ch){return ch===" "||ch==="\n"||ch==="\t";} +function parse(str){str=str.trim();if(!str.length)throw new Error("Broken JSON object.");var result="";while(str&&str[0]===","){str=str.substr(1);} +if(str[0]==="\""||str[0]==="'"){if(str[str.length-1]!==str[0]){throw new Error("Invalid string JSON object.");} +var body="\"";for(var i=1;i'+html+'
    ',null,false));output.find('*').each(function(){trimAttributes(this);});return output.html();} +window.ocSanitize=function(html){return sanitize(html)};}(window);+function($){"use strict";if($.oc===undefined) +$.oc={} +var LOADER_CLASS='oc-loading';$(document).on('ajaxSetup','[data-request][data-request-flash]',function(event,context){context.options.handleErrorMessage=function(message){$.oc.flashMsg({text:message,class:'error'})} +context.options.handleFlashMessage=function(message,type){$.oc.flashMsg({text:message,class:type})}}) +$(document).on('ajaxValidation','[data-request][data-request-validate]',function(event,context,errorMsg,fields){var $this=$(this).closest('form'),$container=$('[data-validate-error]',$this),messages=[],$field +$.each(fields,function(fieldName,fieldMessages){$field=$('[data-validate-for="'+fieldName+'"]',$this) +messages=$.merge(messages,fieldMessages) +if(!!$field.length){if(!$field.text().length||$field.data('emptyMode')==true){$field.data('emptyMode',true).text(fieldMessages.join(', '))} +$field.addClass('visible')}}) +if(!!$container.length){$container=$('[data-validate-error]',$this)} +if(!!$container.length){var $oldMessages=$('[data-message]',$container) +$container.addClass('visible') +if(!!$oldMessages.length){var $clone=$oldMessages.first() +$.each(messages,function(key,message){$clone.clone().text(message).insertAfter($clone)}) +$oldMessages.remove()} +else{$container.text(errorMsg)}} +$this.one('ajaxError',function(event){event.preventDefault()})}) +$(document).on('ajaxPromise','[data-request][data-request-validate]',function(){var $this=$(this).closest('form') +$('[data-validate-for]',$this).removeClass('visible') +$('[data-validate-error]',$this).removeClass('visible')}) +$(document).on('ajaxPromise','[data-request]',function(){var $target=$(this) +if($target.data('attach-loading')!==undefined){$target.addClass(LOADER_CLASS).prop('disabled',true)} +if($target.is('form')){$('[data-attach-loading]',$target).addClass(LOADER_CLASS).prop('disabled',true)}}).on('ajaxFail ajaxDone','[data-request]',function(){var $target=$(this) +if($target.data('attach-loading')!==undefined){$target.removeClass(LOADER_CLASS).prop('disabled',false)} +if($target.is('form')){$('[data-attach-loading]',$target).removeClass(LOADER_CLASS).prop('disabled',false)}}) +var StripeLoadIndicator=function(){var self=this +this.counter=0 +this.indicator=$('
    ').addClass('stripe-loading-indicator loaded').append($('
    ').addClass('stripe')).append($('
    ').addClass('stripe-loaded')) +this.stripe=this.indicator.find('.stripe') +$(document).ready(function(){$(document.body).append(self.indicator)})} +StripeLoadIndicator.prototype.show=function(){this.counter++ +this.stripe.after(this.stripe=this.stripe.clone()).remove() +if(this.counter>1){return} +this.indicator.removeClass('loaded') +$(document.body).addClass('oc-loading')} +StripeLoadIndicator.prototype.hide=function(force){this.counter-- +if(force!==undefined&&force){this.counter=0} +if(this.counter<=0){this.indicator.addClass('loaded') +$(document.body).removeClass('oc-loading')}} +$.oc.stripeLoadIndicator=new StripeLoadIndicator() +$(document).on('ajaxPromise','[data-request]',function(event){event.stopPropagation() +$.oc.stripeLoadIndicator.show() +var $el=$(this) +$(window).one('ajaxUpdateComplete',function(){if($el.closest('html').length===0) +$.oc.stripeLoadIndicator.hide()})}).on('ajaxFail ajaxDone','[data-request]',function(event){event.stopPropagation() +$.oc.stripeLoadIndicator.hide()}) +var FlashMessage=function(options,el){var +options=$.extend({},FlashMessage.DEFAULTS,options),$element=$(el) +$('body > p.flash-message').remove() +if($element.length==0){$element=$('

    ').addClass(options.class).html(options.text)} +$element.addClass('flash-message fade').attr('data-control',null).on('click','button',remove).on('click',remove).append('') +$(document.body).append($element) +setTimeout(function(){$element.addClass('in')},100) +var timer=window.setTimeout(remove,options.interval*1000) +function removeElement(){$element.remove()} +function remove(){window.clearInterval(timer) +$element.removeClass('in') +$.support.transition&&$element.hasClass('fade')?$element.one($.support.transition.end,removeElement).emulateTransitionEnd(500):removeElement()}} +FlashMessage.DEFAULTS={class:'success',text:'Default text',interval:5} +if($.oc===undefined) +$.oc={} +$.oc.flashMsg=FlashMessage +$(document).render(function(){$('[data-control=flash-message]').each(function(){$.oc.flashMsg($(this).data(),this)})})}(window.jQuery); \ No newline at end of file diff --git a/modules/system/assets/js/framework.combined.js b/modules/system/assets/js/framework.combined.js new file mode 100644 index 0000000..75571be --- /dev/null +++ b/modules/system/assets/js/framework.combined.js @@ -0,0 +1,4 @@ +/* +=require framework.js +=require framework.extras.js +*/ diff --git a/modules/system/assets/js/framework.extras.js b/modules/system/assets/js/framework.extras.js new file mode 100644 index 0000000..5b92dcc --- /dev/null +++ b/modules/system/assets/js/framework.extras.js @@ -0,0 +1,256 @@ +/* ======================================================================== + * OctoberCMS: front-end JavaScript extras + * http://octobercms.com + * ======================================================================== + * Copyright 2016-2020 Alexey Bobkov, Samuel Georges + * ======================================================================== */ + ++function ($) { "use strict"; + if ($.oc === undefined) + $.oc = {} + + // @todo Provide an interface for configuration + // - Custom loader CSS class + // - Custom stripe loader color + // - Flash message interval + + var LOADER_CLASS = 'oc-loading'; + + // FLASH HANDLING + // ============================ + + $(document).on('ajaxSetup', '[data-request][data-request-flash]', function(event, context) { + context.options.handleErrorMessage = function(message) { + $.oc.flashMsg({ text: message, class: 'error' }) + } + + context.options.handleFlashMessage = function(message, type) { + $.oc.flashMsg({ text: message, class: type }) + } + }) + + // FORM VALIDATION + // ============================ + + $(document).on('ajaxValidation', '[data-request][data-request-validate]', function(event, context, errorMsg, fields) { + var $this = $(this).closest('form'), + $container = $('[data-validate-error]', $this), + messages = [], + $field + + $.each(fields, function(fieldName, fieldMessages) { + $field = $('[data-validate-for="'+fieldName+'"]', $this) + messages = $.merge(messages, fieldMessages) + if (!!$field.length) { + if (!$field.text().length || $field.data('emptyMode') == true) { + $field + .data('emptyMode', true) + .text(fieldMessages.join(', ')) + } + $field.addClass('visible') + } + }) + + if (!!$container.length) { + $container = $('[data-validate-error]', $this) + } + + if (!!$container.length) { + var $oldMessages = $('[data-message]', $container) + $container.addClass('visible') + + if (!!$oldMessages.length) { + var $clone = $oldMessages.first() + + $.each(messages, function(key, message) { + $clone.clone().text(message).insertAfter($clone) + }) + + $oldMessages.remove() + } + else { + $container.text(errorMsg) + } + } + + $this.one('ajaxError', function(event){ + event.preventDefault() + }) + }) + + $(document).on('ajaxPromise', '[data-request][data-request-validate]', function() { + var $this = $(this).closest('form') + $('[data-validate-for]', $this).removeClass('visible') + $('[data-validate-error]', $this).removeClass('visible') + }) + + // LOADING BUTTONS + // ============================ + + $(document) + .on('ajaxPromise', '[data-request]', function() { + var $target = $(this) + + if ($target.data('attach-loading') !== undefined) { + $target + .addClass(LOADER_CLASS) + .prop('disabled', true) + } + + if ($target.is('form')) { + $('[data-attach-loading]', $target) + .addClass(LOADER_CLASS) + .prop('disabled', true) + } + }) + .on('ajaxFail ajaxDone', '[data-request]', function() { + var $target = $(this) + + if ($target.data('attach-loading') !== undefined) { + $target + .removeClass(LOADER_CLASS) + .prop('disabled', false) + } + + if ($target.is('form')) { + $('[data-attach-loading]', $target) + .removeClass(LOADER_CLASS) + .prop('disabled', false) + } + }) + + // STRIPE LOAD INDICATOR + // ============================ + + var StripeLoadIndicator = function() { + var self = this + this.counter = 0 + this.indicator = $('

    ').addClass('stripe-loading-indicator loaded') + .append($('
    ').addClass('stripe')) + .append($('
    ').addClass('stripe-loaded')) + this.stripe = this.indicator.find('.stripe') + + $(document).ready(function() { + $(document.body).append(self.indicator) + }) + } + + StripeLoadIndicator.prototype.show = function() { + this.counter++ + + // Restart the animation + this.stripe.after(this.stripe = this.stripe.clone()).remove() + + if (this.counter > 1) { + return + } + + this.indicator.removeClass('loaded') + $(document.body).addClass('oc-loading') + } + + StripeLoadIndicator.prototype.hide = function(force) { + this.counter-- + + if (force !== undefined && force) { + this.counter = 0 + } + + if (this.counter <= 0) { + this.indicator.addClass('loaded') + $(document.body).removeClass('oc-loading') + } + } + + $.oc.stripeLoadIndicator = new StripeLoadIndicator() + + // STRIPE LOAD INDICATOR DATA-API + // ============================ + + $(document) + .on('ajaxPromise', '[data-request]', function(event) { + // Prevent this event from bubbling up to a non-related data-request + // element, for example a
    tag wrapping a ') + + $(document.body).append($element) + + setTimeout(function() { + $element.addClass('in') + }, 100) + + var timer = window.setTimeout(remove, options.interval * 1000) + + function removeElement() { + $element.remove() + } + + function remove() { + window.clearInterval(timer) + + $element.removeClass('in') + $.support.transition && $element.hasClass('fade') + ? $element + .one($.support.transition.end, removeElement) + .emulateTransitionEnd(500) + : removeElement() + } + } + + FlashMessage.DEFAULTS = { + class: 'success', + text: 'Default text', + interval: 5 + } + + if ($.oc === undefined) + $.oc = {} + + $.oc.flashMsg = FlashMessage + + // FLASH MESSAGE DATA-API + // =============== + + $(document).render(function(){ + $('[data-control=flash-message]').each(function(){ + $.oc.flashMsg($(this).data(), this) + }) + }) + +}(window.jQuery); diff --git a/modules/system/assets/js/framework.js b/modules/system/assets/js/framework.js new file mode 100644 index 0000000..11af8c1 --- /dev/null +++ b/modules/system/assets/js/framework.js @@ -0,0 +1,977 @@ +/* ======================================================================== + * OctoberCMS: front-end JavaScript framework + * http://octobercms.com + * ======================================================================== + * Copyright 2016-2020 Alexey Bobkov, Samuel Georges + * ======================================================================== */ + +if (window.jQuery === undefined) { + throw new Error('The jQuery library is not loaded. The OctoberCMS framework cannot be initialized.'); +} +if (window.jQuery.request !== undefined) { + throw new Error('The OctoberCMS framework is already loaded.'); +} + ++function ($) { "use strict"; + + var Request = function (element, handler, options) { + var $el = this.$el = $(element); + this.options = options || {}; + + /* + * Validate handler name + */ + if (handler === undefined) { + throw new Error('The request handler name is not specified.') + } + + if (!handler.match(/^(?:\w+\:{2})?on*/)) { + throw new Error('Invalid handler name. The correct handler name format is: "onEvent".') + } + + /* + * Prepare the options + */ + var $form = options.form ? $(options.form) : $el.closest('form'), + $triggerEl = !!$form.length ? $form : $el, + context = { handler: handler, options: options } + + /* + * Validate the form client-side + */ + if ((options.browserValidate !== undefined) && typeof document.createElement('input').reportValidity == 'function' && $form && $form[0] && !$form[0].checkValidity()) { + $form[0].reportValidity(); + return false; + } + + /* + * Execute the request + */ + $el.trigger('ajaxSetup', [context]) + var _event = jQuery.Event('oc.beforeRequest') + $triggerEl.trigger(_event, context) + if (_event.isDefaultPrevented()) return + + var loading = options.loading !== undefined ? options.loading : null, + url = options.url !== undefined ? options.url : window.location.href, + isRedirect = options.redirect !== undefined && options.redirect.length, + useFlash = options.flash !== undefined, + useFiles = options.files !== undefined + + if (useFiles && typeof FormData === 'undefined') { + console.warn('This browser does not support file uploads via FormData') + useFiles = false + } + + if ($.type(loading) == 'string') { + loading = $(loading) + } + + /* + * Request headers + */ + var requestHeaders = { + 'X-OCTOBER-REQUEST-HANDLER': handler, + 'X-OCTOBER-REQUEST-PARTIALS': this.extractPartials(options.update) + } + + if (useFlash) { + requestHeaders['X-OCTOBER-REQUEST-FLASH'] = 1 + } + + var csrfToken = getXSRFToken() + if (csrfToken) { + requestHeaders['X-XSRF-TOKEN'] = csrfToken + } + + /* + * Request data + */ + var requestData, + inputName, + data = {} + + $.each($el.parents('[data-request-data]').toArray().reverse(), function extendRequest() { + $.extend(data, paramToObj('data-request-data', $(this).data('request-data'))) + }) + + if ($el.is(':input') && !$form.length) { + inputName = $el.attr('name') + if (inputName !== undefined && options.data[inputName] === undefined) { + options.data[inputName] = $el.val() + } + } + + if (options.data !== undefined && !$.isEmptyObject(options.data)) { + $.extend(data, options.data) + } + + if (useFiles) { + requestData = new FormData($form.length ? $form.get(0) : undefined) + + if ($el.is(':file') && inputName) { + $.each($el.prop('files'), function() { + requestData.append(inputName, this) + }) + + delete data[inputName] + } + + $.each(data, function(key) { + if (typeof Blob !== "undefined" && this instanceof Blob && this.filename) { + requestData.append(key, this, this.filename) + } else { + requestData.append(key, this) + } + }) + } + else { + requestData = [$form.serialize(), $.param(data)].filter(Boolean).join('&') + } + + /* + * Request options + */ + var requestOptions = { + url: url, + crossDomain: false, + global: options.ajaxGlobal, + context: context, + headers: requestHeaders, + success: function(data, textStatus, jqXHR) { + /* + * Halt here if beforeUpdate() or data-request-before-update returns false + */ + if (this.options.beforeUpdate.apply(this, [data, textStatus, jqXHR]) === false) return + if (options.evalBeforeUpdate && eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalBeforeUpdate+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))') === false) return + + /* + * Trigger 'ajaxBeforeUpdate' on the form, halt if event.preventDefault() is called + */ + var _event = jQuery.Event('ajaxBeforeUpdate') + $triggerEl.trigger(_event, [context, data, textStatus, jqXHR]) + if (_event.isDefaultPrevented()) return + + if (useFlash && data['X_OCTOBER_FLASH_MESSAGES']) { + $.each(data['X_OCTOBER_FLASH_MESSAGES'], function(type, message) { + requestOptions.handleFlashMessage(message, type) + }) + } + + /* + * Proceed with the update process + */ + var updatePromise = requestOptions.handleUpdateResponse(data, textStatus, jqXHR) + + updatePromise.done(function() { + $triggerEl.trigger('ajaxSuccess', [context, data, textStatus, jqXHR]) + options.evalSuccess && eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalSuccess+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))') + }) + + return updatePromise + }, + error: function(jqXHR, textStatus, errorThrown) { + var errorMsg, + updatePromise = $.Deferred() + + if ((window.ocUnloading !== undefined && window.ocUnloading) || errorThrown == 'abort') + return + + /* + * Disable redirects + */ + isRedirect = false + options.redirect = null + + /* + * Error 406 is a "smart error" that returns response object that is + * processed in the same fashion as a successful response. + */ + if (jqXHR.status == 406 && jqXHR.responseJSON) { + errorMsg = jqXHR.responseJSON['X_OCTOBER_ERROR_MESSAGE'] + updatePromise = requestOptions.handleUpdateResponse(jqXHR.responseJSON, textStatus, jqXHR) + } + /* + * Standard error with standard response text + */ + else { + errorMsg = jqXHR.responseText ? jqXHR.responseText : jqXHR.statusText + updatePromise.resolve() + } + + updatePromise.done(function() { + $el.data('error-message', errorMsg) + + /* + * Trigger 'ajaxError' on the form, halt if event.preventDefault() is called + */ + var _event = jQuery.Event('ajaxError') + $triggerEl.trigger(_event, [context, errorMsg, textStatus, jqXHR]) + if (_event.isDefaultPrevented()) return + + /* + * Halt here if the data-request-error attribute returns false + */ + if (options.evalError && eval('(function($el, context, errorMsg, textStatus, jqXHR) {'+options.evalError+'}.call($el.get(0), $el, context, errorMsg, textStatus, jqXHR))') === false) + return + + requestOptions.handleErrorMessage(errorMsg) + }) + + return updatePromise + }, + complete: function(data, textStatus, jqXHR) { + $triggerEl.trigger('ajaxComplete', [context, data, textStatus, jqXHR]) + options.evalComplete && eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalComplete+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))') + }, + + /* + * Custom function, requests confirmation from the user + */ + handleConfirmMessage: function(message) { + var _event = jQuery.Event('ajaxConfirmMessage') + + _event.promise = $.Deferred() + if ($(window).triggerHandler(_event, [message]) !== undefined) { + _event.promise.done(function() { + options.confirm = null + new Request(element, handler, options) + }) + return false + } + + if (_event.isDefaultPrevented()) return + if (message) return confirm(message) + }, + + /* + * Custom function, display an error message to the user + */ + handleErrorMessage: function(message) { + var _event = jQuery.Event('ajaxErrorMessage') + $(window).trigger(_event, [message]) + if (_event.isDefaultPrevented()) return + if (message) alert(message) + }, + + /* + * Custom function, focus fields with errors + */ + handleValidationMessage: function(message, fields) { + $triggerEl.trigger('ajaxValidation', [context, message, fields]) + + var isFirstInvalidField = true + $.each(fields, function focusErrorField(fieldName, fieldMessages) { + fieldName = fieldName.replace(/\.(\w+)/g, '[$1]') + + var fieldElement = $form.find('[name="'+fieldName+'"], [name="'+fieldName+'[]"], [name$="['+fieldName+']"], [name$="['+fieldName+'][]"]').filter(':enabled').first() + if (fieldElement.length > 0) { + + var _event = jQuery.Event('ajaxInvalidField') + $(window).trigger(_event, [fieldElement.get(0), fieldName, fieldMessages, isFirstInvalidField]) + + if (isFirstInvalidField) { + if (!_event.isDefaultPrevented()) fieldElement.focus() + isFirstInvalidField = false + } + } + }) + }, + + /* + * Custom function, display a flash message to the user + */ + handleFlashMessage: function(message, type) {}, + + /* + * Custom function, redirect the browser to another location + */ + handleRedirectResponse: function(url) { + window.location.assign(url) + }, + + /* + * Custom function, handle any application specific response values + * Using a promisary object here in case injected assets need time to load + */ + handleUpdateResponse: function(data, textStatus, jqXHR) { + + /* + * Update partials and finish request + */ + var updatePromise = $.Deferred().done(function() { + for (var partial in data) { + /* + * If a partial has been supplied on the client side that matches the server supplied key, look up + * it's selector and use that. If not, we assume it is an explicit selector reference. + */ + var selector = (options.update[partial]) ? options.update[partial] : partial + if ($.type(selector) == 'string' && selector.charAt(0) == '@') { + $(selector.substring(1)).append(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR]) + } + else if ($.type(selector) == 'string' && selector.charAt(0) == '^') { + $(selector.substring(1)).prepend(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR]) + } + else { + $(selector).trigger('ajaxBeforeReplace') + $(selector).html(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR]) + } + } + + /* + * Wait for .html() method to finish rendering from partial updates + */ + setTimeout(function() { + $(window) + .trigger('ajaxUpdateComplete', [context, data, textStatus, jqXHR]) + .trigger('resize') + }, 0) + }) + + /* + * Handle redirect + */ + if (data['X_OCTOBER_REDIRECT']) { + options.redirect = data['X_OCTOBER_REDIRECT'] + isRedirect = true + } + + if (isRedirect) { + requestOptions.handleRedirectResponse(options.redirect) + } + + /* + * Handle validation + */ + if (data['X_OCTOBER_ERROR_FIELDS']) { + requestOptions.handleValidationMessage(data['X_OCTOBER_ERROR_MESSAGE'], data['X_OCTOBER_ERROR_FIELDS']) + } + + /* + * Handle asset injection + */ + if (data['X_OCTOBER_ASSETS']) { + assetManager.load(data['X_OCTOBER_ASSETS'], $.proxy(updatePromise.resolve, updatePromise)) + } + else { + updatePromise.resolve() + } + + return updatePromise + } + } + + if (useFiles) { + requestOptions.processData = requestOptions.contentType = false + } + + /* + * Allow default business logic to be called from user functions + */ + context.success = requestOptions.success + context.error = requestOptions.error + context.complete = requestOptions.complete + requestOptions = $.extend(requestOptions, options) + requestOptions.data = requestData + + /* + * Initiate request + */ + if (options.confirm && !requestOptions.handleConfirmMessage(options.confirm)) { + return + } + + if (loading) loading.show() + $(window).trigger('ajaxBeforeSend', [context]) + $el.trigger('ajaxPromise', [context]) + + return $.ajax(requestOptions) + .fail(function(jqXHR, textStatus, errorThrown) { + if (!isRedirect) { + $el.trigger('ajaxFail', [context, textStatus, jqXHR]) + } + if (loading) loading.hide() + }) + .done(function(data, textStatus, jqXHR) { + if (!isRedirect) { + $el.trigger('ajaxDone', [context, data, textStatus, jqXHR]) + } + if (loading) loading.hide() + }) + .always(function(dataOrXhr, textStatus, xhrOrError) { + $el.trigger('ajaxAlways', [context, dataOrXhr, textStatus, xhrOrError]) + }) + } + + Request.DEFAULTS = { + update: {}, + type : 'POST', + beforeUpdate: function(data, textStatus, jqXHR) {}, + evalBeforeUpdate: null, + evalSuccess: null, + evalError: null, + evalComplete: null, + ajaxGlobal: false + } + + /* + * Internal function, build a string of partials and their update elements. + */ + Request.prototype.extractPartials = function(update) { + var result = [] + + for (var partial in update) + result.push(partial) + + return result.join('&') + } + + // REQUEST PLUGIN DEFINITION + // ============================ + + var old = $.fn.request + + $.fn.request = function(handler, option) { + var args = arguments + + var $this = $(this).first() + var data = { + evalBeforeUpdate: $this.data('request-before-update'), + evalSuccess: $this.data('request-success'), + evalError: $this.data('request-error'), + evalComplete: $this.data('request-complete'), + ajaxGlobal: $this.data('request-ajax-global'), + confirm: $this.data('request-confirm'), + redirect: $this.data('request-redirect'), + loading: $this.data('request-loading'), + flash: $this.data('request-flash'), + files: $this.data('request-files'), + browserValidate: $this.data('browser-validate'), + form: $this.data('request-form'), + url: $this.data('request-url'), + update: paramToObj('data-request-update', $this.data('request-update')), + data: paramToObj('data-request-data', $this.data('request-data')) + } + if (!handler) handler = $this.data('request') + var options = $.extend(true, {}, Request.DEFAULTS, data, typeof option == 'object' && option) + return new Request($this, handler, options) + } + + $.fn.request.Constructor = Request + + $.request = function(handler, option) { + return $(document).request(handler, option) + } + + // REQUEST NO CONFLICT + // ================= + + $.fn.request.noConflict = function() { + $.fn.request = old + return this + } + + // REQUEST DATA-API + // ============== + + function paramToObj(name, value) { + if (value === undefined) value = '' + if (typeof value == 'object') return value + + try { + return ocJSON("{" + value + "}") + } + catch (e) { + throw new Error('Error parsing the '+name+' attribute value. '+e) + } + } + + function getXSRFToken() { + var cookieValue = null + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';') + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]) + if (cookie.substring(0, 11) == ('XSRF-TOKEN' + '=')) { + cookieValue = decodeURIComponent(cookie.substring(11)) + break + } + } + } + return cookieValue + } + + $(document).on('change', 'select[data-request], input[type=radio][data-request], input[type=checkbox][data-request], input[type=file][data-request]', function documentOnChange() { + $(this).request() + }) + + $(document).on('click', 'a[data-request], button[data-request], input[type=button][data-request], input[type=submit][data-request]', function documentOnClick(e) { + e.preventDefault() + + $(this).request() + + if ($(this).is('[type=submit]')) + return false + }) + + $(document).on('keydown', 'input[type=text][data-request], input[type=submit][data-request], input[type=password][data-request]', function documentOnKeydown(e) { + if (e.key === 'Enter') { + if (this.dataTrackInputTimer !== undefined) + window.clearTimeout(this.dataTrackInputTimer) + + $(this).request() + return false + } + }) + + $(document).on('input', 'input[data-request][data-track-input]', function documentOnKeyup(e) { + var + $el = $(this), + lastValue = $el.data('oc.lastvalue') + + if (!$el.is('[type=email],[type=number],[type=password],[type=search],[type=text]')) + return + + if (lastValue !== undefined && lastValue == this.value) + return + + $el.data('oc.lastvalue', this.value) + + if (this.dataTrackInputTimer !== undefined) + window.clearTimeout(this.dataTrackInputTimer) + + var interval = $(this).data('track-input') + if (!interval) + interval = 300 + + var self = this + this.dataTrackInputTimer = window.setTimeout(function() { + if (self.lastDataTrackInputRequest) { + self.lastDataTrackInputRequest.abort(); + } + self.lastDataTrackInputRequest = $(self).request(); + }, interval) + }) + + $(document).on('submit', '[data-request]', function documentOnSubmit() { + $(this).request() + return false + }) + + $(window).on('beforeunload', function documentOnBeforeUnload() { + window.ocUnloading = true + }) + + /* + * Invent our own event that unifies document.ready with window.ajaxUpdateComplete + * + * $(document).render(function() { }) + * $(document).on('render', function() { }) + */ + + $(document).ready(function triggerRenderOnReady() { + $(document).trigger('render') + }) + + $(window).on('ajaxUpdateComplete', function triggerRenderOnAjaxUpdateComplete() { + $(document).trigger('render') + }) + + $.fn.render = function(callback) { + $(document).on('render', callback) + } + +}(window.jQuery); + +/* + * October CMS JSON Parser + */ ++function(window) { "use strict"; + function parseKey(str, pos, quote) { + var key = ""; + for (var i = pos; i < str.length; i++) { + if (quote && quote === str[i]) { + return key; + } else if (!quote && (str[i] === " " || str[i] === ":")) { + return key; + } + + key += str[i]; + + if (str[i] === "\\" && i + 1 < str.length) { + key += str[i + 1]; + i++; + } + } + throw new Error("Broken JSON syntax near " + key); + } + + function getBody(str, pos) { + // parse string body + if (str[pos] === "\"" || str[pos] === "'") { + var body = str[pos]; + for (var i = pos + 1; i < str.length; i++) { + if (str[i] === "\\") { + body += str[i]; + if (i + 1 < str.length) body += str[i + 1]; + i++; + } else if (str[i] === str[pos]) { + body += str[pos]; + return { + originLength: body.length, + body: body + }; + } else body += str[i]; + } + throw new Error("Broken JSON string body near " + body); + } + + // parse true / false + if (str[pos] === "t") { + if (str.indexOf("true", pos) === pos) { + return { + originLength: "true".length, + body: "true" + }; + } + throw new Error("Broken JSON boolean body near " + str.substr(0, pos + 10)); + } + if (str[pos] === "f") { + if (str.indexOf("f", pos) === pos) { + return { + originLength: "false".length, + body: "false" + }; + } + throw new Error("Broken JSON boolean body near " + str.substr(0, pos + 10)); + } + + // parse null + if (str[pos] === "n") { + if (str.indexOf("null", pos) === pos) { + return { + originLength: "null".length, + body: "null" + }; + } + throw new Error("Broken JSON boolean body near " + str.substr(0, pos + 10)); + } + + // parse number + if (str[pos] === "-" || str[pos] === "+" || str[pos] === "." || (str[pos] >= "0" && str[pos] <= "9")) { + var body = ""; + for (var i = pos; i < str.length; i++) { + if (str[i] === "-" || str[i] === "+" || str[i] === "." || (str[i] >= "0" && str[i] <= "9")) { + body += str[i]; + } else { + return { + originLength: body.length, + body: body + }; + } + } + throw new Error("Broken JSON number body near " + body); + } + + // parse object + if (str[pos] === "{" || str[pos] === "[") { + var stack = [str[pos]]; + var body = str[pos]; + for (var i = pos + 1; i < str.length; i++) { + body += str[i]; + if (str[i] === "\\") { + if (i + 1 < str.length) body += str[i + 1]; + i++; + } else if (str[i] === "\"") { + if (stack[stack.length - 1] === "\"") { + stack.pop(); + } else if (stack[stack.length - 1] !== "'") { + stack.push(str[i]); + } + } else if (str[i] === "'") { + if (stack[stack.length - 1] === "'") { + stack.pop(); + } else if (stack[stack.length - 1] !== "\"") { + stack.push(str[i]); + } + } else if (stack[stack.length - 1] !== "\"" && stack[stack.length - 1] !== "'") { + if (str[i] === "{") { + stack.push("{"); + } else if (str[i] === "}") { + if (stack[stack.length - 1] === "{") { + stack.pop(); + } else { + throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body); + } + } else if (str[i] === "[") { + stack.push("["); + } else if (str[i] === "]") { + if (stack[stack.length - 1] === "[") { + stack.pop(); + } else { + throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body); + } + } + } + if (!stack.length) { + return { + originLength: i - pos, + body: body + }; + } + } + throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body); + } + throw new Error("Broken JSON body near " + str.substr((pos - 5 >= 0) ? pos - 5 : 0, 50)); + } + + function canBeKeyHead(ch) { + if (ch[0] === "\\") return false; + if ((ch[0] >= 'a' && ch[0] <= 'z') || (ch[0] >= 'A' && ch[0] <= 'Z') || ch[0] === '_') return true; + if (ch[0] >= '0' && ch[0] <= '9') return true; + if (ch[0] === '$') return true; + if (ch.charCodeAt(0) > 255) return true; + return false; + } + + function isBlankChar(ch) { + return ch === " " || ch === "\n" || ch === "\t"; + } + + function parse(str) { + str = str.trim(); + if (!str.length) throw new Error("Broken JSON object."); + var result = ""; + + /* + * the mistake ',' + */ + while (str && str[0] === ",") { + str = str.substr(1); + } + + /* + * string + */ + if (str[0] === "\"" || str[0] === "'") { + if (str[str.length - 1] !== str[0]) { + throw new Error("Invalid string JSON object."); + } + + var body = "\""; + for (var i = 1; i < str.length; i++) { + if (str[i] === "\\") { + if (str[i + 1] === "'") { + body += str[i + 1] + } else { + body += str[i]; + body += str[i + 1]; + } + i++; + } else if (str[i] === str[0]) { + body += "\""; + return body + } else if (str[i] === "\"") { + body += "\\\"" + } else body += str[i]; + } + throw new Error("Invalid string JSON object."); + } + + /* + * boolean + */ + if (str === "true" || str === "false") { + return str; + } + + /* + * null + */ + if (str === "null") { + return "null"; + } + + /* + * number + */ + var num = parseFloat(str); + if (!isNaN(num)) { + return num.toString(); + } + + /* + * object + */ + if (str[0] === "{") { + var type = "needKey"; + var result = "{"; + + for (var i = 1; i < str.length; i++) { + if (isBlankChar(str[i])) { + continue; + } else if (type === "needKey" && (str[i] === "\"" || str[i] === "'")) { + var key = parseKey(str, i + 1, str[i]); + result += "\"" + key + "\""; + i += key.length; + i += 1; + type = "afterKey"; + } else if (type === "needKey" && canBeKeyHead(str[i])) { + var key = parseKey(str, i); + result += "\""; + result += key; + result += "\""; + i += key.length - 1; + type = "afterKey"; + } else if (type === "afterKey" && str[i] === ":") { + result += ":"; + type = ":"; + } else if (type === ":") { + var body = getBody(str, i); + + i = i + body.originLength - 1; + result += parse(body.body); + + type = "afterBody"; + } else if (type === "afterBody" || type === "needKey") { + var last = i; + while (str[last] === "," || isBlankChar(str[last])) { + last++; + } + if (str[last] === "}" && last === str.length - 1) { + while (result[result.length - 1] === ",") { + result = result.substr(0, result.length - 1); + } + result += "}"; + return result; + } else if (last !== i && result !== "{") { + result += ","; + type = "needKey"; + i = last - 1; + } + } + } + throw new Error("Broken JSON object near " + result); + } + + /* + * array + */ + if (str[0] === "[") { + var result = "["; + var type = "needBody"; + for (var i = 1; i < str.length; i++) { + if (" " === str[i] || "\n" === str[i] || "\t" === str[i]) { + continue; + } else if (type === "needBody") { + if (str[i] === ",") { + result += "null,"; + continue; + } + if (str[i] === "]" && i === str.length - 1) { + if (result[result.length - 1] === ",") result = result.substr(0, result.length - 1); + result += "]"; + return result; + } + + var body = getBody(str, i); + + i = i + body.originLength - 1; + result += parse(body.body); + + type = "afterBody"; + } else if (type === "afterBody") { + if (str[i] === ",") { + result += ","; + type = "needBody"; + + // deal with mistake "," + while (str[i + 1] === "," || isBlankChar(str[i + 1])) { + if (str[i + 1] === ",") result += "null,"; + i++; + } + } else if (str[i] === "]" && i === str.length - 1) { + result += "]"; + return result; + } + } + } + throw new Error("Broken JSON array near " + result); + } + } + + // Global function + window.ocJSON = function(json) { + var jsonString = parse(json); + return JSON.parse(jsonString); + }; + +}(window); + +/* + * October CMS jQuery HTML Sanitizer + * @see https://gist.github.com/ufologist/5a0da51b2b9ef1b861c30254172ac3c9 + */ ++function(window) { "use strict"; + + function trimAttributes(node) { + $.each(node.attributes, function() { + var attrName = this.name; + var attrValue = this.value; + + /* + * remove attributes where the names start with "on" (for example: onload, onerror...) + * remove attributes where the value starts with the "javascript:" pseudo protocol (for example href="javascript:alert(1)") + */ + if (attrName.indexOf('on') == 0 || attrValue.indexOf('javascript:') == 0) { + $(node).removeAttr(attrName); + } + }); + } + + function sanitize(html) { + /* + * [jQuery.parseHTML(data [, context ] [, keepScripts ])](http://api.jquery.com/jQuery.parseHTML/) added: 1.8 + * Parses a string into an array of DOM nodes. + * + * By default, the context is the current document if not specified or given as null or undefined. If the HTML was to be used + * in another document such as an iframe, that frame's document could be used. + * + * As of 3.0 the default behavior is changed. + * + * If the context is not specified or given as null or undefined, a new document is used. + * This can potentially improve security because inline events will not execute when the HTML is parsed. Once the parsed HTML + * is injected into a document it does execute, but this gives tools a chance to traverse the created DOM and remove anything + * deemed unsafe. This improvement does not apply to internal uses of jQuery.parseHTML as they usually pass in the current + * document. Therefore, a statement like $( "#log" ).append( $( htmlString ) ) is still subject to the injection of malicious code. + * + * without context do not execute script + * $.parseHTML('
    '); + * $.parseHTML('
    ', null); + * + * with context document execute script! + * $.parseHTML('
    ', document); + * + * Most jQuery APIs that accept HTML strings will run scripts that are included in the HTML. jQuery.parseHTML does not run scripts + * in the parsed HTML unless keepScripts is explicitly true. However, it is still possible in most environments to execute scripts + * indirectly, for example via the attribute. + * + * will return [] + * $.parseHTML(' \ No newline at end of file diff --git a/modules/system/assets/ui/docs/drag-sort.md b/modules/system/assets/ui/docs/drag-sort.md new file mode 100644 index 0000000..f106c07 --- /dev/null +++ b/modules/system/assets/ui/docs/drag-sort.md @@ -0,0 +1,108 @@ +# Drag.Sort + +Allows the dragging and sorting of lists. + +### Example + +Sort the buttons + +
      +
    1. First
    2. +
    3. Second
    4. +
    5. Third
    6. +
    + + + + + +## JavaScript API + +The `sortable()` method must be invoked on valid containers, meaning they must match the containerSelector option. + +`.sortable('enable')` +Enable all instantiated sortables in the set of matched elements + +`.sortable('disable')` +Disable all instantiated sortables in the set of matched elements + +`.sortable('refresh')` +Reset all cached element dimensions + +`.sortable('destroy')` +Remove the sortable plugin from the set of matched elements + +`.sortable('serialize')` +Serialize all selected containers. Returns a jQuery object . Use .get() to retrieve the array, if needed. + +### Supported options + +- `useAnimation`: Use animation when an item is removed or inserted into the tree. + +- `usePlaceholderClone`: Placeholder should be a clone of the item being dragged. + +- `afterMove`: This is executed after the placeholder has been moved. $closestItemOrContainer contains the closest item, the placeholder has been put at or the closest empty Container, the placeholder has been appended to. + +- `containerPath`: The exact css path between the container and its items, e.g. "> tbody" + +- `containerSelector`: The css selector of the containers + +- `distance`: Distance the mouse has to travel to start dragging + +- `delay`: Time in milliseconds after mousedown until dragging should start. This option can be used to prevent unwanted drags when clicking on an element. + +- `handle`: The css selector of the drag handle + +- `itemPath`: The exact css path between the item and its subcontainers. It should only match the immediate items of a container. No item of a subcontainer should be matched. E.g. for ol>div>li the itemPath is "> div" + +- `itemSelector`: The css selector of the items + +- `bodyClass`: The class given to "body" while an item is being dragged + +- `draggedClass`: The class giving to an item while being dragged + +- `isValidTarget`: Check if the dragged item may be inside the container. Use with care, since the search for a valid container entails a depth first search and may be quite expensive. + +- `onCancel`: Executed before onDrop if placeholder is detached. This happens if pullPlaceholder is set to false and the drop occurs outside a container. + +- `onDrag`: Executed at the beginning of a mouse move event. The Placeholder has not been moved yet. + +- `onDragStart`: Called after the drag has been started, that is the mouse button is being held down and the mouse is moving. The container is the closest initialized container. Therefore it might not be the container, that actually contains the item. + +- `onDrop`: Called when the mouse button is being released + +- `onMousedown`: Called on mousedown. If falsy value is returned, the dragging will not start. Ignore if element clicked is input, select or textarea + +- `placeholderClass`: The class of the placeholder (must match placeholder option markup) + +- `placeholder`: Template for the placeholder. Can be any valid jQuery input e.g. a string, a DOM element. The placeholder must have the class "placeholder" + +- `pullPlaceholder`: If true, the position of the placeholder is calculated on every mousemove. If false, it is only calculated when the mouse is above a container. + +- `serialize`: Specifies serialization of the container group. The pair $parent/$children is either container/items or item/subcontainers. + +- `tolerance`: Set tolerance while dragging. Positive values decrease sensitivity, negative values increase it. + +### Supported options (container specific) + +- `drag`: If true, items can be dragged from this container + +- `drop`: If true, items can be droped onto this container + +- `exclude`: Exclude items from being draggable, if the selector matches the item + +- `nested`: If true, search for nested containers within an item.If you nest containers, either the original selector with which you call the plugin must only match the top containers, or you need to specify a group (see the bootstrap nav example) + +- `vertical`: If true, the items are assumed to be arranged vertically diff --git a/modules/system/assets/ui/docs/drag-value.md b/modules/system/assets/ui/docs/drag-value.md new file mode 100644 index 0000000..00b44fa --- /dev/null +++ b/modules/system/assets/ui/docs/drag-value.md @@ -0,0 +1,52 @@ +# Drag.Value + +Allows the dragging of elements that result in a custom value when dropped. + +

    + +

    + + + + + +### Clickable + +You can make elements clickable from another input by defining `data-drag-click="true"`. + +

    + +

    + +
    +
      +
    • + Monday +
    • +
    • + Tuesday +
    • +
    • + Happy days! +
    • +
    +
    \ No newline at end of file diff --git a/modules/system/assets/ui/docs/dropdown.md b/modules/system/assets/ui/docs/dropdown.md new file mode 100644 index 0000000..3efb72a --- /dev/null +++ b/modules/system/assets/ui/docs/dropdown.md @@ -0,0 +1,43 @@ +Customized dropdown menu + +### Small dropdown + + + +### Drop "up" + +Add the `dropup` class to the dropdown container and the dropdown will appear in an upward direction. + + + +### Large dropdown + + diff --git a/modules/system/assets/ui/docs/filter.md b/modules/system/assets/ui/docs/filter.md new file mode 100644 index 0000000..bf9ca2f --- /dev/null +++ b/modules/system/assets/ui/docs/filter.md @@ -0,0 +1,54 @@ +# Inspector + +## Dependencies + +- Popover + +# Example + +
    + + + + Categories: + all + + + + + Statuses: + 2 + + + +
    + + +
    + +
    + + \ No newline at end of file diff --git a/modules/system/assets/ui/docs/flag.md b/modules/system/assets/ui/docs/flag.md new file mode 100644 index 0000000..6fd07b4 --- /dev/null +++ b/modules/system/assets/ui/docs/flag.md @@ -0,0 +1,269 @@ +Provides flags of various descriptions using [flag-icon-css](https://github.com/lipis/flag-icon-css). + +*Class 'flag-icon flag-icon-{@country}' was merged into flag-{@country}, to support OctoberCMS standards.* + +## Usage Example +```html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Squared

    + +``` + + diff --git a/modules/system/assets/ui/docs/flashmessage.md b/modules/system/assets/ui/docs/flashmessage.md new file mode 100644 index 0000000..3416e7c --- /dev/null +++ b/modules/system/assets/ui/docs/flashmessage.md @@ -0,0 +1,70 @@ +## Flash message + +Displays a floating flash message on the screen. + +### Display onload + +```html +

    + This message is created from a static element. It will go away in 5 seconds. +

    +``` + +

    + This message is created from a static element. It will go away in 5 seconds. +

    + +
    + + +### Trigger + +

    + + Show Success + + + + Show Error + + + + Show Warning + +

    + + +### Display static + +A flash message can be rendered as a static element by attaching the `static` class. The `data-control` attribute is not needed. + +

    + Import completed successfully (success) +

    + +

    + Informative info box is informational (info) +

    + +

    + Phasers have been set to stun (warning) +

    + +

    + We couldn't help you with that (error) +

    + +### Data attributes + +- data-control="flash-message" - enables the flash message plugin +- data-interval="2" - the interval to display the message in seconds, optional. Default: 2 + +### JavaScript API + +```js +$.oc.flashMsg({ + 'text': 'Record saved.', + 'class': 'success', + 'interval': 3 +}) +``` diff --git a/modules/system/assets/ui/docs/form.md b/modules/system/assets/ui/docs/form.md new file mode 100644 index 0000000..0ebb82f --- /dev/null +++ b/modules/system/assets/ui/docs/form.md @@ -0,0 +1,180 @@ +# Form + +## Types + + +
    + + +
    + +
    + + +
    + +
    + + +
    +
    + +### Complete example + + +
    + + +
    + + +

    Example below help text here.

    +
    + + +
    + + +

    Example below help text here.

    +
    + + +
    + +

    Example above help text here.

    + +
    + + + + + + + + +
    +
    + + +

    Use this checkbox to enable the Googie Berry power-up specifically for this page. You can configure the Googie Berry power-up on the System Settings and Dashboard page.

    +
    +
    + + +
    +
    + +

    Use this checkbox to enable the Googie Berry power-up specifically for this page. You can configure the Googie Berry power-up on the System Settings and Dashboard page.

    +
    + +
    + + +
    + +

    Where should you propose to your beautiful girl?

    + +
    + + +

    Do not send new comment notifications.

    +
    +
    + + +

    Send new comment notifications only to post author.

    +
    +
    + + +

    Notify all users who have permissions to receive blog notifications.

    +
    +
    + + +
    + +

    What cars would you like in your garage?

    + +
    + + +

    Do not send new comment notifications.

    +
    +
    + + +

    Send new comment notifications only to post author.

    +
    +
    + + +

    Notify all users who have permissions to receive blog notifications.

    +
    +
    + +
    + diff --git a/modules/system/assets/ui/docs/foundation.md b/modules/system/assets/ui/docs/foundation.md new file mode 100644 index 0000000..0f943db --- /dev/null +++ b/modules/system/assets/ui/docs/foundation.md @@ -0,0 +1,235 @@ +# Foundation + +The foundation libraries are the core base of all scripts and controls. The goals of this library are: + +- Well structured and readable code. +- Don't leave references to DOM elements. +- Unbind all event handlers. +- Write high-performance code (in cases when it's needed). + +That's especially important on pages where users spend much time interacting with the page, like the CMS and Pages sections, but all back-end controls should follow these rules, because we never know when they are used. + +## Why it's important to release the memory, DOM references and event handlers + +A typical JavaScript control class instance consists of the following parts: + +1. JavaScript object representing the control. +1. A reference to the corresponding DOM element. Usually it's the control's root element containing a tree with the control HTML markup. +1. A number of event handlers to handle user's interaction with the control. + +If any of that components are not released we have these problems: + +1. Non-released JavaScript objects increase the memory footprint. The more memory the application uses, the slower it works. Eventually it could result in a crashed tab or entire browser. +1. Non-released references to DOM elements could result in detached DOM trees. That, in turn, could result in thousands of invisible DOM elements living in a page, increasing the memory footprint and making the application less responsive. +1. Unbound event handlers usually result in non-released DOM elements, which is bad by itself, and also in the code which executes when the user interacts with the application and which should not be executed. That affects the performance. + +## This is how to deal with those problems: + +1. Remove the JavaScript object - usually by removing the data from the control's root element: `this.$el.removeData('oc.myControl')` +Clean all references to DOM elements. Usually it's done by assigning NULL to corresponding object properties. +1. Watch for any references caught by closures (or - better do not use closures, see below). +1. Unbind event handlers. + +October Storm provides everything we need to meet the goals. Please read on to learn more! + +## How to write quality code + +OOP approach and prototypes should be used in all places. This approach automatically deals with closures that could retain references to scope variables. Typical class code template: + +```js +function ($) { "use strict"; + var SomeClass = function() { + this.init() + } + + SomeClass.prototype.init = function (){ + ... + } +} +``` + +## Basics of writing disposable classes + +If a class should be disposable (all UI controls should be disposable), the class should extend `$.oc.foundation.base` class. That class has two useful methods: `proxy(method)` and `dispose()`. + +`proxy()` method is an alternative to jQuery's `$.proxy`, but as `$.oc.foundation.base` implements OOP approach, passing this parameter to the method is not required. This method is good for three reasons. + +1. It's code is very simple and easily controllable and debuggable. +1. It caches bound functions and doesn't create new function as `$.proxy` does. +1. It automatically removes all cached bound functions when the object is disposed with dispose() method. + +`dispose()` method in the base class cleans up bound methods cached by `proxy()` method and provides a common API for disposing objects. All classes that are supposed to do clean-up work, should override that method, do their own clean-up and call the base `dispose()` method. + +Example of a disposable class: + +```js ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var SomeDisposableClass = function(element) { + this.$el = $(element) + + Base.call(this) + this.init() + } + + SomeDisposableClass.prototype = Object.create(BaseProto) + SomeDisposableClass.prototype.constructor = SomeDisposableClass + + SomeDisposableClass.prototype.init = function () { + } + + SomeDisposableClass.prototype.dispose = function () { + this.$el = null + BaseProto.dispose.call(this) + } +} +``` + +A couple of important things to note: + +1. The class constructor should call Base.call(this). +1. The class prototype should be replaced with a copy of the Base class prototype, and its constructor reference should be restored back to the class constructor. It should be done right after the class constructor and before any method is defined in the class prototype. + +## Binding and unbinding events + +When binding events, use this.proxy() to make references to event handlers. Always unbind events in dispose() method: + +```js ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var SomeDisposableClass = function(element) { + this.$el = $(element) + + Base.call(this) + this.init() + } + + [...] + + SomeDisposableClass.prototype.init = function () { + this.$el.on('click', this.proxy(this.onClick)) + } + + SomeDisposableClass.prototype.dispose = function () { + this.$el.off('click', this.proxy(this.onClick)) + this.$el = null + BaseProto.dispose.call(this) + } +} +``` + +## Making disposable controls + +UI controls should support two ways of disposing - with calling their `dispose()` method and with invoking the dispose-control handler. Also, disposable controls should mark their corresponding DOM elements as disposable, with October foundation API. Example: + +```js ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var SomeDisposableControl = function(element) { + this.$el = $(element) + + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + this.init() + } + + ... + + SomeDisposableControl.prototype.init = function () { + this.$el.one('dispose-control', this.proxy(this.dispose)) + } + + SomeDisposableControl.prototype.dispose = function () { + this.$el.off('dispose-control', this.proxy(this.dispose)) + this.$el = null + BaseProto.dispose.call(this) + } +} +``` + +`$.oc.foundation.controlUtils.markDisposable(element)` call in the constructor adds `data-disposable` attribute to the DOM element, allowing the framework to find all disposable elements in a container and dispose them by calling their dispose-control handler when it's required. + +## Full example of a jQuery plugin that creates a disposable control + +We already have a boilerplate code for jQuery code. Disposable controls approach just extends it. Don't forget to remove the data associated with controls from their DOM elements. + +```js ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var SomeDisposableControl = function (element, options) { + this.$el = $(element) + this.options = options || {} + + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + this.init() + } + + SomeDisposableControl.prototype = Object.create(BaseProto) + SomeDisposableControl.prototype.constructor = SomeDisposableControl + + SomeDisposableControl.prototype.init = function() { + this.$el.on('click', this.proxy(this.onClick)) + this.$el.one('dispose-control', this.proxy(this.dispose)) + } + + SomeDisposableControl.prototype.dispose = function() { + this.$el.off('click', this.proxy(this.onClick)) + this.$el.off('dispose-control', this.proxy(this.dispose)) + this.$el.removeData('oc.someDisposableControl') + + this.$el = null + + // In some cases options could contain callbacks, + // so it's better to clean them up too. + this.options = null + + BaseProto.dispose.call(this) + } + + SomeDisposableControl.DEFAULTS = { + someParam: null + } + + // PLUGIN DEFINITION + // ============================ + + var old = $.fn.someDisposableControl + + $.fn.someDisposableControl = function (option) { + var args = Array.prototype.slice.call(arguments, 1), items, result + + items = this.each(function () { + var $this = $(this) + var data = $this.data('oc.someDisposableControl') + var options = $.extend({}, SomeDisposableControl.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.someDisposableControl', (data = new SomeDisposableControl(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : items + } + + $.fn.someDisposableControl.Constructor = SomeDisposableControl + + $.fn.someDisposableControl.noConflict = function () { + $.fn.someDisposableControl = old + return this + } + + // Add this only if required + $(document).render(function (){ + $('[data-some-disposable-control]').someDisposableControl() + }) + +}(window.jQuery); +``` \ No newline at end of file diff --git a/modules/system/assets/ui/docs/icon.md b/modules/system/assets/ui/docs/icon.md new file mode 100644 index 0000000..1897618 --- /dev/null +++ b/modules/system/assets/ui/docs/icon.md @@ -0,0 +1,1134 @@ +# Icon library + +October provides an icon library with icons of various descriptions, based on the popular [Font Awesome collection](http://fortawesome.github.io/Font-Awesome/). + +### Inline icons + +Place icons just about anywhere with the `` tag or to an existing element using the `oc-` prefix. + +```html + icon-camera-retro + +oc-icon-flag-checkered +``` + +
    + icon-camera-retro +
    + oc-icon-flag-checkered +
    + +### Icon sizes + +To increase icon sizes relative to their container, use the `icon-lg` (33% increase), `icon-2x`, `icon-3x`, `icon-4x`, or `icon-5x` classes. + + icon-5x + icon-4x + icon-3x + icon-2x + icon-lg + +### Icon buttons + +Feel free to use them alongside your buttons. + + + Refresh + + + Checkout + + + Comment + + + Delete + + + Settings + + + More Info + + +## Available icons + +### Web Application Icons + +
    +
      +
    • icon-address-book
    • +
    • icon-address-book-o
    • +
    • icon-address-card
    • +
    • icon-address-card-o
    • +
    • icon-adjust
    • +
    • icon-american-sign-language-interpreting
    • +
    • icon-anchor
    • +
    • icon-archive
    • +
    • icon-area-chart
    • +
    • icon-arrows
    • +
    • icon-arrows-h
    • +
    • icon-arrows-v
    • +
    • icon-assistive-listening-systems
    • +
    • icon-asterisk
    • +
    • icon-at
    • +
    • icon-audio-description
    • +
    • icon-balance-scale
    • +
    • icon-ban
    • +
    • icon-bar-chart
    • +
    • icon-barcode
    • +
    • icon-bars
    • +
    • icon-bath
    • +
    • icon-battery-empty
    • +
    • icon-battery-full
    • +
    • icon-battery-half
    • +
    • icon-battery-quarter
    • +
    • icon-battery-three-quarters
    • +
    • icon-bed
    • +
    • icon-beer
    • +
    • icon-bell
    • +
    • icon-bell-o
    • +
    • icon-bell-slash
    • +
    • icon-bell-slash-o
    • +
    • icon-bicycle
    • +
    • icon-binoculars
    • +
    • icon-birthday-cake
    • +
    • icon-blind
    • +
    • icon-bluetooth
    • +
    • icon-bluetooth-b
    • +
    • icon-bolt
    • +
    • icon-bomb
    • +
    • icon-book
    • +
    • icon-bookmark
    • +
    • icon-bookmark-o
    • +
    • icon-braille
    • +
    • icon-briefcase
    • +
    • icon-bug
    • +
    • icon-building
    • +
    • icon-building-o
    • +
    • icon-bullhorn
    • +
    • icon-bullseye
    • +
    • icon-bus
    • +
    • icon-calculator
    • +
    • icon-calendar
    • +
    • icon-calendar-check-o
    • +
    • icon-calendar-minus-o
    • +
    • icon-calendar-o
    • +
    • icon-calendar-plus-o
    • +
    • icon-calendar-times-o
    • +
    • icon-camera
    • +
    • icon-camera-retro
    • +
    • icon-car
    • +
    • icon-caret-square-o-down
    • +
    • icon-caret-square-o-left
    • +
    • icon-caret-square-o-right
    • +
    • icon-caret-square-o-up
    • +
    • icon-cart-arrow-down
    • +
    • icon-cart-plus
    • +
    • icon-cc
    • +
    • icon-certificate
    • +
    • icon-check
    • +
    • icon-check-circle
    • +
    • icon-check-circle-o
    • +
    • icon-check-square
    • +
    • icon-check-square-o
    • +
    • icon-child
    • +
    • icon-circle
    • +
    • icon-circle-o
    • +
    • icon-circle-o-notch
    • +
    • icon-circle-thin
    • +
    • icon-clock-o
    • +
    • icon-clone
    • +
    • icon-cloud
    • +
    • icon-cloud-download
    • +
    • icon-cloud-upload
    • +
    • icon-code
    • +
    • icon-code-fork
    • +
    • icon-coffee
    • +
    • icon-cog
    • +
    • icon-cogs
    • +
    • icon-comment
    • +
    • icon-comment-o
    • +
    • icon-commenting
    • +
    • icon-commenting-o
    • +
    +
      +
    • icon-comments
    • +
    • icon-comments-o
    • +
    • icon-compass
    • +
    • icon-copyright
    • +
    • icon-creative-commons
    • +
    • icon-credit-card
    • +
    • icon-credit-card-alt
    • +
    • icon-crop
    • +
    • icon-crosshairs
    • +
    • icon-cube
    • +
    • icon-cubes
    • +
    • icon-cutlery
    • +
    • icon-database
    • +
    • icon-deaf
    • +
    • icon-desktop
    • +
    • icon-diamond
    • +
    • icon-dot-circle-o
    • +
    • icon-download
    • +
    • icon-ellipsis-h
    • +
    • icon-ellipsis-v
    • +
    • icon-envelope
    • +
    • icon-envelope-o
    • +
    • icon-envelope-open
    • +
    • icon-envelope-open-o
    • +
    • icon-envelope-square
    • +
    • icon-eraser
    • +
    • icon-exchange
    • +
    • icon-exclamation
    • +
    • icon-exclamation-circle
    • +
    • icon-exclamation-triangle
    • +
    • icon-external-link
    • +
    • icon-external-link-square
    • +
    • icon-eye
    • +
    • icon-eye-slash
    • +
    • icon-eyedropper
    • +
    • icon-fax
    • +
    • icon-female
    • +
    • icon-fighter-jet
    • +
    • icon-file-archive-o
    • +
    • icon-file-audio-o
    • +
    • icon-file-code-o
    • +
    • icon-file-excel-o
    • +
    • icon-file-image-o
    • +
    • icon-file-pdf-o
    • +
    • icon-file-powerpoint-o
    • +
    • icon-file-video-o
    • +
    • icon-file-word-o
    • +
    • icon-film
    • +
    • icon-filter
    • +
    • icon-fire
    • +
    • icon-fire-extinguisher
    • +
    • icon-flag
    • +
    • icon-flag-checkered
    • +
    • icon-flag-o
    • +
    • icon-flask
    • +
    • icon-folder
    • +
    • icon-folder-o
    • +
    • icon-folder-open
    • +
    • icon-folder-open-o
    • +
    • icon-frown-o
    • +
    • icon-futbol-o
    • +
    • icon-gamepad
    • +
    • icon-gavel
    • +
    • icon-gift
    • +
    • icon-glass
    • +
    • icon-globe
    • +
    • icon-graduation-cap
    • +
    • icon-hand-lizard-o
    • +
    • icon-hand-paper-o
    • +
    • icon-hand-peace-o
    • +
    • icon-hand-pointer-o
    • +
    • icon-hand-rock-o
    • +
    • icon-hand-scissors-o
    • +
    • icon-hand-spock-o
    • +
    • icon-handshake-o
    • +
    • icon-hashtag
    • +
    • icon-hdd-o
    • +
    • icon-headphones
    • +
    • icon-heart
    • +
    • icon-heart-o
    • +
    • icon-heartbeat
    • +
    • icon-history
    • +
    • icon-home
    • +
    • icon-hourglass
    • +
    • icon-hourglass-end
    • +
    • icon-hourglass-half
    • +
    • icon-hourglass-o
    • +
    • icon-hourglass-start
    • +
    • icon-i-cursor
    • +
    • icon-id-badge
    • +
    • icon-id-card
    • +
    • icon-id-card-o
    • +
    • icon-inbox
    • +
    • icon-industry
    • +
    +
      +
    • icon-info
    • +
    • icon-info-circle
    • +
    • icon-key
    • +
    • icon-keyboard-o
    • +
    • icon-language
    • +
    • icon-laptop
    • +
    • icon-leaf
    • +
    • icon-lemon-o
    • +
    • icon-level-down
    • +
    • icon-level-up
    • +
    • icon-life-ring
    • +
    • icon-lightbulb-o
    • +
    • icon-line-chart
    • +
    • icon-location-arrow
    • +
    • icon-lock
    • +
    • icon-low-vision
    • +
    • icon-magic
    • +
    • icon-magnet
    • +
    • icon-male
    • +
    • icon-map
    • +
    • icon-map-marker
    • +
    • icon-map-o
    • +
    • icon-map-pin
    • +
    • icon-map-signs
    • +
    • icon-meh-o
    • +
    • icon-microchip
    • +
    • icon-microphone
    • +
    • icon-microphone-slash
    • +
    • icon-minus
    • +
    • icon-minus-circle
    • +
    • icon-minus-square
    • +
    • icon-minus-square-o
    • +
    • icon-mobile
    • +
    • icon-money
    • +
    • icon-moon-o
    • +
    • icon-motorcycle
    • +
    • icon-mouse-pointer
    • +
    • icon-music
    • +
    • icon-newspaper-o
    • +
    • icon-object-group
    • +
    • icon-object-ungroup
    • +
    • icon-paint-brush
    • +
    • icon-paper-plane
    • +
    • icon-paper-plane-o
    • +
    • icon-paw
    • +
    • icon-pencil
    • +
    • icon-pencil-square
    • +
    • icon-pencil-square-o
    • +
    • icon-percent
    • +
    • icon-phone
    • +
    • icon-phone-square
    • +
    • icon-picture-o
    • +
    • icon-pie-chart
    • +
    • icon-plane
    • +
    • icon-plug
    • +
    • icon-plus
    • +
    • icon-plus-circle
    • +
    • icon-plus-square
    • +
    • icon-plus-square-o
    • +
    • icon-podcast
    • +
    • icon-power-off
    • +
    • icon-print
    • +
    • icon-puzzle-piece
    • +
    • icon-qrcode
    • +
    • icon-question
    • +
    • icon-question-circle
    • +
    • icon-question-circle-o
    • +
    • icon-quote-left
    • +
    • icon-quote-right
    • +
    • icon-random
    • +
    • icon-recycle
    • +
    • icon-refresh
    • +
    • icon-registered
    • +
    • icon-reply
    • +
    • icon-reply-all
    • +
    • icon-retweet
    • +
    • icon-road
    • +
    • icon-rocket
    • +
    • icon-rss
    • +
    • icon-rss-square
    • +
    • icon-search
    • +
    • icon-search-minus
    • +
    • icon-search-plus
    • +
    • icon-server
    • +
    • icon-share
    • +
    • icon-share-alt
    • +
    • icon-share-alt-square
    • +
    • icon-share-square
    • +
    • icon-share-square-o
    • +
    • icon-shield
    • +
    • icon-ship
    • +
    • icon-shopping-bag
    • +
    • icon-shopping-basket
    • +
    +
      +
    • icon-shopping-cart
    • +
    • icon-shower
    • +
    • icon-sign-in
    • +
    • icon-sign-language
    • +
    • icon-sign-out
    • +
    • icon-signal
    • +
    • icon-sitemap
    • +
    • icon-sliders
    • +
    • icon-smile-o
    • +
    • icon-snowflake-o
    • +
    • icon-sort
    • +
    • icon-sort-alpha-asc
    • +
    • icon-sort-alpha-desc
    • +
    • icon-sort-amount-asc
    • +
    • icon-sort-amount-desc
    • +
    • icon-sort-asc
    • +
    • icon-sort-desc
    • +
    • icon-sort-numeric-asc
    • +
    • icon-sort-numeric-desc
    • +
    • icon-space-shuttle
    • +
    • icon-spinner
    • +
    • icon-spoon
    • +
    • icon-square
    • +
    • icon-square-o
    • +
    • icon-star
    • +
    • icon-star-half
    • +
    • icon-star-half-o
    • +
    • icon-star-o
    • +
    • icon-sticky-note
    • +
    • icon-sticky-note-o
    • +
    • icon-street-view
    • +
    • icon-suitcase
    • +
    • icon-sun-o
    • +
    • icon-tablet
    • +
    • icon-tachometer
    • +
    • icon-tag
    • +
    • icon-tags
    • +
    • icon-tasks
    • +
    • icon-taxi
    • +
    • icon-television
    • +
    • icon-terminal
    • +
    • icon-thermometer-empty
    • +
    • icon-thermometer-full
    • +
    • icon-thermometer-half
    • +
    • icon-thermometer-quarter
    • +
    • icon-thermometer-three-quarters
    • +
    • icon-thumb-tack
    • +
    • icon-thumbs-down
    • +
    • icon-thumbs-o-down
    • +
    • icon-thumbs-o-up
    • +
    • icon-thumbs-up
    • +
    • icon-ticket
    • +
    • icon-times
    • +
    • icon-times-circle
    • +
    • icon-times-circle-o
    • +
    • icon-tint
    • +
    • icon-toggle-off
    • +
    • icon-toggle-on
    • +
    • icon-trademark
    • +
    • icon-trash
    • +
    • icon-trash-o
    • +
    • icon-tree
    • +
    • icon-trophy
    • +
    • icon-truck
    • +
    • icon-tty
    • +
    • icon-umbrella
    • +
    • icon-universal-access
    • +
    • icon-university
    • +
    • icon-unlock
    • +
    • icon-unlock-alt
    • +
    • icon-upload
    • +
    • icon-user
    • +
    • icon-user-circle
    • +
    • icon-user-circle-o
    • +
    • icon-user-o
    • +
    • icon-user-plus
    • +
    • icon-user-secret
    • +
    • icon-user-times
    • +
    • icon-users
    • +
    • icon-video-camera
    • +
    • icon-volume-control-phone
    • +
    • icon-volume-down
    • +
    • icon-volume-off
    • +
    • icon-volume-up
    • +
    • icon-wheelchair
    • +
    • icon-wheelchair-alt
    • +
    • icon-wifi
    • +
    • icon-window-close
    • +
    • icon-window-close-o
    • +
    • icon-window-maximize
    • +
    • icon-window-minimize
    • +
    • icon-window-restore
    • +
    • icon-wrench
    • +
    +
    + +### Medical Icons + +
    +
      +
    • icon-ambulance
    • +
    • icon-h-square
    • +
    • icon-heart
    • +
    • icon-heart-o
    • +
    +
      +
    • icon-heartbeat
    • +
    • icon-hospital-o
    • +
    • icon-medkit
    • +
    +
      +
    • icon-plus-square
    • +
    • icon-stethoscope
    • +
    • icon-user-md
    • +
    +
      +
    • icon-wheelchair
    • +
    • icon-wheelchair-alt
    • +
    +
    + +### Text Editor Icons + +
    +
      +
    • icon-align-center
    • +
    • icon-align-justify
    • +
    • icon-align-left
    • +
    • icon-align-right
    • +
    • icon-bold
    • +
    • icon-chain-broken
    • +
    • icon-clipboard
    • +
    • icon-columns
    • +
    • icon-eraser
    • +
    • icon-file
    • +
    • icon-file-o
    • +
    +
      +
    • icon-file-text
    • +
    • icon-file-text-o
    • +
    • icon-files-o
    • +
    • icon-floppy-o
    • +
    • icon-font
    • +
    • icon-header
    • +
    • icon-indent
    • +
    • icon-italic
    • +
    • icon-link
    • +
    • icon-list
    • +
    +
      +
    • icon-list-alt
    • +
    • icon-list-ol
    • +
    • icon-list-ul
    • +
    • icon-outdent
    • +
    • icon-paperclip
    • +
    • icon-paragraph
    • +
    • icon-repeat
    • +
    • icon-scissors
    • +
    • icon-strikethrough
    • +
    • icon-subscript
    • +
    +
      +
    • icon-superscript
    • +
    • icon-table
    • +
    • icon-text-height
    • +
    • icon-text-width
    • +
    • icon-th
    • +
    • icon-th-large
    • +
    • icon-th-list
    • +
    • icon-underline
    • +
    • icon-undo
    • +
    +
    + +### Spinner Icons + +
    +
      +
    • icon-circle-o-notch
    • +
    • icon-cog
    • +
    +
      +
    • icon-refresh
    • +
    +
      +
    • icon-spinner
    • +
    +
      +
    +
    + +### File Type Icons + +
    +
      +
    • icon-file
    • +
    • icon-file-archive-o
    • +
    • icon-file-audio-o
    • +
    • icon-file-code-o
    • +
    +
      +
    • icon-file-excel-o
    • +
    • icon-file-image-o
    • +
    • icon-file-o
    • +
    +
      +
    • icon-file-pdf-o
    • +
    • icon-file-powerpoint-o
    • +
    • icon-file-text
    • +
    +
      +
    • icon-file-text-o
    • +
    • icon-file-video-o
    • +
    • icon-file-word-o
    • +
    +
    + +### Directional Icons + +
    +
      +
    • icon-angle-double-down
    • +
    • icon-angle-double-left
    • +
    • icon-angle-double-right
    • +
    • icon-angle-double-up
    • +
    • icon-angle-down
    • +
    • icon-angle-left
    • +
    • icon-angle-right
    • +
    • icon-angle-up
    • +
    • icon-arrow-circle-down
    • +
    • icon-arrow-circle-left
    • +
    • icon-arrow-circle-o-down
    • +
    • icon-arrow-circle-o-left
    • +
    • icon-arrow-circle-o-right
    • +
    +
      +
    • icon-arrow-circle-o-up
    • +
    • icon-arrow-circle-right
    • +
    • icon-arrow-circle-up
    • +
    • icon-arrow-down
    • +
    • icon-arrow-left
    • +
    • icon-arrow-right
    • +
    • icon-arrow-up
    • +
    • icon-arrows
    • +
    • icon-arrows-alt
    • +
    • icon-arrows-h
    • +
    • icon-arrows-v
    • +
    • icon-caret-down
    • +
    +
      +
    • icon-caret-left
    • +
    • icon-caret-right
    • +
    • icon-caret-square-o-down
    • +
    • icon-caret-square-o-left
    • +
    • icon-caret-square-o-right
    • +
    • icon-caret-square-o-up
    • +
    • icon-caret-up
    • +
    • icon-chevron-circle-down
    • +
    • icon-chevron-circle-left
    • +
    • icon-chevron-circle-right
    • +
    • icon-chevron-circle-up
    • +
    • icon-chevron-down
    • +
    +
      +
    • icon-chevron-left
    • +
    • icon-chevron-right
    • +
    • icon-chevron-up
    • +
    • icon-exchange
    • +
    • icon-hand-o-down
    • +
    • icon-hand-o-left
    • +
    • icon-hand-o-right
    • +
    • icon-hand-o-up
    • +
    • icon-long-arrow-down
    • +
    • icon-long-arrow-left
    • +
    • icon-long-arrow-right
    • +
    • icon-long-arrow-up
    • +
    +
    + +### Video Player Icons + +
    +
      +
    • icon-arrows-alt
    • +
    • icon-backward
    • +
    • icon-compress
    • +
    • icon-eject
    • +
    • icon-expand
    • +
    • icon-fast-backward
    • +
    +
      +
    • icon-fast-forward
    • +
    • icon-forward
    • +
    • icon-pause
    • +
    • icon-pause-circle
    • +
    • icon-pause-circle-o
    • +
    +
      +
    • icon-play
    • +
    • icon-play-circle
    • +
    • icon-play-circle-o
    • +
    • icon-random
    • +
    • icon-step-backward
    • +
    +
      +
    • icon-step-forward
    • +
    • icon-stop
    • +
    • icon-stop-circle
    • +
    • icon-stop-circle-o
    • +
    • icon-youtube-play
    • +
    +
    + +### Form Control Icons + +
    +
      +
    • icon-check-square
    • +
    • icon-check-square-o
    • +
    • icon-circle
    • +
    +
      +
    • icon-circle-o
    • +
    • icon-dot-circle-o
    • +
    • icon-minus-square
    • +
    +
      +
    • icon-minus-square-o
    • +
    • icon-plus-square
    • +
    • icon-plus-square-o
    • +
    +
      +
    • icon-square
    • +
    • icon-square-o
    • +
    +
    + +### Transportation Icons + +
    +
      +
    • icon-ambulance
    • +
    • icon-bicycle
    • +
    • icon-bus
    • +
    • icon-car
    • +
    • icon-fighter-jet
    • +
    +
      +
    • icon-motorcycle
    • +
    • icon-plane
    • +
    • icon-rocket
    • +
    • icon-ship
    • +
    +
      +
    • icon-space-shuttle
    • +
    • icon-subway
    • +
    • icon-taxi
    • +
    • icon-train
    • +
    +
      +
    • icon-truck
    • +
    • icon-wheelchair
    • +
    • icon-wheelchair-alt
    • +
    +
    + +### Chart Icons + +
    +
      +
    • icon-area-chart
    • +
    • icon-bar-chart
    • +
    +
      +
    • icon-line-chart
    • +
    +
      +
    • icon-pie-chart
    • +
    +
      +
    +
    + +### Brand Icons + +
    +
      +
    • icon-500px
    • +
    • icon-adn
    • +
    • icon-amazon
    • +
    • icon-android
    • +
    • icon-angellist
    • +
    • icon-apple
    • +
    • icon-bandcamp
    • +
    • icon-behance
    • +
    • icon-behance-square
    • +
    • icon-bitbucket
    • +
    • icon-bitbucket-square
    • +
    • icon-black-tie
    • +
    • icon-bluetooth
    • +
    • icon-bluetooth-b
    • +
    • icon-btc
    • +
    • icon-buysellads
    • +
    • icon-cc-amex
    • +
    • icon-cc-diners-club
    • +
    • icon-cc-discover
    • +
    • icon-cc-jcb
    • +
    • icon-cc-mastercard
    • +
    • icon-cc-paypal
    • +
    • icon-cc-stripe
    • +
    • icon-cc-visa
    • +
    • icon-chrome
    • +
    • icon-codepen
    • +
    • icon-codiepie
    • +
    • icon-connectdevelop
    • +
    • icon-contao
    • +
    • icon-css3
    • +
    • icon-dashcube
    • +
    • icon-delicious
    • +
    • icon-deviantart
    • +
    • icon-digg
    • +
    • icon-dribbble
    • +
    • icon-dropbox
    • +
    • icon-drupal
    • +
    • icon-edge
    • +
    • icon-eercast
    • +
    • icon-empire
    • +
    • icon-envira
    • +
    • icon-etsy
    • +
    • icon-expeditedssl
    • +
    • icon-facebook
    • +
    • icon-facebook-official
    • +
    +
      +
    • icon-facebook-square
    • +
    • icon-firefox
    • +
    • icon-first-order
    • +
    • icon-flickr
    • +
    • icon-font-awesome
    • +
    • icon-fonticons
    • +
    • icon-fort-awesome
    • +
    • icon-forumbee
    • +
    • icon-foursquare
    • +
    • icon-free-code-camp
    • +
    • icon-get-pocket
    • +
    • icon-gg
    • +
    • icon-gg-circle
    • +
    • icon-git
    • +
    • icon-git-square
    • +
    • icon-github
    • +
    • icon-github-alt
    • +
    • icon-github-square
    • +
    • icon-gitlab
    • +
    • icon-glide
    • +
    • icon-glide-g
    • +
    • icon-google
    • +
    • icon-google-plus
    • +
    • icon-google-plus-official
    • +
    • icon-google-plus-square
    • +
    • icon-google-wallet
    • +
    • icon-gratipay
    • +
    • icon-grav
    • +
    • icon-hacker-news
    • +
    • icon-houzz
    • +
    • icon-html5
    • +
    • icon-imdb
    • +
    • icon-instagram
    • +
    • icon-internet-explorer
    • +
    • icon-ioxhost
    • +
    • icon-joomla
    • +
    • icon-jsfiddle
    • +
    • icon-lastfm
    • +
    • icon-lastfm-square
    • +
    • icon-leanpub
    • +
    • icon-linkedin
    • +
    • icon-linkedin-square
    • +
    • icon-linode
    • +
    • icon-linux
    • +
    +
      +
    • icon-maxcdn
    • +
    • icon-meanpath
    • +
    • icon-medium
    • +
    • icon-meetup
    • +
    • icon-mixcloud
    • +
    • icon-modx
    • +
    • icon-odnoklassniki
    • +
    • icon-odnoklassniki-square
    • +
    • icon-opencart
    • +
    • icon-openid
    • +
    • icon-opera
    • +
    • icon-optin-monster
    • +
    • icon-pagelines
    • +
    • icon-paypal
    • +
    • icon-pied-piper
    • +
    • icon-pied-piper-alt
    • +
    • icon-pied-piper-pp
    • +
    • icon-pinterest
    • +
    • icon-pinterest-p
    • +
    • icon-pinterest-square
    • +
    • icon-product-hunt
    • +
    • icon-qq
    • +
    • icon-quora
    • +
    • icon-ravelry
    • +
    • icon-rebel
    • +
    • icon-reddit
    • +
    • icon-reddit-alien
    • +
    • icon-reddit-square
    • +
    • icon-renren
    • +
    • icon-safari
    • +
    • icon-scribd
    • +
    • icon-sellsy
    • +
    • icon-share-alt
    • +
    • icon-share-alt-square
    • +
    • icon-shirtsinbulk
    • +
    • icon-simplybuilt
    • +
    • icon-skyatlas
    • +
    • icon-skype
    • +
    • icon-slack
    • +
    • icon-slideshare
    • +
    • icon-snapchat
    • +
    • icon-snapchat-ghost
    • +
    • icon-snapchat-square
    • +
    • icon-soundcloud
    • +
    +
      +
    • icon-spotify
    • +
    • icon-stack-exchange
    • +
    • icon-stack-overflow
    • +
    • icon-steam
    • +
    • icon-steam-square
    • +
    • icon-stumbleupon
    • +
    • icon-stumbleupon-circle
    • +
    • icon-superpowers
    • +
    • icon-telegram
    • +
    • icon-tencent-weibo
    • +
    • icon-themeisle
    • +
    • icon-trello
    • +
    • icon-tripadvisor
    • +
    • icon-tumblr
    • +
    • icon-tumblr-square
    • +
    • icon-twitch
    • +
    • icon-twitter
    • +
    • icon-twitter-square
    • +
    • icon-usb
    • +
    • icon-viacoin
    • +
    • icon-viadeo
    • +
    • icon-viadeo-square
    • +
    • icon-vimeo
    • +
    • icon-vimeo-square
    • +
    • icon-vine
    • +
    • icon-vk
    • +
    • icon-weibo
    • +
    • icon-weixin
    • +
    • icon-whatsapp
    • +
    • icon-wikipedia-w
    • +
    • icon-windows
    • +
    • icon-wordpress
    • +
    • icon-wpbeginner
    • +
    • icon-wpexplorer
    • +
    • icon-wpforms
    • +
    • icon-xing
    • +
    • icon-xing-square
    • +
    • icon-y-combinator
    • +
    • icon-yahoo
    • +
    • icon-yelp
    • +
    • icon-yoast
    • +
    • icon-youtube
    • +
    • icon-youtube-play
    • +
    • icon-youtube-square
    • +
    +
    + +### Hand Icons + +
    +
      +
    • icon-hand-lizard-o
    • +
    • icon-hand-o-down
    • +
    • icon-hand-o-left
    • +
    • icon-hand-o-right
    • +
    +
      +
    • icon-hand-o-up
    • +
    • icon-hand-paper-o
    • +
    • icon-hand-peace-o
    • +
    • icon-hand-pointer-o
    • +
    +
      +
    • icon-hand-rock-o
    • +
    • icon-hand-scissors-o
    • +
    • icon-hand-spock-o
    • +
    • icon-thumbs-down
    • +
    +
      +
    • icon-thumbs-o-down
    • +
    • icon-thumbs-o-up
    • +
    • icon-thumbs-up
    • +
    +
    + +### Payment Icons + +
    +
      +
    • icon-cc-amex
    • +
    • icon-cc-diners-club
    • +
    • icon-cc-discover
    • +
    • icon-cc-jcb
    • +
    +
      +
    • icon-cc-mastercard
    • +
    • icon-cc-paypal
    • +
    • icon-cc-stripe
    • +
    +
      +
    • icon-cc-visa
    • +
    • icon-credit-card
    • +
    • icon-credit-card-alt
    • +
    +
      +
    • icon-google-wallet
    • +
    • icon-paypal
    • +
    +
    + +### Currency Icons + +
    +
      +
    • icon-btc
    • +
    • icon-eur
    • +
    • icon-gbp
    • +
    • icon-gg
    • +
    +
      +
    • icon-gg-circle
    • +
    • icon-ils
    • +
    • icon-inr
    • +
    +
      +
    • icon-jpy
    • +
    • icon-krw
    • +
    • icon-money
    • +
    +
      +
    • icon-rub
    • +
    • icon-try
    • +
    • icon-usd
    • +
    +
    + +### Accessibility Icons + +
    +
      +
    • icon-american-sign-language-interpreting
    • +
    • icon-assistive-listening-systems
    • +
    • icon-audio-description
    • +
    • icon-blind
    • +
    +
      +
    • icon-braille
    • +
    • icon-cc
    • +
    • icon-deaf
    • +
    • icon-low-vision
    • +
    +
      +
    • icon-question-circle-o
    • +
    • icon-sign-language
    • +
    • icon-tty
    • +
    • icon-universal-access
    • +
    +
      +
    • icon-volume-control-phone
    • +
    • icon-wheelchair
    • +
    • icon-wheelchair-alt
    • +
    +
    + +### Gender Icons + +
    +
      +
    • icon-genderless
    • +
    • icon-mars
    • +
    • icon-mars-double
    • +
    • icon-mars-stroke
    • +
    +
      +
    • icon-mars-stroke-h
    • +
    • icon-mars-stroke-v
    • +
    • icon-mercury
    • +
    +
      +
    • icon-neuter
    • +
    • icon-transgender
    • +
    • icon-transgender-alt
    • +
    +
      +
    • icon-venus
    • +
    • icon-venus-double
    • +
    • icon-venus-mars
    • +
    +
    + + + + + + + \ No newline at end of file diff --git a/modules/system/assets/ui/docs/input-hotkey.md b/modules/system/assets/ui/docs/input-hotkey.md new file mode 100644 index 0000000..ccd5c3f --- /dev/null +++ b/modules/system/assets/ui/docs/input-hotkey.md @@ -0,0 +1,29 @@ +# Input Hotkey API + +Allows keyboard shortcuts (hotkeys) to be bound to an element's click event. + +# Example + + + + + +## Javascript API + +If you use a selector other than a button or a link, you will need to add the `hotkeyVisible` property to the hotkey config. + + $('html').hotKey({ + hotkey: 'ctrl+s, cmd+s', + hotkeyVisible: false, + callback: doSomething + }); diff --git a/modules/system/assets/ui/docs/input-monitor.md b/modules/system/assets/ui/docs/input-monitor.md new file mode 100644 index 0000000..a6a1972 --- /dev/null +++ b/modules/system/assets/ui/docs/input-monitor.md @@ -0,0 +1,60 @@ +# Input Monitoring + +This will monitor the user input for unsaved changes and show a confirmation box if the user attempts to leave the page. The script adds the "oc-data-changed" class to the form element when the form data is changed. + +```html +
    + ... +
    +``` + +### Example + +Click the "Mark changed" button and "Reload page". + +
    + + + + + +
    + + + +
    + +## Supported data attributes + +- data-change-monitor - enables the plugin form a form +- data-window-close-confirm - confirmation message to show when a browser window is closing and there is unsaved data + +## Supported events + +- change - marks the form data as "changed". The event can be triggered on any element within a form or on a form itself. +- unchange.oc.changeMonitor - marks the form data as "unchanged". The event can be triggered on any element within a form or on a form itself. +- pause.oc.changeMonitor - temporary pauses the change monitoring. The event can be triggered on any element within a form or on a form itself. +- resume.oc.changeMonitor - resumes the change monitoring. The event can be triggered on any element within a form or on a form itself. + +## Triggered events + +- changed.oc.changeMonitor - triggered when the form data changes. +- unchanged.oc.changeMonitor - triggered when the form data unchanges. +- ready.oc.changeMonitor triggered when the change monitor instance finishes initialization. + +## JavaScript API + +```js +$('#form').changeMonitor() +``` diff --git a/modules/system/assets/ui/docs/input-preset.md b/modules/system/assets/ui/docs/input-preset.md new file mode 100644 index 0000000..b5b8807 --- /dev/null +++ b/modules/system/assets/ui/docs/input-preset.md @@ -0,0 +1,11 @@ +# Input Preset API + +Scripts that manage user input events. + +# Example + + + \ No newline at end of file diff --git a/modules/system/assets/ui/docs/input-trigger.md b/modules/system/assets/ui/docs/input-trigger.md new file mode 100644 index 0000000..58fa367 --- /dev/null +++ b/modules/system/assets/ui/docs/input-trigger.md @@ -0,0 +1,85 @@ +# Input Trigger API + +The API allows to change elements' visibility or status (enabled/disabled) basing on other elements' statuses. Example: enable a button if any checkbox inside another element is checked. + +## Example + +### Checked condition + + + + +### Value condition + +

    + +

    + +
    + +
    + Passphrase is valid! +
    +
    + + +## Supported data attributes + +- data-trigger-action, values: show, hide, enable, disable, empty +- data-trigger: a CSS selector for elements that trigger the action (checkboxes) +- data-trigger-condition, values: + - checked: determines the condition the elements specified in the data-trigger should satisfy in order the condition to be considered as "true". + - unchecked: inverse condition of "checked". + - value[somevalue]: determines if the value of data-trigger equals the specified value (somevalue) the condition is considered "true". +- data-trigger-closest-parent: optional, specifies a CSS selector for a closest common parent for the source and destination input elements. + +Example code: + +```html + +``` + +Multiple actions are supported: + +```html +data-trigger-action="hide|empty" +``` + +Multie value conditions are supported: + +```html +data-trigger-condition="value[foo][bar]" +``` + +### Supported events + +- oc.triggerOn.update - triggers the update. Trigger this event on the element the plugin is bound to to force it to check the condition and update itself. This is useful when the page content is updated with AJAX. +- oc.triggerOn.afterUpdate - triggered after the element is updated + +### JavaScript API + +```html +$('#mybutton').triggerOn({ + triggerCondition: 'checked', + trigger: '#cblist input[type=checkbox]', + triggerAction: 'enable' +}) +``` \ No newline at end of file diff --git a/modules/system/assets/ui/docs/inspector.md b/modules/system/assets/ui/docs/inspector.md new file mode 100644 index 0000000..c109b82 --- /dev/null +++ b/modules/system/assets/ui/docs/inspector.md @@ -0,0 +1,724 @@ +# Inspector control + +Inspector is a visual configuration tool that is used in several places of October back-end. The most known usage of Inspector is the CMS components configuration feature, but Inspector is not limited with the CMS. In fact, it's a universal tool that can be used with any element on a back-end page. + +The Inspector loads the configuration schema from an inspectable element, builds the user interface, and writes values entered by users back to the inspectable element. The first version of Inspector was supporting only a few scalar value types - strings and Booleans, without an option to edit any complex data. + +The current version of Inspector allows to edit any imaginable data structures, including cases where users create enumerable data elements right in the Inspector interface. + +This section describes the client-side Inspector API without going into details about the back-end usage of the data Inspector generates. Inspector accepts the configuration schema in JSON format and generates values in JSON format as well. Providing the configuration and interpreting the generated values is up to developers. For example, the CMS module uses information returned from component's defineProperties() method to generate the configuration JSON string and converts JSON values generated by Inspector to the components configuration in CMS templates. In this document we are focusing only on the JSON format. + +## Configuring inspectable elements + +Clicking an inspectable element displays Inspector for that element. Any HTML element could be made inspectable by adding data attributes to it. The required attributes are: + +* `data-inspectable` - indicates that Inspector should be created when the element is clicked. +* `data-inspector-title` - sets the Inspector popup title. +* `data-inspector-config` - contains the Inspector configuration JSON string. If this attribute is not specified, the configuration is loaded from the server, see the [Dynamic configuration and dynamic items](#dynamic-configuration-and-dynamic-items) section below. + +Inspectable elements should also contain a hidden input element used by Inspector for reading and writing values. The input element should be marked with the `data-inspector-values` data attribute. + +Example inspectable element markup: + +```html +
    + +
    +``` + +### Optional data attributes + +There are several optional data attributes and features that could be defined in an inspectable element or in elements around it: + +* `data-inspector-offset` - sets offset, in pixels, for the Inspector popup. +* `data-inspector-offset-x` - sets horizontal offset, in pixels, for the Inspector popup. +* `data-inspector-offset-y` - sets vertical offset, in pixels, for the Inspector popup. +* `data-inspector-placement` - sets defines placement for the Inspector popup, optional. If omitted, Inspector evaluates a placement automatically. Supported values: top, bottom, left, top. +* `data-inspector-fallback-placement` - sets less preferable placement for the Inspector popup, optional. This value is used if Inspector can't use the placement specified in data-inspector-placement. Supported values: top, bottom, left, top. +* `data-inspector-external-parameters` - if this attribute exists in any parent element of the inspectable element, the external parameters editors will be enabled in Inspector (unless property-specific rules cancel the external editor). + +### Dynamic configuration and dynamic items + +In case if the `data-inspector-config` attribute is missing in the inspectable element Inspector tries to load its configuration from the server. An important note - there should be a FORM element wrapping inspectable elements in order to use any dynamic features of Inspector. + +The AJAX request used for loading the configuration from the server is named `onGetInspectorConfiguration`. The handler should be defined in the back-end controller and should return an array containing the Inspector configuration (in the PHP equivalent of the JSON configuration structure described later in this section), inspector title and description. Example of a server-side AJAX dynamic configuration request handler: + +```php +public function onGetInspectorConfiguration() +{ + // Load and use some values from the posted form + // + $someValue = Request::input('someValue'); + + ... do some processing ... + + return [ + 'configuration' => [ + 'properties' => [list of properties], + 'title' => 'Inspector title', + 'description' => 'Inspector description' + ] + ]; +} +``` + +Some Inspector editors - (drop-down, set, autocomplete) support static and dynamic options. Dynamic options are requested from the server, rather than being defined in the configuration JSON string. For using this feature, the inspectable element must have the `data-inspector-class` attribute defined. The attribute value should contain a name of a PHP class corresponding to the inspectable element. + +The server-side controller should use the `Backend\Traits\InspectableContainer` trait in order to provide the dynamic options loading. The inspectable PHP class (specified with `data-inspector-class`) must either have a method `get[Property]Options()`, where the [Property] part corresponds the name of the dynamic property, or `getPropertyOptions($propertyName)` method that is more universal and accepts the property name as a parameter. The methods should return the `options` array containing associative arrays with keys `option` and `value`. Example: + +```php +public function getContextOptions() +{ + $optionsArray = []; + + $optionsArray[] = ['value' => 'create', 'title' => 'Create']; + $optionsArray[] = ['value' => 'update', 'title' => 'Update']; + $optionsArray[] = ['value' => 'delete', 'title' => 'Delete']; + + return [ + 'options' => $optionsArray + ]; +} +``` + +### Container and popups + +By default Inspector is displayed in a popup, but there's an option to display it right on the page, in a container element. To enable this option, all inspectable elements should be wrapped into another element with `data-inspector-container` attribute. The attribute value should be a CSS selector pointing to an element inside the wrapper. Example: + +```html +
    +
    +
    +
    +
    +``` + +The inner element will act as host element for Inspector when an inspectable element is clicked. The element should have the `inspector-container` class and can be optionally marked with `data-inspector-scrollable` attribute to make the Inspector scrollable. For the scrolling feature, the container element should have height defined explicitly. + +When the container is used, Inspector is still displayed in a popup by default, but users can click an icon in the Inspector header to move it to the container. + +## Data schema configuration + +Inspector configuration, defined with `data-inspector-config` attribute or loaded from the server, should be an array containing a list of property definition. All examples in this section use JSON format. Below is an example of a configuration for two properties: + +```json +[ + { + "property": "firstName", + "title": "First name", + "type": "string" + }, + { + "property": "lastName", + "title": "Last name", + "type": "string" + } +] +``` + +This configuration creates two text fields with titles "First name" and "Last name". When the data is saved back to the inspectable element (to the `data-inspector-values` hidden input element), it would have the following format: + +```json +{"firstName":"John", "lastName":"Smith"} +``` + +Each property should have attributes `property`, `title` and `type`. The `type` attribute defines a type of an editor that should be created for the property. The supported editors are described further. + +Other attributes supported by all (or most of the) property types are: + +* `description` - description string, which is available in a tooltip displayed when a user overs the 'i' icon in the property editor. +* `group` - allows to group multiple properties. The attribute should contain a group name. Groups could be collapsed by users, making the Inspector interface less cluttered. +* `showExternalParam` - enables the inspector parameter editor for the property. External parameters are currently used only by the CMS. Note that some property types do not support external property editors. See also `data-inspector-external-parameters` attribute described above. +* `placeholder` - text to display in the editor if property value is empty. +* `validation` - validation configuration. See the complete validation description below. +* `default` - default property value. The property value format depends on the property type - for the `string` type it's an array, for `stringList` type it's an array of strings. See more details below. + +All other configuration properties are specific for different property types. + +### String editor + +String editor allows entering a single line of a text and represented with a simple input text field. The editor doesn't have any specific parameters. The optional `default` parameter for the editor should contain a string. + +```json +{ + "property": "firstName", + "title": "First name", + "type": "string", + "default": "John" +} +``` + +The editor generates string values: + +```json +{"firstName":"Sam"} +``` + +### Text editor + +Text editor allows entering multi-line long text values in a popup window. The editor doesn't have any specific parameters. The optional `default` parameter for the editor should contain a string. + +```json +{ + "property": "description", + "title": "Description", + "type": "text", + "default": "This is a default description" +} +``` + +The editor generates string values: + +```json +{"description":"This is a description"} +``` + +### String list editor + +Allows users to enter lists of strings. The editor opens in a popup window and displays a text area. Each line of text represents an element in the result array. The optional `default` parameter should contain an array of strings. Example: + +```json +{ + "property": "items", + "title": "Items" + "type": "stringList", + "default": ["String 1", "String 2"] +} +``` + +A value generated by the editor is an array of strings, for example: + +```json +{"items":["String 1","String 2","String 3"]} +``` + +### Autocomplete editor + +This editor works like the `string` editor, but includes the autocomplete feature. Autocompletion options can be specified statically, with the `items` parameter or loaded dynamically. Example with static options: + +```json +{ + "property": "condition", + "title": "Condition" + "type": "autocomplete", + "items": {"start": "Start", "end": "End"} +} +``` + +The items are specified as a key-value object. The `items` parameter is optional, if it's not provided, the items will be loaded from the server - see [Dynamic configuration and dynamic items](#dynamic-configuration-and-dynamic-items) section above. + +Values generated by the editor are strings. Example: + +```json +{"condition":"start"} +``` + +Fields of this type do not support external property editors. + +### Checkbox editor + +Properties of this type are represented with a checkbox in the Inspector UI. This property doesn't have any special parameters. The `default` parameter, if specified, should contain a Boolean value or string values "true", "false", "1", "0". Example: + +```json +{ + "property": "enabled", + "title": "Enabled", + "type": "checkbox", + "default": true +} +``` + +Values generated by the editor are 0 (unchecked) or 1 (checked). Example: + +```json +{"enabled":1} +``` + +### Dropdown editor + +Displays a drop-down list. Options for the drop-down list can be specified statically with the `options` attribute or loaded from the server dynamically. Example: + +```json +{ + "property": "action", + "title": "Action", + "type": "dropdown", + "options": { + "show": "Show", + "hide": "Hide", + "enable": "Enable", + "disable": "Disable", + "empty": "Empty" + } +} +``` + +The `options` attribute should be a key-value object. If the attribute is not specified, Inspector will try to load options from the server - see [Dynamic configuration and dynamic items](#dynamic-configuration-and-dynamic-items) section above. + +The editor generates a string value corresponding to the selected option, for example: + +```json +{"action":"hide"} +``` + +### Dictionary editor + +Dictionary editor allows to create key-value pairs with a simple user interface consisting of a table with two columns. The `default` parameter, if specified, should contain a key-value object. Example: + +```json +{ + "property": "options", + "title": "Options", + "type": "dictionary", + "default": {"option1": "Option 1"} +} +``` + +The editor generates an object value, for example: + +```json +{"options":{"option1":"Option 1","option2":"Option 2"}} +``` + +The dictionary editor supports validation for the entire set (`required` and `length` validators) and for keys and values separately. See the [validation description](#defining-the-validation-rules) further in this document. The `validationKey` and `validationValue` define validation for keys and values, for example: + +```json +{ + "property": "options", + "title": "Options", + "type": "dictionary", + "validation": { + "required": { + "message": "Please create options" + }, + "length": { + "min": { + "value": 2, + "message": "Create at least two options." + } + } + }, + "validationKey": { + "regex": { + "pattern": "^[a-z]+$", + "message": "Keys can contain only lowercase Latin letters" + } + }, + "validationValue": { + "regex": { + "pattern": "^[a-zA-Z0-9]+$", + "message": "Values can contain only Latin letters and digits" + } + } +} +``` + +### Object editor + +Allows to define an object with specific properties editable by users. Object properties are specified with the `properties` attribute. The value of the attribute is an array, which has exactly the same structure as the Inspector properties array. + +```json +{ + "property": "address", + "title": "Address", + "type": "object", + "properties": [ + { + "property": "streetAddress", + "title": "Street address", + "type": "string" + }, + { + "property": "city", + "title": "City", + "type": "string" + }, + { + "property": "country", + "title": "Country", + "type": "dropdown", + "options": {"us": "US", "ca": "Canada"} + } + ] +} +``` + +The example above creates an object with three properties. Two of them are displayed as text fields, and the third as a drop-down. + +Object editor values are objects. Example: + +```json +{ + "address": { + "streetAddress":"321-210 Second ave", + "city":"Springfield", + "country":"us" + } +} +``` + +The object properties can be of any type supported by Inspector, including other objects. + +There's a way to exclude an object from Inspector values completely, if one of the object fields is empty. The field is identified with `ignoreIfPropertyEmpty` parameter. For example: + +```json +{ + "property": "address", + "title": "Address", + "type": "object", + "ignoreIfPropertyEmpty": "title", + "properties": [ + { + "property": "streetAddress", + "title": "Street address", + "type": "string" + }, + { + "property": "city", + "title": "City", + "type": "string" + } + ] +} +``` + +In the example above, if the street address is not specified, the object ("address") will be completely removed from the Inspector output. If there are any validation rules defined on other object properties and the required property is empty, those rules will be ignored. + +A `default` value for the editor, if specified, should be an object with the same properties as defined in the `properties` configuration parameter. + +Object editors do not support the external property editor feature. + +### Object list editor + +The object list editor allows users to create multiple objects with a pre-defined structure. For example, it could be used for creating a list of person, where each person has a name and address. + +The properties of objects that can be created with the editor are defined with `itemProperties` parameter. The parameter should contain an array of properties, similar to Inspector configuration array. Another required parameter is `titleProperty`, which identifies a property that should be used as a title in Inspector UI. Example configuration: + +```json +{ + "property": "people", + "title": "People", + "type": "objectList", + "titleProperty": "fullName", + "itemProperties": [ + { + "property": "fullName", + "title": "Full name", + "type": "string" + }, + { + "property": "address", + "title": "Address", + "type": "string" + } + ] +} +``` + +The array of properties defined with `itemProperties` supports all property types. + +The Object List editor type doesn't support default values. + +By default the value created by the editor of this type is a non-associative array: + +```json +{ + "people":[ + {"fullName":"John Smith","address":"Palo Alto"}, + {"fullName":"Bart Simpson","address":"Springfield"} + ] +} +``` + +If the result value should be an associative array (object), use the `keyProperty` configuration option. The option value should refer to a property that should be used as a key. The key property can use only the string or drop-down editors, its value should be unique and cannot be empty. Example: + +```json +{ + "property": "people", + "title": "People", + "type": "objectList", + "titleProperty": "fullName", + "keyProperty": "login", + "itemProperties": [ + { + "property": "fullName", + "title": "Full name", + "type": "string" + }, + { + "property": "login", + "title": "Login", + "type": "string" + }, + { + "property": "address", + "title": "Address", + "type": "string" + } + ] +} +``` + +The `login` property in the example above will be used as a key in the result value: + +```json +{ + "people":{ + "john":{"fullName":"John Smith","address":"Palo Alto"}, + "bart":{"fullName":"Bart Simpson","address":"Springfield"} + } +} +``` + +### Set editor + +The set editor allows users to select multiple predefined options with checkboxes. Set items can be specified statically with the configuration, using the `items` parameter, or loaded dynamically. Example with static items definition: + +```json +{ + "property": "context", + "title": "Context", + "type": "set", + "items": { + "create": "Create", + "update": "Update", + "preview": "Preview" + }, + "default": ["create", "update"] +} +``` + +The `items` attribute should be a key-value object. If the attribute is not specified, Inspector will try to load options from the server - see [Dynamic configuration and dynamic items](#dynamic-configuration-and-dynamic-items) section above. + +The `default` parameter, if specified, should be an array listing item keys selected by default. + +Set editors do not support the external property editor feature. + +## Defining the validation rules + +Inspector support several validation rules that can be applied to properties. Validation rules can be applied to top-level properties as well as to internal property definitions of object and object list editors. There are two ways to define validation rules - the legacy syntax and the new syntax. + +The legacy syntax is supported for the backwards compatibility with existing CMS components definitions. This syntax will always be supported, but it's limited, and cannot be mixed with the new syntax. Example of the legacy syntax: + +```json +{ + "property": "name", + "title": "Name", + "type": "string", + "required": true, + "validationPattern": "^[a-zA-Z]+$" + "validationMessage": "The Name field is required and can contain only Latin letters.", +} +``` + +The legacy syntax supports only two validation rules - required and regular expression. The new syntax is much more flexible and extendable: + +```json +{ + "property": "name", + "title": "Name", + "type": "string", + "validation": { + "required": { + "message": "The Name field is required" + }, + "regex": { + "message": "The Name field can contain only Latin letters.", + "pattern": "^[a-zA-Z]+$" + } + } +} +``` + +The key value in the `validation` object refers to a validator (see below). Validators are configured with objects, which properties depend on a validator. One property - `message` is common for all validators. + +### required validator + +Checks if a value is not empty. The validator can be used with any editor, including complex editors (sets, dictionaries, object lists, etc.). Example: + +```json +{ + "property": "name", + "title": "Name", + "type": "string", + "validation": { + "required": { + "message": "The Name field is required" + } + } +} +``` + +### regex validator + +Validates string values with a regular expression. The validator can be use only with string-typed editors. Example: + +```json +{ + "property": "name", + "title": "Name", + "type": "string", + "validation": { + "regex": { + "message": "The Name field can contain only Latin letters", + "pattern": "^[a-z]+$", + "modifiers": "i" + } + } +} +``` + +The regular expression is specified with the required `pattern` parameter. The `modifiers` parameter is optional and can be used for setting regular expression modifiers. + +### integer validator + +Checks if the value is integer and can optionally validate if the value is within a specific interval. The validator can be used only with string-typed editors. Example: + +```json +{ + "property": "numOfColumns", + "title": "Number of Columns", + "type": "string", + "validation": { + "integer": { + "message": "The Number of Columns field should contain an integer value", + "allowNegative": true, + "min": { + "value": -10, + "message": "The number of columns should not be less than -10." + }, + "max": { + "value": 10, + "message": "The number of columns should not be greater than 10." + } + } + } +} +``` + +Supported parameters: + +* `allowNegative` - optional, determines if negative values are allowed. By default negative values are not allowed. +* `min` - optional object, defines the minimum allowed value and error message. Object fields: + * `value` - defines the minimum value. + * `message` - optional, defines the error message. +* `max` - optional object, defines the maximum allowed value and error message. Object fields: + * `value` - defines the maximum value. + * `message` - optional, defines the error message. + +### float validator + +Checks if the value is a floating point number. The parameters for this validator match the parameters of the **integer** validator described above. Example: + +```json +{ + "property": "amount", + "title": "Amount", + "type": "string", + "validation": { + "float": { + "message": "The Amount field should contain a positive floating point value." + } + } +} +``` + +Valid floating point number formats: + +* 10 +* 10.302 +* -10 (if `allowNegative` is `true`) +* -10.84 (if `allowNegative` is `true`) + +### length validator + +Checks if a string, array or object is not shorter or longer than specified values. This validator can work with the string, text, set, string list, dictionary and object list editors. In multiple-value editors (set, string list, dictionary and object list) it validates the number of items created in the editor. + +> **Note**: the `length` validator doesn't validate empty values. For example, if it's applied to a set editor, and the set is empty, the validation will pass regardless of the `min` and `max` parameter values. Use the `required` validator together with the `length` validator to make sure that the value is not empty before the length validation is applied. + +```json +{ + "property": "name", + "title": "Name", + "type": "string", + "validation": { + "length": { + "min": { + "value": 2, + "message": "The name should not be shorter than two letters." + }, + "max": { + "value": 10, + "message": "name should not be longer than 10 letters." + } + } + } +} +``` + +Supported parameters: + +* `min` - optional object, defines the minimum allowed length and error message. Object fields: + * `value` - defines the minimum value. + * `message` - optional, defines the error message. +* `max` - optional object, defines the maximum allowed length and error message. Object fields: + * `value` - defines the maximum value. + * `message` - optional, defines the error message. + +## Inspector events + +Inspector triggers several events on the inspectable elements. + +### change + +The `change` event is triggered after Inspector applies updated values to the inspectable element. The event is triggered only if the user has changed values in the Inspector UI. + +### showing.oc.inspector + +The `showing.oc.inspector` event is triggered before Inspector is displayed. The event handler can optionally stop the process with calling `ev.isDefaultPrevented()`. Example - prevent Inspector showing: + +```js +$(document).on('showing.oc.inspector', 'div[data-inspectable]', function(ev, data){ + ev.preventDefault() +}) +``` + +The handler could perform any required processing, even asynchronous, and then call the callback function passed to the handler, to continue showing the Inspector. In this case the handler should call `ev.stopPropagation()` method to stop the default Inspector initialization. Example - continue showing after some processing: + +```js +$(document).on('showing.oc.inspector', 'div[data-inspectable]', function(ev, data){ + ev.stopPropagation() + // The callback function can be called asynchronously + data.callback() +}) +``` + +### hiding.oc.inspector + +The `hiding.oc.inspector` is called before Inspector hiding process starts. The handler can stop the hiding with calling `ev.preventDefault()`. Example: + +```js +$(document).on('hiding.oc.inspector', 'div[data-inspectable]', function(ev, data){ + if (!confirm('Allow hiding?')) { + ev.preventDefault() + } +}) +``` + +The values entered in Inspector are available through the `values` element of the second handler argument: + +```js +$(document).on('hiding.oc.inspector', 'div[data-inspectable]', function(ev, data){ + console.log(data.values) +}) +``` + +### hidden.oc.inspector + +The `hidden.oc.inspector` is triggered after Inspector is hidden. \ No newline at end of file diff --git a/modules/system/assets/ui/docs/list.md b/modules/system/assets/ui/docs/list.md new file mode 100644 index 0000000..4386a25 --- /dev/null +++ b/modules/system/assets/ui/docs/list.md @@ -0,0 +1,336 @@ +### Basic example + +
    + + + + + + + + + + + + + + + + + + + +
    TitleCreatedCategoriesUpdated
    Welcome to OctoberOct 01, 2013NewsOct 01, 2013 
    +
    + +### Complete example + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    +
    TitleCreatedAuthorCategoriesPublishedUpdated
    Welcome to OctoberOct 01, 2013Adam PersonNewsOct 01, 2013Oct 01, 2013 
    The marketplace is open!Oct 15, 2013Sam GeorgesFeaturesOct 16, 2013Oct 16, 2013 
    Welcome to the Builder!Oct 21, 2013Alexey BobkovNews, FeaturesOct 21, 2013Oct 21, 2013 
    Components explainedNov 12, 2013Alexey BobkovTutorialsNov 12, 2013Nov 12, 2013 
    Creating a module in 90 secondsNov 15, 2013Sam GeorgesTutorialsNov 15, 2013Nov 15, 2013 
    + +
    + +### Empty list + +Use the `no-data` class to display a list that contains no records. + +
    + + + + + + + + + + + + +
    TitleCreated
    +
    + +### Row classes + +The following colored classes are available to use on the table row elements. + +
    + + + + + + + + + + + + + + + + + + +
    Class
    Normal text
    .strike
    .frozen
    .processing
    .negative
    .positive
    .disabled / .deleted
    .new / .important
    .safe / .special
    +
    + +### Status column + +It might be fun to include a status column! + +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    StatusTitle
    + + Draft + + Welcome to October
    + + Pending + + What a wonderful day
    + + Approved + + The sun is shining
    + + Cancelled + + The weather is sweet here
    +
    + + +### Badge column + +You can also include an icon badge inside a column. + +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    StatusTitle
    + + + + Draft + Welcome to October
    + + + + Pending + What a wonderful day
    + + + + Approved + The sun is shining
    + + + + Cancelled + The weather is sweet here
    +
    + +### Linking rows + +You may link an entire row by adding the `data-control="rowlink"` attribute to the table element. The first table data (TD) column with an anchor will be used to link the entire row. To bypass this behavior, simply add the `nolink` class to the column. + +
    + + + + + + + + + +
    + Link to this + Row will be linkedThis will also be linked
    +
    + +### Button column + +You may add a small button to a list column by adding the `column-button` class to the table data (TD) element. + +
    + + + + + + + + + + + + + +
    ActionName
    + + Petoria + +
    +
    diff --git a/modules/system/assets/ui/docs/loader.md b/modules/system/assets/ui/docs/loader.md new file mode 100644 index 0000000..138ea90 --- /dev/null +++ b/modules/system/assets/ui/docs/loader.md @@ -0,0 +1,91 @@ +# Loading indicators + +## Container Loading Indicator + +#### Loading Indicator +A loading indicator used in a container. + +
    +
    + +
    +

    This is some content inside the container

    +

    The loading indicator must be prepended to it

    +
    + +#### Text Loading Indicator +A loading indicator can have text by adding a `
    ` element inside. + +
    +
    + +
    Loading...
    +
    +
    + +#### Loading Indicator Sizes + +A loading indicator can have a size by adding `size-X` to the container. These sizes are available: **size-small**. + +
    +
    + +
    Loading (size-small)
    +
    +
    + +#### Loading Indicator Alignment + +A loading indicator can be aligned to the center by adding `indicator-center` to the container and/or indicator. + +
    +
    + +
    +
    + +You may add some optional text: + +
    +
    + +
    Loading...
    +
    +
    + +# Example + +
    +
    + +
    +

    This is some content inside the container

    +

    The loading indicator must be prepended to it

    +
    + +
    +
    + +
    Loading...
    +
    +
    + +
    +
    + +
    Loading (inset)
    +
    +
    + +
    +
    + +
    Loading (size-small)
    +
    +
    + +
    +
    + +
    +
    diff --git a/modules/system/assets/ui/docs/pagination.md b/modules/system/assets/ui/docs/pagination.md new file mode 100644 index 0000000..195de18 --- /dev/null +++ b/modules/system/assets/ui/docs/pagination.md @@ -0,0 +1,23 @@ +### Basic example + +
    + Displayed records: 1-5 of 20 + +
    + +### Complete example + +
    + Displayed records: 1-5 of 20 + + + + + +
    diff --git a/modules/system/assets/ui/docs/popover.md b/modules/system/assets/ui/docs/popover.md new file mode 100644 index 0000000..f34c124 --- /dev/null +++ b/modules/system/assets/ui/docs/popover.md @@ -0,0 +1,131 @@ +# Popover + +Renders a richer version of a tooltip, called a popover. + +## Examples + +### Basic usage + +You may add `data-control="popover"` to an anchor or button to activate a popover. Use the `data-content` attribute to specify the contents. + + + Basic popover + + +### Template content + +Define the popover content as a template and reference it with `data-content-from="#myPopoverContent"`. + +```html + +``` + + + + + Template popover + + +### Event specified content + +```js +$('#btn1').on('showing.oc.popover', function(e, popover) { + popover.options.content = '
    Some other content
    ' +}) +``` + + + Event content popover + + + + +## JavaScript API + +```js +$('#element').ocPopover({ + content: '

    This is a popover

    ' + placement: 'top' +}) +``` + +### Supported methods + +`.ocPopover('hide')` +Closes the popover. There are 3 ways to close the popover: call it's `hide()` method, trigger the `close.oc.popover` on any element inside the popover or click an element with attribute `data-dismiss="popover"` inside the popover. + +### Supported options + +- `placement`: top | bottom | left | right | center. The placement could automatically be changed if the popover doesn't fit into the desired position. + +- `fallbackPlacement`: top | bottom | left | right. The placement to use if the default placement and all other possible placements do not work. The default value is "bottom". + +- `content`: content HTML string or callback + +- `contentFrom`: selector to source the content HTML + +- `width`: content width, optional. If not specified, the content width will be used. + +- `modal`: make the popover modal + +- `highlightModalTarget`: "pop" the popover target above the overlay, making it highlighted. The feature assigns the target position relative. + +- `closeOnPageClick`: close the popover if the page was clicked outside the popover area. + +- `container`: the popover container selector or element. The default container is the document body. The container must be relative positioned. + +- `containerClass` - a CSS class to apply to the popover container element + +- `offset` - offset in pixels to add to the calculated position, to make the position more "random" + +- `offsetX` - X offset in pixels to add to the calculated position, to make the position more "random". If specified, overrides the offset property for the bottom and top popover placement. + +- `offsetY` - Y offset in pixels to add to the calculated position, to make the position more "random". If specified, overrides the offset property for the left and right popover placement. + +- `useAnimation`: adds animation to the open and close sequence, the equivalent of adding the CSS class 'fade' to the containerClass. + +### Supported events + +- `showing.oc.popover` - triggered before the popover is displayed. Allows to override the popover options (for example the content) or cancel the action with e.preventDefault() + +- `show.oc.popover` - triggered after the popover is displayed. + +- `hiding.oc.popover` - triggered before the popover is closed. Allows to cancel the action with e.preventDefault() + +- `hide.oc.popover` - triggered after the popover is hidden. diff --git a/modules/system/assets/ui/docs/popup.md b/modules/system/assets/ui/docs/popup.md new file mode 100644 index 0000000..c1ce47b --- /dev/null +++ b/modules/system/assets/ui/docs/popup.md @@ -0,0 +1,152 @@ +# Popups + +Displays a modal popup, based on the Bootstrap modal implementation. + +- [Examples](#examples) +- [Inline popups](#inline-popups) +- [Remote popups](#remote-popups) +- [API documentation](#api-docs) + + +## Examples + + Launch basic content + + + + Launch Confirmation dialog + + + + +## Inline popups + +An inline popup places the popup content inside the current page, hidden from the view. For example, this container will not be visible on the page. + +```html + +``` + +Use the `data-toggle="modal"` HTML attribute to launch this container as a popup. + +```html + + Launch basic content + +``` + + +## Remote popups + +Content for the popup can be loaded remotely using an AJAX request. Use the `data-handler` attribute to populate a popup with the contents of an AJAX handler. + +```html + + Launch Ajax Form + +``` + +Using the `data-ajax` attribute you can refer to an external file or URL directly. + +```html + + Launch Ajax Form + +``` + +The partial for your rendered popup should follow this structure: + +```html + + + +``` + + +## API documentation + +### Options: +- content: content HTML string or callback + +### Data attributes +- data-control="popup" - enables the ajax popup plugin +- data-ajax="popup-content.htm" - ajax content to load +- data-handler="onLoadContent" - October ajax request name +- data-keyboard="false" - Allow popup to be closed with the keyboard +- data-extra-data="file_id: 1" - October ajax request data +- data-size="large" - Popup size, available sizes: giant, huge, large, small, tiny, adaptive (will scale to fit the window) +- data-adaptive-height="false" - Allow the popup to fill the height of the screen + +### JavaScript API + +```js +$('a#someLink').popup({ ajax: 'popup-content.htm' }) +$('a#someLink').popup({ handler: 'onLoadSomePopup' }) +$('a#someLink').popup({ handler: 'onLoadSomePopup', extraData: { id: 3 } }) +``` diff --git a/modules/system/assets/ui/docs/progressbar.md b/modules/system/assets/ui/docs/progressbar.md new file mode 100644 index 0000000..50fc4b3 --- /dev/null +++ b/modules/system/assets/ui/docs/progressbar.md @@ -0,0 +1,9 @@ +Progress bar + +# Example + +
    +
    + 60% Complete +
    +
    \ No newline at end of file diff --git a/modules/system/assets/ui/docs/scoreboard.md b/modules/system/assets/ui/docs/scoreboard.md new file mode 100644 index 0000000..5d3b24e --- /dev/null +++ b/modules/system/assets/ui/docs/scoreboard.md @@ -0,0 +1,84 @@ +# Scoreboard + +### Scoreboard + +
    +
    +
    +

    Weight

    +

    100

    +

    unit: kg

    +
    + +
    +

    Comments

    +

    44

    +

    previous month: 32

    +
    + +
    +

    Latest commenter

    +

    John Smith

    +

    registered: yes

    +
    +
    +
    + +### Complete example + +
    +
    +
    +
      +
    • Published 84
    • +
    • Drafts 12
    • +
    • Deleted 18
    • +
    +
    + +
    +
      +
    • Published 84
    • +
    • Drafts 12
    • +
    • Deleted 18
    • +
    +
    + +
    +

    Weight

    +

    100

    +

    unit: kg

    +
    + +
    +

    Comments

    +

    44

    +

    previous month: 32

    +
    + +
    +

    Length

    +

    31

    +

    previous: 42

    +
    + +
    +

    Latest commenter

    +

    John Smith

    +

    registered: yes

    +
    + +
    +

    goal meter

    +

    88%

    +

    37 posts remain

    +
    + +
    +

    goal meter

    +

    88%

    +

    37 posts remain

    +
    +
    +
    + diff --git a/modules/system/assets/ui/docs/select.md b/modules/system/assets/ui/docs/select.md new file mode 100644 index 0000000..664ae2a --- /dev/null +++ b/modules/system/assets/ui/docs/select.md @@ -0,0 +1,156 @@ +# Select + +### Select + +Custom select control. + + + +## Sizes + +### Small size + +
    + +
    + +### Large size + +
    + +
    + +## Options + +### Disable search + +Add the `select-no-search` CSS class to disable searching. + +
    + +
    + +### Dynamic option creation + +In addition to a pre-populated menu of options, Select widgets may dynamically create new options from textual input by the user in the search box. This feature is called "tagging". To enable tagging, set the `tags` option to `true`: + + + +## Option groups + +Use the `optgroup` element to create option groups. + + + +## AJAX search + +Use the `data-handler` attribute to source the select options from an AJAX handler. + +```html + +``` + +The AJAX handler should return results in the [Select2 data format](https://select2.org/data-sources/formats). + +```php +public function onGetOptions() +{ + return [ + 'results' => [ + [ + 'id' => 1, + 'text' => 'Foo' + ], + [ + 'id' => 2, + 'text' => 'Bar' + ] + ... + ] + ]; +} +``` + +Or a more full-featured example: + +```php +public function onGetOptions() +{ + return [ + 'results' => [ + [ + 'id' => 1, + 'text' => 'Foo', + 'disabled' => true + ], + [ + 'id' => 2, + 'text' => 'Bar', + 'selected' => true + ], + [ + 'text' => 'Group', + 'children' => [ + [ + 'id' => 3, + 'text' => 'Child 1' + ], + [ + 'id' => 4, + 'text' => 'Child 2' + ] + ... + ] + ] + ... + ], + 'pagination' => [ + 'more' => true + ] + ]; +} +``` + +The results array can be assigned to either the `result` or `results` key. As an alternative to the Select2 format, results can also be provided as an associative array (also assigned to either key). Due to the fact that JavaScript does not guarantee the order of object properties, we suggest the method above for defining results. + +```php +public function onGetOptions() +{ + $results = [ + 'key' => 'value', + ... + ]; + + return ['result' => $results]; +} +``` diff --git a/modules/system/assets/ui/docs/site.md b/modules/system/assets/ui/docs/site.md new file mode 100644 index 0000000..0c3c429 --- /dev/null +++ b/modules/system/assets/ui/docs/site.md @@ -0,0 +1,7 @@ +Includes scaffold for a basic site. + +Reset +Normalize +Grid system +Print +Typography \ No newline at end of file diff --git a/modules/system/assets/ui/docs/tab.md b/modules/system/assets/ui/docs/tab.md new file mode 100644 index 0000000..5caddb2 --- /dev/null +++ b/modules/system/assets/ui/docs/tab.md @@ -0,0 +1,149 @@ +# Tab control + +This plugin is a wrapper for the Twitter Bootstrap Tab component. It provides the following features: + +- Adding tabs +- Optional close icons with 2 states (modified / unmodified). The icon state can be changed by triggering the modified.oc.tab/unmodified.oc.tab events on any element within tab, or on the tab itself. +- Removing tabs with the Close icon, or with triggering an event from inside a tab pane or tab. The removing can be canceled if the confirm.oc.tab event handler returns false. +- Scrolling tabs if they do not fit the screen +- Collapsible tabs + +### Supported CSS modifiers + +These modifiers can be added in addition to the `control-tabs` class: + +- **tabs-inset**: Applies a negative margin to the tabs allowing them to sit well inside a padded container. +- **tabs-offset**: Applies a positive padding to tabs so they sit well inside a flush (non padded) container. +- **tabs-flush**: Tabs to sit flush to the element above it. + +### Master tabs + +
    + +
    +
    + Tab one content +
    +
    + Tab two content +
    +
    + Tab three content +
    +
    +
    + +### Primary tabs + +
    + +
    +
    + Tab one content +
    +
    + Tab two content +
    +
    + Tab three content +
    +
    +
    + +> **Note**: Primary tabs in the October back-end are inset by default and you should use `.tabs-no-inset` to disable this. + +### Secondary tabs + +
    + +
    +
    + Tab one content +
    +
    + Tab two content +
    +
    + Tab three content +
    +
    +
    + +### Content tabs + +
    + +
    +
    + Tab one content +
    +
    + Tab two content +
    +
    + Tab three content +
    +
    +
    + + +### Supported data attributes: + +- data-control="tab" - creates the tab control from an element +- data-closable - enables the Close Tab feature +- data-pane-classes - a list of CSS classes to apply new pane elements + +Example with data attributes (data-control="tab"): + +
    + +
    +
    Home
    +
    +
    + +### JavaScript API + +- $('#mytabs').ocTab({closable: true, closeConfirmation: 'Close this tab? Unsaved data will be lost.'}) +- $('#mytabs').ocTab('addTab', 'Tab title', 'Tab content', identifier) - adds tab. The optional identifier parameter allows to associate a identifier with a tab. The identifier can be used with the goTo() method to find and open a tab by it's identifier. +- $('#mytabs').ocTab('closeTab', '.nav-tabs > li.active', true) - closes a tab. The second argument can point to a tab or tab pane. The thrid argument determines whether the tab should be closed without the user confirmation. The default value is false. +- $('.nav-tabs > li.active').trigger('close.oc.tab') - another way to close a tab. The event can be triggered on a tab, tab pane or any element inside a tab or tab pane. +- $('#mytabs').ocTab('modifyTab', '.nav-tabs > li.active') - marks a tab as modified. Use the 'unmodifyTab' to mark a tab as unmodified. +- $('.nav-tabs > li.active').trigger('modified.oc.tab') - another way to mark a tab as modified. The event can be triggered on a tab, tab pane or any element inside a tab or tab pane. Use the 'unmodified.oc.tab' to mark a tab as unmodified. +- $('#mytabs').ocTab('goTo', 'someidentifier') - Finds a tab by it's identifier and opens it. +- $('#mytabs').ocTab('goToPane', '.tab-content .tab-pane:first') - Opens a tab in context of it's content (pane element) + +### Supported options: + + - closable - adds the "close" icon to the tab and lets users to close tabs. Corresponds the data-closable attribute. + - closeConfirmation - a confirmation to show when a user tries to close a modified tab. Corresponds the data-close-confirmation + attribute. The confirmation is displayed only if the tab was modified. + - slidable - allows the tabs to be switched with the swipe gesture on touch devices. Corresponds the data-slidable attribute. + - paneClasses - a list of CSS classes to apply new pane elements. Corresponds to the data-pane-classes attribute. + - maxTitleSymbols - the maximum number of characters in tab titles. + - titleAsFileNames - treat tab titles as file names. In this mode only the file name part is displayed in the tab, and the directory part + is hidden. + +### Supported events: + +- beforeClose.oc.tab - triggered on a tab pane element before tab is closed by the user. Call the event's + preventDefault() method to cancel the action. +- afterAllClosed.oc.tab - triggered after all tabs have been closed diff --git a/modules/system/assets/ui/docs/toolbar.md b/modules/system/assets/ui/docs/toolbar.md new file mode 100644 index 0000000..d4cbd0a --- /dev/null +++ b/modules/system/assets/ui/docs/toolbar.md @@ -0,0 +1,162 @@ +# Toolbar + +A scrollable set of buttons aligned to the left with a fixed right section. + +All toolbar items (`toolbar-item`) should have a fixed width, except for the primary item (`toolbar-primary`) which will stretch. In the October backend you can use the `data-calculate-width` attribute to have these widths calculated dynamically for you. + +## Basic toolbar + +
    +
    +
    + + + + + + + + + + + + + + + +
    +
    +
    + +
    +
    + +### Button groups + +
    +
    +
    +
    + + +
    +
    +
    +
    + +
    +
    + +### Button with Tooltips + +
    +
    +
    + +
    +
    +
    + +
    +
    + +### Dropdown buttons + +
    +
    +
    + + + +
    +
    +
    + +
    +
    + +## Editor toolbar + +
    +
    +
    + + + + + + + + + + + + + + +
    +
    +
    + + +
    +
    diff --git a/modules/system/assets/ui/docs/tooltip.md b/modules/system/assets/ui/docs/tooltip.md new file mode 100644 index 0000000..8c4c5c7 --- /dev/null +++ b/modules/system/assets/ui/docs/tooltip.md @@ -0,0 +1,30 @@ +# Tooltips + +Tooltips are an alternative to the standard browser title tooltip. + +## Tooltip markup +A standard tooltip + +
    +
    +
    Create a new blog post based on this
    +
    + +## Spawning tooltips +Tooltips can be automatically created when the mouse enters an element using the `data-toggle="tooltip"` tag. + + + Some link + + +# Example + +
    +
    +
    Create a new blog post based on this
    +
    \ No newline at end of file diff --git a/modules/system/assets/ui/docs/utilities.md b/modules/system/assets/ui/docs/utilities.md new file mode 100644 index 0000000..cd453c3 --- /dev/null +++ b/modules/system/assets/ui/docs/utilities.md @@ -0,0 +1,129 @@ +Utility styles are a collection of useful classes designed to reduce the need to create a stylesheet for basic styling needs, such as spacing and positioning. + +### Branding + +```css +.br-p { color: @brand-primary; } +.br-s { color: @brand-secondary; } +.br-a { color: @brand-accent; } +.br-p-s10 { color: saturate(@brand-primary, 10%); } +.br-s-s10 { color: saturate(@brand-secondary, 10%); } +.br-a-s10 { color: saturate(@brand-accent, 10%); } +.br-p-s20 { color: saturate(@brand-primary, 20%); } +.br-s-s20 { color: saturate(@brand-secondary, 20%); } +.br-a-s20 { color: saturate(@brand-accent, 20%); } + +.bg-p { background-color: @brand-primary; } +.bg-s { background-color: @brand-secondary; } +.bg-a { background-color: @brand-accent; } +.bg-p-s10 { background-color: saturate(@brand-primary, 10%); } +.bg-s-s10 { background-color: saturate(@brand-secondary, 10%); } +.bg-a-s10 { background-color: saturate(@brand-accent, 10%); } +.bg-p-s20 { background-color: saturate(@brand-primary, 20%); } +.bg-s-s20 { background-color: saturate(@brand-secondary, 20%); } +.bg-a-s20 { background-color: saturate(@brand-accent, 20%); } +``` + +### Typography + +```css +.t-ww { word-wrap: break-word; } +.t-nw { white-space: nowrap; } +``` + +### Positioning + +```css +.pos-r { position: relative !important; } +.pos-a { position: absolute !important; } +.pos-f { position: fixed !important; } +``` + +### Width + +```css +.w-sm { width: 25% !important; } +.w-md { width: 50% !important; } +.w-lg { width: 75% !important; } +.w-full { width: 100% !important; } +.w-100 { width: 100px !important; } +.w-120 { width: 120px !important; } +.w-130 { width: 130px !important; } +.w-140 { width: 140px !important; } +.w-200 { width: 200px !important; } +.w-300 { width: 300px !important; } +.w-350 { width: 350px !important; } +``` + +### Margin + +Assign `margin` to an element with these shorthand classes. The `@spacer` value is set to 20px by default. + +```css +.m-a-0 { margin: 0 !important; } +.m-t-0 { margin-top: 0 !important; } +.m-r-0 { margin-right: 0 !important; } +.m-b-0 { margin-bottom: 0 !important; } +.m-l-0 { margin-left: 0 !important; } + +.m-a { margin: @spacer !important; } +.m-t { margin-top: @spacer-y !important; } +.m-r { margin-right: @spacer-x !important; } +.m-b { margin-bottom: @spacer-y !important; } +.m-l { margin-left: @spacer-x !important; } +.m-x { margin-right: @spacer-x !important; margin-left: @spacer-x !important; } +.m-y { margin-top: @spacer-y !important; margin-bottom: @spacer-y !important; } +.m-x-auto { margin-right: auto !important; margin-left: auto !important; } + +.m-a-md { margin: (@spacer-y * 1.5) !important; } +.m-t-md { margin-top: (@spacer-y * 1.5) !important; } +.m-r-md { margin-right: (@spacer-y * 1.5) !important; } +.m-b-md { margin-bottom: (@spacer-y * 1.5) !important; } +.m-l-md { margin-left: (@spacer-y * 1.5) !important; } +.m-x-md { margin-right: (@spacer-x * 1.5) !important; margin-left: (@spacer-x * 1.5) !important; } +.m-y-md { margin-top: (@spacer-y * 1.5) !important; margin-bottom: (@spacer-y * 1.5) !important; } + +.m-a-lg { margin: (@spacer-y * 3) !important; } +.m-t-lg { margin-top: (@spacer-y * 3) !important; } +.m-r-lg { margin-right: (@spacer-y * 3) !important; } +.m-b-lg { margin-bottom: (@spacer-y * 3) !important; } +.m-l-lg { margin-left: (@spacer-y * 3) !important; } +.m-x-lg { margin-right: (@spacer-x * 3) !important; margin-left: (@spacer-x * 3) !important; } +.m-y-lg { margin-top: (@spacer-y * 3) !important; margin-bottom: (@spacer-y * 3) !important; } +``` + +### Padding + +Assign `padding` to an element with these shorthand classes. The `@spacer` value is set to 20px by default. + +```css +.p-a-0 { padding: 0 !important; } +.p-t-0 { padding-top: 0 !important; } +.p-r-0 { padding-right: 0 !important; } +.p-b-0 { padding-bottom: 0 !important; } +.p-l-0 { padding-left: 0 !important; } + +.p-a { padding: @spacer !important; } +.p-t { padding-top: @spacer-y !important; } +.p-r { padding-right: @spacer-x !important; } +.p-b { padding-bottom: @spacer-y !important; } +.p-l { padding-left: @spacer-x !important; } +.p-x { padding-right: @spacer-x !important; padding-left: @spacer-x !important; } +.p-y { padding-top: @spacer-y !important; padding-bottom: @spacer-y !important; } + +.p-a-md { padding: (@spacer-y * 1.5) !important; } +.p-t-md { padding-top: (@spacer-y * 1.5) !important; } +.p-r-md { padding-right: (@spacer-y * 1.5) !important; } +.p-b-md { padding-bottom: (@spacer-y * 1.5) !important; } +.p-l-md { padding-left: (@spacer-y * 1.5) !important; } +.p-x-md { padding-right: (@spacer-x * 1.5) !important; padding-left: (@spacer-x * 1.5) !important; } +.p-y-md { padding-top: (@spacer-y * 1.5) !important; padding-bottom: (@spacer-y * 1.5) !important; } + +.p-a-lg { padding: (@spacer-y * 3) !important; } +.p-t-lg { padding-top: (@spacer-y * 3) !important; } +.p-r-lg { padding-right: (@spacer-y * 3) !important; } +.p-b-lg { padding-bottom: (@spacer-y * 3) !important; } +.p-l-lg { padding-left: (@spacer-y * 3) !important; } +.p-x-lg { padding-right: (@spacer-x * 3) !important; padding-left: (@spacer-x * 3) !important; } +.p-y-lg { padding-top: (@spacer-y * 3) !important; padding-bottom: (@spacer-y * 3) !important; } +``` diff --git a/modules/system/assets/ui/font/FontAwesome.otf b/modules/system/assets/ui/font/FontAwesome.otf new file mode 100644 index 0000000..401ec0f Binary files /dev/null and b/modules/system/assets/ui/font/FontAwesome.otf differ diff --git a/modules/system/assets/ui/font/fontawesome-webfont.eot b/modules/system/assets/ui/font/fontawesome-webfont.eot new file mode 100644 index 0000000..e9f60ca Binary files /dev/null and b/modules/system/assets/ui/font/fontawesome-webfont.eot differ diff --git a/modules/system/assets/ui/font/fontawesome-webfont.svg b/modules/system/assets/ui/font/fontawesome-webfont.svg new file mode 100644 index 0000000..855c845 --- /dev/null +++ b/modules/system/assets/ui/font/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/system/assets/ui/font/fontawesome-webfont.ttf b/modules/system/assets/ui/font/fontawesome-webfont.ttf new file mode 100644 index 0000000..35acda2 Binary files /dev/null and b/modules/system/assets/ui/font/fontawesome-webfont.ttf differ diff --git a/modules/system/assets/ui/font/fontawesome-webfont.woff b/modules/system/assets/ui/font/fontawesome-webfont.woff new file mode 100644 index 0000000..400014a Binary files /dev/null and b/modules/system/assets/ui/font/fontawesome-webfont.woff differ diff --git a/modules/system/assets/ui/font/fontawesome-webfont.woff2 b/modules/system/assets/ui/font/fontawesome-webfont.woff2 new file mode 100644 index 0000000..4d13fc6 Binary files /dev/null and b/modules/system/assets/ui/font/fontawesome-webfont.woff2 differ diff --git a/modules/system/assets/ui/images/bitmap-icons.png b/modules/system/assets/ui/images/bitmap-icons.png new file mode 100644 index 0000000..2f09bc0 Binary files /dev/null and b/modules/system/assets/ui/images/bitmap-icons.png differ diff --git a/modules/system/assets/ui/images/loader-transparent.svg b/modules/system/assets/ui/images/loader-transparent.svg new file mode 100644 index 0000000..cf84589 --- /dev/null +++ b/modules/system/assets/ui/images/loader-transparent.svg @@ -0,0 +1,20 @@ + + + +]> + + + + + + + + diff --git a/modules/system/assets/ui/images/loader-white.svg b/modules/system/assets/ui/images/loader-white.svg new file mode 100644 index 0000000..4a0aa7b --- /dev/null +++ b/modules/system/assets/ui/images/loader-white.svg @@ -0,0 +1,20 @@ + + + +]> + + + + + + + + diff --git a/modules/system/assets/ui/images/loader.gif b/modules/system/assets/ui/images/loader.gif new file mode 100644 index 0000000..ad477c3 Binary files /dev/null and b/modules/system/assets/ui/images/loader.gif differ diff --git a/modules/system/assets/ui/images/loader.svg b/modules/system/assets/ui/images/loader.svg new file mode 100644 index 0000000..3b8d4c0 --- /dev/null +++ b/modules/system/assets/ui/images/loader.svg @@ -0,0 +1,19 @@ + + + +]> + + + + + + + + diff --git a/modules/system/assets/ui/images/primary-tab-shape.png b/modules/system/assets/ui/images/primary-tab-shape.png new file mode 100644 index 0000000..339ca4b Binary files /dev/null and b/modules/system/assets/ui/images/primary-tab-shape.png differ diff --git a/modules/system/assets/ui/js/autocomplete.js b/modules/system/assets/ui/js/autocomplete.js new file mode 100644 index 0000000..1203ff4 --- /dev/null +++ b/modules/system/assets/ui/js/autocomplete.js @@ -0,0 +1,421 @@ +/* + * The autcomplete plugin, a forked version of Bootstrap's original typeahead plugin. + * + * Data attributes: + * - data-control="autocomplete" - enables the autocomplete plugin + * + * JavaScript API: + * $('input').autocomplete() + * + * Forked by daftspunk: + * + * - Source can be an object [{ value: 'something', label: 'Something' }, { value: 'else', label: 'Something Else' }] + * - Source can also be { something: 'Something', else: 'Else' } + */ + +!function($){ + + "use strict"; // jshint ;_; + + + /* AUTOCOMPLETE PUBLIC CLASS DEFINITION + * ================================= */ + + var Autocomplete = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.autocomplete.defaults, options) + this.matcher = this.options.matcher || this.matcher + this.sorter = this.options.sorter || this.sorter + this.highlighter = this.options.highlighter || this.highlighter + this.updater = this.options.updater || this.updater + this.source = this.options.source + this.$menu = $(this.options.menu) + this.shown = false + this.listen() + } + + Autocomplete.prototype = { + + constructor: Autocomplete, + + select: function () { + var val = this.$menu.find('.active').attr('data-value') + this.$element + .val(this.updater(val)) + .change() + return this.hide() + }, + + updater: function (item) { + return item + }, + + show: function () { + var offset = this.options.bodyContainer ? this.$element.offset() : this.$element.position(), + pos = $.extend({}, offset, { + height: this.$element[0].offsetHeight + }), + cssOptions = { + top: pos.top + pos.height + , left: pos.left + } + + if (this.options.matchWidth) { + cssOptions.width = this.$element[0].offsetWidth + } + + this.$menu.css(cssOptions) + + if (this.options.bodyContainer) { + $(document.body).append(this.$menu) + } + else { + this.$menu.insertAfter(this.$element) + } + + this.$menu.show() + + this.shown = true + return this + }, + + hide: function () { + this.$menu.hide() + this.shown = false + return this + }, + + lookup: function (event) { + var items + + this.query = this.$element.val() + + if (!this.query || this.query.length < this.options.minLength) { + return this.shown ? this.hide() : this + } + + items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source + + return items ? this.process(items) : this + }, + + itemValue: function (item) { + if (typeof item === 'object') + return item.value; + + return item; + }, + + itemLabel: function (item) { + if (typeof item === 'object') + return item.label; + + return item; + }, + + itemsToArray: function (items) { + var newArray = [] + $.each(items, function(value, label){ + newArray.push({ label: label, value: value }) + }) + return newArray + }, + + process: function (items) { + var that = this + + if (typeof items == 'object') + items = this.itemsToArray(items) + + items = $.grep(items, function (item) { + return that.matcher(item) + }) + + items = this.sorter(items) + + if (!items.length) { + return this.shown ? this.hide() : this + } + + return this.render(items.slice(0, this.options.items)).show() + }, + + matcher: function (item) { + return ~this.itemValue(item).toLowerCase().indexOf(this.query.toLowerCase()) + }, + + sorter: function (items) { + var beginswith = [], + caseSensitive = [], + caseInsensitive = [], + item, + itemValue + + while (item = items.shift()) { + itemValue = this.itemValue(item) + if (!itemValue.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) + else if (~itemValue.indexOf(this.query)) caseSensitive.push(item) + else caseInsensitive.push(item) + } + + return beginswith.concat(caseSensitive, caseInsensitive) + }, + + highlighter: function (item) { + var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&') + return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) { + return '' + match + '' + }) + }, + + render: function (items) { + var that = this + + items = $(items).map(function (i, item) { + i = $(that.options.item).attr('data-value', that.itemValue(item)) + i.find('a').html(that.highlighter(that.itemLabel(item))) + return i[0] + }) + + items.first().addClass('active') + this.$menu.html(items) + return this + }, + + next: function (event) { + var active = this.$menu.find('.active').removeClass('active'), + next = active.next() + + if (!next.length) { + next = $(this.$menu.find('li')[0]) + } + + next.addClass('active') + }, + + prev: function (event) { + var active = this.$menu.find('.active').removeClass('active'), + prev = active.prev() + + if (!prev.length) { + prev = this.$menu.find('li').last() + } + + prev.addClass('active') + }, + + listen: function () { + this.$element + .on('focus.autocomplete', $.proxy(this.focus, this)) + .on('blur.autocomplete', $.proxy(this.blur, this)) + .on('keypress.autocomplete', $.proxy(this.keypress, this)) + .on('keyup.autocomplete', $.proxy(this.keyup, this)) + + if (this.eventSupported('keydown')) { + this.$element.on('keydown.autocomplete', $.proxy(this.keydown, this)) + } + + this.$menu + .on('click.autocomplete', $.proxy(this.click, this)) + .on('mouseenter.autocomplete', 'li', $.proxy(this.mouseenter, this)) + .on('mouseleave.autocomplete', 'li', $.proxy(this.mouseleave, this)) + }, + + eventSupported: function(eventName) { + var isSupported = eventName in this.$element + if (!isSupported) { + this.$element.setAttribute(eventName, 'return;') + isSupported = typeof this.$element[eventName] === 'function' + } + return isSupported + }, + + move: function (e) { + if (!this.shown) return + + switch(e.key) { + case 'Tab': + case 'Enter': + case 'Escape': + e.preventDefault() + break + + case 'ArrowUp': + e.preventDefault() + this.prev() + break + + case 'ArrowDown': + e.preventDefault() + this.next() + break + } + + e.stopPropagation() + }, + + keydown: function (e) { + this.suppressKeyPressRepeat = ~$.inArray(e.key, ['ArrowDown','ArrowUp','Tab','Enter','Escape']) + this.move(e) + }, + + keypress: function (e) { + if (this.suppressKeyPressRepeat) return + this.move(e) + }, + + keyup: function (e) { + switch(e.keyCode) { + case 40: // down arrow + case 38: // up arrow + case 16: // shift + case 17: // ctrl + case 18: // alt + break + + case 9: // tab + case 13: // enter + if (!this.shown) return + this.select() + break + + case 27: // escape + if (!this.shown) return + this.hide() + break + + default: + this.lookup() + } + + e.stopPropagation() + e.preventDefault() + }, + + focus: function (e) { + this.focused = true + }, + + blur: function (e) { + this.focused = false + if (!this.mousedover && this.shown) this.hide() + }, + + click: function (e) { + e.stopPropagation() + e.preventDefault() + this.select() + this.$element.focus() + }, + + mouseenter: function (e) { + this.mousedover = true + this.$menu.find('.active').removeClass('active') + $(e.currentTarget).addClass('active') + }, + + mouseleave: function (e) { + this.mousedover = false + if (!this.focused && this.shown) this.hide() + }, + + destroy: function() { + this.hide() + + this.$element.removeData('autocomplete') + this.$menu.remove() + + this.$element.off('.autocomplete') + this.$menu.off('.autocomplete') + + this.$element = null + this.$menu = null + } + } + + + /* AUTOCOMPLETE PLUGIN DEFINITION + * =========================== */ + + var old = $.fn.autocomplete + + $.fn.autocomplete = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('autocomplete') + , options = typeof option == 'object' && option + if (!data) $this.data('autocomplete', (data = new Autocomplete(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.autocomplete.defaults = { + source: [], + items: 8, + menu: '', + item: '
  • ', + minLength: 1, + bodyContainer: false + } + + $.fn.autocomplete.Constructor = Autocomplete + + + /* AUTOCOMPLETE NO CONFLICT + * =================== */ + + $.fn.autocomplete.noConflict = function () { + $.fn.autocomplete = old + return this + } + + + /* AUTOCOMPLETE DATA-API + * ================== */ + + function paramToObj(name, value) { + if (value === undefined) value = '' + if (typeof value == 'object') return value + + try { + return ocJSON("{" + value + "}") + } + catch (e) { + throw new Error('Error parsing the '+name+' attribute value. '+e) + } + } + + $(document).on('focus.autocomplete.data-api', '[data-control="autocomplete"]', function (e) { + var $this = $(this) + if ($this.data('autocomplete')) return + + var opts = $this.data() + + if (opts.source) { + opts.source = paramToObj('data-source', opts.source) + } + + $this.autocomplete(opts) + }) + +}(window.jQuery); + + +/* ============================================================= + * bootstrap-autocomplete.js v2.3.1 + * http://twitter.github.com/bootstrap/javascript.html#autocomplete + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ diff --git a/modules/system/assets/ui/js/callout.js b/modules/system/assets/ui/js/callout.js new file mode 100644 index 0000000..5756d5d --- /dev/null +++ b/modules/system/assets/ui/js/callout.js @@ -0,0 +1,81 @@ +/* + * Callout + * + * - Documentation: ../docs/callout.md + */ ++function ($) { + 'use strict'; + + // CALLOUT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="callout"]' + var Callout = function (el) { + $(el).on('click', dismiss, this.close) + } + + Callout.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.hasClass('callout') ? $this : $this.parent() + } + + $parent.trigger(e = $.Event('close.oc.callout')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent.trigger('closed.oc.callout').remove() + } + + $.support.transition && $parent.hasClass('fade') + ? $parent + .one($.support.transition.end, removeElement) + .emulateTransitionEnd(500) + : removeElement() + } + + // CALLOUT PLUGIN DEFINITION + // ======================= + + var old = $.fn.callout + + $.fn.callout = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('oc.callout') + + if (!data) $this.data('oc.callout', (data = new Callout(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.callout.Constructor = Callout + + // CALLOUT NO CONFLICT + // ================= + + $.fn.callout.noConflict = function () { + $.fn.callout = old + return this + } + + // CALLOUT DATA-API + // ============== + + $(document).on('click.oc.callout.data-api', dismiss, Callout.prototype.close) + +}(jQuery); diff --git a/modules/system/assets/ui/js/chart.bar.js b/modules/system/assets/ui/js/chart.bar.js new file mode 100644 index 0000000..9ec2fae --- /dev/null +++ b/modules/system/assets/ui/js/chart.bar.js @@ -0,0 +1,138 @@ +/* + * The bar chart plugin. + * + * Data attributes: + * - data-control="chart-bar" - enables the bar chart plugin + * - data-height="200" - optional, height of the graph + * - data-full-width="1" - optional, determines whether the chart should use the full width of the container + * + * JavaScript API: + * $('.scoreboard .chart').barChart() + * + * Dependences: + * - Raphaël (raphael-min.js) + */ ++function ($) { "use strict"; + + var BarChart = function (element, options) { + this.options = options || {} + + var + $el = this.$el = $(element), + size = this.size = $el.height(), + self = this, + values = $.oc.chartUtils.loadListValues($('ul', $el)), + $legend = $.oc.chartUtils.createLegend($('ul', $el)), + indicators = $.oc.chartUtils.initLegendColorIndicators($legend), + isFullWidth = this.isFullWidth(), + chartHeight = this.options.height !== undefined ? this.options.height : size, + chartWidth = isFullWidth ? this.$el.width() : size, + barWidth = (chartWidth - (values.values.length-1)*this.options.gap)/values.values.length + + var $canvas = $('
    ').addClass('canvas').height(chartHeight).width(isFullWidth ? '100%' : chartWidth) + $el.prepend($canvas) + $el.toggleClass('full-width', isFullWidth) + + Raphael($canvas.get(0), isFullWidth ? '100%' : chartWidth, chartHeight, function(){ + self.paper = this + self.bars = this.set() + + self.paper.customAttributes.bar = function (start, height) { + return { + path: [ + ["M", start, chartHeight], + ["L", start, chartHeight-height], + ["L", start + barWidth, chartHeight-height], + ["L", start + barWidth, chartHeight], + ["Z"] + ] + } + } + + // Add bars + var start = 0 + $.each(values.values, function(index, valueInfo) { + var color = valueInfo.color !== undefined ? valueInfo.color : $.oc.chartUtils.getColor(index), + path = self.paper.path().attr({"stroke-width": 0}).attr({bar: [start, 0]}).attr({fill: color}) + + self.bars.push(path) + indicators[index].css('background-color', color) + start += barWidth + self.options.gap + + path.hover(function(ev){ + $.oc.chartUtils.showTooltip(ev.pageX, ev.pageY, + $.trim($.oc.chartUtils.getLegendLabel($legend, index)) + ': '+valueInfo.value+'') + }, function() { + $.oc.chartUtils.hideTooltip() + }) + }) + + // Animate bars + start = 0 + $.each(values.values, function(index, valueInfo) { + var height = (values.max && valueInfo.value) ? chartHeight/values.max * valueInfo.value : 0 + + self.bars[index].animate({bar: [start, height]}, 1000, "bounce") + start += barWidth + self.options.gap + }) + + // Update the full-width chart when the window is redized + if (isFullWidth) { + $(window).on('resize', function(){ + chartWidth = self.$el.width() + barWidth = (chartWidth - (values.values.length-1)*self.options.gap)/values.values.length + + var start = 0 + $.each(values.values, function(index, valueInfo) { + var height = (values.max && valueInfo.value) ? chartHeight/values.max * valueInfo.value : 0 + + self.bars[index].animate({bar: [start, height]}, 10, "bounce") + start += barWidth + self.options.gap + }) + }) + } + }) + } + + BarChart.prototype.isFullWidth = function() { + return this.options.fullWidth !== undefined && this.options.fullWidth + } + + BarChart.DEFAULTS = { + gap: 2 + } + + // BARCHART PLUGIN DEFINITION + // ============================ + + var old = $.fn.barChart + + $.fn.barChart = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('oc.barChart') + var options = $.extend({}, BarChart.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) + $this.data('oc.barChart', new BarChart(this, options)) + }) + } + + $.fn.barChart.Constructor = BarChart + + // BARCHART NO CONFLICT + // ================= + + $.fn.barChart.noConflict = function () { + $.fn.barChart = old + return this + } + + // BARCHART DATA-API + // =============== + + $(document).render(function () { + $('[data-control=chart-bar]').barChart() + }) + +}(window.jQuery) diff --git a/modules/system/assets/ui/js/chart.line.js b/modules/system/assets/ui/js/chart.line.js new file mode 100644 index 0000000..208b0e5 --- /dev/null +++ b/modules/system/assets/ui/js/chart.line.js @@ -0,0 +1,235 @@ +/* + * Line Chart Plugin + * + * Data attributes: + * - data-control="chart-line" - enables the line chart plugin + * - data-reset-zoom-link="#reset-zoom" - specifies a link to reset zoom + * - data-zoomable - indicates that the chart is zoomable + * - data-time-mode="weeks" - if the "weeks" value is specified and the xaxis mode is "time", the X axis labels will be displayed as week end dates. + * - data-chart-options="xaxis: {mode: 'time'}" - specifies the Flot configuration in JSON format. See https://github.com/flot/flot/blob/master/API.md for details. + * + * Data sets are defined with the SPAN elements inside the chart element: + * Data set elements could contain data attributes with names in the format "data-set-color". The names for the data set + * attributes are described in the Flot documentation: https://github.com/flot/flot/blob/master/API.md#data-format + * + * JavaScript API: + * $('.chart').chartLine({ resetZoomLink:'#reset-zoom' }) + * + * Dependences: + * - Flot (jquery.flot.js) + * - Flot Tooltip (jquery.flot.tooltip.js) + * - Flot Resize (jquery.flot.resize.js) + * - Flot Time (jquery.flot.time.js) + */ + ++function ($) { "use strict"; + + // LINE CHART CLASS DEFINITION + // ============================ + + var ChartLine = function(element, options) { + var self = this + + /* + * Flot options + */ + this.chartOptions = { + xaxis: { + mode: "time", + tickLength: 5 + }, + selection: { mode: "x" }, + grid: { + markingsColor: "rgba(0,0,0, 0.02)", + backgroundColor: { colors: ["#fff", "#fff"] }, + borderColor: "#7bafcc", + borderWidth: 0, + color: "#ddd", + hoverable: true, + clickable: true, + labelMargin: 10 + }, + series: { + lines: { + show: true, + fill: true + }, + points: { + show: true + } + }, + tooltip: true, + tooltipOpts: { + defaultTheme: false, + content: "%x: %y", + dateFormat: "%y-%0m-%0d", + shifts: { + x: 10, + y: 20 + } + }, + legend: { + show: true, + noColumns: 2 + } + } + + this.defaultDataSetOptions = { + shadowSize: 0 + } + + var parsedOptions = {} + try { + parsedOptions = ocJSON("{" + options.chartOptions + "}"); + } catch (e) { + throw new Error('Error parsing the data-chart-options attribute value. '+e); + } + + this.chartOptions = $.extend({}, this.chartOptions, parsedOptions) + + this.options = options + this.$el = $(element) + this.fullDataSet = [] + this.resetZoomLink = $(options.resetZoomLink) + + this.$el.trigger('oc.chartLineInit', [this]) + + /* + * Bind Events + */ + + this.resetZoomLink.on('click', $.proxy(this.clearZoom, this)); + + if (this.options.zoomable) { + this.$el.on("plotselected", function (event, ranges) { + var newCoords = { + xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to } + } + + $.plot(self.$el, self.fullDataSet, $.extend(true, {}, self.chartOptions, newCoords)) + self.resetZoomLink.show() + }); + } + + /* + * Markings Helper + */ + + if (this.chartOptions.xaxis.mode == "time" && this.options.timeMode == "weeks") + this.chartOptions.markings = weekendAreas + + function weekendAreas(axes) { + var markings = [], + d = new Date(axes.xaxis.min); + + // Go to the first Saturday + d.setUTCDate(d.getUTCDate() - ((d.getUTCDay() + 1) % 7)) + d.setUTCSeconds(0) + d.setUTCMinutes(0) + d.setUTCHours(0) + var i = d.getTime() + + do { + // When we don't set yaxis, the rectangle automatically + // extends to infinity upwards and downwards + markings.push({ xaxis: { from: i, to: i + 2 * 24 * 60 * 60 * 1000 } }) + i += 7 * 24 * 60 * 60 * 1000 + } while (i < axes.xaxis.max) + + return markings + } + + /* + * Process the datasets + */ + + this.initializing = true + + this.$el.find('>[data-chart="dataset"]').each(function(){ + var data = $(this).data(), + processedData = {}; + + for (var key in data) { + var normalizedKey = key.substring(3), + value = data[key]; + + normalizedKey = normalizedKey.charAt(0).toLowerCase() + normalizedKey.slice(1); + if (normalizedKey == 'data') + value = JSON.parse('['+value+']'); + + processedData[normalizedKey] = value; + } + + self.addDataSet($.extend({}, self.defaultDataSetOptions, processedData)); + }) + + /* + * Build chart + */ + + this.initializing = false + this.rebuildChart() + } + + ChartLine.DEFAULTS = { + chartOptions: "", + timeMode: null, + zoomable: false + } + + /* + * Adds a data set to the chart. + * See https://github.com/flot/flot/blob/master/API.md#data-format for the list + * of supported data set options. + */ + ChartLine.prototype.addDataSet = function (dataSet) { + this.fullDataSet.push(dataSet) + + if (!this.initializing) + this.rebuildChart() + } + + ChartLine.prototype.rebuildChart = function() { + this.$el.trigger('oc.beforeChartLineRender', [this]) + + $.plot(this.$el, this.fullDataSet, this.chartOptions) + } + + ChartLine.prototype.clearZoom = function() { + this.rebuildChart() + this.resetZoomLink.hide() + } + + // LINE CHART PLUGIN DEFINITION + // ============================ + + var old = $.fn.chartLine + + $.fn.chartLine = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('october.chartLine') + var options = $.extend({}, ChartLine.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('october.chartLine', (data = new ChartLine(this, options))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.chartLine.Constructor = ChartLine + + // LINE CHART NO CONFLICT + // ================= + + $.fn.chartLine.noConflict = function () { + $.fn.chartLine = old + return this + } + + + // LINE CHART DATA-API + // =============== + $(document).render(function () { + $('[data-control="chart-line"]').chartLine() + }) + +}(window.jQuery); diff --git a/modules/system/assets/ui/js/chart.meter.js b/modules/system/assets/ui/js/chart.meter.js new file mode 100644 index 0000000..cb78162 --- /dev/null +++ b/modules/system/assets/ui/js/chart.meter.js @@ -0,0 +1,77 @@ +/* + * The goal meter plugin. + * + * Applies the goal meter style to a scoreboard item. + * + * Data attributes: + * - data-control="goal-meter" - enables the goal meter plugin + * - data-value - sets the value, in percents + * + * JavaScript API: + * $('.scoreboard .goal-meter').goalMeter({value: 20}) + * $('.scoreboard .goal-meter').goalMeter(10) // Sets the current value + */ ++function ($) { "use strict"; + + var GoalMeter = function (element, options) { + var + $el = this.$el = $(element), + self = this; + + this.options = options || {}; + + this.$indicatorBar = $('').text(this.options.value + '%') + this.$indicatorOuter = $('').addClass('goal-meter-indicator').append(this.$indicatorBar) + + $('p', this.$el).first().before(this.$indicatorOuter) + + window.setTimeout(function(){ + self.update(self.options.value) + }, 200) + } + + GoalMeter.prototype.update = function(value) { + this.$indicatorBar.css('height', value + '%') + } + + GoalMeter.DEFAULTS = { + value: 50 + } + + // GOALMETER PLUGIN DEFINITION + // ============================ + + var old = $.fn.goalMeter + + $.fn.goalMeter = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('oc.goalMeter') + var options = $.extend({}, GoalMeter.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) + $this.data('oc.goalMeter', (data = new GoalMeter(this, options))) + else + data.update(option) + }) + } + + $.fn.goalMeter.Constructor = GoalMeter + + // GOALMETER NO CONFLICT + // ================= + + $.fn.goalMeter.noConflict = function () { + $.fn.goalMeter = old + return this + } + + // GOALMETER DATA-API + // =============== + + + $(document).render(function () { + $('[data-control=goal-meter]').goalMeter() + }) + +}(window.jQuery); \ No newline at end of file diff --git a/modules/system/assets/ui/js/chart.pie.js b/modules/system/assets/ui/js/chart.pie.js new file mode 100644 index 0000000..b478cef --- /dev/null +++ b/modules/system/assets/ui/js/chart.pie.js @@ -0,0 +1,141 @@ +/* + * The pie chart plugin. + * + * Data attributes: + * - data-control="chart-pie" - enables the pie chart plugin + * - data-size="200" - optional, size of the graph + * - data-center-text - text to display inside the graph + * + * JavaScript API: + * $('.scoreboard .chart').pieChart() + * + * Dependences: + * - Raphaël (raphael-min.js) + * - October chart utilities (chart.utils.js) + */ ++function ($) { "use strict"; + + var PieChart = function (element, options) { + this.options = options || {} + + var + $el = this.$el = $(element), + size = this.size = (this.options.size !== undefined ? this.options.size : $el.height()), + outerRadius = size/2 - 1, + innerRadius = outerRadius - outerRadius/3.5, + values = $.oc.chartUtils.loadListValues($('ul', $el)), + $legend = $.oc.chartUtils.createLegend($('ul', $el)), + indicators = $.oc.chartUtils.initLegendColorIndicators($legend), + self = this + + var $canvas = $('
    ').addClass('canvas').width(size).height(size) + $el.prepend($canvas) + + Raphael($canvas.get(0), size, size, function(){ + self.paper = this + self.segments = this.set() + + self.paper.customAttributes.segment = function (startAngle, endAngle) { + var + p1 = self.arcCoords(outerRadius, startAngle), + p2 = self.arcCoords(outerRadius, endAngle), + p3 = self.arcCoords(innerRadius, endAngle), + p4 = self.arcCoords(innerRadius, startAngle), + flag = (endAngle - startAngle) > 180, + path = [ + ["M", p1.x, p1.y], + ["A", outerRadius, outerRadius, 0, +flag, 0, p2.x, p2.y], + ["L", p3.x, p3.y], + ["A", innerRadius, innerRadius, 0, +flag, 1, p4.x, p4.y], + ["Z"] + ] + + return {path: path} + } + + // Draw the background + self.paper.circle(size/2, size/2, innerRadius + (outerRadius - innerRadius)/2) + .attr({"stroke-width": outerRadius - innerRadius - 0.5}) + .attr({stroke: $.oc.chartUtils.defaultValueColor}) + + // Add segments + $.each(values.values, function(index, valueInfo) { + var color = valueInfo.color !== undefined ? valueInfo.color : $.oc.chartUtils.getColor(index), + path = self.paper.path().attr({"stroke-width": 0}).attr({segment: [0, 0]}).attr({fill: color}) + + self.segments.push(path) + indicators[index].css('background-color', color) + + path.hover(function(ev){ + $.oc.chartUtils.showTooltip(ev.pageX, ev.pageY, + $.trim($.oc.chartUtils.getLegendLabel($legend, index)) + ': '+valueInfo.value+'') + }, function() { + $.oc.chartUtils.hideTooltip() + }) + }) + + // Animate segments + var start = self.options.startAngle + $.each(values.values, function(index, valueInfo) { + var length = (values.total && valueInfo.value) ? 360/values.total * valueInfo.value : 0 + if (length == 360) + length-- + + self.segments[index].animate({segment: [start, start + length]}, 1000, "bounce") + start += length + }) + }) + + if (this.options.centerText !== undefined) { + var $text = $('').addClass('center').html(this.options.centerText) + $canvas.append($text) + } + } + + PieChart.prototype.arcCoords = function(radius, angle) { + var + a = Raphael.rad(angle), + x = this.size/2 + radius * Math.cos(a), + y = this.size/2 - radius * Math.sin(a) + + return {'x': x, 'y': y} + } + + PieChart.DEFAULTS = { + startAngle: 45 + } + + // PIECHART PLUGIN DEFINITION + // ============================ + + var old = $.fn.pieChart + + $.fn.pieChart = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('oc.pieChart') + var options = $.extend({}, PieChart.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) + $this.data('oc.pieChart', new PieChart(this, options)) + }) + } + + $.fn.pieChart.Constructor = PieChart + + // PIECHART NO CONFLICT + // ================= + + $.fn.pieChart.noConflict = function () { + $.fn.pieChart = old + return this + } + + // PIECHART DATA-API + // =============== + + $(document).render(function () { + $('[data-control=chart-pie]').pieChart() + }) + +}(window.jQuery) \ No newline at end of file diff --git a/modules/system/assets/ui/js/chart.utils.js b/modules/system/assets/ui/js/chart.utils.js new file mode 100644 index 0000000..36d869b --- /dev/null +++ b/modules/system/assets/ui/js/chart.utils.js @@ -0,0 +1,112 @@ +/* + * October charting utilities. + */ + ++function ($) { "use strict"; + + var ChartUtils = function() {} + + ChartUtils.prototype.defaultValueColor = '#b8b8b8'; + + ChartUtils.prototype.getColor = function(index) { + var + colors = [ + '#95b753', '#cc3300', '#e5a91a', '#3366ff', '#ff0f00', '#ff6600', + '#ff9e01', '#fcd202', '#f8ff01', '#b0de09', '#04d215', '#0d8ecf', '#0d52d1', + '#2a0cd0', '#8a0ccf', '#cd0d74', '#754deb', '#dddddd', '#999999', '#333333', + '#000000', '#57032a', '#ca9726', '#990000', '#4b0c25' + ], + colorIndex = index % (colors.length-1); + + return colors[colorIndex]; + } + + ChartUtils.prototype.loadListValues = function($list) { + var result = { + values: [], + total: 0, + max: 0 + } + + $('> li', $list).each(function(){ + var value = $(this).data('value') + ? parseFloat($(this).data('value')) + : parseFloat($('span', this).text()); + result.total += value + result.values.push({value: value, color: $(this).data('color')}) + result.max = Math.max(result.max, value) + }) + + return result; + } + + ChartUtils.prototype.getLegendLabel = function($legend, index) { + return $('tr:eq('+index+') td:eq(1)', $legend).html(); + } + + ChartUtils.prototype.initLegendColorIndicators = function($legend) { + var indicators = []; + + $('tr > td:first-child', $legend).each(function(){ + var indicator = $('') + $(this).prepend(indicator) + indicators.push(indicator) + }) + + return indicators; + } + + ChartUtils.prototype.createLegend = function($list) { + var + $legend = $('
    ').addClass('chart-legend'), + $table = $('') + + $legend.append($table) + + $('> li', $list).each(function(){ + var label = $(this).clone().children().remove().end().html(); + + $table.append( + $('') + .append($('');rowStarted=true;} +fragments.push(''+'');} +if(rowStarted) +fragments.push('');if(fragments.length==0) +return;var table='
    ')) + .append($('').html(label)) + .append($('').addClass('value').html($('span', this).html())) + ) + }) + + $legend.insertAfter($list) + $list.remove() + + return $legend; + } + + ChartUtils.prototype.showTooltip = function(x, y, text) { + var $tooltip = $('#chart-tooltip') + + if ($tooltip.length) + $tooltip.remove() + + $tooltip = $('
    ') + .html(text) + .css('visibility', 'hidden') + + x += 10 + y += 10 + + $(document.body).append($tooltip) + var tooltipWidth = $tooltip.outerWidth() + if ((x + tooltipWidth) > $(window).width()) + x = $(window).width() - tooltipWidth - 10; + + $tooltip.css({top: y, left: x, visibility: 'visible'}); + } + + ChartUtils.prototype.hideTooltip = function() { + $('#chart-tooltip').remove() + } + + if ($.oc === undefined) + $.oc = {} + + $.oc.chartUtils = new ChartUtils(); +}(window.jQuery); diff --git a/modules/system/assets/ui/js/checkbox.balloon.js b/modules/system/assets/ui/js/checkbox.balloon.js new file mode 100644 index 0000000..57bd495 --- /dev/null +++ b/modules/system/assets/ui/js/checkbox.balloon.js @@ -0,0 +1,67 @@ +/* + * Balloon selector control. + * + * Data attributes: + * - data-control="balloon-selector" - enables the plugin + * + */ ++function ($) { "use strict"; + + var BalloonSelector = function (element, options) { + + this.$el = $(element) + this.$field = $('input', this.$el) + + this.options = options || {}; + + var self = this; + $('li', this.$el).click(function(){ + if (self.$el.hasClass('control-disabled')) { + return + } + + $('li', self.$el).removeClass('active') + + $(this).addClass('active') + + self.$field + .val($(this).data('value')) + .trigger('change') + }) + } + + BalloonSelector.DEFAULTS = {} + + // BALLOON SELECTOR PLUGIN DEFINITION + // =================================== + + var old = $.fn.balloonSelector + + $.fn.balloonSelector = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('oc.balloon-selector') + var options = $.extend({}, BalloonSelector.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) $this.data('oc.balloon-selector', (data = new BalloonSelector(this, options))) + }) + } + + $.fn.balloonSelector.Constructor = BalloonSelector + + // BALLOON SELECTOR NO CONFLICT + // =================================== + + $.fn.balloonSelector.noConflict = function () { + $.fn.balloonSelector = old + return this + } + + // BALLOON SELECTOR DATA-API + // =================================== + + $(document).on('render', function(){ + $('div[data-control=balloon-selector]').balloonSelector() + }) + +}(window.jQuery); \ No newline at end of file diff --git a/modules/system/assets/ui/js/checkbox.js b/modules/system/assets/ui/js/checkbox.js new file mode 100644 index 0000000..fc61d6f --- /dev/null +++ b/modules/system/assets/ui/js/checkbox.js @@ -0,0 +1,86 @@ +/* + * Checkbox control + * + */ + +(function($) { + + $(document).on('keypress', 'div.custom-checkbox', function(e) { + if (e.key === '(Space character)' || e.key === 'Spacebar' || e.key === ' ') { + var $cb = $('input[type=checkbox]', this) + + if ($cb.data('oc-space-timestamp') == e.timeStamp) + return + + $cb.get(0).checked = !$cb.get(0).checked + $cb.data('oc-space-timestamp', e.timeStamp) + $cb.trigger('change') + return false + } + }) + + // + // Intermediate checkboxes + // + + $(document).render(function() { + $('div.custom-checkbox.is-indeterminate > input').each(function() { + var $el = $(this), + checked = $el.data('checked') + + switch (checked) { + + // Unchecked + case 1: + $el.prop('indeterminate', true) + break + + // Checked + case 2: + $el.prop('indeterminate', false) + $el.prop('checked', true) + break + + // Unchecked + default: + $el.prop('indeterminate', false) + $el.prop('checked', false) + } + }) + }) + + $(document).on('click', 'div.custom-checkbox.is-indeterminate > label', function() { + var $el = $(this).parent().find('input:first'), + checked = $el.data('checked') + + if (checked === undefined) { + checked = $el.is(':checked') ? 1 : 0 + } + + switch (checked) { + + // Unchecked, going indeterminate + case 0: + $el.data('checked', 1) + $el.prop('indeterminate', true) + break + + // Indeterminate, going checked + case 1: + $el.data('checked', 2) + $el.prop('indeterminate', false) + $el.prop('checked', true) + break + + // Checked, going unchecked + default: + $el.data('checked', 0) + $el.prop('indeterminate', false) + $el.prop('checked', false) + } + + $el.trigger('change') + return false + }) + +})(jQuery); diff --git a/modules/system/assets/ui/js/datepicker.js b/modules/system/assets/ui/js/datepicker.js new file mode 100644 index 0000000..d840f01 --- /dev/null +++ b/modules/system/assets/ui/js/datepicker.js @@ -0,0 +1,359 @@ +/* + * DatePicker plugin + * + * - Documentation: ../docs/datepicker.md + * + * Dependences: + * - Pikaday plugin (pikaday.js) + * - Pikaday jQuery addon (pikaday.jquery.js) + * - Clockpicker plugin (jquery-clockpicker.js) + * - Moment library (moment.js) + * - Moment Timezone library (moment.timezone.js) + */ + ++function ($) { "use strict"; + + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var DatePicker = function (element, options) { + this.$el = $(element) + this.options = options || {} + + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + this.init() + } + + DatePicker.prototype = Object.create(BaseProto) + DatePicker.prototype.constructor = DatePicker + + DatePicker.prototype.init = function() { + var self = this, + $form = this.$el.closest('form'), + changeMonitor = $form.data('oc.changeMonitor') + + if (changeMonitor !== undefined) { + changeMonitor.pause() + } + + this.dbDateTimeFormat = 'YYYY-MM-DD HH:mm:ss' + this.dbDateFormat = 'YYYY-MM-DD' + this.dbTimeFormat = 'HH:mm:ss' + + this.$dataLocker = $('[data-datetime-value]', this.$el) + this.$datePicker = $('[data-datepicker]', this.$el) + this.$timePicker = $('[data-timepicker]', this.$el) + this.hasDate = !!this.$datePicker.length + this.hasTime = !!this.$timePicker.length + this.ignoreTimezone = this.$el.get(0).hasAttribute('data-ignore-timezone') + + this.initRegion() + + if (this.hasDate) { + this.initDatePicker() + } + + if (this.hasTime) { + this.initTimePicker() + } + + if (changeMonitor !== undefined) { + changeMonitor.resume() + } + + this.$timePicker.on('change.oc.datepicker', function() { + if (!$.trim($(this).val())) { + self.emptyValues() + } + else { + self.onSelectTimePicker() + } + }) + + this.$datePicker.on('change.oc.datepicker', function() { + if (!$.trim($(this).val())) { + self.emptyValues() + } + }) + + this.$el.one('dispose-control', this.proxy(this.dispose)) + } + + DatePicker.prototype.dispose = function() { + this.$timePicker.off('change.oc.datepicker') + this.$datePicker.off('change.oc.datepicker') + this.$el.off('dispose-control', this.proxy(this.dispose)) + this.$el.removeData('oc.datePicker') + + this.$el = null + this.options = null + + BaseProto.dispose.call(this) + } + + // + // Datepicker + // + + DatePicker.prototype.initDatePicker = function() { + var self = this, + dateFormat = this.getDateFormat(), + now = moment().tz(this.timezone).format(dateFormat) + + var pikadayOptions = { + yearRange: this.options.yearRange, + firstDay: this.options.firstDay, + showWeekNumber: this.options.showWeekNumber, + format: dateFormat, + setDefaultDate: now, + onOpen: function() { + var $field = $(this._o.trigger) + + $(this.el).css({ + left: 'auto', + right: $(window).width() - $field.offset().left - $field.outerWidth() + }) + }, + onSelect: function() { + self.onSelectDatePicker.call(self, this.getMoment()) + } + } + + var lang = this.getLang('datepicker', false) + if (lang) { + pikadayOptions.i18n = lang + } + + this.$datePicker.val(this.getDataLockerValue(dateFormat)) + + if (this.options.minDate) { + pikadayOptions.minDate = new Date(this.options.minDate) + } + + if (this.options.maxDate) { + pikadayOptions.maxDate = new Date(this.options.maxDate) + } + + this.$datePicker.pikaday(pikadayOptions) + } + + DatePicker.prototype.onSelectDatePicker = function(pickerMoment) { + var pickerValue = pickerMoment.format(this.dbDateFormat) + + var timeValue = this.options.mode === 'date' ? '00:00:00' : this.getTimePickerValue() + + var momentObj = moment + .tz(pickerValue + ' ' + timeValue, this.dbDateTimeFormat, this.timezone) + .tz(this.appTimezone) + + var lockerValue = momentObj.format(this.dbDateTimeFormat) + + this.$dataLocker.val(lockerValue) + } + + // Returns in user preference timezone + DatePicker.prototype.getDatePickerValue = function() { + var value = this.$datePicker.val() + + if (!this.hasDate || !value) { + return moment.tz(this.appTimezone) + .tz(this.timezone) + .format(this.dbDateFormat) + } + + return moment(value, this.getDateFormat()).format(this.dbDateFormat) + } + + DatePicker.prototype.getDateFormat = function() { + var format = 'YYYY-MM-DD' + + if (this.options.format) { + format = this.options.format + } + else if (this.locale) { + format = moment() + .locale(this.locale) + .localeData() + .longDateFormat('l') + } + + return format + } + + // + // Timepicker + // + + DatePicker.prototype.initTimePicker = function() { + this.$timePicker.clockpicker({ + autoclose: 'true', + placement: 'auto', + align: 'right', + twelvehour: this.isTimeTwelveHour(), + afterDone: this.proxy(this.onChangeTimePicker) + }) + + this.$timePicker.val(this.getDataLockerValue(this.getTimeFormat())) + } + + DatePicker.prototype.onSelectTimePicker = function() { + var pickerValue = this.$timePicker.val() + + var timeValue = moment(pickerValue, this.getTimeFormat()).format(this.dbTimeFormat) + + var dateValue = this.getDatePickerValue() + + var momentObj = moment + .tz(dateValue + ' ' + timeValue, this.dbDateTimeFormat, this.timezone) + .tz(this.appTimezone) + + var lockerValue = momentObj.format(this.dbDateTimeFormat) + + this.$dataLocker.val(lockerValue) + } + + DatePicker.prototype.onChangeTimePicker = function() { + // Trigger a change event when the time is changed, to allow dependent fields to refresh + this.$timePicker.trigger('change') + } + + // Returns in user preference timezone + DatePicker.prototype.getTimePickerValue = function() { + var value = this.$timePicker.val() + + if (!this.hasTime || !value) { + return moment.tz(this.appTimezone) + .tz(this.timezone) + .format(this.dbTimeFormat) + } + + return moment(value, this.getTimeFormat()).format(this.dbTimeFormat) + } + + DatePicker.prototype.getTimeFormat = function() { + return this.isTimeTwelveHour() + ? 'hh:mm A' + : 'HH:mm' + } + + DatePicker.prototype.isTimeTwelveHour = function() { + return false + + // Disabled for now: The analog clock design is pretty good + // at representing time regardless of the format. If we want + // to enable this, there should be some way to disable it + // again via the form field options. + + // var momentObj = moment() + + // if (this.locale) { + // momentObj = momentObj.locale(this.locale) + // } + + // return momentObj + // .localeData() + // .longDateFormat('LT') + // .indexOf('A') !== -1; + } + + // + // Utilities + // + + DatePicker.prototype.emptyValues = function() { + this.$dataLocker.val('') + this.$datePicker.val('') + this.$timePicker.val('') + } + + DatePicker.prototype.getDataLockerValue = function(format) { + var value = this.$dataLocker.val() + + return value + ? this.getMomentLoadValue(value, format) + : null + } + + DatePicker.prototype.getMomentLoadValue = function(value, format) { + var momentObj = moment.tz(value, this.appTimezone) + + if (this.locale) { + momentObj = momentObj.locale(this.locale) + } + + momentObj = momentObj.tz(this.timezone) + + return momentObj.format(format) + } + + DatePicker.prototype.initRegion = function() { + this.locale = $('meta[name="backend-locale"]').attr('content') + this.timezone = $('meta[name="backend-timezone"]').attr('content') + this.appTimezone = $('meta[name="app-timezone"]').attr('content') + + if (!this.appTimezone) { + this.appTimezone = 'UTC' + } + + if (!this.timezone) { + this.timezone = 'UTC' + } + + // Set both timezones to UTC to disable converting between them + if (this.ignoreTimezone) { + this.appTimezone = 'UTC' + this.timezone = 'UTC' + } + } + + DatePicker.prototype.getLang = function(name, defaultValue) { + if ($.oc === undefined || $.oc.lang === undefined) { + return defaultValue + } + + return $.oc.lang.get(name, defaultValue) + } + + DatePicker.DEFAULTS = { + minDate: null, + maxDate: null, + format: null, + yearRange: 10, + firstDay: 0, + showWeekNumber: false, + mode: 'datetime' + } + + // PLUGIN DEFINITION + // ============================ + + var old = $.fn.datePicker + + $.fn.datePicker = function (option) { + var args = Array.prototype.slice.call(arguments, 1), items, result + + items = this.each(function () { + var $this = $(this) + var data = $this.data('oc.datePicker') + var options = $.extend({}, DatePicker.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.datePicker', (data = new DatePicker(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : items + } + + $.fn.datePicker.Constructor = DatePicker + + $.fn.datePicker.noConflict = function () { + $.fn.datePicker = old + return this + } + + $(document).on('render', function() { + $('[data-control="datepicker"]').datePicker() + }); + +}(window.jQuery); diff --git a/modules/system/assets/ui/js/drag.scroll.js b/modules/system/assets/ui/js/drag.scroll.js new file mode 100644 index 0000000..bcade23 --- /dev/null +++ b/modules/system/assets/ui/js/drag.scroll.js @@ -0,0 +1,445 @@ +/* + * Allows to scroll an element content in the horizontal or horizontal directions. This script doesn't use + * absolute positioning and rely on the scrollLeft/scrollTop DHTML properties. The element width should be + * fixed with the CSS or JavaScript. + * + * Events triggered on the element: + * - start.oc.dragScroll + * - drag.oc.dragScroll + * - stop.oc.dragScroll + * + * Options: + * - start - callback function to execute when the drag starts + * - drag - callback function to execute when the element is dragged + * - stop - callback function to execute when the drag ends + * - vertical - determines if the scroll direction is vertical, true by default + * - scrollClassContainer - if specified, specifies an element or element selector to apply the 'scroll-before' and 'scroll-after' CSS classes, + * depending on whether the scrollable area is in its start or end + * - scrollMarkerContainer - if specified, specifies an element or element selector to inject scroll markers (span elements that con + * contain the ellipses icon, indicating whether scrolling is possible) + * - useDrag - determines if dragging is allowed support, true by default + * - useNative - if native CSS is enabled via "mobile" on the HTML tag, false by default + * - useScroll - determines if the mouse wheel scrolling is allowed, true by default + * - useComboScroll - determines if horizontal scroll should act as vertical, and vice versa, true by default + * - dragSelector - restrict drag events to this selector + * - scrollSelector - restrict scroll events to this selector + * + * Methods: + * - isStart - determines if the scrollable area is in its start (left or top) + * - isEnd - determines if the scrollable area is in its end (right or bottom) + * - goToStart - moves the scrollable area to the start (left or top) + * - goToElement - moves the scrollable area to an element + * + * Require: + * - modernizr/modernizr + * - mousewheel/mousewheel + */ ++function ($) { "use strict"; + + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var DragScroll = function (element, options) { + this.options = $.extend({}, DragScroll.DEFAULTS, options) + + var + $el = $(element), + el = $el.get(0), + dragStart = 0, + startOffset = 0, + self = this, + dragging = false, + eventElementName = this.options.vertical ? 'pageY' : 'pageX', + isNative = this.options.useNative && $('html').hasClass('mobile'); + + this.el = $el + this.scrollClassContainer = this.options.scrollClassContainer ? $(this.options.scrollClassContainer) : $el + this.isScrollable = true + + Base.call(this) + + /* + * Inject scroll markers + */ + if (this.options.scrollMarkerContainer) { + $(this.options.scrollMarkerContainer) + .append($('')) + } + + /* + * Bind events + */ + var $scrollSelect = this.options.scrollSelector ? $(this.options.scrollSelector, $el) : $el + + $scrollSelect.mousewheel(function(event){ + if (!self.options.useScroll) { + return; + } + + var offset, + offsetX = event.deltaFactor * event.deltaX, + offsetY = event.deltaFactor * event.deltaY + + if (!offsetX && self.options.useComboScroll) { + offset = offsetY * -1 + } + else if (!offsetY && self.options.useComboScroll) { + offset = offsetX + } + else { + offset = self.options.vertical ? (offsetY * -1) : offsetX + } + + return !scrollWheel(offset) + }) + + if (this.options.useDrag) { + $el.on('mousedown.dragScroll', this.options.dragSelector, function(event){ + if (event.target && event.target.tagName === 'INPUT') { + return // Don't prevent clicking inputs in the toolbar + } + + if (!self.isScrollable) { + return + } + + startDrag(event) + return false + }) + } + + if (Modernizr.touchevents) { + $el.on('touchstart.dragScroll', this.options.dragSelector, function(event){ + var touchEvent = event.originalEvent + if (touchEvent.touches.length == 1) { + startDrag(touchEvent.touches[0]) + event.stopPropagation() + } + }) + } + + $el.on('click.dragScroll', function() { + // Do not handle item clicks while dragging + if ($(document.body).hasClass(self.options.dragClass)) { + return false + } + }) + + $(document).on('ready', this.proxy(this.fixScrollClasses)) + $(window).on('resize', this.proxy(this.fixScrollClasses)) + + /* + * Internal event, drag has started + */ + function startDrag(event) { + dragStart = event[eventElementName] + startOffset = self.options.vertical ? $el.scrollTop() : $el.scrollLeft() + + if (Modernizr.touchevents) { + $(window).on('touchmove.dragScroll', function(event) { + var touchEvent = event.originalEvent + moveDrag(touchEvent.touches[0]) + if (!isNative) { + event.preventDefault() + } + }) + + $(window).on('touchend.dragScroll', function(event) { + stopDrag() + }) + } + + $(window).on('mousemove.dragScroll', function(event) { + moveDrag(event) + return false + }) + + $(window).on('mouseup.dragScroll', function(mouseUpEvent) { + var isClick = event.pageX == mouseUpEvent.pageX && event.pageY == mouseUpEvent.pageY + stopDrag(isClick) + return false + }) + } + + /* + * Internal event, drag is active + */ + function moveDrag(event) { + var current = event[eventElementName], + offset = dragStart - current + + if (Math.abs(offset) > 3) { + if (!dragging) { + dragging = true + $el.trigger('start.oc.dragScroll') + self.options.start() + $(document.body).addClass(self.options.dragClass) + } + + if (!isNative) { + self.options.vertical + ? $el.scrollTop(startOffset + offset) + : $el.scrollLeft(startOffset + offset) + } + + $el.trigger('drag.oc.dragScroll') + self.options.drag() + } + } + + /* + * Internal event, drag has ended + */ + function stopDrag(click) { + $(window).off('.dragScroll') + + dragging = false; + + if (click) { + $(document.body).removeClass(self.options.dragClass) + } + else { + self.fixScrollClasses() + } + + window.setTimeout(function(){ + if (!click) { + $(document.body).removeClass(self.options.dragClass) + $el.trigger('stop.oc.dragScroll') + self.options.stop() + self.fixScrollClasses() + } + }, 100) + } + + /* + * Scroll wheel has moved by supplied offset + */ + function scrollWheel(offset) { + startOffset = self.options.vertical ? el.scrollTop : el.scrollLeft + + self.options.vertical + ? $el.scrollTop(startOffset + offset) + : $el.scrollLeft(startOffset + offset) + + var scrolled = self.options.vertical + ? el.scrollTop != startOffset + : el.scrollLeft != startOffset + + $el.trigger('drag.oc.dragScroll') + self.options.drag() + + if (scrolled) { + if (self.wheelUpdateTimer !== undefined && self.wheelUpdateTimer !== false) + window.clearInterval(self.wheelUpdateTimer); + + self.wheelUpdateTimer = window.setTimeout(function() { + self.wheelUpdateTimer = false; + self.fixScrollClasses() + }, 100); + } + + return scrolled + } + + this.fixScrollClasses(); + } + + DragScroll.prototype = Object.create(BaseProto) + DragScroll.prototype.constructor = DragScroll + + DragScroll.DEFAULTS = { + vertical: false, + useDrag: true, + useScroll: true, + useNative: false, + useComboScroll: true, + scrollClassContainer: false, + scrollMarkerContainer: false, + scrollSelector: null, + dragSelector: null, + dragClass: 'drag', + start: function() {}, + drag: function() {}, + stop: function() {} + } + + DragScroll.prototype.fixScrollClasses = function() { + var isStart = this.isStart(), + isEnd = this.isEnd() + + this.scrollClassContainer.toggleClass('scroll-before', !isStart) + this.scrollClassContainer.toggleClass('scroll-after', !isEnd) + + this.scrollClassContainer.toggleClass('scroll-active-before', this.isActiveBefore()) + this.scrollClassContainer.toggleClass('scroll-active-after', this.isActiveAfter()) + this.isScrollable = !isStart || !isEnd + } + + DragScroll.prototype.isStart = function() { + if (!this.options.vertical) { + return this.el.scrollLeft() <= 0; + } + else { + return this.el.scrollTop() <= 0; + } + } + + DragScroll.prototype.isEnd = function() { + if (!this.options.vertical) { + return (this.el[0].scrollWidth - (this.el.scrollLeft() + this.el.width())) <= 0 + } + else { + return (this.el[0].scrollHeight - (this.el.scrollTop() + this.el.height())) <= 0 + } + } + + DragScroll.prototype.goToStart = function() { + if (!this.options.vertical) { + return this.el.scrollLeft(0) + } + else { + return this.el.scrollTop(0) + } + } + + /* + * Determines if the element with the class 'active' is hidden before the viewport - + * on the left or on the top, depending on whether the scrollbar is horizontal or vertical. + */ + DragScroll.prototype.isActiveAfter = function() { + var activeElement = $('.active', this.el); + if (activeElement.length == 0) { + return false + } + + if (!this.options.vertical) { + return activeElement.get(0).offsetLeft > (this.el.scrollLeft() + this.el.width()) + } + else { + return activeElement.get(0).offsetTop > (this.el.scrollTop() + this.el.height()) + } + } + + /* + * Determines if the element with the class 'active' is hidden after the viewport - + * on the right or on the bottom, depending on whether the scrollbar is horizontal or vertical. + */ + DragScroll.prototype.isActiveBefore = function() { + var activeElement = $('.active', this.el); + if (activeElement.length == 0) { + return false + } + + if (!this.options.vertical) { + return (activeElement.get(0).offsetLeft + activeElement.width()) < this.el.scrollLeft() + } + else { + return (activeElement.get(0).offsetTop + activeElement.height()) < this.el.scrollTop() + } + } + + DragScroll.prototype.goToElement = function(element, callback, options) { + var $el = $(element) + if (!$el.length) + return; + + var self = this, + params = { + duration: 300, + queue: false, + complete: function(){ + self.fixScrollClasses() + if (callback !== undefined) + callback() + } + } + + params = $.extend(params, options || {}) + + var offset = 0, + animated = false + + if (!this.options.vertical) { + offset = $el.get(0).offsetLeft - this.el.scrollLeft() + + if (offset < 0) { + this.el.animate({'scrollLeft': $el.get(0).offsetLeft}, params) + animated = true + } + else { + offset = $el.get(0).offsetLeft + $el.width() - (this.el.scrollLeft() + this.el.width()) + if (offset > 0) { + this.el.animate({'scrollLeft': $el.get(0).offsetLeft + $el.width() - this.el.width()}, params) + animated = true + } + } + } + else { + offset = $el.get(0).offsetTop - this.el.scrollTop() + + if (offset < 0) { + this.el.animate({'scrollTop': $el.get(0).offsetTop}, params) + animated = true + } + else { + offset = $el.get(0).offsetTop - (this.el.scrollTop() + this.el.height()) + if (offset > 0) { + this.el.animate({'scrollTop': $el.get(0).offsetTop + $el.height() - this.el.height()}, params) + animated = true + } + } + } + + if (!animated && callback !== undefined) { + callback() + } + } + + DragScroll.prototype.dispose = function() { + this.scrollClassContainer = null + + $(document).off('ready', this.proxy(this.fixScrollClasses)) + $(window).off('resize', this.proxy(this.fixScrollClasses)) + this.el.off('.dragScroll') + + this.el.removeData('oc.dragScroll') + + this.el = null + BaseProto.dispose.call(this) + } + + // DRAGSCROLL PLUGIN DEFINITION + // ============================ + + var old = $.fn.dragScroll + + $.fn.dragScroll = function (option) { + var args = arguments; + + return this.each(function () { + var $this = $(this) + var data = $this.data('oc.dragScroll') + var options = typeof option == 'object' && option + + if (!data) $this.data('oc.dragScroll', (data = new DragScroll(this, options))) + if (typeof option == 'string') { + var methodArgs = []; + for (var i=1; i').addClass('dropdown-title').text(title)) + + var container = $('
  • ').addClass('dropdown-container'), + ul = $('
  • '+entry.label+'
    '+fragments.join("")+'
    ';if(options.legend.container!=null) +$(options.legend.container).html(table);else{var pos="",p=options.legend.position,m=options.legend.margin;if(m[0]==null) +m=[m,m];if(p.charAt(0)=="n") +pos+='top:'+(m[1]+plotOffset.top)+'px;';else if(p.charAt(0)=="s") +pos+='bottom:'+(m[1]+plotOffset.bottom)+'px;';if(p.charAt(1)=="e") +pos+='right:'+(m[0]+plotOffset.right)+'px;';else if(p.charAt(1)=="w") +pos+='left:'+(m[0]+plotOffset.left)+'px;';var legend=$('
    '+table.replace('style="','style="position:absolute;'+pos+';')+'
    ').appendTo(placeholder);if(options.legend.backgroundOpacity!=0.0){var c=options.legend.backgroundColor;if(c==null){c=options.grid.backgroundColor;if(c&&typeof c=="string") +c=$.color.parse(c);else +c=$.color.extract(legend,'background-color');c.a=1;c=c.toString();} +var div=legend.children();$('
    ').prependTo(legend).css('opacity',options.legend.backgroundOpacity);}}} +var highlights=[],redrawTimeout=null;function findNearbyItem(mouseX,mouseY,seriesFilter){var maxDistance=options.grid.mouseActiveRadius,smallestDistance=maxDistance*maxDistance+1,item=null,foundPoint=false,i,j,ps;for(i=series.length-1;i>=0;--i){if(!seriesFilter(series[i])) +continue;var s=series[i],axisx=s.xaxis,axisy=s.yaxis,points=s.datapoints.points,mx=axisx.c2p(mouseX),my=axisy.c2p(mouseY),maxx=maxDistance/axisx.scale,maxy=maxDistance/axisy.scale;ps=s.datapoints.pointsize;if(axisx.options.inverseTransform) +maxx=Number.MAX_VALUE;if(axisy.options.inverseTransform) +maxy=Number.MAX_VALUE;if(s.lines.show||s.points.show){for(j=0;jmaxx||x-mx<-maxx||y-my>maxy||y-my<-maxy) +continue;var dx=Math.abs(axisx.p2c(x)-mouseX),dy=Math.abs(axisy.p2c(y)-mouseY),dist=dx*dx+dy*dy;if(dist=Math.min(b,x)&&my>=y+barLeft&&my<=y+barRight):(mx>=x+barLeft&&mx<=x+barRight&&my>=Math.min(b,y)&&my<=Math.max(b,y))) +item=[i,j/ps];}}} +if(item){i=item[0];j=item[1];ps=series[i].datapoints.pointsize;return{datapoint:series[i].datapoints.points.slice(j*ps,(j+1)*ps),dataIndex:j,series:series[i],seriesIndex:i};} +return null;} +function onMouseMove(e){if(options.grid.hoverable) +triggerClickHoverEvent("plothover",e,function(s){return s["hoverable"]!=false;});} +function onMouseLeave(e){if(options.grid.hoverable) +triggerClickHoverEvent("plothover",e,function(s){return false;});} +function onClick(e){triggerClickHoverEvent("plotclick",e,function(s){return s["clickable"]!=false;});} +function triggerClickHoverEvent(eventname,event,seriesFilter){var offset=eventHolder.offset(),canvasX=event.pageX-offset.left-plotOffset.left,canvasY=event.pageY-offset.top-plotOffset.top,pos=canvasToAxisCoords({left:canvasX,top:canvasY});pos.pageX=event.pageX;pos.pageY=event.pageY;var item=findNearbyItem(canvasX,canvasY,seriesFilter);if(item){item.pageX=parseInt(item.series.xaxis.p2c(item.datapoint[0])+offset.left+plotOffset.left,10);item.pageY=parseInt(item.series.yaxis.p2c(item.datapoint[1])+offset.top+plotOffset.top,10);} +if(options.grid.autoHighlight){for(var i=0;iaxisx.max||yaxisy.max) +return;var pointRadius=series.points.radius+series.points.lineWidth/2;octx.lineWidth=pointRadius;octx.strokeStyle=highlightColor;var radius=1.5*pointRadius;x=axisx.p2c(x);y=axisy.p2c(y);octx.beginPath();if(series.points.symbol=="circle") +octx.arc(x,y,radius,0,2*Math.PI,false);else +series.points.symbol(octx,x,y,radius,false);octx.closePath();octx.stroke();} +function drawBarHighlight(series,point){var highlightColor=(typeof series.highlightColor==="string")?series.highlightColor:$.color.parse(series.color).scale('a',0.5).toString(),fillStyle=highlightColor,barLeft=series.bars.align=="left"?0:-series.bars.barWidth/2;octx.lineWidth=series.bars.lineWidth;octx.strokeStyle=highlightColor;drawBar(point[0],point[1],point[2]||0,barLeft,barLeft+series.bars.barWidth,0,function(){return fillStyle;},series.xaxis,series.yaxis,octx,series.bars.horizontal,series.bars.lineWidth);} +function getColorOrGradient(spec,bottom,top,defaultColor){if(typeof spec=="string") +return spec;else{var gradient=ctx.createLinearGradient(0,top,0,bottom);for(var i=0,l=spec.colors.length;i0){$tip=$('#flotTip');} +else{$tip=$('
    ').attr('id','flotTip');$tip.appendTo('body').hide().css({position:'absolute'});if(this.tooltipOptions.defaultTheme){$tip.css({'background':'#fff','z-index':'100','padding':'0.4em 0.6em','border-radius':'0.5em','font-size':'0.8em','border':'1px solid #111','display':'inline-block','white-space':'nowrap'});}} +return $tip;};FlotTooltip.prototype.updateTooltipPosition=function(pos){var totalTipWidth=$("#flotTip").outerWidth()+this.tooltipOptions.shifts.x;var totalTipHeight=$("#flotTip").outerHeight()+this.tooltipOptions.shifts.y;if((pos.x-$(window).scrollLeft())>($(window).innerWidth()-totalTipWidth)){pos.x-=totalTipWidth;} +if((pos.y-$(window).scrollTop())>($(window).innerHeight()-totalTipHeight)){pos.y-=totalTipHeight;} +this.tipPosition.x=pos.x;this.tipPosition.y=pos.y;};FlotTooltip.prototype.stringFormat=function(content,item){var percentPattern=/%p\.{0,1}(\d{0,})/;var seriesPattern=/%s/;var xPattern=/%x\.{0,1}(\d{0,})/;var yPattern=/%y\.{0,1}(\d{0,})/;if(typeof(content)==='function'){content=content(item.series.data[item.dataIndex][0],item.series.data[item.dataIndex][1]);} +if(typeof(item.series.percent)!=='undefined'){content=this.adjustValPrecision(percentPattern,content,item.series.percent);} +if(typeof(item.series.label)!=='undefined'){content=content.replace(seriesPattern,item.series.label);} +if(this.isTimeMode('xaxis',item)&&this.isXDateFormat(item)){content=content.replace(xPattern,this.timestampToDate(item.series.data[item.dataIndex][0],this.tooltipOptions.xDateFormat));} +if(this.isTimeMode('yaxis',item)&&this.isYDateFormat(item)){content=content.replace(yPattern,this.timestampToDate(item.series.data[item.dataIndex][1],this.tooltipOptions.yDateFormat));} +if(typeof item.series.data[item.dataIndex][0]==='number'){content=this.adjustValPrecision(xPattern,content,item.series.data[item.dataIndex][0]);} +if(typeof item.series.data[item.dataIndex][1]==='number'){content=this.adjustValPrecision(yPattern,content,item.series.data[item.dataIndex][1]);} +if(typeof item.series.xaxis.tickFormatter!=='undefined'){content=content.replace(xPattern,item.series.xaxis.tickFormatter(item.series.data[item.dataIndex][0],item.series.xaxis));} +if(typeof item.series.yaxis.tickFormatter!=='undefined'){content=content.replace(yPattern,item.series.yaxis.tickFormatter(item.series.data[item.dataIndex][1],item.series.yaxis));} +return content;};FlotTooltip.prototype.isTimeMode=function(axisName,item){return(typeof item.series[axisName].options.mode!=='undefined'&&item.series[axisName].options.mode==='time');};FlotTooltip.prototype.isXDateFormat=function(item){return(typeof this.tooltipOptions.xDateFormat!=='undefined'&&this.tooltipOptions.xDateFormat!==null);};FlotTooltip.prototype.isYDateFormat=function(item){return(typeof this.tooltipOptions.yDateFormat!=='undefined'&&this.tooltipOptions.yDateFormat!==null);};FlotTooltip.prototype.timestampToDate=function(tmst,dateFormat){var theDate=new Date(tmst);return $.plot.formatDate(theDate,dateFormat);};FlotTooltip.prototype.adjustValPrecision=function(pattern,content,value){var precision;if(content.match(pattern)!==null){if(RegExp.$1!==''){precision=RegExp.$1;value=value.toFixed(precision);content=content.replace(pattern,value);}} +return content;};var init=function(plot){new FlotTooltip(plot);};$.plot.plugins.push({init:init,options:defaultOptions,name:'tooltip',version:'0.6.1'});})(jQuery);(function($){var options={};function init(plot){function onResize(){var placeholder=plot.getPlaceholder();if(placeholder.width()==0||placeholder.height()==0) +return;plot.resize();plot.setupGrid();plot.draw();} +function bindEvents(plot,eventHolder){$(window).bind('resize',onResize)} +function shutdown(plot,eventHolder){$(window).unbind('resize',onResize)} +plot.hooks.bindEvents.push(bindEvents);plot.hooks.shutdown.push(shutdown);} +$.plot.plugins.push({init:init,options:options,name:'resize',version:'1.0'});})(jQuery);(function($){var options={xaxis:{timezone:null,timeformat:null,twelveHourClock:false,monthNames:null}};function floorInBase(n,base){return base*Math.floor(n/base);} +function formatDate(d,fmt,monthNames,dayNames){if(typeof d.strftime=="function"){return d.strftime(fmt);} +var leftPad=function(n,pad){n=""+n;pad=""+(pad==null?"0":pad);return n.length==1?pad+n:n;};var r=[];var escape=false;var hours=d.getHours();var isAM=hours<12;if(monthNames==null){monthNames=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];} +if(dayNames==null){dayNames=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];} +var hours12;if(hours>12){hours12=hours-12;}else if(hours==0){hours12=12;}else{hours12=hours;} +for(var i=0;i=minSize){break;}} +var size=spec[i][0];var unit=spec[i][1];if(unit=="year"){if(opts.minTickSize!=null&&opts.minTickSize[1]=="year"){size=Math.floor(opts.minTickSize[0]);}else{var magn=Math.pow(10,Math.floor(Math.log(axis.delta/timeUnitSize.year)/Math.LN10));var norm=(axis.delta/timeUnitSize.year)/magn;if(norm<1.5){size=1;}else if(norm<3){size=2;}else if(norm<7.5){size=5;}else{size=10;} +size*=magn;} +if(size<1){size=1;}} +axis.tickSize=opts.tickSize||[size,unit];var tickSize=axis.tickSize[0];unit=axis.tickSize[1];var step=tickSize*timeUnitSize[unit];if(unit=="second"){d.setSeconds(floorInBase(d.getSeconds(),tickSize));}else if(unit=="minute"){d.setMinutes(floorInBase(d.getMinutes(),tickSize));}else if(unit=="hour"){d.setHours(floorInBase(d.getHours(),tickSize));}else if(unit=="month"){d.setMonth(floorInBase(d.getMonth(),tickSize));}else if(unit=="quarter"){d.setMonth(3*floorInBase(d.getMonth()/3,tickSize));}else if(unit=="year"){d.setFullYear(floorInBase(d.getFullYear(),tickSize));} +d.setMilliseconds(0);if(step>=timeUnitSize.minute){d.setSeconds(0);} +if(step>=timeUnitSize.hour){d.setMinutes(0);} +if(step>=timeUnitSize.day){d.setHours(0);} +if(step>=timeUnitSize.day*4){d.setDate(1);} +if(step>=timeUnitSize.month*2){d.setMonth(floorInBase(d.getMonth(),3));} +if(step>=timeUnitSize.quarter*2){d.setMonth(floorInBase(d.getMonth(),6));} +if(step>=timeUnitSize.year){d.setMonth(0);} +var carry=0;var v=Number.NaN;var prev;do{prev=v;v=d.getTime();ticks.push(v);if(unit=="month"||unit=="quarter"){if(tickSize<1){d.setDate(1);var start=d.getTime();d.setMonth(d.getMonth()+ +(unit=="quarter"?3:1));var end=d.getTime();d.setTime(v+carry*timeUnitSize.hour+(end-start)*tickSize);carry=d.getHours();d.setHours(0);}else{d.setMonth(d.getMonth()+ +tickSize*(unit=="quarter"?3:1));}}else if(unit=="year"){d.setFullYear(d.getFullYear()+tickSize);}else{d.setTime(v+step);}}while(v0){name.splice(i-1,2);i-=2;}}} +name=name.join("/");}else if(name.indexOf('./')===0){name=name.substring(2);}} +if((baseParts||starMap)&&map){nameParts=name.split('/');for(i=nameParts.length;i>0;i-=1){nameSegment=nameParts.slice(0,i).join("/");if(baseParts){for(j=baseParts.length;j>0;j-=1){mapValue=map[baseParts.slice(0,j).join('/')];if(mapValue){mapValue=mapValue[nameSegment];if(mapValue){foundMap=mapValue;foundI=i;break;}}}} +if(foundMap){break;} +if(!foundStarMap&&starMap&&starMap[nameSegment]){foundStarMap=starMap[nameSegment];starI=i;}} +if(!foundMap&&foundStarMap){foundMap=foundStarMap;foundI=starI;} +if(foundMap){nameParts.splice(0,foundI,foundMap);name=nameParts.join('/');}} +return name;} +function makeRequire(relName,forceSync){return function(){var args=aps.call(arguments,0);if(typeof args[0]!=='string'&&args.length===1){args.push(null);} +return req.apply(undef,args.concat([relName,forceSync]));};} +function makeNormalize(relName){return function(name){return normalize(name,relName);};} +function makeLoad(depName){return function(value){defined[depName]=value;};} +function callDep(name){if(hasProp(waiting,name)){var args=waiting[name];delete waiting[name];defining[name]=true;main.apply(undef,args);} +if(!hasProp(defined,name)&&!hasProp(defining,name)){throw new Error('No '+name);} +return defined[name];} +function splitPrefix(name){var prefix,index=name?name.indexOf('!'):-1;if(index>-1){prefix=name.substring(0,index);name=name.substring(index+1,name.length);} +return[prefix,name];} +makeMap=function(name,relName){var plugin,parts=splitPrefix(name),prefix=parts[0];name=parts[1];if(prefix){prefix=normalize(prefix,relName);plugin=callDep(prefix);} +if(prefix){if(plugin&&plugin.normalize){name=plugin.normalize(name,makeNormalize(relName));}else{name=normalize(name,relName);}}else{name=normalize(name,relName);parts=splitPrefix(name);prefix=parts[0];name=parts[1];if(prefix){plugin=callDep(prefix);}} +return{f:prefix?prefix+'!'+name:name,n:name,pr:prefix,p:plugin};};function makeConfig(name){return function(){return(config&&config.config&&config.config[name])||{};};} +handlers={require:function(name){return makeRequire(name);},exports:function(name){var e=defined[name];if(typeof e!=='undefined'){return e;}else{return(defined[name]={});}},module:function(name){return{id:name,uri:'',exports:defined[name],config:makeConfig(name)};}};main=function(name,deps,callback,relName){var cjsModule,depName,ret,map,i,args=[],callbackType=typeof callback,usingExports;relName=relName||name;if(callbackType==='undefined'||callbackType==='function'){deps=!deps.length&&callback.length?['require','exports','module']:deps;for(i=0;i0){unshift.call(arguments,SuperClass.prototype.constructor);calledConstructor=DecoratorClass.prototype.constructor;} +calledConstructor.apply(this,arguments);} +DecoratorClass.displayName=SuperClass.displayName;function ctr(){this.constructor=DecoratedClass;} +DecoratedClass.prototype=new ctr();for(var m=0;m':'>','"':'"','\'':''','/':'/'};if(typeof markup!=='string'){return markup;} +return String(markup).replace(/[&<>"'\/\\]/g,function(match){return replaceMap[match];});};Utils.appendMany=function($element,$nodes){if($.fn.jquery.substr(0,3)==='1.7'){var $jqNodes=$();$.map($nodes,function(node){$jqNodes=$jqNodes.add(node);});$nodes=$jqNodes;} +$element.append($nodes);};return Utils;});S2.define('select2/results',['jquery','./utils'],function($,Utils){function Results($element,options,dataAdapter){this.$element=$element;this.data=dataAdapter;this.options=options;Results.__super__.constructor.call(this);} +Utils.Extend(Results,Utils.Observable);Results.prototype.render=function(){var $results=$('
      ');if(this.options.get('multiple')){$results.attr('aria-multiselectable','true');} +this.$results=$results;return $results;};Results.prototype.clear=function(){this.$results.empty();};Results.prototype.displayMessage=function(params){var escapeMarkup=this.options.get('escapeMarkup');this.clear();this.hideLoading();var $message=$('
    • ');var message=this.options.get('translations').get(params.message);$message.append(escapeMarkup(message(params.args)));$message[0].className+=' select2-results__message';this.$results.append($message);};Results.prototype.hideMessages=function(){this.$results.find('.select2-results__message').remove();};Results.prototype.append=function(data){this.hideLoading();var $options=[];if(data.results==null||data.results.length===0){if(this.$results.children().length===0){this.trigger('results:message',{message:'noResults'});} +return;} +data.results=this.sort(data.results);for(var d=0;d0){$selected.first().trigger('mouseenter');}else{$options.first().trigger('mouseenter');} +this.ensureHighlightVisible();};Results.prototype.setClasses=function(){var self=this;this.data.current(function(selected){var selectedIds=$.map(selected,function(s){return s.id.toString();});var $options=self.$results.find('.select2-results__option[aria-selected]');$options.each(function(){var $option=$(this);var item=$.data(this,'data');var id=''+item.id;if((item.element!=null&&item.element.selected)||(item.element==null&&$.inArray(id,selectedIds)>-1)){$option.attr('aria-selected','true');}else{$option.attr('aria-selected','false');}});});};Results.prototype.showLoading=function(params){this.hideLoading();var loadingMore=this.options.get('translations').get('searching');var loading={disabled:true,loading:true,text:loadingMore(params)};var $loading=this.option(loading);$loading.className+=' loading-results';this.$results.prepend($loading);};Results.prototype.hideLoading=function(){this.$results.find('.loading-results').remove();};Results.prototype.option=function(data){var option=document.createElement('li');option.className='select2-results__option';var attrs={'role':'treeitem','aria-selected':'false'};if(data.disabled){delete attrs['aria-selected'];attrs['aria-disabled']='true';} +if(data.id==null){delete attrs['aria-selected'];} +if(data._resultId!=null){option.id=data._resultId;} +if(data.title){option.title=data.title;} +if(data.children){attrs.role='group';attrs['aria-label']=data.text;delete attrs['aria-selected'];} +for(var attr in attrs){var val=attrs[attr];option.setAttribute(attr,val);} +if(data.children){var $option=$(option);var label=document.createElement('strong');label.className='select2-results__group';var $label=$(label);this.template(data,label);var $children=[];for(var c=0;c',{'class':'select2-results__options select2-results__options--nested'});$childrenContainer.append($children);$option.append(label);$option.append($childrenContainer);}else{this.template(data,option);} +$.data(option,'data',data);return option;};Results.prototype.bind=function(container,$container){var self=this;var id=container.id+'-results';this.$results.attr('id',id);container.on('results:all',function(params){self.clear();self.append(params.data);if(container.isOpen()){self.setClasses();self.highlightFirstItem();}});container.on('results:append',function(params){self.append(params.data);if(container.isOpen()){self.setClasses();}});container.on('query',function(params){self.hideMessages();self.showLoading(params);});container.on('select',function(){if(!container.isOpen()){return;} +self.setClasses();self.highlightFirstItem();});container.on('unselect',function(){if(!container.isOpen()){return;} +self.setClasses();self.highlightFirstItem();});container.on('open',function(){self.$results.attr('aria-expanded','true');self.$results.attr('aria-hidden','false');self.setClasses();self.ensureHighlightVisible();});container.on('close',function(){self.$results.attr('aria-expanded','false');self.$results.attr('aria-hidden','true');self.$results.removeAttr('aria-activedescendant');});container.on('results:toggle',function(){var $highlighted=self.getHighlightedResults();if($highlighted.length===0){return;} +$highlighted.trigger('mouseup');});container.on('results:select',function(){var $highlighted=self.getHighlightedResults();if($highlighted.length===0){return;} +var data=$highlighted.data('data');if($highlighted.attr('aria-selected')=='true'){self.trigger('close',{});}else{self.trigger('select',{data:data});}});container.on('results:previous',function(){var $highlighted=self.getHighlightedResults();var $options=self.$results.find('[aria-selected]');var currentIndex=$options.index($highlighted);if(currentIndex===0){return;} +var nextIndex=currentIndex-1;if($highlighted.length===0){nextIndex=0;} +var $next=$options.eq(nextIndex);$next.trigger('mouseenter');var currentOffset=self.$results.offset().top;var nextTop=$next.offset().top;var nextOffset=self.$results.scrollTop()+(nextTop-currentOffset);if(nextIndex===0){self.$results.scrollTop(0);}else if(nextTop-currentOffset<0){self.$results.scrollTop(nextOffset);}});container.on('results:next',function(){var $highlighted=self.getHighlightedResults();var $options=self.$results.find('[aria-selected]');var currentIndex=$options.index($highlighted);var nextIndex=currentIndex+1;if(nextIndex>=$options.length){return;} +var $next=$options.eq(nextIndex);$next.trigger('mouseenter');var currentOffset=self.$results.offset().top+ +self.$results.outerHeight(false);var nextBottom=$next.offset().top+$next.outerHeight(false);var nextOffset=self.$results.scrollTop()+nextBottom-currentOffset;if(nextIndex===0){self.$results.scrollTop(0);}else if(nextBottom>currentOffset){self.$results.scrollTop(nextOffset);}});container.on('results:focus',function(params){params.element.addClass('select2-results__option--highlighted');});container.on('results:message',function(params){self.displayMessage(params);});if($.fn.mousewheel){this.$results.on('mousewheel',function(e){var top=self.$results.scrollTop();var bottom=self.$results.get(0).scrollHeight-top+e.deltaY;var isAtTop=e.deltaY>0&&top-e.deltaY<=0;var isAtBottom=e.deltaY<0&&bottom<=self.$results.height();if(isAtTop){self.$results.scrollTop(0);e.preventDefault();e.stopPropagation();}else if(isAtBottom){self.$results.scrollTop(self.$results.get(0).scrollHeight-self.$results.height());e.preventDefault();e.stopPropagation();}});} +this.$results.on('mouseup','.select2-results__option[aria-selected]',function(evt){var $this=$(this);var data=$this.data('data');if($this.attr('aria-selected')==='true'){if(self.options.get('multiple')){self.trigger('unselect',{originalEvent:evt,data:data});}else{self.trigger('close',{});} +return;} +self.trigger('select',{originalEvent:evt,data:data});});this.$results.on('mouseenter','.select2-results__option[aria-selected]',function(evt){var data=$(this).data('data');self.getHighlightedResults().removeClass('select2-results__option--highlighted');self.trigger('results:focus',{data:data,element:$(this)});});};Results.prototype.getHighlightedResults=function(){var $highlighted=this.$results.find('.select2-results__option--highlighted');return $highlighted;};Results.prototype.destroy=function(){this.$results.remove();};Results.prototype.ensureHighlightVisible=function(){var $highlighted=this.getHighlightedResults();if($highlighted.length===0){return;} +var $options=this.$results.find('[aria-selected]');var currentIndex=$options.index($highlighted);var currentOffset=this.$results.offset().top;var nextTop=$highlighted.offset().top;var nextOffset=this.$results.scrollTop()+(nextTop-currentOffset);var offsetDelta=nextTop-currentOffset;nextOffset-=$highlighted.outerHeight(false)*2;if(currentIndex<=2){this.$results.scrollTop(0);}else if(offsetDelta>this.$results.outerHeight()||offsetDelta<0){this.$results.scrollTop(nextOffset);}};Results.prototype.template=function(result,container){var template=this.options.get('templateResult');var escapeMarkup=this.options.get('escapeMarkup');var content=template(result,container);if(content==null){container.style.display='none';}else if(typeof content==='string'){container.innerHTML=escapeMarkup(content);}else{$(container).append(content);}};return Results;});S2.define('select2/keys',[],function(){var KEYS={BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46};return KEYS;});S2.define('select2/selection/base',['jquery','../utils','../keys'],function($,Utils,KEYS){function BaseSelection($element,options){this.$element=$element;this.options=options;BaseSelection.__super__.constructor.call(this);} +Utils.Extend(BaseSelection,Utils.Observable);BaseSelection.prototype.render=function(){var $selection=$('');this._tabindex=0;if(this.$element.data('old-tabindex')!=null){this._tabindex=this.$element.data('old-tabindex');}else if(this.$element.attr('tabindex')!=null){this._tabindex=this.$element.attr('tabindex');} +$selection.attr('title',this.$element.attr('title'));$selection.attr('tabindex',this._tabindex);this.$selection=$selection;return $selection;};BaseSelection.prototype.bind=function(container,$container){var self=this;var id=container.id+'-container';var resultsId=container.id+'-results';this.container=container;this.$selection.on('focus',function(evt){self.trigger('focus',evt);});this.$selection.on('blur',function(evt){self._handleBlur(evt);});this.$selection.on('keydown',function(evt){self.trigger('keypress',evt);if(evt.which===KEYS.SPACE){evt.preventDefault();}});container.on('results:focus',function(params){self.$selection.attr('aria-activedescendant',params.data._resultId);});container.on('selection:update',function(params){self.update(params.data);});container.on('open',function(){self.$selection.attr('aria-expanded','true');self.$selection.attr('aria-owns',resultsId);self._attachCloseHandler(container);});container.on('close',function(){self.$selection.attr('aria-expanded','false');self.$selection.removeAttr('aria-activedescendant');self.$selection.removeAttr('aria-owns');self.$selection.focus();self._detachCloseHandler(container);});container.on('enable',function(){self.$selection.attr('tabindex',self._tabindex);});container.on('disable',function(){self.$selection.attr('tabindex','-1');});};BaseSelection.prototype._handleBlur=function(evt){var self=this;window.setTimeout(function(){if((document.activeElement==self.$selection[0])||($.contains(self.$selection[0],document.activeElement))){return;} +self.trigger('blur',evt);},1);};BaseSelection.prototype._attachCloseHandler=function(container){var self=this;$(document.body).on('mousedown.select2.'+container.id,function(e){var $target=$(e.target);var $select=$target.closest('.select2');var $all=$('.select2.select2-container--open');$all.each(function(){var $this=$(this);if(this==$select[0]){return;} +var $element=$this.data('element');$element.select2('close');});});};BaseSelection.prototype._detachCloseHandler=function(container){$(document.body).off('mousedown.select2.'+container.id);};BaseSelection.prototype.position=function($selection,$container){var $selectionContainer=$container.find('.selection');$selectionContainer.append($selection);};BaseSelection.prototype.destroy=function(){this._detachCloseHandler(this.container);};BaseSelection.prototype.update=function(data){throw new Error('The `update` method must be defined in child classes.');};return BaseSelection;});S2.define('select2/selection/single',['jquery','./base','../utils','../keys'],function($,BaseSelection,Utils,KEYS){function SingleSelection(){SingleSelection.__super__.constructor.apply(this,arguments);} +Utils.Extend(SingleSelection,BaseSelection);SingleSelection.prototype.render=function(){var $selection=SingleSelection.__super__.render.call(this);$selection.addClass('select2-selection--single');$selection.html(''+''+''+'');return $selection;};SingleSelection.prototype.bind=function(container,$container){var self=this;SingleSelection.__super__.bind.apply(this,arguments);var id=container.id+'-container';this.$selection.find('.select2-selection__rendered').attr('id',id);this.$selection.attr('aria-labelledby',id);this.$selection.on('mousedown',function(evt){if(evt.which!==1){return;} +self.trigger('toggle',{originalEvent:evt});});this.$selection.on('focus',function(evt){});this.$selection.on('blur',function(evt){});container.on('focus',function(evt){if(!container.isOpen()){self.$selection.focus();}});container.on('selection:update',function(params){self.update(params.data);});};SingleSelection.prototype.clear=function(){this.$selection.find('.select2-selection__rendered').empty();};SingleSelection.prototype.display=function(data,container){var template=this.options.get('templateSelection');var escapeMarkup=this.options.get('escapeMarkup');return escapeMarkup(template(data,container));};SingleSelection.prototype.selectionContainer=function(){return $('');};SingleSelection.prototype.update=function(data){if(data.length===0){this.clear();return;} +var selection=data[0];var $rendered=this.$selection.find('.select2-selection__rendered');var formatted=this.display(selection,$rendered);$rendered.empty().append(formatted);$rendered.prop('title',selection.title||selection.text);};return SingleSelection;});S2.define('select2/selection/multiple',['jquery','./base','../utils'],function($,BaseSelection,Utils){function MultipleSelection($element,options){MultipleSelection.__super__.constructor.apply(this,arguments);} +Utils.Extend(MultipleSelection,BaseSelection);MultipleSelection.prototype.render=function(){var $selection=MultipleSelection.__super__.render.call(this);$selection.addClass('select2-selection--multiple');$selection.html('
        ');return $selection;};MultipleSelection.prototype.bind=function(container,$container){var self=this;MultipleSelection.__super__.bind.apply(this,arguments);this.$selection.on('click',function(evt){self.trigger('toggle',{originalEvent:evt});});this.$selection.on('click','.select2-selection__choice__remove',function(evt){if(self.options.get('disabled')){return;} +var $remove=$(this);var $selection=$remove.parent();var data=$selection.data('data');self.trigger('unselect',{originalEvent:evt,data:data});});};MultipleSelection.prototype.clear=function(){this.$selection.find('.select2-selection__rendered').empty();};MultipleSelection.prototype.display=function(data,container){var template=this.options.get('templateSelection');var escapeMarkup=this.options.get('escapeMarkup');return escapeMarkup(template(data,container));};MultipleSelection.prototype.selectionContainer=function(){var $container=$('
      • '+''+'×'+''+'
      • ');return $container;};MultipleSelection.prototype.update=function(data){this.clear();if(data.length===0){return;} +var $selections=[];for(var d=0;d1;if(multipleSelections||singlePlaceholder){return decorated.call(this,data);} +this.clear();var $placeholder=this.createPlaceholder(this.placeholder);this.$selection.find('.select2-selection__rendered').append($placeholder);};return Placeholder;});S2.define('select2/selection/allowClear',['jquery','../keys'],function($,KEYS){function AllowClear(){} +AllowClear.prototype.bind=function(decorated,container,$container){var self=this;decorated.call(this,container,$container);if(this.placeholder==null){if(this.options.get('debug')&&window.console&&console.error){console.error('Select2: The `allowClear` option should be used in combination '+'with the `placeholder` option.');}} +this.$selection.on('mousedown','.select2-selection__clear',function(evt){self._handleClear(evt);});container.on('keypress',function(evt){self._handleKeyboardClear(evt,container);});};AllowClear.prototype._handleClear=function(_,evt){if(this.options.get('disabled')){return;} +var $clear=this.$selection.find('.select2-selection__clear');if($clear.length===0){return;} +evt.stopPropagation();var data=$clear.data('data');for(var d=0;d0||data.length===0){return;} +var $remove=$(''+'×'+'');$remove.data('data',data);this.$selection.find('.select2-selection__rendered').prepend($remove);};return AllowClear;});S2.define('select2/selection/search',['jquery','../utils','../keys'],function($,Utils,KEYS){function Search(decorated,$element,options){decorated.call(this,$element,options);} +Search.prototype.render=function(decorated){var $search=$('');this.$searchContainer=$search;this.$search=$search.find('input');var $rendered=decorated.call(this);this._transferTabIndex();return $rendered;};Search.prototype.bind=function(decorated,container,$container){var self=this;decorated.call(this,container,$container);container.on('open',function(){self.$search.trigger('focus');});container.on('close',function(){self.$search.val('');self.$search.removeAttr('aria-activedescendant');self.$search.trigger('focus');});container.on('enable',function(){self.$search.prop('disabled',false);self._transferTabIndex();});container.on('disable',function(){self.$search.prop('disabled',true);});container.on('focus',function(evt){self.$search.trigger('focus');});container.on('results:focus',function(params){self.$search.attr('aria-activedescendant',params.id);});this.$selection.on('focusin','.select2-search--inline',function(evt){self.trigger('focus',evt);});this.$selection.on('focusout','.select2-search--inline',function(evt){self._handleBlur(evt);});this.$selection.on('keydown','.select2-search--inline',function(evt){evt.stopPropagation();self.trigger('keypress',evt);self._keyUpPrevented=evt.isDefaultPrevented();var key=evt.which;if(key===KEYS.BACKSPACE&&self.$search.val()===''){var $previousChoice=self.$searchContainer.prev('.select2-selection__choice');if($previousChoice.length>0){var item=$previousChoice.data('data');self.searchRemoveChoice(item);evt.preventDefault();}}});var msie=document.documentMode;var disableInputEvents=msie&&msie<=11;this.$selection.on('input.searchcheck','.select2-search--inline',function(evt){if(disableInputEvents){self.$selection.off('input.search input.searchcheck');return;} +self.$selection.off('keyup.search');});this.$selection.on('keyup.search input.search','.select2-search--inline',function(evt){if(disableInputEvents&&evt.type==='input'){self.$selection.off('input.search input.searchcheck');return;} +var key=evt.which;if(key==KEYS.SHIFT||key==KEYS.CTRL||key==KEYS.ALT){return;} +if(key==KEYS.TAB){return;} +self.handleSearch(evt);});};Search.prototype._transferTabIndex=function(decorated){this.$search.attr('tabindex',this.$selection.attr('tabindex'));this.$selection.attr('tabindex','-1');};Search.prototype.createPlaceholder=function(decorated,placeholder){this.$search.attr('placeholder',placeholder.text);};Search.prototype.update=function(decorated,data){var searchHadFocus=this.$search[0]==document.activeElement;this.$search.attr('placeholder','');decorated.call(this,data);this.$selection.find('.select2-selection__rendered').append(this.$searchContainer);this.resizeSearch();if(searchHadFocus){this.$search.focus();}};Search.prototype.handleSearch=function(){this.resizeSearch();if(!this._keyUpPrevented){var input=this.$search.val();this.trigger('query',{term:input});} +this._keyUpPrevented=false;};Search.prototype.searchRemoveChoice=function(decorated,item){this.trigger('unselect',{data:item});this.$search.val(item.text);this.handleSearch();};Search.prototype.resizeSearch=function(){this.$search.css('width','25px');var width='';if(this.$search.attr('placeholder')!==''){width=this.$selection.find('.select2-selection__rendered').innerWidth();}else{var minimumWidth=this.$search.val().length+1;width=(minimumWidth*0.75)+'em';} +this.$search.css('width',width);};return Search;});S2.define('select2/selection/eventRelay',['jquery'],function($){function EventRelay(){} +EventRelay.prototype.bind=function(decorated,container,$container){var self=this;var relayEvents=['open','opening','close','closing','select','selecting','unselect','unselecting'];var preventableEvents=['opening','closing','selecting','unselecting'];decorated.call(this,container,$container);container.on('*',function(name,params){if($.inArray(name,relayEvents)===-1){return;} +params=params||{};var evt=$.Event('select2:'+name,{params:params});self.$element.trigger(evt);if($.inArray(name,preventableEvents)===-1){return;} +params.prevented=evt.isDefaultPrevented();});};return EventRelay;});S2.define('select2/translation',['jquery','require'],function($,require){function Translation(dict){this.dict=dict||{};} +Translation.prototype.all=function(){return this.dict;};Translation.prototype.get=function(key){return this.dict[key];};Translation.prototype.extend=function(translation){this.dict=$.extend({},translation.all(),this.dict);};Translation._cache={};Translation.loadPath=function(path){if(!(path in Translation._cache)){var translations=require(path);Translation._cache[path]=translations;} +return new Translation(Translation._cache[path]);};return Translation;});S2.define('select2/diacritics',[],function(){var diacritics={'\u24B6':'A','\uFF21':'A','\u00C0':'A','\u00C1':'A','\u00C2':'A','\u1EA6':'A','\u1EA4':'A','\u1EAA':'A','\u1EA8':'A','\u00C3':'A','\u0100':'A','\u0102':'A','\u1EB0':'A','\u1EAE':'A','\u1EB4':'A','\u1EB2':'A','\u0226':'A','\u01E0':'A','\u00C4':'A','\u01DE':'A','\u1EA2':'A','\u00C5':'A','\u01FA':'A','\u01CD':'A','\u0200':'A','\u0202':'A','\u1EA0':'A','\u1EAC':'A','\u1EB6':'A','\u1E00':'A','\u0104':'A','\u023A':'A','\u2C6F':'A','\uA732':'AA','\u00C6':'AE','\u01FC':'AE','\u01E2':'AE','\uA734':'AO','\uA736':'AU','\uA738':'AV','\uA73A':'AV','\uA73C':'AY','\u24B7':'B','\uFF22':'B','\u1E02':'B','\u1E04':'B','\u1E06':'B','\u0243':'B','\u0182':'B','\u0181':'B','\u24B8':'C','\uFF23':'C','\u0106':'C','\u0108':'C','\u010A':'C','\u010C':'C','\u00C7':'C','\u1E08':'C','\u0187':'C','\u023B':'C','\uA73E':'C','\u24B9':'D','\uFF24':'D','\u1E0A':'D','\u010E':'D','\u1E0C':'D','\u1E10':'D','\u1E12':'D','\u1E0E':'D','\u0110':'D','\u018B':'D','\u018A':'D','\u0189':'D','\uA779':'D','\u01F1':'DZ','\u01C4':'DZ','\u01F2':'Dz','\u01C5':'Dz','\u24BA':'E','\uFF25':'E','\u00C8':'E','\u00C9':'E','\u00CA':'E','\u1EC0':'E','\u1EBE':'E','\u1EC4':'E','\u1EC2':'E','\u1EBC':'E','\u0112':'E','\u1E14':'E','\u1E16':'E','\u0114':'E','\u0116':'E','\u00CB':'E','\u1EBA':'E','\u011A':'E','\u0204':'E','\u0206':'E','\u1EB8':'E','\u1EC6':'E','\u0228':'E','\u1E1C':'E','\u0118':'E','\u1E18':'E','\u1E1A':'E','\u0190':'E','\u018E':'E','\u24BB':'F','\uFF26':'F','\u1E1E':'F','\u0191':'F','\uA77B':'F','\u24BC':'G','\uFF27':'G','\u01F4':'G','\u011C':'G','\u1E20':'G','\u011E':'G','\u0120':'G','\u01E6':'G','\u0122':'G','\u01E4':'G','\u0193':'G','\uA7A0':'G','\uA77D':'G','\uA77E':'G','\u24BD':'H','\uFF28':'H','\u0124':'H','\u1E22':'H','\u1E26':'H','\u021E':'H','\u1E24':'H','\u1E28':'H','\u1E2A':'H','\u0126':'H','\u2C67':'H','\u2C75':'H','\uA78D':'H','\u24BE':'I','\uFF29':'I','\u00CC':'I','\u00CD':'I','\u00CE':'I','\u0128':'I','\u012A':'I','\u012C':'I','\u0130':'I','\u00CF':'I','\u1E2E':'I','\u1EC8':'I','\u01CF':'I','\u0208':'I','\u020A':'I','\u1ECA':'I','\u012E':'I','\u1E2C':'I','\u0197':'I','\u24BF':'J','\uFF2A':'J','\u0134':'J','\u0248':'J','\u24C0':'K','\uFF2B':'K','\u1E30':'K','\u01E8':'K','\u1E32':'K','\u0136':'K','\u1E34':'K','\u0198':'K','\u2C69':'K','\uA740':'K','\uA742':'K','\uA744':'K','\uA7A2':'K','\u24C1':'L','\uFF2C':'L','\u013F':'L','\u0139':'L','\u013D':'L','\u1E36':'L','\u1E38':'L','\u013B':'L','\u1E3C':'L','\u1E3A':'L','\u0141':'L','\u023D':'L','\u2C62':'L','\u2C60':'L','\uA748':'L','\uA746':'L','\uA780':'L','\u01C7':'LJ','\u01C8':'Lj','\u24C2':'M','\uFF2D':'M','\u1E3E':'M','\u1E40':'M','\u1E42':'M','\u2C6E':'M','\u019C':'M','\u24C3':'N','\uFF2E':'N','\u01F8':'N','\u0143':'N','\u00D1':'N','\u1E44':'N','\u0147':'N','\u1E46':'N','\u0145':'N','\u1E4A':'N','\u1E48':'N','\u0220':'N','\u019D':'N','\uA790':'N','\uA7A4':'N','\u01CA':'NJ','\u01CB':'Nj','\u24C4':'O','\uFF2F':'O','\u00D2':'O','\u00D3':'O','\u00D4':'O','\u1ED2':'O','\u1ED0':'O','\u1ED6':'O','\u1ED4':'O','\u00D5':'O','\u1E4C':'O','\u022C':'O','\u1E4E':'O','\u014C':'O','\u1E50':'O','\u1E52':'O','\u014E':'O','\u022E':'O','\u0230':'O','\u00D6':'O','\u022A':'O','\u1ECE':'O','\u0150':'O','\u01D1':'O','\u020C':'O','\u020E':'O','\u01A0':'O','\u1EDC':'O','\u1EDA':'O','\u1EE0':'O','\u1EDE':'O','\u1EE2':'O','\u1ECC':'O','\u1ED8':'O','\u01EA':'O','\u01EC':'O','\u00D8':'O','\u01FE':'O','\u0186':'O','\u019F':'O','\uA74A':'O','\uA74C':'O','\u01A2':'OI','\uA74E':'OO','\u0222':'OU','\u24C5':'P','\uFF30':'P','\u1E54':'P','\u1E56':'P','\u01A4':'P','\u2C63':'P','\uA750':'P','\uA752':'P','\uA754':'P','\u24C6':'Q','\uFF31':'Q','\uA756':'Q','\uA758':'Q','\u024A':'Q','\u24C7':'R','\uFF32':'R','\u0154':'R','\u1E58':'R','\u0158':'R','\u0210':'R','\u0212':'R','\u1E5A':'R','\u1E5C':'R','\u0156':'R','\u1E5E':'R','\u024C':'R','\u2C64':'R','\uA75A':'R','\uA7A6':'R','\uA782':'R','\u24C8':'S','\uFF33':'S','\u1E9E':'S','\u015A':'S','\u1E64':'S','\u015C':'S','\u1E60':'S','\u0160':'S','\u1E66':'S','\u1E62':'S','\u1E68':'S','\u0218':'S','\u015E':'S','\u2C7E':'S','\uA7A8':'S','\uA784':'S','\u24C9':'T','\uFF34':'T','\u1E6A':'T','\u0164':'T','\u1E6C':'T','\u021A':'T','\u0162':'T','\u1E70':'T','\u1E6E':'T','\u0166':'T','\u01AC':'T','\u01AE':'T','\u023E':'T','\uA786':'T','\uA728':'TZ','\u24CA':'U','\uFF35':'U','\u00D9':'U','\u00DA':'U','\u00DB':'U','\u0168':'U','\u1E78':'U','\u016A':'U','\u1E7A':'U','\u016C':'U','\u00DC':'U','\u01DB':'U','\u01D7':'U','\u01D5':'U','\u01D9':'U','\u1EE6':'U','\u016E':'U','\u0170':'U','\u01D3':'U','\u0214':'U','\u0216':'U','\u01AF':'U','\u1EEA':'U','\u1EE8':'U','\u1EEE':'U','\u1EEC':'U','\u1EF0':'U','\u1EE4':'U','\u1E72':'U','\u0172':'U','\u1E76':'U','\u1E74':'U','\u0244':'U','\u24CB':'V','\uFF36':'V','\u1E7C':'V','\u1E7E':'V','\u01B2':'V','\uA75E':'V','\u0245':'V','\uA760':'VY','\u24CC':'W','\uFF37':'W','\u1E80':'W','\u1E82':'W','\u0174':'W','\u1E86':'W','\u1E84':'W','\u1E88':'W','\u2C72':'W','\u24CD':'X','\uFF38':'X','\u1E8A':'X','\u1E8C':'X','\u24CE':'Y','\uFF39':'Y','\u1EF2':'Y','\u00DD':'Y','\u0176':'Y','\u1EF8':'Y','\u0232':'Y','\u1E8E':'Y','\u0178':'Y','\u1EF6':'Y','\u1EF4':'Y','\u01B3':'Y','\u024E':'Y','\u1EFE':'Y','\u24CF':'Z','\uFF3A':'Z','\u0179':'Z','\u1E90':'Z','\u017B':'Z','\u017D':'Z','\u1E92':'Z','\u1E94':'Z','\u01B5':'Z','\u0224':'Z','\u2C7F':'Z','\u2C6B':'Z','\uA762':'Z','\u24D0':'a','\uFF41':'a','\u1E9A':'a','\u00E0':'a','\u00E1':'a','\u00E2':'a','\u1EA7':'a','\u1EA5':'a','\u1EAB':'a','\u1EA9':'a','\u00E3':'a','\u0101':'a','\u0103':'a','\u1EB1':'a','\u1EAF':'a','\u1EB5':'a','\u1EB3':'a','\u0227':'a','\u01E1':'a','\u00E4':'a','\u01DF':'a','\u1EA3':'a','\u00E5':'a','\u01FB':'a','\u01CE':'a','\u0201':'a','\u0203':'a','\u1EA1':'a','\u1EAD':'a','\u1EB7':'a','\u1E01':'a','\u0105':'a','\u2C65':'a','\u0250':'a','\uA733':'aa','\u00E6':'ae','\u01FD':'ae','\u01E3':'ae','\uA735':'ao','\uA737':'au','\uA739':'av','\uA73B':'av','\uA73D':'ay','\u24D1':'b','\uFF42':'b','\u1E03':'b','\u1E05':'b','\u1E07':'b','\u0180':'b','\u0183':'b','\u0253':'b','\u24D2':'c','\uFF43':'c','\u0107':'c','\u0109':'c','\u010B':'c','\u010D':'c','\u00E7':'c','\u1E09':'c','\u0188':'c','\u023C':'c','\uA73F':'c','\u2184':'c','\u24D3':'d','\uFF44':'d','\u1E0B':'d','\u010F':'d','\u1E0D':'d','\u1E11':'d','\u1E13':'d','\u1E0F':'d','\u0111':'d','\u018C':'d','\u0256':'d','\u0257':'d','\uA77A':'d','\u01F3':'dz','\u01C6':'dz','\u24D4':'e','\uFF45':'e','\u00E8':'e','\u00E9':'e','\u00EA':'e','\u1EC1':'e','\u1EBF':'e','\u1EC5':'e','\u1EC3':'e','\u1EBD':'e','\u0113':'e','\u1E15':'e','\u1E17':'e','\u0115':'e','\u0117':'e','\u00EB':'e','\u1EBB':'e','\u011B':'e','\u0205':'e','\u0207':'e','\u1EB9':'e','\u1EC7':'e','\u0229':'e','\u1E1D':'e','\u0119':'e','\u1E19':'e','\u1E1B':'e','\u0247':'e','\u025B':'e','\u01DD':'e','\u24D5':'f','\uFF46':'f','\u1E1F':'f','\u0192':'f','\uA77C':'f','\u24D6':'g','\uFF47':'g','\u01F5':'g','\u011D':'g','\u1E21':'g','\u011F':'g','\u0121':'g','\u01E7':'g','\u0123':'g','\u01E5':'g','\u0260':'g','\uA7A1':'g','\u1D79':'g','\uA77F':'g','\u24D7':'h','\uFF48':'h','\u0125':'h','\u1E23':'h','\u1E27':'h','\u021F':'h','\u1E25':'h','\u1E29':'h','\u1E2B':'h','\u1E96':'h','\u0127':'h','\u2C68':'h','\u2C76':'h','\u0265':'h','\u0195':'hv','\u24D8':'i','\uFF49':'i','\u00EC':'i','\u00ED':'i','\u00EE':'i','\u0129':'i','\u012B':'i','\u012D':'i','\u00EF':'i','\u1E2F':'i','\u1EC9':'i','\u01D0':'i','\u0209':'i','\u020B':'i','\u1ECB':'i','\u012F':'i','\u1E2D':'i','\u0268':'i','\u0131':'i','\u24D9':'j','\uFF4A':'j','\u0135':'j','\u01F0':'j','\u0249':'j','\u24DA':'k','\uFF4B':'k','\u1E31':'k','\u01E9':'k','\u1E33':'k','\u0137':'k','\u1E35':'k','\u0199':'k','\u2C6A':'k','\uA741':'k','\uA743':'k','\uA745':'k','\uA7A3':'k','\u24DB':'l','\uFF4C':'l','\u0140':'l','\u013A':'l','\u013E':'l','\u1E37':'l','\u1E39':'l','\u013C':'l','\u1E3D':'l','\u1E3B':'l','\u017F':'l','\u0142':'l','\u019A':'l','\u026B':'l','\u2C61':'l','\uA749':'l','\uA781':'l','\uA747':'l','\u01C9':'lj','\u24DC':'m','\uFF4D':'m','\u1E3F':'m','\u1E41':'m','\u1E43':'m','\u0271':'m','\u026F':'m','\u24DD':'n','\uFF4E':'n','\u01F9':'n','\u0144':'n','\u00F1':'n','\u1E45':'n','\u0148':'n','\u1E47':'n','\u0146':'n','\u1E4B':'n','\u1E49':'n','\u019E':'n','\u0272':'n','\u0149':'n','\uA791':'n','\uA7A5':'n','\u01CC':'nj','\u24DE':'o','\uFF4F':'o','\u00F2':'o','\u00F3':'o','\u00F4':'o','\u1ED3':'o','\u1ED1':'o','\u1ED7':'o','\u1ED5':'o','\u00F5':'o','\u1E4D':'o','\u022D':'o','\u1E4F':'o','\u014D':'o','\u1E51':'o','\u1E53':'o','\u014F':'o','\u022F':'o','\u0231':'o','\u00F6':'o','\u022B':'o','\u1ECF':'o','\u0151':'o','\u01D2':'o','\u020D':'o','\u020F':'o','\u01A1':'o','\u1EDD':'o','\u1EDB':'o','\u1EE1':'o','\u1EDF':'o','\u1EE3':'o','\u1ECD':'o','\u1ED9':'o','\u01EB':'o','\u01ED':'o','\u00F8':'o','\u01FF':'o','\u0254':'o','\uA74B':'o','\uA74D':'o','\u0275':'o','\u01A3':'oi','\u0223':'ou','\uA74F':'oo','\u24DF':'p','\uFF50':'p','\u1E55':'p','\u1E57':'p','\u01A5':'p','\u1D7D':'p','\uA751':'p','\uA753':'p','\uA755':'p','\u24E0':'q','\uFF51':'q','\u024B':'q','\uA757':'q','\uA759':'q','\u24E1':'r','\uFF52':'r','\u0155':'r','\u1E59':'r','\u0159':'r','\u0211':'r','\u0213':'r','\u1E5B':'r','\u1E5D':'r','\u0157':'r','\u1E5F':'r','\u024D':'r','\u027D':'r','\uA75B':'r','\uA7A7':'r','\uA783':'r','\u24E2':'s','\uFF53':'s','\u00DF':'s','\u015B':'s','\u1E65':'s','\u015D':'s','\u1E61':'s','\u0161':'s','\u1E67':'s','\u1E63':'s','\u1E69':'s','\u0219':'s','\u015F':'s','\u023F':'s','\uA7A9':'s','\uA785':'s','\u1E9B':'s','\u24E3':'t','\uFF54':'t','\u1E6B':'t','\u1E97':'t','\u0165':'t','\u1E6D':'t','\u021B':'t','\u0163':'t','\u1E71':'t','\u1E6F':'t','\u0167':'t','\u01AD':'t','\u0288':'t','\u2C66':'t','\uA787':'t','\uA729':'tz','\u24E4':'u','\uFF55':'u','\u00F9':'u','\u00FA':'u','\u00FB':'u','\u0169':'u','\u1E79':'u','\u016B':'u','\u1E7B':'u','\u016D':'u','\u00FC':'u','\u01DC':'u','\u01D8':'u','\u01D6':'u','\u01DA':'u','\u1EE7':'u','\u016F':'u','\u0171':'u','\u01D4':'u','\u0215':'u','\u0217':'u','\u01B0':'u','\u1EEB':'u','\u1EE9':'u','\u1EEF':'u','\u1EED':'u','\u1EF1':'u','\u1EE5':'u','\u1E73':'u','\u0173':'u','\u1E77':'u','\u1E75':'u','\u0289':'u','\u24E5':'v','\uFF56':'v','\u1E7D':'v','\u1E7F':'v','\u028B':'v','\uA75F':'v','\u028C':'v','\uA761':'vy','\u24E6':'w','\uFF57':'w','\u1E81':'w','\u1E83':'w','\u0175':'w','\u1E87':'w','\u1E85':'w','\u1E98':'w','\u1E89':'w','\u2C73':'w','\u24E7':'x','\uFF58':'x','\u1E8B':'x','\u1E8D':'x','\u24E8':'y','\uFF59':'y','\u1EF3':'y','\u00FD':'y','\u0177':'y','\u1EF9':'y','\u0233':'y','\u1E8F':'y','\u00FF':'y','\u1EF7':'y','\u1E99':'y','\u1EF5':'y','\u01B4':'y','\u024F':'y','\u1EFF':'y','\u24E9':'z','\uFF5A':'z','\u017A':'z','\u1E91':'z','\u017C':'z','\u017E':'z','\u1E93':'z','\u1E95':'z','\u01B6':'z','\u0225':'z','\u0240':'z','\u2C6C':'z','\uA763':'z','\u0386':'\u0391','\u0388':'\u0395','\u0389':'\u0397','\u038A':'\u0399','\u03AA':'\u0399','\u038C':'\u039F','\u038E':'\u03A5','\u03AB':'\u03A5','\u038F':'\u03A9','\u03AC':'\u03B1','\u03AD':'\u03B5','\u03AE':'\u03B7','\u03AF':'\u03B9','\u03CA':'\u03B9','\u0390':'\u03B9','\u03CC':'\u03BF','\u03CD':'\u03C5','\u03CB':'\u03C5','\u03B0':'\u03C5','\u03C9':'\u03C9','\u03C2':'\u03C3'};return diacritics;});S2.define('select2/data/base',['../utils'],function(Utils){function BaseAdapter($element,options){BaseAdapter.__super__.constructor.call(this);} +Utils.Extend(BaseAdapter,Utils.Observable);BaseAdapter.prototype.current=function(callback){throw new Error('The `current` method must be defined in child classes.');};BaseAdapter.prototype.query=function(params,callback){throw new Error('The `query` method must be defined in child classes.');};BaseAdapter.prototype.bind=function(container,$container){};BaseAdapter.prototype.destroy=function(){};BaseAdapter.prototype.generateResultId=function(container,data){var id=container.id+'-result-';id+=Utils.generateChars(4);if(data.id!=null){id+='-'+data.id.toString();}else{id+='-'+Utils.generateChars(4);} +return id;};return BaseAdapter;});S2.define('select2/data/select',['./base','../utils','jquery'],function(BaseAdapter,Utils,$){function SelectAdapter($element,options){this.$element=$element;this.options=options;SelectAdapter.__super__.constructor.call(this);} +Utils.Extend(SelectAdapter,BaseAdapter);SelectAdapter.prototype.current=function(callback){var data=[];var self=this;this.$element.find(':selected').each(function(){var $option=$(this);var option=self.item($option);data.push(option);});callback(data);};SelectAdapter.prototype.select=function(data){var self=this;data.selected=true;if($(data.element).is('option')){data.element.selected=true;this.$element.trigger('change');return;} +if(this.$element.prop('multiple')){this.current(function(currentData){var val=[];data=[data];data.push.apply(data,currentData);for(var d=0;d=0){var $existingOption=$existing.filter(onlyItem(item));var existingData=this.item($existingOption);var newData=$.extend(true,{},item,existingData);var $newOption=this.option(newData);$existingOption.replaceWith($newOption);continue;} +var $option=this.option(item);if(item.children){var $children=this.convertToOptions(item.children);Utils.appendMany($option,$children);} +$options.push($option);} +return $options;};return ArrayAdapter;});S2.define('select2/data/ajax',['./array','../utils','jquery'],function(ArrayAdapter,Utils,$){function AjaxAdapter($element,options){this.ajaxOptions=this._applyDefaults(options.get('ajax'));if(this.ajaxOptions.processResults!=null){this.processResults=this.ajaxOptions.processResults;} +AjaxAdapter.__super__.constructor.call(this,$element,options);} +Utils.Extend(AjaxAdapter,ArrayAdapter);AjaxAdapter.prototype._applyDefaults=function(options){var defaults={data:function(params){return $.extend({},params,{q:params.term});},transport:function(params,success,failure){var $request=$.ajax(params);$request.then(success);$request.fail(failure);return $request;}};return $.extend({},defaults,options,true);};AjaxAdapter.prototype.processResults=function(results){return results;};AjaxAdapter.prototype.query=function(params,callback){var matches=[];var self=this;if(this._request!=null){if($.isFunction(this._request.abort)){this._request.abort();} +this._request=null;} +var options=$.extend({type:'GET'},this.ajaxOptions);if(typeof options.url==='function'){options.url=options.url.call(this.$element,params);} +if(typeof options.data==='function'){options.data=options.data.call(this.$element,params);} +function request(){var $request=options.transport(options,function(data){var results=self.processResults(data,params);if(self.options.get('debug')&&window.console&&console.error){if(!results||!results.results||!$.isArray(results.results)){console.error('Select2: The AJAX results did not return an array in the '+'`results` key of the response.');}} +callback(results);},function(){if($request.status&&$request.status==='0'){return;} +self.trigger('results:message',{message:'errorLoading'});});self._request=$request;} +if(this.ajaxOptions.delay&¶ms.term!=null){if(this._queryTimeout){window.clearTimeout(this._queryTimeout);} +this._queryTimeout=window.setTimeout(request,this.ajaxOptions.delay);}else{request();}};return AjaxAdapter;});S2.define('select2/data/tags',['jquery'],function($){function Tags(decorated,$element,options){var tags=options.get('tags');var createTag=options.get('createTag');if(createTag!==undefined){this.createTag=createTag;} +var insertTag=options.get('insertTag');if(insertTag!==undefined){this.insertTag=insertTag;} +decorated.call(this,$element,options);if($.isArray(tags)){for(var t=0;t0&¶ms.term.length>this.maximumInputLength){this.trigger('results:message',{message:'inputTooLong',args:{maximum:this.maximumInputLength,input:params.term,params:params}});return;} +decorated.call(this,params,callback);};return MaximumInputLength;});S2.define('select2/data/maximumSelectionLength',[],function(){function MaximumSelectionLength(decorated,$e,options){this.maximumSelectionLength=options.get('maximumSelectionLength');decorated.call(this,$e,options);} +MaximumSelectionLength.prototype.query=function(decorated,params,callback){var self=this;this.current(function(currentData){var count=currentData!=null?currentData.length:0;if(self.maximumSelectionLength>0&&count>=self.maximumSelectionLength){self.trigger('results:message',{message:'maximumSelected',args:{maximum:self.maximumSelectionLength}});return;} +decorated.call(self,params,callback);});};return MaximumSelectionLength;});S2.define('select2/dropdown',['jquery','./utils'],function($,Utils){function Dropdown($element,options){this.$element=$element;this.options=options;Dropdown.__super__.constructor.call(this);} +Utils.Extend(Dropdown,Utils.Observable);Dropdown.prototype.render=function(){var $dropdown=$(''+''+'');$dropdown.attr('dir',this.options.get('dir'));this.$dropdown=$dropdown;return $dropdown;};Dropdown.prototype.bind=function(){};Dropdown.prototype.position=function($dropdown,$container){};Dropdown.prototype.destroy=function(){this.$dropdown.remove();};return Dropdown;});S2.define('select2/dropdown/search',['jquery','../utils'],function($,Utils){function Search(){} +Search.prototype.render=function(decorated){var $rendered=decorated.call(this);var $search=$(''+''+'');this.$searchContainer=$search;this.$search=$search.find('input');$rendered.prepend($search);return $rendered;};Search.prototype.bind=function(decorated,container,$container){var self=this;decorated.call(this,container,$container);this.$search.on('keydown',function(evt){self.trigger('keypress',evt);self._keyUpPrevented=evt.isDefaultPrevented();});this.$search.on('input',function(evt){$(this).off('keyup');});this.$search.on('keyup input',function(evt){self.handleSearch(evt);});container.on('open',function(){self.$search.attr('tabindex',0);self.$search.focus();window.setTimeout(function(){self.$search.focus();},0);});container.on('close',function(){self.$search.attr('tabindex',-1);self.$search.val('');});container.on('focus',function(){if(container.isOpen()){self.$search.focus();}});container.on('results:all',function(params){if(params.query.term==null||params.query.term===''){var showSearch=self.showSearch(params);if(showSearch){self.$searchContainer.removeClass('select2-search--hide');}else{self.$searchContainer.addClass('select2-search--hide');}}});};Search.prototype.handleSearch=function(evt){if(!this._keyUpPrevented){var input=this.$search.val();this.trigger('query',{term:input});} +this._keyUpPrevented=false;};Search.prototype.showSearch=function(_,params){return true;};return Search;});S2.define('select2/dropdown/hidePlaceholder',[],function(){function HidePlaceholder(decorated,$element,options,dataAdapter){this.placeholder=this.normalizePlaceholder(options.get('placeholder'));decorated.call(this,$element,options,dataAdapter);} +HidePlaceholder.prototype.append=function(decorated,data){data.results=this.removePlaceholder(data.results);decorated.call(this,data);};HidePlaceholder.prototype.normalizePlaceholder=function(_,placeholder){if(typeof placeholder==='string'){placeholder={id:'',text:placeholder};} +return placeholder;};HidePlaceholder.prototype.removePlaceholder=function(_,data){var modifiedData=data.slice(0);for(var d=data.length-1;d>=0;d--){var item=data[d];if(this.placeholder.id===item.id){modifiedData.splice(d,1);}} +return modifiedData;};return HidePlaceholder;});S2.define('select2/dropdown/infiniteScroll',['jquery'],function($){function InfiniteScroll(decorated,$element,options,dataAdapter){this.lastParams={};decorated.call(this,$element,options,dataAdapter);this.$loadingMore=this.createLoadingMore();this.loading=false;} +InfiniteScroll.prototype.append=function(decorated,data){this.$loadingMore.remove();this.loading=false;decorated.call(this,data);if(this.showLoadingMore(data)){this.$results.append(this.$loadingMore);}};InfiniteScroll.prototype.bind=function(decorated,container,$container){var self=this;decorated.call(this,container,$container);container.on('query',function(params){self.lastParams=params;self.loading=true;});container.on('query:append',function(params){self.lastParams=params;self.loading=true;});this.$results.on('scroll',function(){var isLoadMoreVisible=$.contains(document.documentElement,self.$loadingMore[0]);if(self.loading||!isLoadMoreVisible){return;} +var currentOffset=self.$results.offset().top+ +self.$results.outerHeight(false);var loadingMoreOffset=self.$loadingMore.offset().top+ +self.$loadingMore.outerHeight(false);if(currentOffset+50>=loadingMoreOffset){self.loadMore();}});};InfiniteScroll.prototype.loadMore=function(){this.loading=true;var params=$.extend({},{page:1},this.lastParams);params.page++;this.trigger('query:append',params);};InfiniteScroll.prototype.showLoadingMore=function(_,data){return data.pagination&&data.pagination.more;};InfiniteScroll.prototype.createLoadingMore=function(){var $option=$('
      • ');var message=this.options.get('translations').get('loadingMore');$option.html(message(this.lastParams));return $option;};return InfiniteScroll;});S2.define('select2/dropdown/attachBody',['jquery','../utils'],function($,Utils){function AttachBody(decorated,$element,options){this.$dropdownParent=options.get('dropdownParent')||$(document.body);decorated.call(this,$element,options);} +AttachBody.prototype.bind=function(decorated,container,$container){var self=this;var setupResultsEvents=false;decorated.call(this,container,$container);container.on('open',function(){self._showDropdown();self._attachPositioningHandler(container);if(!setupResultsEvents){setupResultsEvents=true;container.on('results:all',function(){self._positionDropdown();self._resizeDropdown();});container.on('results:append',function(){self._positionDropdown();self._resizeDropdown();});}});container.on('close',function(){self._hideDropdown();self._detachPositioningHandler(container);});this.$dropdownContainer.on('mousedown',function(evt){evt.stopPropagation();});};AttachBody.prototype.destroy=function(decorated){decorated.call(this);this.$dropdownContainer.remove();};AttachBody.prototype.position=function(decorated,$dropdown,$container){$dropdown.attr('class',$container.attr('class'));$dropdown.removeClass('select2');$dropdown.addClass('select2-container--open');$dropdown.css({position:'absolute',top:-999999});this.$container=$container;};AttachBody.prototype.render=function(decorated){var $container=$('');var $dropdown=decorated.call(this);$container.append($dropdown);this.$dropdownContainer=$container;return $container;};AttachBody.prototype._hideDropdown=function(decorated){this.$dropdownContainer.detach();};AttachBody.prototype._attachPositioningHandler=function(decorated,container){var self=this;var scrollEvent='scroll.select2.'+container.id;var resizeEvent='resize.select2.'+container.id;var orientationEvent='orientationchange.select2.'+container.id;var $watchers=this.$container.parents().filter(Utils.hasScroll);$watchers.each(function(){$(this).data('select2-scroll-position',{x:$(this).scrollLeft(),y:$(this).scrollTop()});});$watchers.on(scrollEvent,function(ev){var position=$(this).data('select2-scroll-position');$(this).scrollTop(position.y);});$(window).on(scrollEvent+' '+resizeEvent+' '+orientationEvent,function(e){self._positionDropdown();self._resizeDropdown();});};AttachBody.prototype._detachPositioningHandler=function(decorated,container){var scrollEvent='scroll.select2.'+container.id;var resizeEvent='resize.select2.'+container.id;var orientationEvent='orientationchange.select2.'+container.id;var $watchers=this.$container.parents().filter(Utils.hasScroll);$watchers.off(scrollEvent);$(window).off(scrollEvent+' '+resizeEvent+' '+orientationEvent);};AttachBody.prototype._positionDropdown=function(){var $window=$(window);var isCurrentlyAbove=this.$dropdown.hasClass('select2-dropdown--above');var isCurrentlyBelow=this.$dropdown.hasClass('select2-dropdown--below');var newDirection=null;var offset=this.$container.offset();offset.bottom=offset.top+this.$container.outerHeight(false);var container={height:this.$container.outerHeight(false)};container.top=offset.top;container.bottom=offset.top+container.height;var dropdown={height:this.$dropdown.outerHeight(false)};var viewport={top:$window.scrollTop(),bottom:$window.scrollTop()+$window.height()};var enoughRoomAbove=viewport.top<(offset.top-dropdown.height);var enoughRoomBelow=viewport.bottom>(offset.bottom+dropdown.height);var css={left:offset.left,top:container.bottom};var $offsetParent=this.$dropdownParent;if($offsetParent.css('position')==='static'){$offsetParent=$offsetParent.offsetParent();} +var parentOffset=$offsetParent.offset();css.top-=parentOffset.top;css.left-=parentOffset.left;if(!isCurrentlyAbove&&!isCurrentlyBelow){newDirection='below';} +if(!enoughRoomBelow&&enoughRoomAbove&&!isCurrentlyAbove){newDirection='above';}else if(!enoughRoomAbove&&enoughRoomBelow&&isCurrentlyAbove){newDirection='below';} +if(newDirection=='above'||(isCurrentlyAbove&&newDirection!=='below')){css.top=container.top-parentOffset.top-dropdown.height;} +if(newDirection!=null){this.$dropdown.removeClass('select2-dropdown--below select2-dropdown--above').addClass('select2-dropdown--'+newDirection);this.$container.removeClass('select2-container--below select2-container--above').addClass('select2-container--'+newDirection);} +this.$dropdownContainer.css(css);};AttachBody.prototype._resizeDropdown=function(){var css={width:this.$container.outerWidth(false)+'px'};if(this.options.get('dropdownAutoWidth')){css.minWidth=css.width;css.position='relative';css.width='auto';} +this.$dropdown.css(css);};AttachBody.prototype._showDropdown=function(decorated){this.$dropdownContainer.appendTo(this.$dropdownParent);this._positionDropdown();this._resizeDropdown();};return AttachBody;});S2.define('select2/dropdown/minimumResultsForSearch',[],function(){function countResults(data){var count=0;for(var d=0;d0){options.dataAdapter=Utils.Decorate(options.dataAdapter,MinimumInputLength);} +if(options.maximumInputLength>0){options.dataAdapter=Utils.Decorate(options.dataAdapter,MaximumInputLength);} +if(options.maximumSelectionLength>0){options.dataAdapter=Utils.Decorate(options.dataAdapter,MaximumSelectionLength);} +if(options.tags){options.dataAdapter=Utils.Decorate(options.dataAdapter,Tags);} +if(options.tokenSeparators!=null||options.tokenizer!=null){options.dataAdapter=Utils.Decorate(options.dataAdapter,Tokenizer);} +if(options.query!=null){var Query=require(options.amdBase+'compat/query');options.dataAdapter=Utils.Decorate(options.dataAdapter,Query);} +if(options.initSelection!=null){var InitSelection=require(options.amdBase+'compat/initSelection');options.dataAdapter=Utils.Decorate(options.dataAdapter,InitSelection);}} +if(options.resultsAdapter==null){options.resultsAdapter=ResultsList;if(options.ajax!=null){options.resultsAdapter=Utils.Decorate(options.resultsAdapter,InfiniteScroll);} +if(options.placeholder!=null){options.resultsAdapter=Utils.Decorate(options.resultsAdapter,HidePlaceholder);} +if(options.selectOnClose){options.resultsAdapter=Utils.Decorate(options.resultsAdapter,SelectOnClose);}} +if(options.dropdownAdapter==null){if(options.multiple){options.dropdownAdapter=Dropdown;}else{var SearchableDropdown=Utils.Decorate(Dropdown,DropdownSearch);options.dropdownAdapter=SearchableDropdown;} +if(options.minimumResultsForSearch!==0){options.dropdownAdapter=Utils.Decorate(options.dropdownAdapter,MinimumResultsForSearch);} +if(options.closeOnSelect){options.dropdownAdapter=Utils.Decorate(options.dropdownAdapter,CloseOnSelect);} +if(options.dropdownCssClass!=null||options.dropdownCss!=null||options.adaptDropdownCssClass!=null){var DropdownCSS=require(options.amdBase+'compat/dropdownCss');options.dropdownAdapter=Utils.Decorate(options.dropdownAdapter,DropdownCSS);} +options.dropdownAdapter=Utils.Decorate(options.dropdownAdapter,AttachBody);} +if(options.selectionAdapter==null){if(options.multiple){options.selectionAdapter=MultipleSelection;}else{options.selectionAdapter=SingleSelection;} +if(options.placeholder!=null){options.selectionAdapter=Utils.Decorate(options.selectionAdapter,Placeholder);} +if(options.allowClear){options.selectionAdapter=Utils.Decorate(options.selectionAdapter,AllowClear);} +if(options.multiple){options.selectionAdapter=Utils.Decorate(options.selectionAdapter,SelectionSearch);} +if(options.containerCssClass!=null||options.containerCss!=null||options.adaptContainerCssClass!=null){var ContainerCSS=require(options.amdBase+'compat/containerCss');options.selectionAdapter=Utils.Decorate(options.selectionAdapter,ContainerCSS);} +options.selectionAdapter=Utils.Decorate(options.selectionAdapter,EventRelay);} +if(typeof options.language==='string'){if(options.language.indexOf('-')>0){var languageParts=options.language.split('-');var baseLanguage=languageParts[0];options.language=[options.language,baseLanguage];}else{options.language=[options.language];}} +if($.isArray(options.language)){var languages=new Translation();options.language.push('en');var languageNames=options.language;for(var l=0;l0){var match=$.extend(true,{},data);for(var c=data.children.length-1;c>=0;c--){var child=data.children[c];var matches=matcher(params,child);if(matches==null){match.children.splice(c,1);}} +if(match.children.length>0){return match;} +return matcher(params,match);} +var original=stripDiacritics(data.text).toUpperCase();var term=stripDiacritics(params.term).toUpperCase();if(original.indexOf(term)>-1){return data;} +return null;} +this.defaults={amdBase:'./',amdLanguageBase:'./i18n/',closeOnSelect:true,debug:false,dropdownAutoWidth:false,escapeMarkup:Utils.escapeMarkup,language:EnglishTranslation,matcher:matcher,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:false,sorter:function(data){return data;},templateResult:function(result){return result.text;},templateSelection:function(selection){return selection.text;},theme:'default',width:'resolve'};};Defaults.prototype.set=function(key,value){var camelKey=$.camelCase(key);var data={};data[camelKey]=value;var convertedData=Utils._convertData(data);$.extend(this.defaults,convertedData);};var defaults=new Defaults();return defaults;});S2.define('select2/options',['require','jquery','./defaults','./utils'],function(require,$,Defaults,Utils){function Options(options,$element){this.options=options;if($element!=null){this.fromElement($element);} +this.options=Defaults.apply(this.options);if($element&&$element.is('input')){var InputCompat=require(this.get('amdBase')+'compat/inputData');this.options.dataAdapter=Utils.Decorate(this.options.dataAdapter,InputCompat);}} +Options.prototype.fromElement=function($e){var excludedData=['select2'];if(this.options.multiple==null){this.options.multiple=$e.prop('multiple');} +if(this.options.disabled==null){this.options.disabled=$e.prop('disabled');} +if(this.options.language==null){if($e.prop('lang')){this.options.language=$e.prop('lang').toLowerCase();}else if($e.closest('[lang]').prop('lang')){this.options.language=$e.closest('[lang]').prop('lang');}} +if(this.options.dir==null){if($e.prop('dir')){this.options.dir=$e.prop('dir');}else if($e.closest('[dir]').prop('dir')){this.options.dir=$e.closest('[dir]').prop('dir');}else{this.options.dir='ltr';}} +$e.prop('disabled',this.options.disabled);$e.prop('multiple',this.options.multiple);if($e.data('select2Tags')){if(this.options.debug&&window.console&&console.warn){console.warn('Select2: The `data-select2-tags` attribute has been changed to '+'use the `data-data` and `data-tags="true"` attributes and will be '+'removed in future versions of Select2.');} +$e.data('data',$e.data('select2Tags'));$e.data('tags',true);} +if($e.data('ajaxUrl')){if(this.options.debug&&window.console&&console.warn){console.warn('Select2: The `data-ajax-url` attribute has been changed to '+'`data-ajax--url` and support for the old attribute will be removed'+' in future versions of Select2.');} +$e.attr('ajax--url',$e.data('ajaxUrl'));$e.data('ajax--url',$e.data('ajaxUrl'));} +var dataset={};if($.fn.jquery&&$.fn.jquery.substr(0,2)=='1.'&&$e[0].dataset){dataset=$.extend(true,{},$e[0].dataset,$e.data());}else{dataset=$e.data();} +var data=$.extend(true,{},dataset);data=Utils._convertData(data);for(var key in data){if($.inArray(key,excludedData)>-1){continue;} +if($.isPlainObject(this.options[key])){$.extend(this.options[key],data[key]);}else{this.options[key]=data[key];}} +return this;};Options.prototype.get=function(key){return this.options[key];};Options.prototype.set=function(key,val){this.options[key]=val;};return Options;});S2.define('select2/core',['jquery','./options','./utils','./keys'],function($,Options,Utils,KEYS){var Select2=function($element,options){if($element.data('select2')!=null){$element.data('select2').destroy();} +this.$element=$element;this.id=this._generateId($element);options=options||{};this.options=new Options(options,$element);Select2.__super__.constructor.call(this);var tabindex=$element.attr('tabindex')||0;$element.data('old-tabindex',tabindex);$element.attr('tabindex','-1');var DataAdapter=this.options.get('dataAdapter');this.dataAdapter=new DataAdapter($element,this.options);var $container=this.render();this._placeContainer($container);var SelectionAdapter=this.options.get('selectionAdapter');this.selection=new SelectionAdapter($element,this.options);this.$selection=this.selection.render();this.selection.position(this.$selection,$container);var DropdownAdapter=this.options.get('dropdownAdapter');this.dropdown=new DropdownAdapter($element,this.options);this.$dropdown=this.dropdown.render();this.dropdown.position(this.$dropdown,$container);var ResultsAdapter=this.options.get('resultsAdapter');this.results=new ResultsAdapter($element,this.options,this.dataAdapter);this.$results=this.results.render();this.results.position(this.$results,this.$dropdown);var self=this;this._bindAdapters();this._registerDomEvents();this._registerDataEvents();this._registerSelectionEvents();this._registerDropdownEvents();this._registerResultsEvents();this._registerEvents();this.dataAdapter.current(function(initialData){self.trigger('selection:update',{data:initialData});});$element.addClass('select2-hidden-accessible');$element.attr('aria-hidden','true');this._syncAttributes();$element.data('select2',this);};Utils.Extend(Select2,Utils.Observable);Select2.prototype._generateId=function($element){var id='';if($element.attr('id')!=null){id=$element.attr('id');}else if($element.attr('name')!=null){id=$element.attr('name')+'-'+Utils.generateChars(2);}else{id=Utils.generateChars(4);} +id=id.replace(/(:|\.|\[|\]|,)/g,'');id='select2-'+id;return id;};Select2.prototype._placeContainer=function($container){$container.insertAfter(this.$element);var width=this._resolveWidth(this.$element,this.options.get('width'));if(width!=null){$container.css('width',width);}};Select2.prototype._resolveWidth=function($element,method){var WIDTH=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if(method=='resolve'){var styleWidth=this._resolveWidth($element,'style');if(styleWidth!=null){return styleWidth;} +return this._resolveWidth($element,'element');} +if(method=='element'){var elementWidth=$element.outerWidth(false);if(elementWidth<=0){return'auto';} +return elementWidth+'px';} +if(method=='style'){var style=$element.attr('style');if(typeof(style)!=='string'){return null;} +var attrs=style.split(';');for(var i=0,l=attrs.length;i=1){return matches[1];}} +return null;} +return method;};Select2.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container);this.selection.bind(this,this.$container);this.dropdown.bind(this,this.$container);this.results.bind(this,this.$container);};Select2.prototype._registerDomEvents=function(){var self=this;this.$element.on('change.select2',function(){self.dataAdapter.current(function(data){self.trigger('selection:update',{data:data});});});this.$element.on('focus.select2',function(evt){self.trigger('focus',evt);});this._syncA=Utils.bind(this._syncAttributes,this);this._syncS=Utils.bind(this._syncSubtree,this);if(this.$element[0].attachEvent){this.$element[0].attachEvent('onpropertychange',this._syncA);} +var observer=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;if(observer!=null){this._observer=new observer(function(mutations){$.each(mutations,self._syncA);$.each(mutations,self._syncS);});this._observer.observe(this.$element[0],{attributes:true,childList:true,subtree:false});}else if(this.$element[0].addEventListener){this.$element[0].addEventListener('DOMAttrModified',self._syncA,false);this.$element[0].addEventListener('DOMNodeInserted',self._syncS,false);this.$element[0].addEventListener('DOMNodeRemoved',self._syncS,false);}};Select2.prototype._registerDataEvents=function(){var self=this;this.dataAdapter.on('*',function(name,params){self.trigger(name,params);});};Select2.prototype._registerSelectionEvents=function(){var self=this;var nonRelayEvents=['toggle','focus'];this.selection.on('toggle',function(){self.toggleDropdown();});this.selection.on('focus',function(params){self.focus(params);});this.selection.on('*',function(name,params){if($.inArray(name,nonRelayEvents)!==-1){return;} +self.trigger(name,params);});};Select2.prototype._registerDropdownEvents=function(){var self=this;this.dropdown.on('*',function(name,params){self.trigger(name,params);});};Select2.prototype._registerResultsEvents=function(){var self=this;this.results.on('*',function(name,params){self.trigger(name,params);});};Select2.prototype._registerEvents=function(){var self=this;this.on('open',function(){self.$container.addClass('select2-container--open');});this.on('close',function(){self.$container.removeClass('select2-container--open');});this.on('enable',function(){self.$container.removeClass('select2-container--disabled');});this.on('disable',function(){self.$container.addClass('select2-container--disabled');});this.on('blur',function(){self.$container.removeClass('select2-container--focus');});this.on('query',function(params){if(!self.isOpen()){self.trigger('open',{});} +this.dataAdapter.query(params,function(data){self.trigger('results:all',{data:data,query:params});});});this.on('query:append',function(params){this.dataAdapter.query(params,function(data){self.trigger('results:append',{data:data,query:params});});});this.on('keypress',function(evt){var key=evt.which;if(self.isOpen()){if(key===KEYS.ESC||key===KEYS.TAB||(key===KEYS.UP&&evt.altKey)){self.close();evt.preventDefault();}else if(key===KEYS.ENTER){self.trigger('results:select',{});evt.preventDefault();}else if((key===KEYS.SPACE&&evt.ctrlKey)){self.trigger('results:toggle',{});evt.preventDefault();}else if(key===KEYS.UP){self.trigger('results:previous',{});evt.preventDefault();}else if(key===KEYS.DOWN){self.trigger('results:next',{});evt.preventDefault();}}else{if(key===KEYS.ENTER||key===KEYS.SPACE||(key===KEYS.DOWN&&evt.altKey)){self.open();evt.preventDefault();}}});};Select2.prototype._syncAttributes=function(){this.options.set('disabled',this.$element.prop('disabled'));if(this.options.get('disabled')){if(this.isOpen()){this.close();} +this.trigger('disable',{});}else{this.trigger('enable',{});}};Select2.prototype._syncSubtree=function(evt,mutations){var changed=false;var self=this;if(evt&&evt.target&&(evt.target.nodeName!=='OPTION'&&evt.target.nodeName!=='OPTGROUP')){return;} +if(!mutations){changed=true;}else if(mutations.addedNodes&&mutations.addedNodes.length>0){for(var n=0;n0){changed=true;} +if(changed){this.dataAdapter.current(function(currentData){self.trigger('selection:update',{data:currentData});});}};Select2.prototype.trigger=function(name,args){var actualTrigger=Select2.__super__.trigger;var preTriggerMap={'open':'opening','close':'closing','select':'selecting','unselect':'unselecting'};if(args===undefined){args={};} +if(name in preTriggerMap){var preTriggerName=preTriggerMap[name];var preTriggerArgs={prevented:false,name:name,args:args};actualTrigger.call(this,preTriggerName,preTriggerArgs);if(preTriggerArgs.prevented){args.prevented=true;return;}} +actualTrigger.call(this,name,args);};Select2.prototype.toggleDropdown=function(){if(this.options.get('disabled')){return;} +if(this.isOpen()){this.close();}else{this.open();}};Select2.prototype.open=function(){if(this.isOpen()){return;} +this.trigger('query',{});};Select2.prototype.close=function(){if(!this.isOpen()){return;} +this.trigger('close',{});};Select2.prototype.isOpen=function(){return this.$container.hasClass('select2-container--open');};Select2.prototype.hasFocus=function(){return this.$container.hasClass('select2-container--focus');};Select2.prototype.focus=function(data){if(this.hasFocus()){return;} +this.$container.addClass('select2-container--focus');this.trigger('focus',{});};Select2.prototype.enable=function(args){if(this.options.get('debug')&&window.console&&console.warn){console.warn('Select2: The `select2("enable")` method has been deprecated and will'+' be removed in later Select2 versions. Use $element.prop("disabled")'+' instead.');} +if(args==null||args.length===0){args=[true];} +var disabled=!args[0];this.$element.prop('disabled',disabled);};Select2.prototype.data=function(){if(this.options.get('debug')&&arguments.length>0&&window.console&&console.warn){console.warn('Select2: Data can no longer be set using `select2("data")`. You '+'should consider setting the value instead using `$element.val()`.');} +var data=[];this.dataAdapter.current(function(currentData){data=currentData;});return data;};Select2.prototype.val=function(args){if(this.options.get('debug')&&window.console&&console.warn){console.warn('Select2: The `select2("val")` method has been deprecated and will be'+' removed in later Select2 versions. Use $element.val() instead.');} +if(args==null||args.length===0){return this.$element.val();} +var newVal=args[0];if($.isArray(newVal)){newVal=$.map(newVal,function(obj){return obj.toString();});} +this.$element.val(newVal).trigger('change');};Select2.prototype.destroy=function(){this.$container.remove();if(this.$element[0].detachEvent){this.$element[0].detachEvent('onpropertychange',this._syncA);} +if(this._observer!=null){this._observer.disconnect();this._observer=null;}else if(this.$element[0].removeEventListener){this.$element[0].removeEventListener('DOMAttrModified',this._syncA,false);this.$element[0].removeEventListener('DOMNodeInserted',this._syncS,false);this.$element[0].removeEventListener('DOMNodeRemoved',this._syncS,false);} +this._syncA=null;this._syncS=null;this.$element.off('.select2');this.$element.attr('tabindex',this.$element.data('old-tabindex'));this.$element.removeClass('select2-hidden-accessible');this.$element.attr('aria-hidden','false');this.$element.removeData('select2');this.dataAdapter.destroy();this.selection.destroy();this.dropdown.destroy();this.results.destroy();this.dataAdapter=null;this.selection=null;this.dropdown=null;this.results=null;};Select2.prototype.render=function(){var $container=$(''+''+''+'');$container.attr('dir',this.options.get('dir'));this.$container=$container;this.$container.addClass('select2-container--'+this.options.get('theme'));$container.data('element',this.$element);return $container;};return Select2;});S2.define('select2/compat/utils',['jquery'],function($){function syncCssClasses($dest,$src,adapter){var classes,replacements=[],adapted;classes=$.trim($dest.attr('class'));if(classes){classes=''+classes;$(classes.split(/\s+/)).each(function(){if(this.indexOf('select2-')===0){replacements.push(this);}});} +classes=$.trim($src.attr('class'));if(classes){classes=''+classes;$(classes.split(/\s+/)).each(function(){if(this.indexOf('select2-')!==0){adapted=adapter(this);if(adapted!=null){replacements.push(adapted);}}});} +$dest.attr('class',replacements.join(' '));} +return{syncCssClasses:syncCssClasses};});S2.define('select2/compat/containerCss',['jquery','./utils'],function($,CompatUtils){function _containerAdapter(clazz){return null;} +function ContainerCSS(){} +ContainerCSS.prototype.render=function(decorated){var $container=decorated.call(this);var containerCssClass=this.options.get('containerCssClass')||'';if($.isFunction(containerCssClass)){containerCssClass=containerCssClass(this.$element);} +var containerCssAdapter=this.options.get('adaptContainerCssClass');containerCssAdapter=containerCssAdapter||_containerAdapter;if(containerCssClass.indexOf(':all:')!==-1){containerCssClass=containerCssClass.replace(':all:','');var _cssAdapter=containerCssAdapter;containerCssAdapter=function(clazz){var adapted=_cssAdapter(clazz);if(adapted!=null){return adapted+' '+clazz;} +return clazz;};} +var containerCss=this.options.get('containerCss')||{};if($.isFunction(containerCss)){containerCss=containerCss(this.$element);} +CompatUtils.syncCssClasses($container,this.$element,containerCssAdapter);$container.css(containerCss);$container.addClass(containerCssClass);return $container;};return ContainerCSS;});S2.define('select2/compat/dropdownCss',['jquery','./utils'],function($,CompatUtils){function _dropdownAdapter(clazz){return null;} +function DropdownCSS(){} +DropdownCSS.prototype.render=function(decorated){var $dropdown=decorated.call(this);var dropdownCssClass=this.options.get('dropdownCssClass')||'';if($.isFunction(dropdownCssClass)){dropdownCssClass=dropdownCssClass(this.$element);} +var dropdownCssAdapter=this.options.get('adaptDropdownCssClass');dropdownCssAdapter=dropdownCssAdapter||_dropdownAdapter;if(dropdownCssClass.indexOf(':all:')!==-1){dropdownCssClass=dropdownCssClass.replace(':all:','');var _cssAdapter=dropdownCssAdapter;dropdownCssAdapter=function(clazz){var adapted=_cssAdapter(clazz);if(adapted!=null){return adapted+' '+clazz;} +return clazz;};} +var dropdownCss=this.options.get('dropdownCss')||{};if($.isFunction(dropdownCss)){dropdownCss=dropdownCss(this.$element);} +CompatUtils.syncCssClasses($dropdown,this.$element,dropdownCssAdapter);$dropdown.css(dropdownCss);$dropdown.addClass(dropdownCssClass);return $dropdown;};return DropdownCSS;});S2.define('select2/compat/initSelection',['jquery'],function($){function InitSelection(decorated,$element,options){if(options.get('debug')&&window.console&&console.warn){console.warn('Select2: The `initSelection` option has been deprecated in favor'+' of a custom data adapter that overrides the `current` method. '+'This method is now called multiple times instead of a single '+'time when the instance is initialized. Support will be removed '+'for the `initSelection` option in future versions of Select2');} +this.initSelection=options.get('initSelection');this._isInitialized=false;decorated.call(this,$element,options);} +InitSelection.prototype.current=function(decorated,callback){var self=this;if(this._isInitialized){decorated.call(this,callback);return;} +this.initSelection.call(null,this.$element,function(data){self._isInitialized=true;if(!$.isArray(data)){data=[data];} +callback(data);});};return InitSelection;});S2.define('select2/compat/inputData',['jquery'],function($){function InputData(decorated,$element,options){this._currentData=[];this._valueSeparator=options.get('valueSeparator')||',';if($element.prop('type')==='hidden'){if(options.get('debug')&&console&&console.warn){console.warn('Select2: Using a hidden input with Select2 is no longer '+'supported and may stop working in the future. It is recommended '+'to use a `'+arr.join('')+'
        ';if(isArray(opts.yearRange)){i=opts.yearRange[0];j=opts.yearRange[1]+1;}else{i=year-opts.yearRange;j=1+year+opts.yearRange;} +for(arr=[];i=opts.minYear){arr.push('');}} +yearHtml='
        '+year+opts.yearSuffix+'
        ';if(opts.showMonthAfterYear){html+=yearHtml+monthHtml;}else{html+=monthHtml+yearHtml;} +if(isMinYear&&(month===0||opts.minMonth>=month)){prev=false;} +if(isMaxYear&&(month===11||opts.maxMonth<=month)){next=false;} +if(c===0){html+='';} +if(c===(instance._o.numberOfMonths-1)){html+='';} +return html+='
        ';},renderTable=function(opts,data,randId) +{return''+renderHead(opts)+renderBody(data)+'
        ';},Pikaday=function(options) +{var self=this,opts=self.config(options);self._onMouseDown=function(e) +{if(!self._v){return;} +e=e||window.event;var target=e.target||e.srcElement;if(!target){return;} +if(!hasClass(target,'is-disabled')){if(hasClass(target,'pika-button')&&!hasClass(target,'is-empty')&&!hasClass(target.parentNode,'is-disabled')){self.setDate(new Date(target.getAttribute('data-pika-year'),target.getAttribute('data-pika-month'),target.getAttribute('data-pika-day')));if(opts.bound){sto(function(){self.hide();if(opts.blurFieldOnSelect&&opts.field){opts.field.blur();}},100);}} +else if(hasClass(target,'pika-prev')){self.prevMonth();} +else if(hasClass(target,'pika-next')){self.nextMonth();}} +if(!hasClass(target,'pika-select')){if(e.preventDefault){e.preventDefault();}else{e.returnValue=false;return false;}}else{self._c=true;}};self._onChange=function(e) +{e=e||window.event;var target=e.target||e.srcElement;if(!target){return;} +if(hasClass(target,'pika-select-month')){self.gotoMonth(target.value);} +else if(hasClass(target,'pika-select-year')){self.gotoYear(target.value);}};self._onKeyChange=function(e) +{e=e||window.event;if(self.isVisible()){switch(e.keyCode){case 13:case 27:if(opts.field){opts.field.blur();} +break;case 37:self.adjustDate('subtract',1);break;case 38:self.adjustDate('subtract',7);break;case 39:self.adjustDate('add',1);break;case 40:self.adjustDate('add',7);break;case 8:case 46:self.setDate(null);break;}}};self._parseFieldValue=function() +{if(opts.parse){return opts.parse(opts.field.value,opts.format);}else if(hasMoment){var date=moment(opts.field.value,opts.format,opts.formatStrict);return(date&&date.isValid())?date.toDate():null;}else{return new Date(Date.parse(opts.field.value));}};self._onInputChange=function(e) +{var date;if(e.firedBy===self){return;} +date=self._parseFieldValue();if(isDate(date)){self.setDate(date);} +if(!self._v){self.show();}};self._onInputFocus=function() +{self.show();};self._onInputClick=function() +{self.show();};self._onInputBlur=function() +{var pEl=document.activeElement;do{if(hasClass(pEl,'pika-single')){return;}} +while((pEl=pEl.parentNode));if(!self._c){self._b=sto(function(){self.hide();},50);} +self._c=false;};self._onClick=function(e) +{e=e||window.event;var target=e.target||e.srcElement,pEl=target;if(!target){return;} +if(!hasEventListeners&&hasClass(target,'pika-select')){if(!target.onchange){target.setAttribute('onchange','return;');addEvent(target,'change',self._onChange);}} +do{if(hasClass(pEl,'pika-single')||pEl===opts.trigger){return;}} +while((pEl=pEl.parentNode));if(self._v&&target!==opts.trigger&&pEl!==opts.trigger){self.hide();}};self.el=document.createElement('div');self.el.className='pika-single'+(opts.isRTL?' is-rtl':'')+(opts.theme?' '+opts.theme:'');addEvent(self.el,'mousedown',self._onMouseDown,true);addEvent(self.el,'touchend',self._onMouseDown,true);addEvent(self.el,'change',self._onChange);if(opts.keyboardInput){addEvent(document,'keydown',self._onKeyChange);} +if(opts.field){if(opts.container){opts.container.appendChild(self.el);}else if(opts.bound){document.body.appendChild(self.el);}else{opts.field.parentNode.insertBefore(self.el,opts.field.nextSibling);} +addEvent(opts.field,'change',self._onInputChange);if(!opts.defaultDate){opts.defaultDate=self._parseFieldValue();opts.setDefaultDate=true;}} +var defDate=opts.defaultDate;if(isDate(defDate)){if(opts.setDefaultDate){self.setDate(defDate,true);}else{self.gotoDate(defDate);}}else{self.gotoDate(new Date());} +if(opts.bound){this.hide();self.el.className+=' is-bound';addEvent(opts.trigger,'click',self._onInputClick);addEvent(opts.trigger,'focus',self._onInputFocus);addEvent(opts.trigger,'blur',self._onInputBlur);}else{this.show();}};Pikaday.prototype={config:function(options) +{if(!this._o){this._o=extend({},defaults,true);} +var opts=extend(this._o,options,true);opts.isRTL=!!opts.isRTL;opts.field=(opts.field&&opts.field.nodeName)?opts.field:null;opts.theme=(typeof opts.theme)==='string'&&opts.theme?opts.theme:null;opts.bound=!!(opts.bound!==undefined?opts.field&&opts.bound:opts.field);opts.trigger=(opts.trigger&&opts.trigger.nodeName)?opts.trigger:opts.field;opts.disableWeekends=!!opts.disableWeekends;opts.disableDayFn=(typeof opts.disableDayFn)==='function'?opts.disableDayFn:null;var nom=parseInt(opts.numberOfMonths,10)||1;opts.numberOfMonths=nom>4?4:nom;if(!isDate(opts.minDate)){opts.minDate=false;} +if(!isDate(opts.maxDate)){opts.maxDate=false;} +if((opts.minDate&&opts.maxDate)&&opts.maxDate100){opts.yearRange=100;}} +return opts;},toString:function(format) +{format=format||this._o.format;if(!isDate(this._d)){return'';} +if(this._o.toString){return this._o.toString(this._d,format);} +if(hasMoment){return moment(this._d).format(format);} +return this._d.toDateString();},getMoment:function() +{return hasMoment?moment(this._d):null;},setMoment:function(date,preventOnSelect) +{if(hasMoment&&moment.isMoment(date)){this.setDate(date.toDate(),preventOnSelect);}},getDate:function() +{return isDate(this._d)?new Date(this._d.getTime()):null;},setDate:function(date,preventOnSelect) +{if(!date){this._d=null;if(this._o.field){this._o.field.value='';fireEvent(this._o.field,'change',{firedBy:this});} +return this.draw();} +if(typeof date==='string'){date=new Date(Date.parse(date));} +if(!isDate(date)){return;} +var min=this._o.minDate,max=this._o.maxDate;if(isDate(min)&&datemax){date=max;} +this._d=new Date(date.getTime());setToStartOfDay(this._d);this.gotoDate(this._d);if(this._o.field){this._o.field.value=this.toString();fireEvent(this._o.field,'change',{firedBy:this});} +if(!preventOnSelect&&typeof this._o.onSelect==='function'){this._o.onSelect.call(this,this.getDate());}},clear:function() +{this.setDate(null);},gotoDate:function(date) +{var newCalendar=true;if(!isDate(date)){return;} +if(this.calendars){var firstVisibleDate=new Date(this.calendars[0].year,this.calendars[0].month,1),lastVisibleDate=new Date(this.calendars[this.calendars.length-1].year,this.calendars[this.calendars.length-1].month,1),visibleDate=date.getTime();lastVisibleDate.setMonth(lastVisibleDate.getMonth()+1);lastVisibleDate.setDate(lastVisibleDate.getDate()-1);newCalendar=(visibleDate=maxYear){this._y=maxYear;if(!isNaN(maxMonth)&&this._m>maxMonth){this._m=maxMonth;}} +for(var c=0;c';} +this.el.innerHTML=html;if(opts.bound){if(opts.field.type!=='hidden'){sto(function(){opts.trigger.focus();},1);}} +if(typeof this._o.onDraw==='function'){this._o.onDraw(this);} +if(opts.bound){opts.field.setAttribute('aria-label',opts.ariaLabel);}},adjustPosition:function() +{var field,pEl,width,height,viewportWidth,viewportHeight,scrollTop,left,top,clientRect,leftAligned,bottomAligned;if(this._o.container)return;this.el.style.position='absolute';field=this._o.trigger;pEl=field;width=this.el.offsetWidth;height=this.el.offsetHeight;viewportWidth=window.innerWidth||document.documentElement.clientWidth;viewportHeight=window.innerHeight||document.documentElement.clientHeight;scrollTop=window.pageYOffset||document.body.scrollTop||document.documentElement.scrollTop;leftAligned=true;bottomAligned=true;if(typeof field.getBoundingClientRect==='function'){clientRect=field.getBoundingClientRect();left=clientRect.left+window.pageXOffset;top=clientRect.bottom+window.pageYOffset;}else{left=pEl.offsetLeft;top=pEl.offsetTop+pEl.offsetHeight;while((pEl=pEl.offsetParent)){left+=pEl.offsetLeft;top+=pEl.offsetTop;}} +if((this._o.reposition&&left+width>viewportWidth)||(this._o.position.indexOf('right')>-1&&left-width+field.offsetWidth>0)){left=left-width+field.offsetWidth;leftAligned=false;} +if((this._o.reposition&&top+height>viewportHeight+scrollTop)||(this._o.position.indexOf('top')>-1&&top-height-field.offsetHeight>0)){top=top-height-field.offsetHeight;bottomAligned=false;} +this.el.style.left=left+'px';this.el.style.top=top+'px';addClass(this.el,leftAligned?'left-aligned':'right-aligned');addClass(this.el,bottomAligned?'bottom-aligned':'top-aligned');removeClass(this.el,!leftAligned?'left-aligned':'right-aligned');removeClass(this.el,!bottomAligned?'bottom-aligned':'top-aligned');},render:function(year,month,randId) +{var opts=this._o,now=new Date(),days=getDaysInMonth(year,month),before=new Date(year,month,1).getDay(),data=[],row=[];setToStartOfDay(now);if(opts.firstDay>0){before-=opts.firstDay;if(before<0){before+=7;}} +var previousMonth=month===0?11:month-1,nextMonth=month===11?0:month+1,yearOfPreviousMonth=month===0?year-1:year,yearOfNextMonth=month===11?year+1:year,daysInPreviousMonth=getDaysInMonth(yearOfPreviousMonth,previousMonth);var cells=days+before,after=cells;while(after>7){after-=7;} +cells+=7-after;var isWeekSelected=false;for(var i=0,r=0;i=(days+before),dayNumber=1+(i-before),monthNumber=month,yearNumber=year,isStartRange=opts.startRange&&compareDates(opts.startRange,day),isEndRange=opts.endRange&&compareDates(opts.endRange,day),isInRange=opts.startRange&&opts.endRange&&opts.startRangeopts.maxDate)||(opts.disableWeekends&&isWeekend(day))||(opts.disableDayFn&&opts.disableDayFn(day));if(isEmpty){if(i';supported=(el.firstChild&&el.firstChild.namespaceURI)==svgNS;el.innerHTML='';return supported;})();var transitionSupported=(function(){var style=document.createElement('div').style;return'transition'in style||'WebkitTransition'in style||'MozTransition'in style||'msTransition'in style||'OTransition'in style;})();var touchSupported='ontouchstart'in window,mousedownEvent='mousedown'+(touchSupported?' touchstart':''),mousemoveEvent='mousemove.clockpicker'+(touchSupported?' touchmove.clockpicker':''),mouseupEvent='mouseup.clockpicker'+(touchSupported?' touchend.clockpicker':'');var vibrate=navigator.vibrate?'vibrate':navigator.webkitVibrate?'webkitVibrate':null;function createSvgElement(name){return document.createElementNS(svgNS,name);} +function leadingZero(num){return(num<10?'0':'')+num;} +var idCounter=0;function uniqueId(prefix){var id=++idCounter+'';return prefix?prefix+id:id;} +var dialRadius=100,outerRadius=80,innerRadius=54,tickRadius=13,diameter=dialRadius*2,duration=transitionSupported?350:1;var tpl=['
        ','
        ','
        ','',':',' ','','
        ','
        ','
        ','
        ','
        ','
        ','
        ','','','
        ','
        '].join('');function ClockPicker(element,options){var popover=$(tpl),plate=popover.find('.clockpicker-plate'),hoursView=popover.find('.clockpicker-hours'),minutesView=popover.find('.clockpicker-minutes'),amPmBlock=popover.find('.clockpicker-am-pm-block'),isInput=element.prop('tagName')==='INPUT',input=isInput?element:element.find('input'),addon=element.find('.input-group-addon'),self=this,timer;this.id=uniqueId('cp');this.element=element;this.options=options;this.isAppended=false;this.isShown=false;this.currentView='hours';this.isInput=isInput;this.input=input;this.addon=addon;this.popover=popover;this.plate=plate;this.hoursView=hoursView;this.minutesView=minutesView;this.amPmBlock=amPmBlock;this.spanHours=popover.find('.clockpicker-span-hours');this.spanMinutes=popover.find('.clockpicker-span-minutes');this.spanAmPm=popover.find('.clockpicker-span-am-pm');this.amOrPm="PM";if(options.twelvehour){var amPmButtonsTemplate=['
        ','','','
        '].join('');var amPmButtons=$(amPmButtonsTemplate);$('').on("click",function(){self.amOrPm="AM";$('.clockpicker-span-am-pm').empty().append('AM');}).appendTo(this.amPmBlock);$('').on("click",function(){self.amOrPm='PM';$('.clockpicker-span-am-pm').empty().append('PM');}).appendTo(this.amPmBlock);} +if(!options.autoclose){$('').click($.proxy(this.done,this)).appendTo(popover);} +if((options.placement==='top'||options.placement==='bottom'||options.placement==='auto')&&(options.align==='top'||options.align==='bottom'))options.align='left';if((options.placement==='left'||options.placement==='right')&&(options.align==='left'||options.align==='right'))options.align='top';popover.addClass(options.placement);popover.addClass('clockpicker-align-'+options.align);this.spanHours.click($.proxy(this.toggleView,this,'hours'));this.spanMinutes.click($.proxy(this.toggleView,this,'minutes'));input.on('focus.clockpicker click.clockpicker',$.proxy(this.show,this));addon.on('click.clockpicker',$.proxy(this.toggle,this));var tickTpl=$('
        '),i,tick,radian,radius;if(options.twelvehour){for(i=1;i<13;i+=1){tick=tickTpl.clone();radian=i/6*Math.PI;radius=outerRadius;tick.css('font-size','120%');tick.css({left:dialRadius+Math.sin(radian)*radius-tickRadius,top:dialRadius-Math.cos(radian)*radius-tickRadius});tick.html(i===0?'00':i);hoursView.append(tick);tick.on(mousedownEvent,mousedown);}}else{for(i=0;i<24;i+=1){tick=tickTpl.clone();radian=i/6*Math.PI;var inner=i>0&&i<13;radius=inner?innerRadius:outerRadius;tick.css({left:dialRadius+Math.sin(radian)*radius-tickRadius,top:dialRadius-Math.cos(radian)*radius-tickRadius});if(inner){tick.addClass('tick-inner');} +tick.html(i===0?'00':i);hoursView.append(tick);tick.on(mousedownEvent,mousedown);}} +for(i=0;i<60;i+=5){tick=tickTpl.clone();radian=i/30*Math.PI;tick.css({left:dialRadius+Math.sin(radian)*outerRadius-tickRadius,top:dialRadius-Math.cos(radian)*outerRadius-tickRadius});tick.html(leadingZero(i));minutesView.append(tick);tick.on(mousedownEvent,mousedown);} +plate.on(mousedownEvent,function(e){if($(e.target).closest('.clockpicker-tick').length===0){mousedown(e,true);}});function mousedown(e,space){var offset=plate.offset(),isTouch=/^touch/.test(e.type),x0=offset.left+dialRadius,y0=offset.top+dialRadius,dx=(isTouch?e.originalEvent.touches[0]:e).pageX-x0,dy=(isTouch?e.originalEvent.touches[0]:e).pageY-y0,z=Math.sqrt(dx*dx+dy*dy),moved=false;if(space&&(zouterRadius+tickRadius)){return;} +e.preventDefault();var movingTimer=setTimeout(function(){$body.addClass('clockpicker-moving');},200);if(svgSupported){plate.append(self.canvas);} +self.setHand(dx,dy,!space,true);$doc.off(mousemoveEvent).on(mousemoveEvent,function(e){e.preventDefault();var isTouch=/^touch/.test(e.type),x=(isTouch?e.originalEvent.touches[0]:e).pageX-x0,y=(isTouch?e.originalEvent.touches[0]:e).pageY-y0;if(!moved&&x===dx&&y===dy){return;} +moved=true;self.setHand(x,y,false,true);});$doc.off(mouseupEvent).on(mouseupEvent,function(e){$doc.off(mouseupEvent);e.preventDefault();var isTouch=/^touch/.test(e.type),x=(isTouch?e.originalEvent.changedTouches[0]:e).pageX-x0,y=(isTouch?e.originalEvent.changedTouches[0]:e).pageY-y0;if((space||moved)&&x===dx&&y===dy){self.setHand(x,y);} +if(self.currentView==='hours'){self.toggleView('minutes',duration/2);}else{if(options.autoclose){self.minutesView.addClass('clockpicker-dial-out');setTimeout(function(){self.done();},duration/2);}} +plate.prepend(canvas);clearTimeout(movingTimer);$body.removeClass('clockpicker-moving');$doc.off(mousemoveEvent);});} +if(svgSupported){var canvas=popover.find('.clockpicker-canvas'),svg=createSvgElement('svg');svg.setAttribute('class','clockpicker-svg');svg.setAttribute('width',diameter);svg.setAttribute('height',diameter);var g=createSvgElement('g');g.setAttribute('transform','translate('+dialRadius+','+dialRadius+')');var bearing=createSvgElement('circle');bearing.setAttribute('class','clockpicker-canvas-bearing');bearing.setAttribute('cx',0);bearing.setAttribute('cy',0);bearing.setAttribute('r',2);var hand=createSvgElement('line');hand.setAttribute('x1',0);hand.setAttribute('y1',0);var bg=createSvgElement('circle');bg.setAttribute('class','clockpicker-canvas-bg');bg.setAttribute('r',tickRadius);var fg=createSvgElement('circle');fg.setAttribute('class','clockpicker-canvas-fg');fg.setAttribute('r',3.5);g.appendChild(hand);g.appendChild(bg);g.appendChild(fg);g.appendChild(bearing);svg.appendChild(g);canvas.append(svg);this.hand=hand;this.bg=bg;this.fg=fg;this.bearing=bearing;this.g=g;this.canvas=canvas;} +raiseCallback(this.options.init);} +function raiseCallback(callbackFunction){if(callbackFunction&&typeof callbackFunction==="function"){callbackFunction();}} +ClockPicker.DEFAULTS={'default':'',fromnow:0,placement:'bottom',align:'left',donetext:'Done',autoclose:false,twelvehour:false,vibrate:true};ClockPicker.prototype.toggle=function(){this[this.isShown?'hide':'show']();};ClockPicker.prototype.locate=function(){var element=this.element,popover=this.popover,offset=element.offset(),width=element.outerWidth(),height=element.outerHeight(),placement=this.options.placement,align=this.options.align,styles={},self=this,viewportHeight=window.innerHeight||document.documentElement.clientHeight,scrollTop=window.pageYOffset||document.body.scrollTop||document.documentElement.scrollTop;popover.show();if(placement==='auto'){if(offset.top+popover.outerHeight()>viewportHeight+scrollTop){placement='top';}else{placement='bottom';}} +switch(placement){case'bottom':styles.top=offset.top+height;break;case'right':styles.left=offset.left+width;break;case'top':styles.top=offset.top-popover.outerHeight();break;case'left':styles.left=offset.left-popover.outerWidth();break;} +switch(align){case'left':styles.left=offset.left;break;case'right':styles.left=offset.left+width-popover.outerWidth();break;case'top':styles.top=offset.top;break;case'bottom':styles.top=offset.top+height-popover.outerHeight();break;} +popover.css(styles);};ClockPicker.prototype.show=function(e){if(this.isShown){return;} +raiseCallback(this.options.beforeShow);var self=this;if(!this.isAppended){$body=$(document.body).append(this.popover);$win.on('resize.clockpicker'+this.id,function(){if(self.isShown){self.locate();}});this.isAppended=true;} +var value=((this.input.prop('value')||this.options['default']||'')+'');if(this.options.twelvehour){var amPmValue=value.split(' ');if(amPmValue[1]){value=amPmValue[0];this.amOrPm=amPmValue[1];}} +value=value.split(':');if(value[0]==='now'){var now=new Date(+new Date()+this.options.fromnow);value=[now.getHours(),now.getMinutes()];} +this.hours=+value[0]||0;this.minutes=+value[1]||0;this.spanHours.html(leadingZero(this.hours));this.spanMinutes.html(leadingZero(this.minutes));if(this.options.twelvehour){this.spanAmPm.html(this.amOrPm);} +this.toggleView('hours');this.locate();this.isShown=true;$doc.on('click.clockpicker.'+this.id+' focusin.clockpicker.'+this.id,function(e){var target=$(e.target);if(target.closest(self.popover).length===0&&target.closest(self.addon).length===0&&target.closest(self.input).length===0){self.hide();}});$doc.on('keyup.clockpicker.'+this.id,function(e){if(e.keyCode===27){self.hide();}});raiseCallback(this.options.afterShow);};ClockPicker.prototype.hide=function(){raiseCallback(this.options.beforeHide);this.isShown=false;$doc.off('click.clockpicker.'+this.id+' focusin.clockpicker.'+this.id);$doc.off('keyup.clockpicker.'+this.id);this.popover.hide();raiseCallback(this.options.afterHide);};ClockPicker.prototype.toggleView=function(view,delay){var raiseAfterHourSelect=false;if(view==='minutes'&&$(this.hoursView).css("visibility")==="visible"){raiseCallback(this.options.beforeHourSelect);raiseAfterHourSelect=true;} +var isHours=view==='hours',nextView=isHours?this.hoursView:this.minutesView,hideView=isHours?this.minutesView:this.hoursView;this.currentView=view;this.spanHours.toggleClass('text-primary',isHours);this.spanMinutes.toggleClass('text-primary',!isHours);hideView.addClass('clockpicker-dial-out');nextView.css('visibility','visible').removeClass('clockpicker-dial-out');this.resetClock(delay);clearTimeout(this.toggleViewTimer);this.toggleViewTimer=setTimeout(function(){hideView.css('visibility','hidden');},duration);if(raiseAfterHourSelect){raiseCallback(this.options.afterHourSelect);}};ClockPicker.prototype.resetClock=function(delay){var view=this.currentView,value=this[view],isHours=view==='hours',unit=Math.PI/(isHours?6:30),radian=value*unit,radius=isHours&&value>0&&value<13?innerRadius:outerRadius,x=Math.sin(radian)*radius,y=-Math.cos(radian)*radius,self=this;if(svgSupported&&delay){self.canvas.addClass('clockpicker-canvas-out');setTimeout(function(){self.canvas.removeClass('clockpicker-canvas-out');self.setHand(x,y);},delay);}else{this.setHand(x,y);}};ClockPicker.prototype.setHand=function(x,y,roundBy5,dragging){var radian=Math.atan2(x,-y),isHours=this.currentView==='hours',unit=Math.PI/(isHours||roundBy5?6:30),z=Math.sqrt(x*x+y*y),options=this.options,inner=isHours&&z<(outerRadius+innerRadius)/2,radius=inner?innerRadius:outerRadius,value;if(options.twelvehour){radius=outerRadius;} +if(radian<0){radian=Math.PI*2+radian;} +value=Math.round(radian/unit);radian=value*unit;if(options.twelvehour){if(isHours){if(value===0){value=12;}}else{if(roundBy5){value*=5;} +if(value===60){value=0;}}}else{if(isHours){if(value===12){value=0;} +value=inner?(value===0?12:value):value===0?0:value+12;}else{if(roundBy5){value*=5;} +if(value===60){value=0;}}} +if(this[this.currentView]!==value){if(vibrate&&this.options.vibrate){if(!this.vibrateTimer){navigator[vibrate](10);this.vibrateTimer=setTimeout($.proxy(function(){this.vibrateTimer=null;},this),100);}}} +this[this.currentView]=value;this[isHours?'spanHours':'spanMinutes'].html(leadingZero(value));if(!svgSupported){this[isHours?'hoursView':'minutesView'].find('.clockpicker-tick').each(function(){var tick=$(this);tick.toggleClass('active',value===+tick.html());});return;} +if(dragging||(!isHours&&value%5)){this.g.insertBefore(this.hand,this.bearing);this.g.insertBefore(this.bg,this.fg);this.bg.setAttribute('class','clockpicker-canvas-bg clockpicker-canvas-bg-trans');}else{this.g.insertBefore(this.hand,this.bg);this.g.insertBefore(this.fg,this.bg);this.bg.setAttribute('class','clockpicker-canvas-bg');} +var cx=Math.sin(radian)*radius,cy=-Math.cos(radian)*radius;this.hand.setAttribute('x2',cx);this.hand.setAttribute('y2',cy);this.bg.setAttribute('cx',cx);this.bg.setAttribute('cy',cy);this.fg.setAttribute('cx',cx);this.fg.setAttribute('cy',cy);};ClockPicker.prototype.done=function(){raiseCallback(this.options.beforeDone);this.hide();var last=this.input.prop('value'),value=leadingZero(this.hours)+':'+leadingZero(this.minutes);if(this.options.twelvehour){value=value+' '+this.amOrPm;} +this.input.prop('value',value);if(value!==last){this.input.triggerHandler('change');if(!this.isInput){this.element.trigger('change');}} +if(this.options.autoclose){this.input.trigger('blur');} +raiseCallback(this.options.afterDone);};ClockPicker.prototype.remove=function(){this.element.removeData('clockpicker');this.input.off('focus.clockpicker click.clockpicker');this.addon.off('click.clockpicker');if(this.isShown){this.hide();} +if(this.isAppended){$win.off('resize.clockpicker'+this.id);this.popover.remove();}};$.fn.clockpicker=function(option){var args=Array.prototype.slice.call(arguments,1);return this.each(function(){var $this=$(this),data=$this.data('clockpicker');if(!data){var options=$.extend({},ClockPicker.DEFAULTS,$this.data(),typeof option=='object'&&option);$this.data('clockpicker',new ClockPicker($this,options));}else{if(typeof data[option]==='function'){data[option].apply(data,args);}}});};}());+function($){"use strict";if($.oc===undefined) +$.oc={} +if($.oc.foundation===undefined) +$.oc.foundation={} +$.oc.foundation._proxyCounter=0 +var Base=function(){this.proxiedMethods={}} +Base.prototype.dispose=function(){for(var key in this.proxiedMethods){this.proxiedMethods[key]=null} +this.proxiedMethods=null} +Base.prototype.proxy=function(method){if(method.ocProxyId===undefined){$.oc.foundation._proxyCounter++ +method.ocProxyId=$.oc.foundation._proxyCounter} +if(this.proxiedMethods[method.ocProxyId]!==undefined) +return this.proxiedMethods[method.ocProxyId] +this.proxiedMethods[method.ocProxyId]=method.bind(this) +return this.proxiedMethods[method.ocProxyId]} +$.oc.foundation.base=Base;}(window.jQuery);+function($){"use strict";if($.oc===undefined) +$.oc={} +if($.oc.foundation===undefined) +$.oc.foundation={} +var Element={hasClass:function(el,className){if(el.classList) +return el.classList.contains(className);return new RegExp('(^| )'+className+'( |$)','gi').test(el.className);},addClass:function(el,className){var classes=className.split(' ') +for(var i=0,len=classes.length;i=elementPosition.left&&point.x<=elementRight&&point.y>=elementPosition.top&&point.y<=elementBottom}} +$.oc.foundation.element=Element;}(window.jQuery);+function($){"use strict";if($.oc===undefined) +$.oc={} +if($.oc.foundation===undefined) +$.oc.foundation={} +var Event={getTarget:function(ev,tag){var target=ev.target?ev.target:ev.srcElement +if(tag===undefined) +return target +var tagName=target.tagName +while(tagName!=tag){target=target.parentNode +if(!target) +return null +tagName=target.tagName} +return target},stop:function(ev){if(ev.stopPropagation) +ev.stopPropagation() +else +ev.cancelBubble=true +if(ev.preventDefault) +ev.preventDefault() +else +ev.returnValue=false},pageCoordinates:function(ev){if(ev.pageX||ev.pageY){return{x:ev.pageX,y:ev.pageY}} +else if(ev.clientX||ev.clientY){return{x:(ev.clientX+document.body.scrollLeft+document.documentElement.scrollLeft),y:(ev.clientY+document.body.scrollTop+document.documentElement.scrollTop)}} +return{x:0,y:0}}} +$.oc.foundation.event=Event;}(window.jQuery);+function($){"use strict";if($.oc===undefined) +$.oc={} +if($.oc.foundation===undefined) +$.oc.foundation={} +var ControlUtils={markDisposable:function(el){el.setAttribute('data-disposable','')},disposeControls:function(container){var controls=container.querySelectorAll('[data-disposable]') +for(var i=0,len=controls.length;i p.flash-message').remove() +if($element.length==0){$element=$('

        ').addClass(options.class).html(options.text)} +$element.addClass('flash-message fade') +$element.attr('data-control',null) +$element.append('') +$element.on('click','button',remove) +$element.on('click',remove) +$(document.body).append($element) +setTimeout(function(){$element.addClass('in')},100) +var timer=window.setTimeout(remove,options.interval*1000) +function removeElement(){$element.remove()} +function remove(){window.clearInterval(timer) +$element.removeClass('in') +$.support.transition&&$element.hasClass('fade')?$element.one($.support.transition.end,removeElement).emulateTransitionEnd(500):removeElement()}} +FlashMessage.DEFAULTS={class:'success',text:'Default text',interval:5} +if($.oc===undefined) +$.oc={} +$.oc.flashMsg=FlashMessage +$(document).render(function(){$('[data-control=flash-message]').each(function(){$.oc.flashMsg($(this).data(),this)})})}(window.jQuery);!function($){"use strict";var Autocomplete=function(element,options){this.$element=$(element) +this.options=$.extend({},$.fn.autocomplete.defaults,options) +this.matcher=this.options.matcher||this.matcher +this.sorter=this.options.sorter||this.sorter +this.highlighter=this.options.highlighter||this.highlighter +this.updater=this.options.updater||this.updater +this.source=this.options.source +this.$menu=$(this.options.menu) +this.shown=false +this.listen()} +Autocomplete.prototype={constructor:Autocomplete,select:function(){var val=this.$menu.find('.active').attr('data-value') +this.$element.val(this.updater(val)).change() +return this.hide()},updater:function(item){return item},show:function(){var offset=this.options.bodyContainer?this.$element.offset():this.$element.position(),pos=$.extend({},offset,{height:this.$element[0].offsetHeight}),cssOptions={top:pos.top+pos.height,left:pos.left} +if(this.options.matchWidth){cssOptions.width=this.$element[0].offsetWidth} +this.$menu.css(cssOptions) +if(this.options.bodyContainer){$(document.body).append(this.$menu)} +else{this.$menu.insertAfter(this.$element)} +this.$menu.show() +this.shown=true +return this},hide:function(){this.$menu.hide() +this.shown=false +return this},lookup:function(event){var items +this.query=this.$element.val() +if(!this.query||this.query.length'+match+''})},render:function(items){var that=this +items=$(items).map(function(i,item){i=$(that.options.item).attr('data-value',that.itemValue(item)) +i.find('a').html(that.highlighter(that.itemLabel(item))) +return i[0]}) +items.first().addClass('active') +this.$menu.html(items) +return this},next:function(event){var active=this.$menu.find('.active').removeClass('active'),next=active.next() +if(!next.length){next=$(this.$menu.find('li')[0])} +next.addClass('active')},prev:function(event){var active=this.$menu.find('.active').removeClass('active'),prev=active.prev() +if(!prev.length){prev=this.$menu.find('li').last()} +prev.addClass('active')},listen:function(){this.$element.on('focus.autocomplete',$.proxy(this.focus,this)).on('blur.autocomplete',$.proxy(this.blur,this)).on('keypress.autocomplete',$.proxy(this.keypress,this)).on('keyup.autocomplete',$.proxy(this.keyup,this)) +if(this.eventSupported('keydown')){this.$element.on('keydown.autocomplete',$.proxy(this.keydown,this))} +this.$menu.on('click.autocomplete',$.proxy(this.click,this)).on('mouseenter.autocomplete','li',$.proxy(this.mouseenter,this)).on('mouseleave.autocomplete','li',$.proxy(this.mouseleave,this))},eventSupported:function(eventName){var isSupported=eventName in this.$element +if(!isSupported){this.$element.setAttribute(eventName,'return;') +isSupported=typeof this.$element[eventName]==='function'} +return isSupported},move:function(e){if(!this.shown)return +switch(e.key){case'Tab':case'Enter':case'Escape':e.preventDefault() +break +case'ArrowUp':e.preventDefault() +this.prev() +break +case'ArrowDown':e.preventDefault() +this.next() +break} +e.stopPropagation()},keydown:function(e){this.suppressKeyPressRepeat=~$.inArray(e.key,['ArrowDown','ArrowUp','Tab','Enter','Escape']) +this.move(e)},keypress:function(e){if(this.suppressKeyPressRepeat)return +this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break +case 9:case 13:if(!this.shown)return +this.select() +break +case 27:if(!this.shown)return +this.hide() +break +default:this.lookup()} +e.stopPropagation() +e.preventDefault()},focus:function(e){this.focused=true},blur:function(e){this.focused=false +if(!this.mousedover&&this.shown)this.hide()},click:function(e){e.stopPropagation() +e.preventDefault() +this.select() +this.$element.focus()},mouseenter:function(e){this.mousedover=true +this.$menu.find('.active').removeClass('active') +$(e.currentTarget).addClass('active')},mouseleave:function(e){this.mousedover=false +if(!this.focused&&this.shown)this.hide()},destroy:function(){this.hide() +this.$element.removeData('autocomplete') +this.$menu.remove() +this.$element.off('.autocomplete') +this.$menu.off('.autocomplete') +this.$element=null +this.$menu=null}} +var old=$.fn.autocomplete +$.fn.autocomplete=function(option){return this.each(function(){var $this=$(this),data=$this.data('autocomplete'),options=typeof option=='object'&&option +if(!data)$this.data('autocomplete',(data=new Autocomplete(this,options))) +if(typeof option=='string')data[option]()})} +$.fn.autocomplete.defaults={source:[],items:8,menu:'

        ',item:'
      • ',minLength:1,bodyContainer:false} +$.fn.autocomplete.Constructor=Autocomplete +$.fn.autocomplete.noConflict=function(){$.fn.autocomplete=old +return this} +function paramToObj(name,value){if(value===undefined)value='' +if(typeof value=='object')return value +try{return ocJSON("{"+value+"}")} +catch(e){throw new Error('Error parsing the '+name+' attribute value. '+e)}} +$(document).on('focus.autocomplete.data-api','[data-control="autocomplete"]',function(e){var $this=$(this) +if($this.data('autocomplete'))return +var opts=$this.data() +if(opts.source){opts.source=paramToObj('data-source',opts.source)} +$this.autocomplete(opts)})}(window.jQuery);(function($){$(document).on('keypress','div.custom-checkbox',function(e){if(e.key==='(Space character)'||e.key==='Spacebar'||e.key===' '){var $cb=$('input[type=checkbox]',this) +if($cb.data('oc-space-timestamp')==e.timeStamp) +return +$cb.get(0).checked=!$cb.get(0).checked +$cb.data('oc-space-timestamp',e.timeStamp) +$cb.trigger('change') +return false}}) +$(document).render(function(){$('div.custom-checkbox.is-indeterminate > input').each(function(){var $el=$(this),checked=$el.data('checked') +switch(checked){case 1:$el.prop('indeterminate',true) +break +case 2:$el.prop('indeterminate',false) +$el.prop('checked',true) +break +default:$el.prop('indeterminate',false) +$el.prop('checked',false)}})}) +$(document).on('click','div.custom-checkbox.is-indeterminate > label',function(){var $el=$(this).parent().find('input:first'),checked=$el.data('checked') +if(checked===undefined){checked=$el.is(':checked')?1:0} +switch(checked){case 0:$el.data('checked',1) +$el.prop('indeterminate',true) +break +case 1:$el.data('checked',2) +$el.prop('indeterminate',false) +$el.prop('checked',true) +break +default:$el.data('checked',0) +$el.prop('indeterminate',false) +$el.prop('checked',false)} +$el.trigger('change') +return false})})(jQuery);+function($){"use strict";var BalloonSelector=function(element,options){this.$el=$(element) +this.$field=$('input',this.$el) +this.options=options||{};var self=this;$('li',this.$el).click(function(){if(self.$el.hasClass('control-disabled')){return} +$('li',self.$el).removeClass('active') +$(this).addClass('active') +self.$field.val($(this).data('value')).trigger('change')})} +BalloonSelector.DEFAULTS={} +var old=$.fn.balloonSelector +$.fn.balloonSelector=function(option){return this.each(function(){var $this=$(this) +var data=$this.data('oc.balloon-selector') +var options=$.extend({},BalloonSelector.DEFAULTS,$this.data(),typeof option=='object'&&option) +if(!data)$this.data('oc.balloon-selector',(data=new BalloonSelector(this,options)))})} +$.fn.balloonSelector.Constructor=BalloonSelector +$.fn.balloonSelector.noConflict=function(){$.fn.balloonSelector=old +return this} +$(document).on('render',function(){$('div[data-control=balloon-selector]').balloonSelector()})}(window.jQuery);+function($){"use strict";$(document).on('shown.bs.dropdown','.dropdown',function(event,relatedTarget){$(document.body).addClass('dropdown-open') +var dropdown=$(relatedTarget.relatedTarget).siblings('.dropdown-menu'),dropdownContainer=$(this).data('dropdown-container') +if(dropdown.length===0){dropdown=$('.dropdown-menu',this)} +if($('.dropdown-container',dropdown).length==0){var title=$('[data-toggle=dropdown]',this).text(),titleAttr=dropdown.data('dropdown-title'),timer=null +if(titleAttr!==undefined) +title=titleAttr +$('li:first-child',dropdown).addClass('first-item') +$('li:last-child',dropdown).addClass('last-item') +dropdown.prepend($('
      • ').addClass('dropdown-title').text(title)) +var container=$('
      • ').addClass('dropdown-container'),ul=$('
      • ', $content->parsedMarkup); + } +} diff --git a/tests/unit/cms/classes/ControllerTest.php b/tests/unit/cms/classes/ControllerTest.php new file mode 100644 index 0000000..c7860c4 --- /dev/null +++ b/tests/unit/cms/classes/ControllerTest.php @@ -0,0 +1,542 @@ +themeUrl(); + $this->assertEquals(url('/themes/test'), $url); + + $url = $controller->themeUrl('foo/bar.css'); + $this->assertEquals(url('/themes/test/foo/bar.css'), $url); + + // + // These tests seem to bear different results + // + + // $url = $controller->themeUrl(['assets/css/style1.css', 'assets/css/style2.css']); + // $url = substr($url, 0, strpos($url, '-')); + // $this->assertEquals('/combine/88634b8fa6f4f6442ce830d38296640a', $url); + + // $url = $controller->themeUrl(['assets/js/script1.js', 'assets/js/script2.js']); + // $url = substr($url, 0, strpos($url, '-')); + // $this->assertEquals('/combine/860afc990164a60a8e90682d04da27ee', $url); + } + + public function test404() + { + /* + * Test the built-in 404 page + */ + $theme = Theme::load('apitest'); + $controller = new Controller($theme); + $response = $controller->run('/some-page-that-doesnt-exist'); + $this->assertNotEmpty($response); + $this->assertInstanceOf('\Illuminate\Http\Response', $response); + ob_start(); + include base_path().'/modules/cms/views/404.php'; + $page404Content = ob_get_contents(); + ob_end_clean(); + $this->assertEquals($page404Content, $response->getContent()); + + /* + * Test the theme 404 page + */ + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/some-page-that-doesnt-exist'); + $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response); + $content = $response->getContent(); + $this->assertIsString($content); + $this->assertEquals('

        Page not found

        ', $content); + } + + public function testRoot() + { + /* + * Test the / route and the fallback layout + */ + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/'); + $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response); + $content = $response->getContent(); + $this->assertIsString($content); + $this->assertEquals('

        My Webpage

        ', trim($content)); + } + + public function testLayoutNotFound() + { + $this->expectException(\Cms\Classes\CmsException::class); + $this->expectExceptionMessageMatches('/is\snot\sfound/'); + + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/no-layout'); + } + + public function testExistingLayout() + { + /* + * Test existing layout + */ + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/with-layout'); + $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response); + $content = $response->getContent(); + $this->assertEquals('

        Hey

        ', $content); + } + + public function testPartials() + { + /* + * Test partials referred in the layout and page + */ + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/with-partials')->getContent(); + $this->assertEquals('
        LAYOUT PARTIAL

        Hey PAGE PARTIAL Homer Simpson A partial

        ', $response); + } + + public function testContent() + { + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/with-content')->getContent(); + $this->assertEquals('
        LAYOUT CONTENT

        Hey PAGE CONTENT A content

        ', $response); + } + + public function testBlocks() + { + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/with-placeholder')->getContent(); + $this->assertEquals("
        LAYOUT CONTENT BLOCK\n DEFAULT

        Hey PAGE CONTENT

        SECOND BLOCK", $response); + } + + public function testLayoutInSubdirectory() + { + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/apage')->getContent(); + $this->assertEquals("
        LAYOUT CONTENT

        This page is a subdirectory

        ", $response); + } + + public function testPartialNotFound() + { + $this->expectException(\Twig\Error\RuntimeError::class); + $this->expectExceptionMessageMatches('/is\snot\sfound/'); + + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/no-partial')->getContent(); + } + + public function testPageLifeCycle() + { + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/cycle-test')->getContent(); + $this->assertEquals('12345', $response); + } + + protected function configAjaxRequestMock($handler, $partials = false) + { + $requestMock = $this + ->getMockBuilder('Illuminate\Http\Request') + ->disableOriginalConstructor() + ->setMethods(['ajax', 'method', 'header']) + ->getMock(); + + $map = [ + ['X_OCTOBER_REQUEST_HANDLER', null, $handler], + ['X_OCTOBER_REQUEST_PARTIALS', null, $partials], + ]; + + $requestMock->expects($this->any()) + ->method('ajax') + ->will($this->returnValue(true)); + + $requestMock->expects($this->any()) + ->method('method') + ->will($this->returnValue('POST')); + + $requestMock->expects($this->any()) + ->method('header') + ->will($this->returnValueMap($map)); + + return $requestMock; + } + + public function testAjaxHandlerNotFound() + { + $this->expectException(\Cms\Classes\CmsException::class); + $this->expectExceptionMessage('AJAX handler \'onNoHandler\' was not found.'); + + Request::swap($this->configAjaxRequestMock('onNoHandler', '')); + + $theme = Theme::load('test'); + $controller = new Controller($theme); + $controller->run('/ajax-test'); + } + + public function testAjaxInvalidHandlerName() + { + $this->expectException(\Cms\Classes\CmsException::class); + $this->expectExceptionMessage('Invalid AJAX handler name: delete.'); + + Request::swap($this->configAjaxRequestMock('delete')); + + $theme = Theme::load('test'); + $controller = new Controller($theme); + $controller->run('/ajax-test'); + } + + public function testAjaxInvalidPartial() + { + $this->expectException(\Cms\Classes\CmsException::class); + $this->expectExceptionMessage('Invalid partial name: p:artial.'); + + Request::swap($this->configAjaxRequestMock('onTest', 'p:artial')); + + $theme = Theme::load('test'); + $controller = new Controller($theme); + $controller->run('/ajax-test'); + } + + public function testAjaxPartialNotFound() + { + $this->expectException(\Cms\Classes\CmsException::class); + $this->expectExceptionMessage('The partial \'partial\' is not found.'); + + Request::swap($this->configAjaxRequestMock('onTest', 'partial')); + + $theme = Theme::load('test'); + $controller = new Controller($theme); + $controller->run('/ajax-test'); + } + + public function testPageAjax() + { + Request::swap($this->configAjaxRequestMock('onTest', 'ajax-result')); + + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/ajax-test'); + $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response); + + $content = $response->getOriginalContent(); + $this->assertIsArray($content); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertCount(1, $content); + $this->assertArrayHasKey('ajax-result', $content); + $this->assertEquals('page', $content['ajax-result']); + } + + public function testLayoutAjax() + { + Request::swap($this->configAjaxRequestMock('onTestLayout', 'ajax-result')); + + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/ajax-test'); + $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response); + + $content = $response->getOriginalContent(); + $this->assertIsArray($content); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertCount(1, $content); + $this->assertArrayHasKey('ajax-result', $content); + $this->assertEquals('layout-test', $content['ajax-result']); + } + + public function testAjaxMultiplePartials() + { + Request::swap($this->configAjaxRequestMock('onTest', 'ajax-result&ajax-second-result')); + + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/ajax-test'); + $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response); + + $content = $response->getOriginalContent(); + $this->assertIsArray($content); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertCount(2, $content); + $this->assertArrayHasKey('ajax-result', $content); + $this->assertArrayHasKey('ajax-second-result', $content); + $this->assertEquals('page', $content['ajax-result']); + $this->assertEquals('second', $content['ajax-second-result']); + } + + public function testBasicComponents() + { + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/with-component')->getContent(); + $page = self::getProtectedProperty($controller, 'page'); + $this->assertArrayHasKey('testArchive', $page->components); + + $component = $page->components['testArchive']; + $details = $component->componentDetails(); + + $content = <<LAYOUT CONTENT

        This page uses components.

        +

        Lorum ipsum

        +

        Post Content #1

        +

        La Playa Nudista

        +

        Second Post Content

        +
        +ESC; + + $this->assertEquals(str_replace(PHP_EOL, "\n", $content), $response); + $this->assertEquals(69, $component->property('posts-per-page')); + $this->assertEquals('Blog Archive Dummy Component', $details['name']); + $this->assertEquals('Displays an archive of blog posts.', $details['description']); + } + + public function testComponentAliases() + { + include_once base_path() . '/tests/fixtures/plugins/october/tester/components/Archive.php'; + + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/with-components')->getContent(); + $page = self::getProtectedProperty($controller, 'page'); + + $this->assertArrayHasKey('firstAlias', $page->components); + $this->assertArrayHasKey('secondAlias', $page->components); + + $component = $page->components['firstAlias']; + $component2 = $page->components['secondAlias']; + + $content = <<LAYOUT CONTENT

        This page uses components.

        +

        Lorum ipsum

        +

        Post Content #1

        +

        La Playa Nudista

        +

        Second Post Content

        +
        +ESC; + + $this->assertEquals(str_replace(PHP_EOL, "\n", $content), $response); + $this->assertEquals(6, $component->property('posts-per-page')); + $this->assertEquals(9, $component2->property('posts-per-page')); + } + + public function testComponentAjax() + { + Request::swap($this->configAjaxRequestMock('testArchive::onTestAjax', 'ajax-result')); + + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/with-component'); + $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response); + + $content = $response->getOriginalContent(); + $this->assertIsArray($content); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertCount(1, $content); + $this->assertArrayHasKey('ajax-result', $content); + $this->assertEquals('page', $content['ajax-result']); + } + + public function testComponentClassNotFound() + { + $this->expectException(\October\Rain\Exception\SystemException::class); + $this->expectExceptionMessageMatches('/is\snot\sregistered\sfor\sthe\scomponent/'); + + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/no-component-class')->getContent(); + } + + public function testSoftComponentClassNotFound() + { + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/no-soft-component-class')->getContent(); + + $this->assertEquals('

        Hey

        ', $response); + } + + public function testSoftComponentClassFound() + { + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/with-soft-component-class')->getContent(); + $page = $controller->getPage(); + $this->assertArrayHasKey('testArchive', $page->components); + + $component = $page->components['testArchive']; + $details = $component->componentDetails(); + + $content = <<LAYOUT CONTENT

        This page uses components.

        +

        Lorum ipsum

        +

        Post Content #1

        +

        La Playa Nudista

        +

        Second Post Content

        +
        +ESC; + + $this->assertEquals(str_replace(PHP_EOL, "\n", $content), $response); + $this->assertEquals(69, $component->property('posts-per-page')); + $this->assertEquals('Blog Archive Dummy Component', $details['name']); + $this->assertEquals('Displays an archive of blog posts.', $details['description']); + } + + public function testSoftComponentWithAliasClassFound() + { + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/with-soft-component-class-alias')->getContent(); + $page = $controller->getPage(); + $this->assertArrayHasKey('someAlias', $page->components); + + $component = $page->components['someAlias']; + $details = $component->componentDetails(); + + $content = <<LAYOUT CONTENT

        This page uses components.

        +

        Lorum ipsum

        +

        Post Content #1

        +

        La Playa Nudista

        +

        Second Post Content

        +
        +ESC; + + $this->assertEquals(str_replace(PHP_EOL, "\n", $content), $response); + $this->assertEquals(69, $component->property('posts-per-page')); + $this->assertEquals('Blog Archive Dummy Component', $details['name']); + $this->assertEquals('Displays an archive of blog posts.', $details['description']); + } + + public function testComponentNotFound() + { + // + // This test should probably be throwing an exception... -sg + // + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/no-component')->getContent(); + + $this->assertEquals('

        Hey

        ', $response); + } + + public function testComponentPartial() + { + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/component-partial')->getContent(); + + $this->assertEquals('

        DEFAULT MARKUP: I am a post yay

        ', $response); + } + + public function testComponentPartialAliasOverride() + { + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/component-partial-alias-override')->getContent(); + + // + // Testing case sensitivity + // + // Component alias: overRide1 + // Target path: partials\override1\default.htm + // + $this->assertEquals('

        I am an override alias partial! Yay

        ', $response); + } + + public function testComponentPartialOverride() + { + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/component-partial-override')->getContent(); + + // + // Testing case sensitivity + // + // Component code: testPost + // Target path: partials\testpost\default.htm + // + $this->assertEquals('

        I am an override partial! Yay

        ', $response); + } + + public function testComponentPartialNesting() + { + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/component-partial-nesting')->getContent(); + + $content = <<Level 1 +
          + Home + Blog + About + Contact + Home + Blog + About + Contact + Home + Blog + About + Contact +
        + +

        Level 2

        +

        DEFAULT MARKUP: I am a post yay

        I am another post, deep down

        + +

        Level 3

        +

        DEFAULT MARKUP: Menu

        +
          +
        • DEFAULT: Home
        • +
        • DEFAULT: Blog
        • +
        • DEFAULT: About
        • +
        • DEFAULT: Contact
        • +
        +

        Insert post here

        +ESC; + + $this->assertEquals(str_replace(PHP_EOL, "\n", $content), $response); + } + + public function testComponentWithOnRender() + { + $theme = Theme::load('test'); + $controller = new Controller($theme); + $response = $controller->run('/component-custom-render')->getContent(); + + $content = <<assertEquals(str_replace(PHP_EOL, "\n", $content), $response); + } +} diff --git a/tests/unit/cms/classes/PartialStackTest.php b/tests/unit/cms/classes/PartialStackTest.php new file mode 100644 index 0000000..f9371a3 --- /dev/null +++ b/tests/unit/cms/classes/PartialStackTest.php @@ -0,0 +1,58 @@ +stackPartial(); + $stack->addComponent('override1', 'October\Tester\Components\MainMenu'); + $stack->addComponent('override2', 'October\Tester\Components\ContentBlock'); + + $stack->stackPartial(); + $stack->addComponent('override3', 'October\Tester\Components\Post'); + $stack->addComponent('post', 'October\Tester\Components\Post'); + + $stack->stackPartial(); + $stack->addComponent('mainMenu', 'October\Tester\Components\MainMenu'); + + /* + * Knock em down + */ + $this->assertEquals('October\Tester\Components\MainMenu', $stack->getComponent('mainMenu')); + $this->assertEquals('October\Tester\Components\MainMenu', $stack->getComponent('override1')); + + $stack->unstackPartial(); + + $this->assertNull($stack->getComponent('mainMenu')); + $this->assertEquals('October\Tester\Components\ContentBlock', $stack->getComponent('override2')); + $this->assertEquals('October\Tester\Components\Post', $stack->getComponent('override3')); + + $stack->unstackPartial(); + + $this->assertNull($stack->getComponent('mainMenu')); + $this->assertNull($stack->getComponent('post')); + $this->assertEquals('October\Tester\Components\MainMenu', $stack->getComponent('override1')); + + $stack->unstackPartial(); + + $this->assertNull($stack->getComponent('post')); + $this->assertNull($stack->getComponent('mainMenu')); + $this->assertNull($stack->getComponent('override1')); + $this->assertNull($stack->getComponent('override2')); + $this->assertNull($stack->getComponent('override3')); + } + + public function testEmptyStack() + { + $stack = new PartialStack; + $this->assertNull($stack->getComponent('xxx')); + } +} diff --git a/tests/unit/cms/classes/RouterTest.php b/tests/unit/cms/classes/RouterTest.php new file mode 100644 index 0000000..f4eeda2 --- /dev/null +++ b/tests/unit/cms/classes/RouterTest.php @@ -0,0 +1,179 @@ +getMethod($name); + $method->setAccessible(true); + return $method; + } + + public static function getProperty($name) + { + $class = new ReflectionClass('\Cms\Classes\Router'); + $property = $class->getProperty($name); + $property->setAccessible(true); + return $property; + } + + public function testLoadUrlMap() + { + $method = self::getMethod('loadUrlMap'); + $property = self::getProperty('urlMap'); + $router = new Router(self::$theme); + + /* + * The first time the map should be loaded from the disk + */ + $value = $method->invoke($router); + $this->assertFalse($value); + $map = $property->getValue($router); + + $this->assertIsArray($map); + $this->assertGreaterThanOrEqual(4, count($map)); + + /* + * The second time the map should be loaded from the disk + */ + $value = $method->invoke($router); + $this->assertTrue($value); + $map = $property->getValue($router); + $this->assertIsArray($map); + $this->assertGreaterThanOrEqual(4, count($map)); + } + + public function testUrlListCaching() + { + $router = new Router(self::$theme); + $method = self::getMethod('getCachedUrlFileName'); + $urlList = []; + + /* + * The first time the page should be loaded from the disk. + */ + $result = $method->invokeArgs($router, ['/', &$urlList]); + $this->assertNull($result); + + /* + * Resolve the page to initialize the cache + */ + $page = $router->findByUrl('/'); + $this->assertNotEmpty($page); + $this->assertEquals('index.htm', $page->getFileName()); + + /* + * The second time the page should be loaded from the cache. + */ + $result = $method->invokeArgs($router, ['/', &$urlList]); + $this->assertEquals('index.htm', $result); + + /* + * Clear the cache + */ + $router->clearCache(); + $result = $method->invokeArgs($router, ['/', &$urlList]); + $this->assertNull($result); + } + + public function testFindPageByUrl() + { + $router = new Router(self::$theme); + $page = $router->findByUrl('/'); + $this->assertNotEmpty($page); + $this->assertEquals('index.htm', $page->getFileName()); + + $page = $router->findByUrl('blog/post'); + $this->assertEmpty($page); + + $page = $router->findByUrl('blog/post/my-post-title'); + $parameters = $router->getParameters(); + $this->assertNotEmpty($page); + $this->assertEquals('blog-post.htm', $page->getFileName()); + $this->assertCount(1, $parameters); + $this->assertArrayHasKey('url_title', $parameters); + $this->assertEquals('my-post-title', $parameters['url_title']); + + // Test cached + $page = $router->findByUrl('blog/post/my-post-title'); + $parameters = $router->getParameters(); + $this->assertNotEmpty($page); + $this->assertEquals('blog-post.htm', $page->getFileName()); + $this->assertCount(1, $parameters); + $this->assertArrayHasKey('url_title', $parameters); + $this->assertEquals('my-post-title', $parameters['url_title']); + + $page = $router->findByUrl('AuthOrs'); + $parameters = $router->getParameters(); + $this->assertNotEmpty($page); + $this->assertEquals('authors.htm', $page->getFileName()); + $this->assertCount(1, $parameters); + $this->assertArrayHasKey('author_id', $parameters); + $this->assertEquals('no-author', $parameters['author_id']); + + $page = $router->findByUrl('AuthOrs/test'); + $this->assertEmpty($page); + + $page = $router->findByUrl('AuthOrs/test/12'); + $this->assertEmpty($page); + + $page = $router->findByUrl('AuthOrs/44/'); + $parameters = $router->getParameters(); + $this->assertNotEmpty($page); + $this->assertEquals('authors.htm', $page->getFileName()); + $this->assertCount(1, $parameters); + $this->assertArrayHasKey('author_id', $parameters); + $this->assertEquals('44', $parameters['author_id']); + + $page = $router->findByUrl('blog/archive-page'); + $parameters = $router->getParameters(); + $this->assertNotEmpty($page); + $this->assertEquals('blog-archive.htm', $page->getFileName()); + $this->assertCount(1, $parameters); + + $page = $router->findByUrl('blog/category-page'); + $parameters = $router->getParameters(); + $this->assertNotEmpty($page); + $this->assertEquals('blog-category.htm', $page->getFileName()); + $this->assertCount(1, $parameters); + $this->assertEquals(array_keys($parameters)[0], 'category_name'); + $this->assertEmpty($parameters[array_keys($parameters)[0]]); + + $page = $router->findByUrl('blog/category-page/categoryName'); + $parameters = $router->getParameters(); + $this->assertNotEmpty($page); + $this->assertEquals('blog-category.htm', $page->getFileName()); + $this->assertCount(1, $parameters); + + $page = $router->findByUrl('blog/category-page/categoryName/subCategoryName'); + $parameters = $router->getParameters(); + $this->assertNotEmpty($page); + $this->assertEquals('blog-category.htm', $page->getFileName()); + $this->assertCount(1, $parameters); + } + + public function testFindPageFromSubdirectory() + { + $router = new Router(self::$theme); + $page = $router->findByUrl('/apage'); + $this->assertNotEmpty($page); + $this->assertEquals('a/a-page.htm', $page->getFileName()); + + $page = $router->findByUrl('/bpage'); + $this->assertNotEmpty($page); + $this->assertEquals('b/b-page.htm', $page->getFileName()); + } +} diff --git a/tests/unit/cms/classes/ThemeTest.php b/tests/unit/cms/classes/ThemeTest.php new file mode 100644 index 0000000..c0e53c5 --- /dev/null +++ b/tests/unit/cms/classes/ThemeTest.php @@ -0,0 +1,90 @@ +setMaxDepth(1); + $it->rewind(); + + while ($it->valid()) { + if (!$it->isDot() && !$it->isDir() && $it->getExtension() == 'htm') { + $result++; + } + + $it->next(); + } + + return $result; + } + + public function testGetPath() + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestIncomplete('Need to fix Windows testing here'); + } + + $theme = Theme::load('test'); + + $this->assertEquals(base_path('tests/fixtures/themes/test'), $theme->getPath()); + } + + public function testListPages() + { + $theme = Theme::load('test'); + + $pageCollection = $theme->listPages(); + $pages = array_values($pageCollection->all()); + $this->assertIsArray($pages); + + $expectedPageNum = $this->countThemePages(base_path().'/tests/fixtures/themes/test/pages'); + $this->assertCount($expectedPageNum, $pages); + + $this->assertInstanceOf('\Cms\Classes\Page', $pages[0]); + $this->assertNotEmpty($pages[0]->url); + $this->assertInstanceOf('\Cms\Classes\Page', $pages[1]); + $this->assertNotEmpty($pages[1]->url); + } + + public function testGetActiveTheme() + { + $activeTheme = Theme::getActiveTheme(); + + $this->assertNotNull($activeTheme); + $this->assertEquals('test', $activeTheme->getDirName()); + } + + public function testNoActiveTheme() + { + $this->expectException(\October\Rain\Exception\SystemException::class); + $this->expectExceptionMessage('The active theme is not set.'); + + Config::set('cms.activeTheme', null); + Theme::getActiveTheme(); + } + + public function testApiTheme() + { + Event::flush('cms.theme.getActiveTheme'); + Event::listen('cms.theme.getActiveTheme', function () { + return 'apitest'; + }); + + $activeTheme = Theme::getActiveTheme(); + $this->assertNotNull($activeTheme); + $this->assertEquals('apitest', $activeTheme->getDirName()); + } +} diff --git a/tests/unit/cms/helpers/FileTest.php b/tests/unit/cms/helpers/FileTest.php new file mode 100644 index 0000000..dde19f0 --- /dev/null +++ b/tests/unit/cms/helpers/FileTest.php @@ -0,0 +1,18 @@ +assertFalse(FileHelper::validateName('')); + $this->assertTrue(FileHelper::validateName('01test-testdat')); + $this->assertTrue(FileHelper::validateName('test/testdat')); + $this->assertFalse(FileHelper::validateName('test\testdat')); + $this->assertTrue(FileHelper::validateName('01test-test.dat')); + $this->assertFalse(FileHelper::validateName('test@test.dat')); + $this->assertFalse(FileHelper::validateName('test::test')); + $this->assertFalse(FileHelper::validateName('@test')); + } +} diff --git a/tests/unit/phpunit.xml b/tests/unit/phpunit.xml new file mode 100644 index 0000000..29a3bb3 --- /dev/null +++ b/tests/unit/phpunit.xml @@ -0,0 +1,23 @@ + + + + + ./ + + + + + + + + \ No newline at end of file diff --git a/tests/unit/plugins/backend/ImportModelDbTest.php b/tests/unit/plugins/backend/ImportModelDbTest.php new file mode 100644 index 0000000..61a1d8e --- /dev/null +++ b/tests/unit/plugins/backend/ImportModelDbTest.php @@ -0,0 +1,42 @@ + base_path().'/tests/fixtures/backend/reference/file1.txt', + 'is_public' => false, + ]); + + $file2 = FileModel::create([ + 'data' => base_path().'/tests/fixtures/backend/reference/file2.txt', + 'is_public' => false, + ]); + + $model->import_file()->add($file1, $sessionKey); + $model->import_file()->add($file2, $sessionKey); + + $this->assertEquals( + $file2->getLocalPath(), + $model->getImportFilePath($sessionKey), + 'ImportModel::getImportFilePath() should return the last uploaded file.' + ); + } +} diff --git a/tests/unit/plugins/database/AttachManyModelTest.php b/tests/unit/plugins/database/AttachManyModelTest.php new file mode 100644 index 0000000..9c316c0 --- /dev/null +++ b/tests/unit/plugins/database/AttachManyModelTest.php @@ -0,0 +1,53 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testDeleteFlagDestroyRelationship() + { + Model::unguard(); + $user = User::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + Model::reguard(); + + $this->assertEmpty($user->photos); + $user->photos()->create(['data' => base_path().'/tests/fixtures/plugins/database/tester/assets/images/avatar.png']); + $user->reloadRelations(); + $this->assertNotEmpty($user->photos); + + $photo = $user->photos->first(); + $photoId = $photo->id; + + $user->photos()->remove($photo); + $this->assertNull(FileModel::find($photoId)); + } + + public function testDeleteFlagDeleteModel() + { + Model::unguard(); + $user = User::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + Model::reguard(); + + $this->assertEmpty($user->photos); + $user->photos()->create(['data' => base_path().'/tests/fixtures/plugins/database/tester/assets/images/avatar.png']); + $user->reloadRelations(); + $this->assertNotEmpty($user->photos); + + $photo = $user->photos->first(); + $this->assertNotNull($photo); + $photoId = $photo->id; + + $user->delete(); + $this->assertNull(FileModel::find($photoId)); + } +} diff --git a/tests/unit/plugins/database/AttachOneModelTest.php b/tests/unit/plugins/database/AttachOneModelTest.php new file mode 100644 index 0000000..d50debd --- /dev/null +++ b/tests/unit/plugins/database/AttachOneModelTest.php @@ -0,0 +1,109 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testSetRelationValue() + { + Model::unguard(); + $user = User::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $user2 = User::create(['name' => 'Joe', 'email' => 'joe@email.tld']); + Model::reguard(); + + // Set by string + $user->avatar = base_path().'/tests/fixtures/plugins/database/tester/assets/images/avatar.png'; + + // @todo $user->avatar currently sits as a string, not good for validation + // this should really assert as an UploadedFile instead. + + // Commit the file and it should snap to a File model + $user->save(); + + $this->assertNotNull($user->avatar); + $this->assertEquals('avatar.png', $user->avatar->file_name); + + // Set by Uploaded file + $sample = $user->avatar; + $upload = new UploadedFile( + base_path().'/tests/fixtures/plugins/database/tester/assets/images/avatar.png', + $sample->file_name, + $sample->content_type, + $sample->file_size, + null, + true + ); + + $user2->avatar = $upload; + + // The file is prepped but not yet commited, this is for validation + $this->assertNotNull($user2->avatar); + $this->assertEquals($upload, $user2->avatar); + + // Commit the file and it should snap to a File model + $user2->save(); + + $this->assertNotNull($user2->avatar); + $this->assertEquals('avatar.png', $user2->avatar->file_name); + } + + public function testDeleteFlagDestroyRelationship() + { + Model::unguard(); + $user = User::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + Model::reguard(); + + $this->assertNull($user->avatar); + $user->avatar()->create(['data' => base_path().'/tests/fixtures/plugins/database/tester/assets/images/avatar.png']); + $user->reloadRelations(); + $this->assertNotNull($user->avatar); + + $avatar = $user->avatar; + $avatarId = $avatar->id; + + $user->avatar()->remove($avatar); + $this->assertNull(FileModel::find($avatarId)); + } + + public function testDeleteFlagDeleteModel() + { + Model::unguard(); + $user = User::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + Model::reguard(); + + $this->assertNull($user->avatar); + $user->avatar()->create(['data' => base_path().'/tests/fixtures/plugins/database/tester/assets/images/avatar.png']); + $user->reloadRelations(); + $this->assertNotNull($user->avatar); + + $avatarId = $user->avatar->id; + $user->delete(); + $this->assertNull(FileModel::find($avatarId)); + } + + public function testDeleteFlagSoftDeleteModel() + { + Model::unguard(); + $user = SoftDeleteUser::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + Model::reguard(); + + $user->avatar()->create(['data' => base_path().'/tests/fixtures/plugins/database/tester/assets/images/avatar.png']); + $this->assertNotNull($user->avatar); + + $avatarId = $user->avatar->id; + $user->delete(); + $this->assertNotNull(FileModel::find($avatarId)); + } +} diff --git a/tests/unit/plugins/database/BelongsToManyModelTest.php b/tests/unit/plugins/database/BelongsToManyModelTest.php new file mode 100644 index 0000000..771b75c --- /dev/null +++ b/tests/unit/plugins/database/BelongsToManyModelTest.php @@ -0,0 +1,213 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testSetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + $role3 = Role::create(['name' => "Manager", 'description' => "Budget"]); + Model::reguard(); + + // Add/remove to collection + $this->assertFalse($author->roles->contains($role1->id)); + $author->roles()->add($role1); + $author->roles()->add($role2); + $this->assertTrue($author->roles->contains($role1->id)); + $this->assertTrue($author->roles->contains($role2->id)); + + // Set by Model object + $author->roles = $role1; + $this->assertEquals(1, $author->roles->count()); + $this->assertEquals('Designer', $author->roles->first()->name); + + $author->roles = [$role1, $role2, $role3]; + $this->assertEquals(3, $author->roles->count()); + + // Set by primary key + $author->roles = $role2->id; + $this->assertEquals(1, $author->roles->count()); + $this->assertEquals('Programmer', $author->roles->first()->name); + + $author->roles = [$role2->id, $role3->id]; + $this->assertEquals(2, $author->roles->count()); + + // Nullify + $author->roles = null; + $this->assertEquals(0, $author->roles->count()); + + // Extra nullify checks (still exists in DB until saved) + $author->reloadRelations('roles'); + $this->assertEquals(2, $author->roles->count()); + $author->save(); + $author->reloadRelations('roles'); + $this->assertEquals(0, $author->roles->count()); + + // Deferred in memory + $author->roles = [$role2->id, $role3->id]; + $this->assertEquals(2, $author->roles->count()); + $this->assertEquals('Programmer', $author->roles->first()->name); + } + + public function testGetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + Model::reguard(); + + $author->roles()->add($role1); + $author->roles()->add($role2); + + $this->assertEquals([$role1->id, $role2->id], $author->getRelationValue('roles')); + } + + public function testDeferredBinding() + { + $sessionKey = uniqid('session_key', true); + + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + + $category = Category::create(['name' => 'News']); + $post1 = PostModel::create(['title' => 'First post']); + $post2 = PostModel::create(['title' => 'Second post']); + Model::reguard(); + + // Deferred add + $author->roles()->add($role1, $sessionKey); + $author->roles()->add($role2, $sessionKey); + $category->posts()->add($post1, $sessionKey, [ + 'category_name' => $category->name . ' in pivot', + 'post_name' => $post1->title . ' in pivot', + ]); + $category->posts()->add($post2, $sessionKey, [ + 'category_name' => $category->name . ' in pivot', + 'post_name' => $post2->title . ' in pivot', + ]); + $this->assertEmpty($author->roles); + $this->assertEmpty($category->posts); + + $this->assertEquals(0, $author->roles()->count()); + $this->assertEquals(2, $author->roles()->withDeferred($sessionKey)->count()); + $this->assertEquals(0, $category->posts()->count()); + $this->assertEquals(2, $category->posts()->withDeferred($sessionKey)->count()); + + // Get simple value (implicit) + $author->reloadRelations(); + $author->sessionKey = $sessionKey; + $this->assertEquals([$role1->id, $role2->id], $author->getRelationValue('roles')); + $category->reloadRelations(); + $category->sessionKey = $sessionKey; + $this->assertEquals([$post1->id, $post2->id], $category->getRelationValue('posts')); + + // Get simple value (explicit) + $relatedIds = $author->roles()->allRelatedIds($sessionKey)->all(); + $this->assertEquals([$role1->id, $role2->id], $relatedIds); + $relatedIds = $category->posts()->allRelatedIds($sessionKey)->all(); + $this->assertEquals([$post1->id, $post2->id], $relatedIds); + + // Commit deferred + $author->save(null, $sessionKey); + $category->save(null, $sessionKey); + $this->assertEquals(2, $author->roles()->count()); + $this->assertEquals('Designer', $author->roles->first()->name); + $this->assertEquals(2, $category->posts()->count()); + $this->assertEquals('First post', $category->posts->first()->title); + $this->assertEquals('Second post', $category->posts->last()->title); + $this->assertEquals('First post in pivot', $category->posts->first()->pivot->post_name); + $this->assertEquals('Second post in pivot', $category->posts->last()->pivot->post_name); + $this->assertEquals('News in pivot', $category->posts->first()->pivot->category_name); + $this->assertEquals('News in pivot', $category->posts->last()->pivot->category_name); + + // New session + $sessionKey = uniqid('session_key', true); + + // Deferred remove + $author->roles()->remove($role1, $sessionKey); + $author->roles()->remove($role2, $sessionKey); + $category->posts()->remove($post1, $sessionKey); + $category->posts()->remove($post2, $sessionKey); + $this->assertEquals(2, $author->roles()->count()); + $this->assertEquals(0, $author->roles()->withDeferred($sessionKey)->count()); + $this->assertEquals(2, $category->posts()->count()); + $this->assertEquals(0, $category->posts()->withDeferred($sessionKey)->count()); + $this->assertEquals('Designer', $author->roles->first()->name); + $this->assertEquals('First post', $category->posts->first()->title); + $this->assertEquals('Second post', $category->posts->last()->title); + $this->assertEquals('First post in pivot', $category->posts->first()->pivot->post_name); + $this->assertEquals('Second post in pivot', $category->posts->last()->pivot->post_name); + $this->assertEquals('News in pivot', $category->posts->first()->pivot->category_name); + $this->assertEquals('News in pivot', $category->posts->last()->pivot->category_name); + + // Commit deferred + $author->save(null, $sessionKey); + $category->save(null, $sessionKey); + $this->assertEquals(0, $author->roles()->count()); + $this->assertEquals(0, $author->roles->count()); + $this->assertEquals(0, $category->posts()->count()); + $this->assertEquals(0, $category->posts->count()); + } + + public function testDetachAfterDelete() + { + // Needed for other "delete" events + include_once base_path().'/tests/fixtures/plugins/database/tester/models/User.php'; + include_once base_path().'/tests/fixtures/plugins/database/tester/models/EventLog.php'; + + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + $role3 = Role::create(['name' => "Manager", 'description' => "Budget"]); + Model::reguard(); + + $author->roles()->add($role1); + $author->roles()->add($role2); + $author->roles()->add($role3); + $this->assertEquals(3, Db::table('database_tester_authors_roles')->where('author_id', $author->id)->count()); + + $author->delete(); + $this->assertEquals(0, Db::table('database_tester_authors_roles')->where('author_id', $author->id)->count()); + } + + public function testConditionsWithPivotAttributes() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + $role3 = Role::create(['name' => "Manager", 'description' => "Budget"]); + Model::reguard(); + + $author->roles()->add($role1, null, ['is_executive' => 1]); + $author->roles()->add($role2, null, ['is_executive' => 1]); + $author->roles()->add($role3, null, ['is_executive' => 0]); + + $this->assertEquals([1, 2], $author->executive_authors->lists('id')); + $this->assertEquals([1, 2], $author->executive_authors()->lists('id')); + $this->assertEquals([1, 2], $author->executive_authors()->get()->lists('id')); + } +} diff --git a/tests/unit/plugins/database/BelongsToModelTest.php b/tests/unit/plugins/database/BelongsToModelTest.php new file mode 100644 index 0000000..8fca6ff --- /dev/null +++ b/tests/unit/plugins/database/BelongsToModelTest.php @@ -0,0 +1,99 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testSetRelationValue() + { + Model::unguard(); + $post = Post::create(['title' => "First post", 'description' => "Yay!!"]); + $author1 = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $author2 = Author::create(['name' => 'Louie', 'email' => 'louie@email.tld']); + $author3 = Author::make(['name' => 'Charlie', 'email' => 'charlie@email.tld']); + Model::reguard(); + + // Set by Model object + $post->author = $author1; + $this->assertEquals($author1->id, $post->author_id); + $this->assertEquals('Stevie', $post->author->name); + + // Set by primary key + $post->author = $author2->id; + $this->assertEquals($author2->id, $post->author_id); + $this->assertEquals('Louie', $post->author->name); + + // Nullify + $post->author = null; + $this->assertNull($post->author_id); + $this->assertNull($post->author); + + // Deferred in memory + $post->author = $author3; + $this->assertEquals('Charlie', $post->author->name); + $this->assertNull($post->author_id); + $author3->save(); + $this->assertEquals($author3->id, $post->author_id); + } + + public function testGetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $post = Post::make(['title' => "First post", 'author_id' => $author->id]); + Model::reguard(); + + $this->assertEquals($author->id, $post->getRelationValue('author')); + } + + public function testDeferredBinding() + { + $sessionKey = uniqid('session_key', true); + + Model::unguard(); + $post = Post::make(['title' => "First post"]); + $author = Author::create(['name' => 'Stevie']); + Model::reguard(); + + // Deferred add + $post->author()->add($author, $sessionKey); + $this->assertNull($post->author_id); + $this->assertNull($post->author); + + $this->assertEquals(0, $post->author()->count()); + $this->assertEquals(1, $post->author()->withDeferred($sessionKey)->count()); + + // Commit deferred + $post->save(null, $sessionKey); + $this->assertEquals(1, $post->author()->count()); + $this->assertEquals($author->id, $post->author_id); + $this->assertEquals('Stevie', $post->author->name); + + // New session + $sessionKey = uniqid('session_key', true); + + // Deferred remove + $post->author()->remove($author, $sessionKey); + $this->assertEquals(1, $post->author()->count()); + $this->assertEquals(0, $post->author()->withDeferred($sessionKey)->count()); + $this->assertEquals($author->id, $post->author_id); + $this->assertEquals('Stevie', $post->author->name); + + // Commit deferred + $post->save(null, $sessionKey); + $this->assertEquals(0, $post->author()->count()); + $this->assertNull($post->author_id); + $this->assertNull($post->author); + } +} diff --git a/tests/unit/plugins/database/DeferredBindingTest.php b/tests/unit/plugins/database/DeferredBindingTest.php new file mode 100644 index 0000000..e364602 --- /dev/null +++ b/tests/unit/plugins/database/DeferredBindingTest.php @@ -0,0 +1,108 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testNegatedBinding() + { + $sessionKey = uniqid('session_key', true); + DeferredBinding::truncate(); + + Model::unguard(); + $author = Author::make(['name' => 'Stevie']); + $post = Post::create(['title' => "First post"]); + $post2 = Post::create(['title' => "Second post"]); + Model::reguard(); + + $author->posts()->add($post, $sessionKey); + $this->assertEquals(1, DeferredBinding::count()); + + // Skip repeat bindings + $author->posts()->add($post, $sessionKey); + $this->assertEquals(1, DeferredBinding::count()); + + // Remove add-delete pairs + $author->posts()->remove($post, $sessionKey); + $this->assertEquals(0, DeferredBinding::count()); + + // Multi ball + $sessionKey = uniqid('session_key', true); + $author->posts()->add($post, $sessionKey); + $author->posts()->add($post, $sessionKey); + $author->posts()->add($post, $sessionKey); + $author->posts()->add($post, $sessionKey); + $author->posts()->add($post2, $sessionKey); + $author->posts()->add($post2, $sessionKey); + $author->posts()->add($post2, $sessionKey); + $author->posts()->add($post2, $sessionKey); + $author->posts()->add($post2, $sessionKey); + $this->assertEquals(2, DeferredBinding::count()); + + // Clean up add-delete pairs + $author->posts()->remove($post, $sessionKey); + $author->posts()->remove($post2, $sessionKey); + $this->assertEquals(0, DeferredBinding::count()); + + // Double negative + $author->posts()->remove($post, $sessionKey); + $author->posts()->remove($post2, $sessionKey); + $this->assertEquals(2, DeferredBinding::count()); + + // Skip repeat bindings + $author->posts()->remove($post, $sessionKey); + $author->posts()->remove($post2, $sessionKey); + $this->assertEquals(2, DeferredBinding::count()); + + // Clean up add-delete pairs again + $author->posts()->add($post, $sessionKey); + $author->posts()->add($post2, $sessionKey); + $this->assertEquals(0, DeferredBinding::count()); + } + + public function testCancelBinding() + { + $sessionKey = uniqid('session_key', true); + DeferredBinding::truncate(); + + Model::unguard(); + $author = Author::make(['name' => 'Stevie']); + $post = Post::create(['title' => "First post"]); + Model::reguard(); + + $author->posts()->add($post, $sessionKey); + $this->assertEquals(1, DeferredBinding::count()); + + $author->cancelDeferred($sessionKey); + $this->assertEquals(0, DeferredBinding::count()); + } + + public function testCommitBinding() + { + $sessionKey = uniqid('session_key', true); + DeferredBinding::truncate(); + + Model::unguard(); + $author = Author::make(['name' => 'Stevie']); + $post = Post::create(['title' => "First post"]); + Model::reguard(); + + $author->posts()->add($post, $sessionKey); + $this->assertEquals(1, DeferredBinding::count()); + + $author->commitDeferred($sessionKey); + $this->assertEquals(0, DeferredBinding::count()); + } +} diff --git a/tests/unit/plugins/database/HasManyModelTest.php b/tests/unit/plugins/database/HasManyModelTest.php new file mode 100644 index 0000000..9a1def0 --- /dev/null +++ b/tests/unit/plugins/database/HasManyModelTest.php @@ -0,0 +1,122 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testSetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $post1 = Post::create(['title' => "First post", 'description' => "Yay!!"]); + $post2 = Post::create(['title' => "Second post", 'description' => "Woohoo!!"]); + $post3 = Post::create(['title' => "Third post", 'description' => "Yipiee!!"]); + $post4 = Post::make(['title' => "Fourth post", 'description' => "Hooray!!"]); + Model::reguard(); + + // Set by Model object + $author->posts = new Collection([$post1, $post2]); + $author->save(); + $this->assertEquals($author->id, $post1->author_id); + $this->assertEquals($author->id, $post2->author_id); + $this->assertEquals([ + 'First post', + 'Second post' + ], $author->posts->lists('title')); + + // Set by primary key + $postId = $post3->id; + $author->posts = $postId; + $author->save(); + $post3 = Post::find($postId); + $this->assertEquals($author->id, $post3->author_id); + $this->assertEquals([ + 'Third post' + ], $author->posts->lists('title')); + + // Nullify + $author->posts = null; + $author->save(); + $post3 = Post::find($postId); + $this->assertNull($post3->author_id); + $this->assertNull($post3->author); + + // Deferred in memory + $author->posts = $post4; + $this->assertEquals($author->id, $post4->author_id); + $this->assertEquals([ + 'Fourth post' + ], $author->posts->lists('title')); + } + + public function testGetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $post1 = Post::create(['title' => "First post", 'author_id' => $author->id]); + $post2 = Post::create(['title' => "Second post", 'author_id' => $author->id]); + Model::reguard(); + + $this->assertEquals([$post1->id, $post2->id], $author->getRelationValue('posts')); + } + + public function testDeferredBinding() + { + $sessionKey = uniqid('session_key', true); + + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $post = Post::create(['title' => "First post", 'description' => "Yay!!"]); + Model::reguard(); + + $postId = $post->id; + + // Deferred add + $author->posts()->add($post, $sessionKey); + $this->assertNull($post->author_id); + $this->assertEmpty($author->posts); + + $this->assertEquals(0, $author->posts()->count()); + $this->assertEquals(1, $author->posts()->withDeferred($sessionKey)->count()); + + // Commit deferred + $author->save(null, $sessionKey); + $post = Post::find($postId); + $this->assertEquals(1, $author->posts()->count()); + $this->assertEquals($author->id, $post->author_id); + $this->assertEquals([ + 'First post' + ], $author->posts->lists('title')); + + // New session + $sessionKey = uniqid('session_key', true); + + // Deferred remove + $author->posts()->remove($post, $sessionKey); + $this->assertEquals(1, $author->posts()->count()); + $this->assertEquals(0, $author->posts()->withDeferred($sessionKey)->count()); + $this->assertEquals($author->id, $post->author_id); + $this->assertEquals([ + 'First post' + ], $author->posts->lists('title')); + + // Commit deferred + $author->save(null, $sessionKey); + $post = Post::find($postId); + $this->assertEquals(0, $author->posts()->count()); + $this->assertNull($post->author_id); + $this->assertEmpty($author->posts); + } +} diff --git a/tests/unit/plugins/database/HasManyThroughModelTest.php b/tests/unit/plugins/database/HasManyThroughModelTest.php new file mode 100644 index 0000000..85ac947 --- /dev/null +++ b/tests/unit/plugins/database/HasManyThroughModelTest.php @@ -0,0 +1,54 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testGet() + { + Model::unguard(); + $country = Country::create(['name' => 'Australia']); + $author1 = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $author2 = Author::create(['name' => 'Louie', 'email' => 'louie@email.tld']); + $post1 = Post::create(['title' => "First post", 'description' => "Yay!!"]); + $post2 = Post::create(['title' => "Second post", 'description' => "Woohoo!!"]); + $post3 = Post::create(['title' => "Third post", 'description' => "Yipiee!!"]); + $post4 = Post::make(['title' => "Fourth post", 'description' => "Hooray!!"]); + Model::reguard(); + + // Set data + $author1->country = $country; + $author2->country = $country; + + $author1->posts = new Collection([$post1, $post2]); + $author2->posts = new Collection([$post3, $post4]); + + $author1->save(); + $author2->save(); + + $country = Country::with([ + 'posts' + ])->find($country->id); + + $this->assertEquals([ + $post1->id, + $post2->id, + $post3->id, + $post4->id + ], $country->posts->pluck('id')->toArray()); + } +} diff --git a/tests/unit/plugins/database/HasOneModelTest.php b/tests/unit/plugins/database/HasOneModelTest.php new file mode 100644 index 0000000..e6bd0f4 --- /dev/null +++ b/tests/unit/plugins/database/HasOneModelTest.php @@ -0,0 +1,134 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testSetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $phone1 = Phone::create(['number' => '0404040404']); + $phone2 = Phone::create(['number' => '0505050505']); + $phone3 = Phone::make(['number' => '0606060606']); + Model::reguard(); + + // Set by Model object + $author->phone = $phone1; + $author->save(); + $this->assertEquals($author->id, $phone1->author_id); + $this->assertEquals('0404040404', $author->phone->number); + + // Double check + $phone1 = Phone::find($phone1->id); + $this->assertEquals($author->id, $phone1->author_id); + + // Set by primary key + $phoneId = $phone2->id; + $author->phone = $phoneId; + $author->save(); + $phone2 = Phone::find($phoneId); + $this->assertEquals($author->id, $phone2->author_id); + $this->assertEquals('0505050505', $author->phone->number); + + // Ensure relationship is "stolen" from first model + $phone1 = Phone::find($phone1->id); + $this->assertNotEquals($author->id, $phone1->author_id); + + // Nullify + $author->phone = null; + $author->save(); + $phone2 = Phone::find($phoneId); + $this->assertNull($phone2->author_id); + $this->assertNull($phone2->author); + + // Deferred in memory + $author->phone = $phone3; + $this->assertEquals('0606060606', $author->phone->number); + $this->assertEquals($author->id, $phone3->author_id); + } + + public function testSetRelationValueTwice() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $phone = Phone::create(['number' => '0505050505']); + Model::reguard(); + + $phoneId = $phone->id; + $author->phone = $phoneId; + $author->save(); + + $author->phone = $phoneId; + $author->save(); + + $phone = Phone::find($phoneId); + $this->assertEquals($author->id, $phone->author_id); + $this->assertEquals('0505050505', $author->phone->number); + } + + public function testGetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $phone = Phone::create(['number' => '0404040404', 'author_id' => $author->id]); + Model::reguard(); + + $this->assertEquals($phone->id, $author->getRelationValue('phone')); + } + + public function testDeferredBinding() + { + $sessionKey = uniqid('session_key', true); + + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $phone = Phone::create(['number' => '0404040404']); + Model::reguard(); + + $phoneId = $phone->id; + + // Deferred add + $author->phone()->add($phone, $sessionKey); + $this->assertNull($phone->author_id); + $this->assertNull($author->phone); + + $this->assertEquals(0, $author->phone()->count()); + $this->assertEquals(1, $author->phone()->withDeferred($sessionKey)->count()); + + // Commit deferred + $author->save(null, $sessionKey); + $phone = Phone::find($phoneId); + $this->assertEquals(1, $author->phone()->count()); + $this->assertEquals($author->id, $phone->author_id); + $this->assertEquals('0404040404', $author->phone->number); + + // New session + $sessionKey = uniqid('session_key', true); + + // Deferred remove + $author->phone()->remove($phone, $sessionKey); + $this->assertEquals(1, $author->phone()->count()); + $this->assertEquals(0, $author->phone()->withDeferred($sessionKey)->count()); + $this->assertEquals($author->id, $phone->author_id); + $this->assertEquals('0404040404', $author->phone->number); + + // Commit deferred + $author->save(null, $sessionKey); + $phone = Phone::find($phoneId); + $this->assertEquals(0, $author->phone()->count()); + $this->assertNull($phone->author_id); + $this->assertNull($author->phone); + } +} diff --git a/tests/unit/plugins/database/HasOneThroughModelTest.php b/tests/unit/plugins/database/HasOneThroughModelTest.php new file mode 100644 index 0000000..91be83b --- /dev/null +++ b/tests/unit/plugins/database/HasOneThroughModelTest.php @@ -0,0 +1,39 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testGet() + { + Model::unguard(); + $phone = Phone::create(['number' => '08 1234 5678']); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $user = User::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + Model::reguard(); + + // Set data + $author->phone = $phone; + $author->user = $user; + $author->save(); + + $user = User::with([ + 'phone' + ])->find($user->id); + + $this->assertEquals($phone->id, $user->phone->id); + } +} diff --git a/tests/unit/plugins/database/MorphManyModelTest.php b/tests/unit/plugins/database/MorphManyModelTest.php new file mode 100644 index 0000000..c621ec1 --- /dev/null +++ b/tests/unit/plugins/database/MorphManyModelTest.php @@ -0,0 +1,171 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testSetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $event1 = EventLog::create(['action' => "user-created"]); + $event2 = EventLog::create(['action' => "user-updated"]); + $event3 = EventLog::create(['action' => "user-deleted"]); + $event4 = EventLog::make(['action' => "user-restored"]); + Model::reguard(); + + // Set by Model object + $author->event_log = new Collection([$event1, $event2]); + $author->save(); + $this->assertEquals($author->id, $event1->related_id); + $this->assertEquals($author->id, $event2->related_id); + $this->assertEquals('Database\Tester\Models\Author', $event1->related_type); + $this->assertEquals('Database\Tester\Models\Author', $event2->related_type); + $this->assertEquals([ + 'user-created', + 'user-updated' + ], $author->event_log->lists('action')); + + // Set by primary key + $eventId = $event3->id; + $author->event_log = $eventId; + $author->save(); + $event3 = EventLog::find($eventId); + $this->assertEquals($author->id, $event3->related_id); + $this->assertEquals('Database\Tester\Models\Author', $event3->related_type); + $this->assertEquals([ + 'user-deleted' + ], $author->event_log->lists('action')); + + // Nullify + $author->event_log = null; + $author->save(); + $event3 = EventLog::find($eventId); + $this->assertNull($event3->related_type); + $this->assertNull($event3->related_id); + $this->assertNull($event3->related); + + // Deferred in memory + $author->event_log = $event4; + $this->assertEquals($author->id, $event4->related_id); + $this->assertEquals('Database\Tester\Models\Author', $event4->related_type); + $this->assertEquals([ + 'user-restored' + ], $author->event_log->lists('action')); + } + + public function testGetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $event1 = EventLog::create(['action' => "user-created", 'related_id' => $author->id, 'related_type' => 'Database\Tester\Models\Author']); + $event2 = EventLog::create(['action' => "user-updated", 'related_id' => $author->id, 'related_type' => 'Database\Tester\Models\Author']); + Model::reguard(); + + $this->assertEquals([$event1->id, $event2->id], $author->getRelationValue('event_log')); + } + + public function testDeferredBinding() + { + $sessionKey = uniqid('session_key', true); + + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $event = EventLog::create(['action' => "user-created"]); + $post = Post::create(['title' => 'Hello world!']); + $tagForAuthor = Tag::create(['name' => 'ForAuthor']); + $tagForPost = Tag::create(['name' => 'ForPost']); + Model::reguard(); + + $eventId = $event->id; + + // Deferred add + $author->event_log()->add($event, $sessionKey); + $this->assertNull($event->related_id); + $this->assertEmpty($author->event_log); + + $this->assertEquals(0, $author->event_log()->count()); + $this->assertEquals(1, $author->event_log()->withDeferred($sessionKey)->count()); + + $author->tags()->add($tagForAuthor, $sessionKey, ['added_by' => 99]); + $this->assertEmpty($author->tags); + + $this->assertEquals(0, $author->tags()->count()); + $this->assertEquals(1, $author->tags()->withDeferred($sessionKey)->count()); + + $tagForPost->posts()->add($post, $sessionKey, ['added_by' => 88]); + $this->assertEmpty($tagForPost->posts); + + $this->assertEquals(0, $tagForPost->posts()->count()); + $this->assertEquals(1, $tagForPost->posts()->withDeferred($sessionKey)->count()); + + // Commit deferred + $author->save(null, $sessionKey); + $event = EventLog::find($eventId); + $this->assertEquals(1, $author->event_log()->count()); + $this->assertEquals($author->id, $event->related_id); + $this->assertEquals([ + 'user-created' + ], $author->event_log->lists('action')); + + $this->assertEquals(1, $author->tags()->count()); + $this->assertEquals([$tagForAuthor->id], $author->tags->lists('id')); + $this->assertEquals(99, $author->tags->first()->pivot->added_by); + + $tagForPost->save(null, $sessionKey); + $this->assertEquals(1, $tagForPost->posts()->count()); + $this->assertEquals([$post->id], $tagForPost->posts->lists('id')); + $this->assertEquals(88, $tagForPost->posts->first()->pivot->added_by); + + // New session + $sessionKey = uniqid('session_key', true); + + // Deferred remove + $author->event_log()->remove($event, $sessionKey); + $this->assertEquals(1, $author->event_log()->count()); + $this->assertEquals(0, $author->event_log()->withDeferred($sessionKey)->count()); + $this->assertEquals($author->id, $event->related_id); + $this->assertEquals([ + 'user-created' + ], $author->event_log->lists('action')); + + $author->tags()->remove($tagForAuthor, $sessionKey); + $this->assertEquals(1, $author->tags()->count()); + $this->assertEquals(0, $author->tags()->withDeferred($sessionKey)->count()); + $this->assertEquals([$tagForAuthor->id], $author->tags->lists('id')); + $this->assertEquals(99, $author->tags->first()->pivot->added_by); + + $tagForPost->posts()->remove($post, $sessionKey); + $this->assertEquals(1, $tagForPost->posts()->count()); + $this->assertEquals(0, $tagForPost->posts()->withDeferred($sessionKey)->count()); + $this->assertEquals([$post->id], $tagForPost->posts->lists('id')); + $this->assertEquals(88, $tagForPost->posts->first()->pivot->added_by); + + + // Commit deferred (model is deleted as per definition) + $author->save(null, $sessionKey); + $event = EventLog::find($eventId); + $this->assertEquals(0, $author->event_log()->count()); + $this->assertNull($event); + $this->assertEmpty($author->event_log); + + $this->assertEmpty(0, $author->tags); + $this->assertEmpty(0, $tagForPost->posts); + } +} diff --git a/tests/unit/plugins/database/MorphOneModelTest.php b/tests/unit/plugins/database/MorphOneModelTest.php new file mode 100644 index 0000000..e8c6f60 --- /dev/null +++ b/tests/unit/plugins/database/MorphOneModelTest.php @@ -0,0 +1,188 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testSetRelationValue() + { + Model::unguard(); + $post = Post::create(['title' => "First post", 'description' => "Yay!!"]); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $meta1 = Meta::create([ + 'meta_title' => 'Question', + 'meta_description' => 'Industry', + 'meta_keywords' => 'major', + 'canonical_url' => 'http://google.com/search/jobs', + 'redirect_url' => 'http://google.com', + 'robot_index' => 'index', + 'robot_follow' => 'follow', + ]); + $meta2 = Meta::create([ + 'meta_title' => 'Comment', + 'meta_description' => 'Social', + 'meta_keywords' => 'startup', + 'canonical_url' => 'http://facebook.com/search/users', + 'redirect_url' => 'http://facebook.com', + 'robot_index' => 'index', + 'robot_follow' => 'follow', + ]); + $meta3 = Meta::make([ + 'meta_title' => 'Answer', + 'meta_description' => 'Employment', + 'meta_keywords' => 'minor', + 'canonical_url' => 'http://yahoo.com/search/stats', + 'redirect_url' => 'http://yahoo.com', + 'robot_index' => 'index', + 'robot_follow' => 'follow', + ]); + Model::reguard(); + + // Set by Model object + $post->meta = $meta1; + $post->save(); + $this->assertEquals($post->id, $meta1->taggable_id); + $this->assertEquals(get_class($post), $meta1->taggable_type); + $this->assertEquals('Question', $post->meta->meta_title); + + // Double check + $meta1 = Meta::find($meta1->id); + $this->assertEquals($post->id, $meta1->taggable_id); + $this->assertEquals(get_class($post), $meta1->taggable_type); + + // Set by primary key + $metaId = $meta2->id; + $author->meta = $metaId; + $author->save(); + $meta2 = Meta::find($metaId); + $this->assertEquals($author->id, $meta2->taggable_id); + $this->assertEquals(get_class($author), $meta2->taggable_type); + $this->assertEquals('Comment', $author->meta->meta_title); + + // Nullify + $author->meta = null; + $author->save(); + $meta = Meta::find($metaId); + $this->assertNull($meta->taggable_type); + $this->assertNull($meta->taggable_id); + $this->assertNull($meta->taggable); + + // Deferred in memory + $author->meta = $meta3; + $this->assertEquals('Answer', $author->meta->meta_title); + $this->assertEquals($author->id, $meta3->taggable_id); + } + + public function testSetRelationValueTwice() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $meta = Meta::create([ + 'meta_title' => 'Question', + 'meta_description' => 'Industry', + 'meta_keywords' => 'major', + 'canonical_url' => 'http://google.com/search/jobs', + 'redirect_url' => 'http://google.com', + 'robot_index' => 'index', + 'robot_follow' => 'follow', + ]); + Model::reguard(); + + $metaId = $meta->id; + $author->meta = $metaId; + $author->save(); + + $author->meta = $metaId; + $author->save(); + + $meta = Meta::find($metaId); + $this->assertEquals($author->id, $meta->taggable_id); + $this->assertEquals(get_class($author), $meta->taggable_type); + } + + public function testGetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $meta = Meta::create([ + 'taggable_id' => $author->id, + 'taggable_type' => get_class($author), + 'meta_title' => 'Question', + 'meta_description' => 'Industry', + 'meta_keywords' => 'major', + 'canonical_url' => 'http://google.com/search/jobs', + 'redirect_url' => 'http://google.com', + 'robot_index' => 'index', + 'robot_follow' => 'follow', + ]); + Model::reguard(); + + $this->assertEquals($meta->id, $author->getRelationValue('meta')); + } + + public function testDeferredBinding() + { + $sessionKey = uniqid('session_key', true); + + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $meta = Meta::create([ + 'meta_title' => 'Comment', + 'meta_description' => 'Social', + 'meta_keywords' => 'startup', + 'canonical_url' => 'http://facebook.com/search/users', + 'redirect_url' => 'http://facebook.com', + 'robot_index' => 'index', + 'robot_follow' => 'follow', + ]); + Model::reguard(); + + $metaId = $meta->id; + + // Deferred add + $author->meta()->add($meta, $sessionKey); + $this->assertNull($meta->taggable_id); + $this->assertNull($author->meta); + + $this->assertEquals(0, $author->meta()->count()); + $this->assertEquals(1, $author->meta()->withDeferred($sessionKey)->count()); + + // Commit deferred + $author->save(null, $sessionKey); + $meta = Meta::find($metaId); + $this->assertEquals(1, $author->meta()->count()); + $this->assertEquals($author->id, $meta->taggable_id); + $this->assertEquals('Comment', $author->meta->meta_title); + + // New session + $sessionKey = uniqid('session_key', true); + + // Deferred remove + $author->meta()->remove($meta, $sessionKey); + $this->assertEquals(1, $author->meta()->count()); + $this->assertEquals(0, $author->meta()->withDeferred($sessionKey)->count()); + $this->assertEquals($author->id, $meta->taggable_id); + $this->assertEquals('Comment', $author->meta->meta_title); + + // Commit deferred + $author->save(null, $sessionKey); + $meta = Meta::find($metaId); + $this->assertEquals(0, $author->meta()->count()); + $this->assertNull($meta->taggable_id); + $this->assertNull($author->meta); + } +} diff --git a/tests/unit/plugins/database/MorphToModelTest.php b/tests/unit/plugins/database/MorphToModelTest.php new file mode 100644 index 0000000..b0eb37f --- /dev/null +++ b/tests/unit/plugins/database/MorphToModelTest.php @@ -0,0 +1,62 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testSetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $post1 = Post::create(['title' => "First post", 'description' => "Yay!!"]); + $post2 = Post::make(['title' => "Second post", 'description' => "Woohoo!!"]); + $event = EventLog::create(['action' => "user-created"]); + Model::reguard(); + + // Set by Model object + $event->related = $author; + $event->save(); + $this->assertEquals($author->id, $event->related_id); + $this->assertEquals('Stevie', $event->related->name); + + // Set by primary key + $event->related = [$post1->id, get_class($post1)]; + $this->assertEquals($post1->id, $event->related_id); + $this->assertEquals('First post', $event->related->title); + + // Nullify + $event->related = null; + $this->assertNull($event->related_id); + $this->assertNull($event->related); + + // Deferred in memory + $event->related = $post2; + $this->assertEquals('Second post', $event->related->title); + $this->assertNull($event->related_id); + $event->save(); + $this->assertEquals($post2->id, $event->related_id); + } + + public function testGetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $event = EventLog::make(['action' => "user-created", 'related_id' => $author->id, 'related_type' => get_class($author)]); + Model::reguard(); + + $this->assertEquals([$author->id, get_class($author)], $event->getRelationValue('related')); + } +} diff --git a/tests/unit/plugins/database/NestedTreeModelTest.php b/tests/unit/plugins/database/NestedTreeModelTest.php new file mode 100644 index 0000000..49d4676 --- /dev/null +++ b/tests/unit/plugins/database/NestedTreeModelTest.php @@ -0,0 +1,151 @@ +runPluginRefreshCommand('Database.Tester'); + $this->seedSampleTree(); + } + + public function testGetNested() + { + $items = CategoryNested::getNested(); + + // Eager loaded + $items->each(function ($item) { + $this->assertTrue($item->relationLoaded('children')); + }); + + $this->assertEquals(2, $items->count()); + } + + public function testGetAllRoot() + { + $items = CategoryNested::getAllRoot(); + + // Not eager loaded + $items->each(function ($item) { + $this->assertFalse($item->relationLoaded('children')); + }); + + $this->assertEquals(2, $items->count()); + } + + public function testListsNested() + { + $array = CategoryNested::listsNested('name', 'id'); + $this->assertEquals([ + 1 => 'Category Orange', + 2 => '   Autumn Leaves', + 3 => '      September', + 4 => '      October', + 5 => '      November', + 6 => '   Summer Breeze', + 7 => 'Category Green', + 8 => '   Winter Snow', + 9 => '   Spring Trees' + ], $array); + + $array = CategoryNested::listsNested('name', 'id', '--'); + $this->assertEquals([ + 1 => 'Category Orange', + 2 => '--Autumn Leaves', + 3 => '----September', + 4 => '----October', + 5 => '----November', + 6 => '--Summer Breeze', + 7 => 'Category Green', + 8 => '--Winter Snow', + 9 => '--Spring Trees' + ], $array); + + $array = CategoryNested::listsNested('description', 'name', '**'); + $this->assertEquals([ + 'Category Orange' => 'A root level test category', + 'Autumn Leaves' => '**Disccusion about the season of falling leaves.', + 'September' => '****The start of the fall season.', + 'October' => '****The middle of the fall season.', + 'November' => '****The end of the fall season.', + 'Summer Breeze' => '**Disccusion about the wind at the ocean.', + 'Category Green' => 'A root level test category', + 'Winter Snow' => '**Disccusion about the frosty snow flakes.', + 'Spring Trees' => '**Disccusion about the blooming gardens.' + ], $array); + } + + public function testListsNestedFromCollection() + { + $array = CategoryNested::get()->listsNested('custom_name', 'id', '...'); + $this->assertEquals([ + 1 => 'Category Orange (#1)', + 2 => '...Autumn Leaves (#2)', + 3 => '......September (#3)', + 4 => '......October (#4)', + 5 => '......November (#5)', + 6 => '...Summer Breeze (#6)', + 7 => 'Category Green (#7)', + 8 => '...Winter Snow (#8)', + 9 => '...Spring Trees (#9)' + ], $array); + } + + public function seedSampleTree() + { + Model::unguard(); + + $orange = CategoryNested::create([ + 'name' => 'Category Orange', + 'description' => 'A root level test category', + ]); + + $autumn = $orange->children()->create([ + 'name' => 'Autumn Leaves', + 'description' => 'Disccusion about the season of falling leaves.' + ]); + + $autumn->children()->create([ + 'name' => 'September', + 'description' => 'The start of the fall season.' + ]); + + $october = $autumn->children()->create([ + 'name' => 'October', + 'description' => 'The middle of the fall season.' + ]); + + $autumn->children()->create([ + 'name' => 'November', + 'description' => 'The end of the fall season.' + ]); + + $orange->children()->create([ + 'name' => 'Summer Breeze', + 'description' => 'Disccusion about the wind at the ocean.' + ]); + + $green = CategoryNested::create([ + 'name' => 'Category Green', + 'description' => 'A root level test category', + ]); + + $green->children()->create([ + 'name' => 'Winter Snow', + 'description' => 'Disccusion about the frosty snow flakes.' + ]); + + $green->children()->create([ + 'name' => 'Spring Trees', + 'description' => 'Disccusion about the blooming gardens.' + ]); + + Model::reguard(); + } +} diff --git a/tests/unit/plugins/database/NullableModelTest.php b/tests/unit/plugins/database/NullableModelTest.php new file mode 100644 index 0000000..9d6d611 --- /dev/null +++ b/tests/unit/plugins/database/NullableModelTest.php @@ -0,0 +1,58 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testNullifyingFields() + { + // Save as SQL default + $post = NullablePost::create(['author_nickname' => ''])->reload(); + $this->assertEquals('October', $post->author_nickname); + + // Save as empty string + $post->author_nickname = ''; + $post->save(); + $this->assertNull($post->author_nickname); + } + + public function testNonEmptyValuesAreIgnored() + { + // Save as value + $post = NullablePost::create(['author_nickname' => 'Joe']); + $this->assertEquals('Joe', $post->author_nickname); + + // Save as zero integer + $post->author_nickname = 0; + $post->save(); + $this->assertNotNull($post->author_nickname); + $this->assertEquals(0, $post->author_nickname); + + // Save as zero float + $post->author_nickname = 0.0; + $post->save(); + $this->assertNotNull($post->author_nickname); + $this->assertEquals(0.0, $post->author_nickname); + + // Save as zero string + $post->author_nickname = '0'; + $post->save(); + $this->assertNotNull($post->author_nickname); + $this->assertEquals('0', $post->author_nickname); + + // Save as false + $post->author_nickname = false; + $post->save(); + $this->assertNotNull($post->author_nickname); + $this->assertEquals(false, $post->author_nickname); + } +} diff --git a/tests/unit/plugins/database/PluginModelTest.php b/tests/unit/plugins/database/PluginModelTest.php new file mode 100644 index 0000000..85d7e31 --- /dev/null +++ b/tests/unit/plugins/database/PluginModelTest.php @@ -0,0 +1,33 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testCreateFirstPost() + { + Post::truncate(); + $post = new Post; + $post->title = "First post"; + $post->description = "Yay!!"; + $post->save(); + $this->assertEquals(1, $post->id); + } + + public function testGuardedAttribute() + { + $this->expectException(\Illuminate\Database\Eloquent\MassAssignmentException::class); + $this->expectExceptionMessageMatches('/title/'); + + Post::create(['title' => 'Hi!', 'slug' => 'authenticity']); + } +} diff --git a/tests/unit/plugins/database/RevisionableModelTest.php b/tests/unit/plugins/database/RevisionableModelTest.php new file mode 100644 index 0000000..c8fa19a --- /dev/null +++ b/tests/unit/plugins/database/RevisionableModelTest.php @@ -0,0 +1,141 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testUpdateNothing() + { + $post = RevisionablePost::create(['title' => 'Hello World!']); + $this->assertEquals('Hello World!', $post->title); + $this->assertEquals(0, $post->revision_history()->count()); + + $post->revisionsEnabled = false; + $post->title = 'Helloooooooooooo!'; + $post->save(); + $this->assertEquals(0, $post->revision_history()->count()); + } + + public function testUpdateSingleField() + { + $post = RevisionablePost::create(['title' => 'Hello World!']); + $this->assertEquals('Hello World!', $post->title); + $this->assertEquals(0, $post->revision_history()->count()); + + $post->title = 'Helloooooooooooo!'; + $post->save(); + $this->assertEquals(1, $post->revision_history()->count()); + + $item = $post->revision_history()->first(); + + $this->assertEquals('title', $item->field); + $this->assertEquals('Hello World!', $item->old_value); + $this->assertEquals('Helloooooooooooo!', $item->new_value); + $this->assertEquals(7, $item->user_id); + } + + public function testUpdateMultipleFields() + { + $post = RevisionablePost::create([ + 'title' => 'Hello World!', + 'slug' => 'hello-world', + 'description' => 'Good day, Commander', + 'is_published' => true, + 'published_at' => new DateTime + ]); + + $this->assertEquals(0, $post->revision_history()->count()); + + $post->title = "Gday mate"; + $post->slug = "gday-mate"; + $post->description = 'Wazzaaaaaaaaaaaaap'; + $post->is_published = false; + $post->published_at = Carbon::now()->addDays(1); + $post->save(); + + $history = $post->revision_history; + + $this->assertEquals(5, $history->count()); + $this->assertEquals([ + 'title', + 'slug', + 'description', + 'is_published', + 'published_at' + ], $history->lists('field')); + } + + public function testExceedingRevisionLimit() + { + $post = RevisionablePost::create([ + 'title' => 'Hello World!', + 'slug' => 'hello-world', + 'description' => 'Good day, Commander', + 'is_published' => true, + 'published_at' => new DateTime + ]); + + $this->assertEquals(0, $post->revision_history()->count()); + + $post->title = "Gday mate"; + $post->slug = "gday-mate"; + $post->description = 'Wazzaaaaaaaaaaaaap'; + $post->is_published = false; + $post->published_at = Carbon::now()->addDays(1); + $post->save(); + + $post->title = 'The Boss'; + $post->slug = 'the-boss'; + $post->description = 'Paid the cost to be the boss'; + $post->is_published = true; + $post->published_at = Carbon::now()->addDays(10); + $post->save(); + + // Count 10 changes above, limit is 8 + $this->assertEquals(8, $post->revision_history()->count()); + } + + public function testSoftDeletes() + { + $post = RevisionablePost::create(['title' => 'Hello World!']); + $this->assertEquals('Hello World!', $post->title); + $this->assertEquals(0, $post->revision_history()->count()); + + $post->title = 'Helloooooooooooo!'; + $post->save(); + $this->assertEquals(1, $post->revision_history()->count()); + + $post->delete(); + $this->assertEquals(2, $post->revision_history()->count()); + } + + public function testRevisionDateCast() + { + $post = RevisionablePost::create([ + 'title' => 'Hello World!', + 'published_at' => Carbon::now() + ]); + $this->assertEquals(0, $post->revision_history()->count()); + + $post->published_at = Carbon::now()->addDays(1); + $post->save(); + + $this->assertEquals(1, $post->revision_history()->count()); + + $item = $post->revision_history()->first(); + $this->assertEquals('published_at', $item->field); + $this->assertEquals('date', $item->cast); + $this->assertInstanceOf('Carbon\Carbon', $item->old_value); + $this->assertInstanceOf('Carbon\Carbon', $item->new_value); + } +} diff --git a/tests/unit/plugins/database/SimpleTreeModelTest.php b/tests/unit/plugins/database/SimpleTreeModelTest.php new file mode 100644 index 0000000..c22b11d --- /dev/null +++ b/tests/unit/plugins/database/SimpleTreeModelTest.php @@ -0,0 +1,241 @@ +runPluginRefreshCommand('Database.Tester'); + $this->seedSampleTree(); + } + + public function testGetNested() + { + $items = CategorySimple::getNested(); + + // Eager loaded + $items->each(function ($item) { + $this->assertTrue($item->relationLoaded('children')); + }); + + $this->assertEquals(3, $items->count()); + } + + public function testGetAllRoot() + { + $items = CategorySimple::getAllRoot(); + + // Not eager loaded + $items->each(function ($item) { + $this->assertFalse($item->relationLoaded('children')); + }); + + $this->assertEquals(3, $items->count()); + } + + public function testGetChildren() + { + // Not eager loaded + $item = CategorySimple::first(); + $this->assertFalse($item->relationLoaded('children')); + $this->assertEquals(6, $item->getChildren()->count()); + + // Not eager loaded + $item = CategorySimple::getAllRoot()->first(); + $this->assertFalse($item->relationLoaded('children')); + $this->assertEquals(6, $item->getChildren()->count()); + + // Eager loaded + $item = CategorySimple::getNested()->first(); + $this->assertTrue($item->relationLoaded('children')); + $this->assertEquals(6, $item->getChildren()->count()); + } + + public function testGetChildCount() + { + // Not eager loaded + $item = CategorySimple::first(); + $this->assertFalse($item->relationLoaded('children')); + $this->assertEquals(9, $item->getChildCount()); + + // Not eager loaded + $item = CategorySimple::getAllRoot()->first(); + $this->assertFalse($item->relationLoaded('children')); + $this->assertEquals(9, $item->getChildCount()); + + // Eager loaded + $item = CategorySimple::getNested()->first(); + $this->assertTrue($item->relationLoaded('children')); + $this->assertEquals(9, $item->getChildCount()); + } + + public function testGetAllChildren() + { + // Not eager loaded + $item = CategorySimple::first(); + $this->assertFalse($item->relationLoaded('children')); + $this->assertEquals(9, $item->getAllChildren()->count()); + + // Not eager loaded + $item = CategorySimple::getAllRoot()->first(); + $this->assertFalse($item->relationLoaded('children')); + $this->assertEquals(9, $item->getAllChildren()->count()); + + // Eager loaded + $item = CategorySimple::getNested()->first(); + $this->assertTrue($item->relationLoaded('children')); + $this->assertEquals(9, $item->getAllChildren()->count()); + } + + public function testListsNested() + { + $array = CategorySimple::listsNested('name', 'id'); + $this->assertEquals([ + 1 => 'Web development', + 2 => '   HTML5', + 3 => '   CSS3', + 4 => '   jQuery', + 5 => '   Bootstrap', + 6 => '   Laravel', + 7 => '   OctoberCMS', + 8 => '      September', + 9 => '      October', + 10 => '      November', + 11 => 'Mobile development', + 12 => '   iOS', + 13 => '   iPhone', + 14 => '   iPad', + 15 => '   Android', + 16 => 'Graphic design', + 17 => '   Photoshop', + 18 => '   Illustrator', + 19 => '   Fireworks' + ], $array); + + $array = CategorySimple::listsNested('name', 'id', '--'); + $this->assertEquals([ + 1 => 'Web development', + 2 => '--HTML5', + 3 => '--CSS3', + 4 => '--jQuery', + 5 => '--Bootstrap', + 6 => '--Laravel', + 7 => '--OctoberCMS', + 8 => '----September', + 9 => '----October', + 10 => '----November', + 11 => 'Mobile development', + 12 => '--iOS', + 13 => '--iPhone', + 14 => '--iPad', + 15 => '--Android', + 16 => 'Graphic design', + 17 => '--Photoshop', + 18 => '--Illustrator', + 19 => '--Fireworks' + ], $array); + + $array = CategorySimple::listsNested('id', 'name', '**'); + $this->assertEquals([ + 'Web development' => '1', + 'HTML5' => '**2', + 'CSS3' => '**3', + 'jQuery' => '**4', + 'Bootstrap' => '**5', + 'Laravel' => '**6', + 'OctoberCMS' => '**7', + 'September' => '****8', + 'October' => '****9', + 'November' => '****10', + 'Mobile development' => '11', + 'iOS' => '**12', + 'iPhone' => '**13', + 'iPad' => '**14', + 'Android' => '**15', + 'Graphic design' => '16', + 'Photoshop' => '**17', + 'Illustrator' => '**18', + 'Fireworks' => '**19' + ], $array); + } + + public function testListsNestedUnknownColumn() + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Column mismatch in listsNested method'); + + CategorySimple::listsNested('custom_name', 'id'); + } + + public function testListsNestedFromCollection() + { + $array = CategorySimple::get()->listsNested('custom_name', 'id', '...'); + + $this->assertEquals([ + 1 => 'Web development (#1)', + 2 => '...HTML5 (#2)', + 3 => '...CSS3 (#3)', + 4 => '...jQuery (#4)', + 5 => '...Bootstrap (#5)', + 6 => '...Laravel (#6)', + 7 => '...OctoberCMS (#7)', + 8 => '......September (#8)', + 9 => '......October (#9)', + 10 => '......November (#10)', + 11 => 'Mobile development (#11)', + 12 => '...iOS (#12)', + 13 => '...iPhone (#13)', + 14 => '...iPad (#14)', + 15 => '...Android (#15)', + 16 => 'Graphic design (#16)', + 17 => '...Photoshop (#17)', + 18 => '...Illustrator (#18)', + 19 => '...Fireworks (#19)' + ], $array); + } + + + public function seedSampleTree() + { + Model::unguard(); + + $webdev = CategorySimple::create([ + 'name' => 'Web development' + ]); + + $webdev->children()->create(['name' => 'HTML5']); + $webdev->children()->create(['name' => 'CSS3']); + $webdev->children()->create(['name' => 'jQuery']); + $webdev->children()->create(['name' => 'Bootstrap']); + $webdev->children()->create(['name' => 'Laravel']); + $october = $webdev->children()->create(['name' => 'OctoberCMS']); + $october->children()->create(['name' => 'September']); + $october->children()->create(['name' => 'October']); + $october->children()->create(['name' => 'November']); + + $mobdev = CategorySimple::create([ + 'name' => 'Mobile development' + ]); + + $mobdev->children()->create(['name' => 'iOS']); + $mobdev->children()->create(['name' => 'iPhone']); + $mobdev->children()->create(['name' => 'iPad']); + $mobdev->children()->create(['name' => 'Android']); + + $design = CategorySimple::create([ + 'name' => 'Graphic design' + ]); + + $design->children()->create(['name' => 'Photoshop']); + $design->children()->create(['name' => 'Illustrator']); + $design->children()->create(['name' => 'Fireworks']); + + Model::reguard(); + } +} diff --git a/tests/unit/plugins/database/SluggableModelTest.php b/tests/unit/plugins/database/SluggableModelTest.php new file mode 100644 index 0000000..22cad18 --- /dev/null +++ b/tests/unit/plugins/database/SluggableModelTest.php @@ -0,0 +1,98 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testFillPost() + { + $post = SluggablePost::create(['title' => 'Hello World!']); + $this->assertEquals('hello-world', $post->slug); + } + + public function testSetAttributeOnPost() + { + $post = new SluggablePost; + $post->title = "Let's go, rock show!"; + $post->save(); + + $this->assertEquals('lets-go-rock-show', $post->slug); + } + + public function testSetSlugAttributeManually() + { + $post = new SluggablePost; + $post->title = 'We parked in a comfortable spot'; + $post->slug = 'war-is-pain'; + $post->save(); + + $this->assertEquals('war-is-pain', $post->slug); + } + + public function testConcatenatedSlug() + { + $post = new SluggablePost; + $post->title = 'Sweetness and Light'; + $post->description = 'Itchee and Scratchee'; + $post->save(); + + $this->assertEquals('sweetness-and-light-itchee-and-scratchee', $post->long_slug); + } + + public function testDuplicateSlug() + { + $post1 = SluggablePost::create(['title' => 'Pace yourself']); + $post2 = SluggablePost::create(['title' => 'Pace yourself']); + $post3 = SluggablePost::create(['title' => 'Pace yourself']); + + $this->assertEquals('pace-yourself', $post1->slug); + $this->assertEquals('pace-yourself-2', $post2->slug); + $this->assertEquals('pace-yourself-3', $post3->slug); + } + + public function testCollisionWithSelf() + { + $post1 = SluggablePost::create(['title' => 'Watch yourself']); + $post2 = SluggablePost::create(['title' => 'Watch yourself']); + $post3 = SluggablePost::create(['title' => 'Watch yourself']); + + $this->assertEquals('watch-yourself', $post1->slug); + $this->assertEquals('watch-yourself-2', $post2->slug); + $this->assertEquals('watch-yourself-3', $post3->slug); + + $post3->slugAttributes(); + $post3->save(); + $post2->slugAttributes(); + $post2->save(); + $post1->slugAttributes(); + $post1->save(); + + $this->assertEquals('watch-yourself', $post1->slug); + $this->assertEquals('watch-yourself-2', $post2->slug); + $this->assertEquals('watch-yourself-3', $post3->slug); + } + + public function testSuffixCollision() + { + $post1 = SluggablePost::create(['title' => 'Type 1']); + $post2 = SluggablePost::create(['title' => 'Type 2']); + $post3 = SluggablePost::create(['title' => 'Type 3']); + $post4 = SluggablePost::create(['title' => 'Type 3']); + $post5 = SluggablePost::create(['title' => 'Type 3']); + + $this->assertEquals('type-1', $post1->slug); + $this->assertEquals('type-2', $post2->slug); + $this->assertEquals('type-3', $post3->slug); + $this->assertEquals('type-3-2', $post4->slug); + $this->assertEquals('type-3-3', $post5->slug); + } +} diff --git a/tests/unit/plugins/database/SoftDeleteModelTest.php b/tests/unit/plugins/database/SoftDeleteModelTest.php new file mode 100644 index 0000000..fc52124 --- /dev/null +++ b/tests/unit/plugins/database/SoftDeleteModelTest.php @@ -0,0 +1,97 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testDeleteOptionOnHardModel() + { + Model::unguard(); + $user = UserWithAuthor::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $author = Author::create(['name' => 'Louie', 'email' => 'louie@email.tld', 'user_id' => $user->id]); + Model::reguard(); + + $authorId = $author->id; + $user->delete(); // Hard + $this->assertNull(Author::find($authorId)); + } + + public function testSoftDeleteOptionOnHardModel() + { + Model::unguard(); + $user = UserWithSoftAuthor::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $author = Author::create(['name' => 'Louie', 'email' => 'louie@email.tld', 'user_id' => $user->id]); + Model::reguard(); + + $authorId = $author->id; + $user->delete(); // Hard + $this->assertNotNull(Author::find($authorId)); // Do nothing + } + + public function testSoftDeleteOptionOnSoftModel() + { + Model::unguard(); + $user = UserWithSoftAuthorAndSoftDelete::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $author = SoftDeleteAuthor::create(['name' => 'Louie', 'email' => 'louie@email.tld', 'user_id' => $user->id]); + Model::reguard(); + + $authorId = $author->id; + $user->delete(); // Soft + $this->assertNull(SoftDeleteAuthor::find($authorId)); + $this->assertNotNull(SoftDeleteAuthor::withTrashed()->find($authorId)); + } + + public function testDeleteOptionOnSoftModel() + { + Model::unguard(); + $user = UserWithAuthorAndSoftDelete::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $author = Author::create(['name' => 'Louie', 'email' => 'louie@email.tld', 'user_id' => $user->id]); + Model::reguard(); + + $authorId = $author->id; + $user->delete(); // Soft + $this->assertNotNull(Author::find($authorId)); // Do nothing + + $userId = $user->id; + $user = UserWithAuthorAndSoftDelete::withTrashed()->find($userId); + $user->restore(); + + $user->forceDelete(); // Hard + $this->assertNull(Author::find($authorId)); + } + + public function testRestoreSoftDeleteRelation() + { + Model::unguard(); + $user = UserWithSoftAuthorAndSoftDelete::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']); + $author = SoftDeleteAuthor::create(['name' => 'Louie', 'email' => 'louie@email.tld', 'user_id' => $user->id]); + Model::reguard(); + + $authorId = $author->id; + $user->delete(); // Soft + $this->assertNull(SoftDeleteAuthor::find($authorId)); + $this->assertNotNull(SoftDeleteAuthor::withTrashed()->find($authorId)); + + $userId = $user->id; + $user = UserWithSoftAuthorAndSoftDelete::withTrashed()->find($userId); + $user->restore(); + + $this->assertNotNull(SoftDeleteAuthor::find($authorId)); + } +} diff --git a/tests/unit/plugins/database/ValidationModelTest.php b/tests/unit/plugins/database/ValidationModelTest.php new file mode 100644 index 0000000..f5ddb55 --- /dev/null +++ b/tests/unit/plugins/database/ValidationModelTest.php @@ -0,0 +1,34 @@ +runPluginRefreshCommand('Database.Tester'); + } + + public function testUniqueTableValidation() + { + $this->expectException(\October\Rain\Database\ModelException::class); + + $post = ValidationPost::create([ + 'title' => 'This is a new post', + 'slug' => 'post-1', + 'description' => 'Testing...' + ]); + + $this->assertNotFalse($post); + + $post2 = ValidationPost::create([ + 'title' => 'this is another post with the same slug', + 'slug' => 'post-1', + 'description' => 'testing....' + ]); + } +} diff --git a/tests/unit/system/AliasesTest.php b/tests/unit/system/AliasesTest.php new file mode 100644 index 0000000..8d389cd --- /dev/null +++ b/tests/unit/system/AliasesTest.php @@ -0,0 +1,22 @@ +assertTrue(class_exists('Illuminate\Support\Facades\Input')); + $this->assertInstanceOf( + \October\Rain\Support\Facades\Input::class, + new \Illuminate\Support\Facades\Input() + ); + } + + public function testHtmlDumperAlias() + { + $this->assertTrue(class_exists('Illuminate\Support\Debug\HtmlDumper')); + $this->assertInstanceOf( + \Symfony\Component\VarDumper\Dumper\HtmlDumper::class, + new \Illuminate\Support\Debug\HtmlDumper() + ); + } +} diff --git a/tests/unit/system/classes/AutoDatasourceTest.php b/tests/unit/system/classes/AutoDatasourceTest.php new file mode 100644 index 0000000..14dc6f5 --- /dev/null +++ b/tests/unit/system/classes/AutoDatasourceTest.php @@ -0,0 +1,115 @@ +fixtures = []; + + // Create fixtures of template data + $this->fixtures[] = CmsThemeTemplateFixture::create([ + 'source' => 'test', + 'path' => 'partials/page-partial.htm', + 'content' => 'AutoDatasource partials/page-partial.htm', + 'file_size' => 40 + ]); + + $this->fixtures[] = CmsThemeTemplateFixture::create([ + 'source' => 'test', + 'path' => 'partials/testpost/default.htm', + 'content' => 'AutoDatasource partials/testpost/default.htm', + 'file_size' => 44 + ]); + + $this->fixtures[] = CmsThemeTemplateFixture::create([ + 'source' => 'test', + 'path' => 'partials/subdir/test.htm', + 'content' => 'AutoDatasource partials/subdir/test.htm', + 'file_size' => 39 + ]); + + $this->fixtures[] = CmsThemeTemplateFixture::create([ + 'source' => 'test', + 'path' => 'partials/nesting/level2.htm', + 'content' => 'AutoDatasource partials/nesting/level2.htm', + 'file_size' => 42, + 'deleted_at' => '2019-01-01 00:00:00' + ]); + + // Create AutoDatasource + $this->datasource = new AutoDatasource([ + 'database' => new DbDatasource('test', 'cms_theme_templates'), + 'filesystem' => new FileDatasource(base_path('tests/fixtures/themes/test'), App::make('files')), + ]); + } + + public function tearDown(): void + { + foreach ($this->fixtures as $fixture) { + $fixture->delete(); + } + + parent::tearDown(); + } + + public function testSelect() + { + $results = collect($this->datasource->select('partials')) + ->keyBy('fileName') + ->toArray(); + + // Should be 14 partials in filesystem (tests/fixtures/themes/test), and 1 created directly in database. + // 1 of the filesystem partials should be marked deleted in database. + $this->assertCount(14, $results); + + // Database-only partial should be available + $this->assertArrayHasKey('subdir/test.htm', $results); + $this->assertEquals( + 'AutoDatasource partials/subdir/test.htm', + $results['subdir/test.htm']['content'] + ); + + // Two filesystem partials should be overriden by database + $this->assertEquals( + 'AutoDatasource partials/page-partial.htm', + $results['page-partial.htm']['content'] + ); + $this->assertEquals( + 'AutoDatasource partials/testpost/default.htm', + $results['testpost/default.htm']['content'] + ); + + // One filesystem partial should be marked deleted in database + $this->assertArrayNotHasKey('nesting/level2.htm', $results); + } +} diff --git a/tests/unit/system/classes/CombineAssetsTest.php b/tests/unit/system/classes/CombineAssetsTest.php new file mode 100644 index 0000000..5c5d313 --- /dev/null +++ b/tests/unit/system/classes/CombineAssetsTest.php @@ -0,0 +1,104 @@ +assertIsArray($jsExt); + + $cssExt = self::getProtectedProperty($combiner, 'cssExtensions'); + $this->assertIsArray($cssExt); + + /* + * Check service methods + */ + $this->assertTrue(method_exists($combiner, 'combine')); + $this->assertTrue(method_exists($combiner, 'resetCache')); + } + + public function testCombine() + { + $combiner = CombineAssets::instance(); + + $url = $combiner->combine( + [ + 'assets/css/style1.css', + 'assets/css/style2.css' + ], + base_path().'/tests/fixtures/themes/test' + ); + $this->assertNotNull($url); + $this->assertRegExp('/\w+[-]\d+/i', $url); // Must contain hash-number + + $url = $combiner->combine( + [ + 'assets/js/script1.js', + 'assets/js/script2.js' + ], + base_path().'/tests/fixtures/themes/test' + ); + $this->assertNotNull($url); + $this->assertRegExp('/\w+[-]\d+/i', $url); // Must contain hash-number + } + + public function testPutCache() + { + $sampleId = md5('testhash'); + $sampleStore = ['version' => 12345678]; + $samplePath = '/tests/fixtures/Cms/themes/test'; + + $combiner = CombineAssets::instance(); + $value = self::callProtectedMethod($combiner, 'putCache', [$sampleId, $sampleStore]); + + $this->assertTrue($value); + } + + public function testGetTargetPath() + { + $combiner = CombineAssets::instance(); + + $value = self::callProtectedMethod($combiner, 'getTargetPath', ['/combine']); + $this->assertEquals('combine/', $value); + + $value = self::callProtectedMethod($combiner, 'getTargetPath', ['/index.php/combine']); + $this->assertEquals('index-php/combine/', $value); + } + + public function testMakeCacheId() + { + $sampleResources = ['assets/css/style1.css', 'assets/css/style2.css']; + $samplePath = base_path().'/tests/fixtures/cms/themes/test'; + + $combiner = CombineAssets::instance(); + self::setProtectedProperty($combiner, 'localPath', $samplePath); + + $value = self::callProtectedMethod($combiner, 'getCacheKey', [$sampleResources]); + $this->assertEquals(md5($samplePath.implode('|', $sampleResources)), $value); + } + + public function testResetCache() + { + $combiner = CombineAssets::instance(); + $this->assertNull($combiner->resetCache()); + } +} diff --git a/tests/unit/system/classes/CoreLangTest.php b/tests/unit/system/classes/CoreLangTest.php new file mode 100644 index 0000000..54899a8 --- /dev/null +++ b/tests/unit/system/classes/CoreLangTest.php @@ -0,0 +1,48 @@ +app['translator']; + $translator->setLocale('en'); + + $validator = Validator::make( + ['name' => 'me'], + ['name' => 'required|min:5'] + ); + + $this->assertTrue($validator->fails()); + + $messages = $validator->messages(); + $this->assertCount(1, $messages); + $this->assertEquals('The name must be at least 5 characters.', $messages->all()[0]); + } + + public function testValidCoreLanguageFiles() + { + $translator = $this->app['translator']; + $locales = $translator->get('system::lang.locale'); + $this->assertNotEmpty($locales); + + $locales = array_keys($locales); + $modules = ['system', 'backend', 'cms']; + $files = ['lang.php', 'validation.php', 'client.php']; + + foreach ($modules as $module) { + foreach ($locales as $locale) { + foreach ($files as $file) { + $srcPath = base_path() . '/modules/'.$module.'/lang/'.$locale.'/'.$file; + if (!file_exists($srcPath)) { + continue; + } + $messages = require $srcPath; + $this->assertNotEmpty($messages); + $this->assertNotCount(0, $messages); + } + } + } + } +} diff --git a/tests/unit/system/classes/FileManifestTest.php b/tests/unit/system/classes/FileManifestTest.php new file mode 100644 index 0000000..a7246e2 --- /dev/null +++ b/tests/unit/system/classes/FileManifestTest.php @@ -0,0 +1,58 @@ +fileManifest = new FileManifest(base_path('tests/fixtures/manifest/2'), ['test', 'test2']); + } + + public function testGetFiles() + { + $this->assertEquals([ + '/modules/test/file1.php' => '6f9b0b94528a85b2a6bb67b5621e074aef1b4c9fc9ee3ea1bd69100ea14cb3db', + '/modules/test/file2.php' => '96ae9f6b6377ad29226ea169f952de49fc29ae895f18a2caed76aeabdf050f1b', + '/modules/test2/file1.php' => '94bd47b1ac7b2837b31883ebcd38c8101687321f497c3c4b9744f68ae846721d', + ], $this->fileManifest->getFiles()); + } + + public function testGetModuleChecksums() + { + $this->assertEquals([ + 'test' => 'c0b794ff210862a4ce16223802efe6e28969f5a4fb42480ec8c2fef2da23d181', + 'test2' => '32c9f2fb6e0a22dde288a0fe1e4834798360b25e5a91d2597409d9302221381d', + ], $this->fileManifest->getModuleChecksums()); + } + + public function testGetFilesInvalidRoot() + { + $this->expectException(ApplicationException::class); + $this->expectExceptionMessage('Invalid root specified for the file manifest.'); + + $this->fileManifest->setRoot(base_path('tests/fixtures/manifest/invalid')); + + $this->fileManifest->getFiles(); + } + + public function testSingleModule() + { + $this->fileManifest->setModules(['test']); + + $this->assertEquals([ + '/modules/test/file1.php' => '6f9b0b94528a85b2a6bb67b5621e074aef1b4c9fc9ee3ea1bd69100ea14cb3db', + '/modules/test/file2.php' => '96ae9f6b6377ad29226ea169f952de49fc29ae895f18a2caed76aeabdf050f1b', + ], $this->fileManifest->getFiles()); + + $this->assertEquals([ + 'test' => 'c0b794ff210862a4ce16223802efe6e28969f5a4fb42480ec8c2fef2da23d181', + ], $this->fileManifest->getModuleChecksums()); + } +} diff --git a/tests/unit/system/classes/ImageResizerTest.php b/tests/unit/system/classes/ImageResizerTest.php new file mode 100644 index 0000000..6bc97be --- /dev/null +++ b/tests/unit/system/classes/ImageResizerTest.php @@ -0,0 +1,407 @@ +removeMedia(); + ImageResizer::flushAvailableSources(); + parent::tearDown(); + } + + /** + * Tests configuration through the constructor as well as events. + * + * @return void + */ + public function testConfiguration() + { + // Resize with default options + $imageResizer = new ImageResizer( + (new CmsController())->themeUrl('assets/images/october.png'), + 100, + 100 + ); + self::assertArraySubset([ + 'width' => 100, + 'height' => 100, + 'options' => [ + 'mode' => 'auto', + 'offset' => [0, 0], + 'sharpen' => 0, + 'interlace' => false, + 'quality' => 90, + 'extension' => 'png', + ], + ], $imageResizer->getConfig()); + + // Resize with customised options + $imageResizer = new ImageResizer( + (new CmsController())->themeUrl('assets/images/october.png'), + 150, + 120, + [ + 'mode' => 'fit', + 'offset' => [2, 2], + 'sharpen' => 23, + 'interlace' => true, + 'quality' => 73, + 'extension' => 'jpg' + ] + ); + self::assertArraySubset([ + 'width' => 150, + 'height' => 120, + 'options' => [ + 'mode' => 'fit', + 'offset' => [2, 2], + 'sharpen' => 23, + 'interlace' => true, + 'quality' => 73, + 'extension' => 'jpg' + ], + ], $imageResizer->getConfig()); + + // Resize with an customised defaults + Event::listen('system.resizer.getDefaultOptions', function (&$options) { + $options = array_merge($options, [ + 'mode' => 'fit', + 'offset' => [2, 2], + 'sharpen' => 23, + 'interlace' => true, + 'quality' => 73, + ]); + }); + + $imageResizer = new ImageResizer( + (new CmsController())->themeUrl('assets/images/october.png'), + 100, + 100, + [] + ); + self::assertArraySubset([ + 'width' => 100, + 'height' => 100, + 'options' => [ + 'mode' => 'fit', + 'offset' => [2, 2], + 'sharpen' => 23, + 'interlace' => true, + 'quality' => 73, + 'extension' => 'png', + ], + ], $imageResizer->getConfig()); + + Event::forget('system.resizer.getDefaultOptions'); + + // Resize with a falsey height specified + $imageResizer = new ImageResizer( + (new CmsController())->themeUrl('assets/images/october.png'), + 100, + false + ); + self::assertArraySubset([ + 'width' => 100, + 'height' => 0, + ], $imageResizer->getConfig()); + + $imageResizer = new ImageResizer( + (new CmsController())->themeUrl('assets/images/october.png'), + 100, + null + ); + self::assertArraySubset([ + 'width' => 100, + 'height' => 0, + ], $imageResizer->getConfig()); + + // Resize with a falsey width specified + $imageResizer = new ImageResizer( + (new CmsController())->themeUrl('assets/images/october.png'), + '', + 100 + ); + self::assertArraySubset([ + 'width' => 0, + 'height' => 100, + ], $imageResizer->getConfig()); + + $imageResizer = new ImageResizer( + (new CmsController())->themeUrl('assets/images/october.png'), + "0", + 100 + ); + self::assertArraySubset([ + 'width' => 0, + 'height' => 100, + ], $imageResizer->getConfig()); + } + + /** + * Tests URLs for sources that can be accessed via URL. + * + * @return void + */ + public function testURLSources() + { + // Theme URL (absolute URL) + $this->setUpStorage(); + $this->copyMedia(); + + $imageResizer = new ImageResizer( + (new CmsController())->themeUrl('assets/images/october.png'), + 100, + 100 + ); + $this->assertEquals('png', $imageResizer->getConfig()['options']['extension']); + + // Theme URL (relative URL) + $this->setUpStorage(); + $this->copyMedia(); + + $imageResizer = new ImageResizer( + '/themes/test/assets/images/october.png', + 100, + 100 + ); + $this->assertEquals('png', $imageResizer->getConfig()['options']['extension']); + + // Media URL (absolute URL) + $this->setUpStorage(); + $this->copyMedia(); + + $imageResizer = new ImageResizer( + URL::to(MediaLibrary::url('october.png')), + 100, + 100 + ); + $this->assertEquals('png', $imageResizer->getConfig()['options']['extension']); + + // Media URL (relative URL) + $this->setUpStorage(); + $this->copyMedia(); + + $imageResizer = new ImageResizer( + MediaLibrary::url('october.png'), + 100, + 100 + ); + $this->assertEquals('png', $imageResizer->getConfig()['options']['extension']); + + // Media URL (absolute URL) + $this->setUpStorage(); + $this->copyMedia(); + + $imageResizer = new ImageResizer( + URL::to(MediaLibrary::url('october.png')), + 100, + 100 + ); + $this->assertEquals('png', $imageResizer->getConfig()['options']['extension']); + + // Plugin URL (relative URL) + $imageResizer = new ImageResizer( + '/plugins/database/tester/assets/images/avatar.png', + 100, + 100 + ); + $this->assertEquals('png', $imageResizer->getConfig()['options']['extension']); + + // Plugin URL (absolute URL) + $imageResizer = new ImageResizer( + URL::to('plugins/database/tester/assets/images/avatar.png'), + 100, + 100 + ); + $this->assertEquals('png', $imageResizer->getConfig()['options']['extension']); + + // Module URL (relative URL) + $imageResizer = new ImageResizer( + '/modules/backend/assets/images/favicon.png', + 100, + 100 + ); + $this->assertEquals('png', $imageResizer->getConfig()['options']['extension']); + + // Module URL (absolute URL) + $imageResizer = new ImageResizer( + Backend::skinAsset('assets/images/favicon.png'), + 100, + 100 + ); + $this->assertEquals('png', $imageResizer->getConfig()['options']['extension']); + + // URL for a FileModel instance (absolute URL) + $fileModel = new FileModel(); + $fileModel->fromFile(base_path('tests/fixtures/plugins/database/tester/assets/images/avatar.png')); + $fileModel->save(); + + $imageResizer = new ImageResizer( + FileModel::first()->getPath(), + 100, + 100 + ); + $this->assertEquals('png', $imageResizer->getConfig()['options']['extension']); + + // Remove FileModel instance + $fileModel->delete(); + + // URL of a FileModel instance (relative URL) + $fileModel = new FileModel(); + $fileModel->fromFile(base_path('tests/fixtures/plugins/database/tester/assets/images/avatar.png')); + $fileModel->save(); + + $imageResizer = new ImageResizer( + str_replace(url('') . '/', '/', FileModel::first()->getPath()), + 100, + 100 + ); + $this->assertEquals('png', $imageResizer->getConfig()['options']['extension']); + } + + public function testDirectSources() + { + // FileModel instance itself + $fileModel = new FileModel(); + $fileModel->fromFile(base_path('tests/fixtures/plugins/database/tester/assets/images/avatar.png')); + $fileModel->save(); + + $imageResizer = new ImageResizer( + $fileModel, + 100, + 100 + ); + $this->assertEquals('png', $imageResizer->getConfig()['options']['extension']); + + // Remove FileModel instance + $fileModel->delete(); + } + + public function testInvalidInputPath() + { + $this->expectException(SystemException::class); + $this->expectExceptionMessageMatches('/^Unable to process the provided image/'); + + $imageResizer = new ImageResizer( + '/plugins/database/tester/assets/images/MISSING.png', + 100, + 100 + ); + } + + public function testInvalidInputFileModel() + { + $this->expectException(SystemException::class); + $this->expectExceptionMessageMatches('/^Unable to process the provided image/'); + + $imageResizer = new ImageResizer( + FileModel::first(), + 100, + 100 + ); + } + + public function testSpaceInFilename() + { + // Media URL with space + $this->setUpStorage(); + $this->copyMedia(); + + $imageResizer = new ImageResizer( + URL::to(MediaLibrary::url('october space.png')), + 100, + 100 + ); + + $this->assertStringContainsString('october%20space', $imageResizer->getResizedUrl(), 'Resized URLs are not properly URL encoded'); + } + + public function testGetResizedUrl() + { + $imageResizer = new ImageResizer((new CmsController())->themeUrl('assets/images/october.png')); + + Config::set('cms.linkPolicy', 'force'); + $url = $imageResizer->getResizedUrl(); + $this->assertTrue(starts_with($url, 'http')); + + Config::set('cms.linkPolicy', 'detect'); + $url = $imageResizer->getResizedUrl(); + $this->assertTrue(starts_with($url, Config::get('cms.storage.resized.path', '/storage/app/resized'))); + } + + public function testGetResizerUrl() + { + $imageResizer = new ImageResizer((new CmsController())->themeUrl('assets/images/october.png')); + + Config::set('cms.linkPolicy', 'force'); + $url = $imageResizer->getResizerUrl(); + $this->assertTrue(starts_with($url, 'http')); + + Config::set('cms.linkPolicy', 'detect'); + $url = $imageResizer->getResizerUrl(); + $this->assertTrue(starts_with($url, '/resizer/')); + } + + protected function setUpStorage() + { + $this->app->useStoragePath(base_path('storage/temp')); + + Config::set('filesystems.disks.test_local', [ + 'driver' => 'local', + 'root' => storage_path('app'), + ]); + + Config::set('cms.storage.media', [ + 'disk' => 'test_local', + 'folder' => 'media', + 'path' => '/storage/temp/app/media', + ]); + } + + protected function copyMedia() + { + $mediaPath = storage_path('app/media'); + + if (!is_dir($mediaPath)) { + mkdir($mediaPath, 0777, true); + } + + foreach (glob(base_path('tests/fixtures/media/*')) as $file) { + $path = pathinfo($file); + copy($file, $mediaPath . DIRECTORY_SEPARATOR . $path['basename']); + } + } + + protected function removeMedia() + { + if ($this->app->storagePath() !== base_path('storage/temp')) { + return; + } + + foreach (glob(storage_path('app/media/*')) as $file) { + unlink($file); + } + + rmdir(storage_path('app/media')); + rmdir(storage_path('app')); + } +} diff --git a/tests/unit/system/classes/MarkupManagerTest.php b/tests/unit/system/classes/MarkupManagerTest.php new file mode 100644 index 0000000..f4ee00a --- /dev/null +++ b/tests/unit/system/classes/MarkupManagerTest.php @@ -0,0 +1,83 @@ +assertFalse($result); + + $callable = ['Form', 'open']; + $result = self::callProtectedMethod($manager, 'isWildCallable', [$callable]); + $this->assertFalse($result); + + $callable = function () { + return 'O, Hai!'; + }; + $result = self::callProtectedMethod($manager, 'isWildCallable', [$callable]); + $this->assertFalse($result); + + /* + * String + */ + $callable = 'something_*'; + $result = self::callProtectedMethod($manager, 'isWildCallable', [$callable]); + $this->assertTrue($result); + + $result = self::callProtectedMethod($manager, 'isWildCallable', [$callable, 'delicious']); + $this->assertEquals('something_delicious', $result); + + /* + * Array + */ + $callable = ['Class', 'foo_*']; + $result = self::callProtectedMethod($manager, 'isWildCallable', [$callable]); + $this->assertTrue($result); + + $result = self::callProtectedMethod($manager, 'isWildCallable', [$callable, 'bar']); + $this->assertArrayHasKey(0, $result); + $this->assertArrayHasKey(1, $result); + $this->assertEquals('Class', $result[0]); + $this->assertEquals('foo_bar', $result[1]); + + $callable = ['My*', 'method']; + $result = self::callProtectedMethod($manager, 'isWildCallable', [$callable]); + $this->assertTrue($result); + + $result = self::callProtectedMethod($manager, 'isWildCallable', [$callable, 'Class']); + $this->assertArrayHasKey(0, $result); + $this->assertArrayHasKey(1, $result); + $this->assertEquals('MyClass', $result[0]); + $this->assertEquals('method', $result[1]); + + $callable = ['My*', 'my*']; + $result = self::callProtectedMethod($manager, 'isWildCallable', [$callable]); + $this->assertTrue($result); + + $result = self::callProtectedMethod($manager, 'isWildCallable', [$callable, 'Food']); + $this->assertArrayHasKey(0, $result); + $this->assertArrayHasKey(1, $result); + $this->assertEquals('MyFood', $result[0]); + $this->assertEquals('myFood', $result[1]); + } +} diff --git a/tests/unit/system/classes/MediaLibraryTest.php b/tests/unit/system/classes/MediaLibraryTest.php new file mode 100644 index 0000000..6437ec4 --- /dev/null +++ b/tests/unit/system/classes/MediaLibraryTest.php @@ -0,0 +1,169 @@ +removeMedia(); + parent::tearDown(); + } + + public function invalidPathsProvider() + { + return [ + ['./file'], + ['../secret'], + ['.../secret'], + ['/../secret'], + ['/.../secret'], + ['/secret/..'], + ['file/../secret'], + ['file/..'], + ['......./secret'], + ['./file'], + ]; + } + + public function validPathsProvider() + { + return [ + ['file'], + ['folder/file'], + ['/file'], + ['/folder/file'], + ['/.file'], + ['/..file'], + ['/...file'], + ['file.ext'], + ['file..ext'], + ['file...ext'], + ['one,two.ext'], + ['one(two)[].ext'], + ['one=(two)[].ext'], + ['one_(two)[].ext'], + /* + Example of a unicode-based filename with a single quote + @see: https://github.com/octobercms/october/pull/4564 + */ + ['BG中国通讯期刊(Blend\'r)创刊号.pdf'], + ]; + } + + /** + * @dataProvider invalidPathsProvider + */ + public function testInvalidPathsOnValidatePath($path) + { + $this->expectException('ApplicationException'); + MediaLibrary::validatePath($path); + } + + /** + * @dataProvider validPathsProvider + */ + public function testValidPathsOnValidatePath($path) + { + $result = MediaLibrary::validatePath($path); + $this->assertIsString($result); + } + + public function testListFolderContents() + { + $this->setUpStorage(); + $this->copyMedia(); + + $contents = MediaLibrary::instance()->listFolderContents(); + $this->assertNotEmpty($contents, 'Media library item is not discovered'); + $this->assertCount(3, $contents); + + $this->assertEquals('file', $contents[1]->type, 'Media library item does not have the right type'); + $this->assertEquals('/october.png', $contents[1]->path, 'Media library item does not have the right path'); + $this->assertNotEmpty($contents[1]->lastModified, 'Media library item last modified is empty'); + $this->assertNotEmpty($contents[1]->size, 'Media library item size is empty'); + + $this->assertEquals('file', $contents[2]->type, 'Media library item does not have the right type'); + $this->assertEquals('/text.txt', $contents[2]->path, 'Media library item does not have the right path'); + $this->assertNotEmpty($contents[2]->lastModified, 'Media library item last modified is empty'); + $this->assertNotEmpty($contents[2]->size, 'Media library item size is empty'); + } + + public function testListAllDirectories() + { + $disk = $this->createConfiguredMock(FilesystemAdapter::class, [ + 'allDirectories' => [ + '/media/.ignore1', + '/media/.ignore2', + '/media/dir', + '/media/dir/sub', + '/media/exclude', + '/media/hidden', + '/media/hidden/sub1', + '/media/hidden/sub1/deep1', + '/media/hidden/sub2', + '/media/hidden but not really', + '/media/name' + ] + ]); + + $this->app['config']->set('cms.storage.media.folder', 'media'); + $this->app['config']->set('cms.storage.media.ignore', ['hidden']); + $this->app['config']->set('cms.storage.media.ignorePatterns', ['^\..*']); + $instance = MediaLibrary::instance(); + $this->setProtectedProperty($instance, 'storageDisk', $disk); + + $this->assertEquals(['/', '/dir', '/dir/sub', '/hidden but not really', '/name'], $instance->listAllDirectories(['/exclude'])); + } + + protected function setUpStorage() + { + $this->app->useStoragePath(base_path('storage/temp')); + + config(['filesystems.disks.test_local' => [ + 'driver' => 'local', + 'root' => storage_path('app'), + ]]); + + config(['cms.storage.media' => [ + 'disk' => 'test_local', + 'folder' => 'media', + 'path' => '/storage/app/media', + ]]); + } + + protected function copyMedia() + { + $mediaPath = storage_path('app/media'); + + if (!is_dir($mediaPath)) { + mkdir($mediaPath, 0777, true); + } + + foreach (glob(base_path('tests/fixtures/media/*')) as $file) { + $path = pathinfo($file); + copy($file, $mediaPath . DIRECTORY_SEPARATOR . $path['basename']); + } + } + + protected function removeMedia() + { + if ($this->app->storagePath() !== base_path('storage/temp')) { + return; + } + + foreach (glob(storage_path('app/media/*')) as $file) { + unlink($file); + } + + rmdir(storage_path('app/media')); + rmdir(storage_path('app')); + } +} diff --git a/tests/unit/system/classes/PluginManagerTest.php b/tests/unit/system/classes/PluginManagerTest.php new file mode 100644 index 0000000..c963f2d --- /dev/null +++ b/tests/unit/system/classes/PluginManagerTest.php @@ -0,0 +1,243 @@ +loadPlugins(); + self::callProtectedMethod($manager, 'loadDependencies'); + + $this->manager = $manager; + } + + // + // Tests + // + + public function testLoadPlugins() + { + $result = $this->manager->loadPlugins(); + + $this->assertCount(9, $result); + $this->assertArrayHasKey('October.NoUpdates', $result); + $this->assertArrayHasKey('October.Sample', $result); + $this->assertArrayHasKey('October.Tester', $result); + $this->assertArrayHasKey('Database.Tester', $result); + $this->assertArrayHasKey('TestVendor.Test', $result); + $this->assertArrayHasKey('DependencyTest.Found', $result); + $this->assertArrayHasKey('DependencyTest.NotFound', $result); + $this->assertArrayHasKey('DependencyTest.WrongCase', $result); + $this->assertArrayHasKey('DependencyTest.Dependency', $result); + + $this->assertArrayNotHasKey('TestVendor.Goto', $result); + + $this->assertInstanceOf('October\NoUpdates\Plugin', $result['October.NoUpdates']); + $this->assertInstanceOf('October\Sample\Plugin', $result['October.Sample']); + $this->assertInstanceOf('October\Tester\Plugin', $result['October.Tester']); + $this->assertInstanceOf('Database\Tester\Plugin', $result['Database.Tester']); + $this->assertInstanceOf('TestVendor\Test\Plugin', $result['TestVendor.Test']); + $this->assertInstanceOf('DependencyTest\Found\Plugin', $result['DependencyTest.Found']); + $this->assertInstanceOf('DependencyTest\NotFound\Plugin', $result['DependencyTest.NotFound']); + $this->assertInstanceOf('DependencyTest\WrongCase\Plugin', $result['DependencyTest.WrongCase']); + $this->assertInstanceOf('DependencyTest\Dependency\Plugin', $result['DependencyTest.Dependency']); + } + + public function testUnloadablePlugin() + { + $pluginNamespaces = $this->manager->getPluginNamespaces(); + $result = $this->manager->loadPlugin('\\testvendor\\goto', $pluginNamespaces['\\testvendor\\goto']); + $this->assertNull($result); + } + + public function testGetPluginPath() + { + $result = $this->manager->getPluginPath('October\Tester'); + $basePath = str_replace('\\', '/', base_path()); + $this->assertEquals($basePath . '/tests/fixtures/plugins/october/tester', $result); + } + + public function testGetPlugins() + { + $result = $this->manager->getPlugins(); + + $this->assertCount(8, $result); + $this->assertArrayHasKey('October.NoUpdates', $result); + $this->assertArrayHasKey('October.Sample', $result); + $this->assertArrayHasKey('October.Tester', $result); + $this->assertArrayHasKey('Database.Tester', $result); + $this->assertArrayHasKey('TestVendor.Test', $result); + $this->assertArrayHasKey('DependencyTest.Found', $result); + $this->assertArrayHasKey('DependencyTest.WrongCase', $result); + $this->assertArrayHasKey('DependencyTest.Dependency', $result); + + $this->assertArrayNotHasKey('DependencyTest.NotFound', $result); + $this->assertArrayNotHasKey('TestVendor.Goto', $result); + + $this->assertInstanceOf('October\NoUpdates\Plugin', $result['October.NoUpdates']); + $this->assertInstanceOf('October\Sample\Plugin', $result['October.Sample']); + $this->assertInstanceOf('October\Tester\Plugin', $result['October.Tester']); + $this->assertInstanceOf('Database\Tester\Plugin', $result['Database.Tester']); + $this->assertInstanceOf('TestVendor\Test\Plugin', $result['TestVendor.Test']); + $this->assertInstanceOf('DependencyTest\Found\Plugin', $result['DependencyTest.Found']); + $this->assertInstanceOf('DependencyTest\WrongCase\Plugin', $result['DependencyTest.WrongCase']); + $this->assertInstanceOf('DependencyTest\Dependency\Plugin', $result['DependencyTest.Dependency']); + } + + public function testFindByNamespace() + { + $result = $this->manager->findByNamespace('October\Tester'); + $this->assertInstanceOf('October\Tester\Plugin', $result); + } + + public function testHasPlugin() + { + $result = $this->manager->hasPlugin('October\Tester'); + $this->assertTrue($result); + + $result = $this->manager->hasPlugin('DependencyTest.Found'); + $this->assertTrue($result); + + $result = $this->manager->hasPlugin('DependencyTest\WrongCase'); + $this->assertTrue($result); + + $result = $this->manager->hasPlugin('DependencyTest\NotFound'); + $this->assertTrue($result); + + $result = $this->manager->hasPlugin('October\XXXXX'); + $this->assertFalse($result); + + /** + * Test case for https://github.com/octobercms/october/pull/4337 + */ + $result = $this->manager->hasPlugin('dependencyTest\Wrongcase'); + $this->assertTrue($result); + + $result = $this->manager->hasPlugin('dependencyTest.Wrongcase'); + $this->assertTrue($result); + } + + public function testGetPluginNamespaces() + { + $result = $this->manager->getPluginNamespaces(); + + $this->assertCount(10, $result); + $this->assertArrayHasKey('\october\noupdates', $result); + $this->assertArrayHasKey('\october\sample', $result); + $this->assertArrayHasKey('\october\tester', $result); + $this->assertArrayHasKey('\database\tester', $result); + $this->assertArrayHasKey('\testvendor\test', $result); + $this->assertArrayHasKey('\testvendor\goto', $result); + $this->assertArrayHasKey('\dependencytest\found', $result); + $this->assertArrayHasKey('\dependencytest\notfound', $result); + $this->assertArrayHasKey('\dependencytest\wrongcase', $result); + $this->assertArrayHasKey('\dependencytest\dependency', $result); + } + + public function testGetVendorAndPluginNames() + { + $vendors = $this->manager->getVendorAndPluginNames(); + + $this->assertCount(4, $vendors); + $this->assertArrayHasKey('october', $vendors); + $this->assertArrayHasKey('noupdates', $vendors['october']); + $this->assertArrayHasKey('sample', $vendors['october']); + $this->assertArrayHasKey('tester', $vendors['october']); + + $this->assertArrayHasKey('database', $vendors); + $this->assertArrayHasKey('tester', $vendors['database']); + + $this->assertArrayHasKey('testvendor', $vendors); + $this->assertArrayHasKey('test', $vendors['testvendor']); + $this->assertArrayHasKey('goto', $vendors['testvendor']); + + $this->assertArrayHasKey('dependencytest', $vendors); + $this->assertArrayHasKey('found', $vendors['dependencytest']); + $this->assertArrayHasKey('notfound', $vendors['dependencytest']); + $this->assertArrayHasKey('wrongcase', $vendors['dependencytest']); + $this->assertArrayHasKey('dependency', $vendors['dependencytest']); + } + + public function testPluginDetails() + { + $testPlugin = $this->manager->findByNamespace('October\XXXXX'); + $this->assertNull($testPlugin); + + $testPlugin = $this->manager->findByNamespace('October\Tester'); + $this->assertNotNull($testPlugin); + $pluginDetails = $testPlugin->pluginDetails(); + + $this->assertEquals('October Test Plugin', $pluginDetails['name']); + $this->assertEquals('Test plugin used by unit tests.', $pluginDetails['description']); + $this->assertEquals('Alexey Bobkov, Samuel Georges', $pluginDetails['author']); + } + + public function testUnregisterall() + { + $result = $this->manager->getPlugins(); + $this->assertCount(8, $result); + + $this->manager->unregisterAll(); + $this->assertEmpty($this->manager->getPlugins()); + } + + public function testGetDependencies() + { + $result = $this->manager->getDependencies('DependencyTest.Found'); + $this->assertCount(1, $result); + $this->assertContains('DependencyTest.Dependency', $result); + + $result = $this->manager->getDependencies('DependencyTest.WrongCase'); + $this->assertCount(1, $result); + $this->assertContains('Dependencytest.dependency', $result); + + $result = $this->manager->getDependencies('DependencyTest.NotFound'); + $this->assertCount(1, $result); + $this->assertContains('DependencyTest.Missing', $result); + } + + public function testIsDisabled() + { + $result = $this->manager->isDisabled('DependencyTest.Found'); + $this->assertFalse($result); + + $result = $this->manager->isDisabled('DependencyTest.WrongCase'); + $this->assertFalse($result); + + $result = $this->manager->isDisabled('DependencyTest.NotFound'); + $this->assertTrue($result); + + /** + * Test case for https://github.com/octobercms/october/pull/4838 + */ + $result = $this->manager->isDisabled('dependencyTest\Wrongcase'); + $this->assertFalse($result); + + $result = $this->manager->isDisabled('dependencyTest.Wrongcase'); + $this->assertFalse($result); + + $result = $this->manager->isDisabled('dependencytest.notfound'); + $this->assertTrue($result); + } + + public function testExists() + { + $result = $this->manager->exists('DependencyTest.Found'); + $this->assertTrue($result); + + $result = $this->manager->exists('DependencyTest.WrongCase'); + $this->assertTrue($result); + + $result = $this->manager->exists('DependencyTest.NotFound'); + $this->assertFalse($result); + + $result = $this->manager->exists('Unknown.Plugin'); + $this->assertFalse($result); + } +} diff --git a/tests/unit/system/classes/SourceManifestTest.php b/tests/unit/system/classes/SourceManifestTest.php new file mode 100644 index 0000000..41d845e --- /dev/null +++ b/tests/unit/system/classes/SourceManifestTest.php @@ -0,0 +1,198 @@ +builds = [ + 1 => new FileManifest(base_path('tests/fixtures/manifest/1'), ['test', 'test2']), + 2 => new FileManifest(base_path('tests/fixtures/manifest/2'), ['test', 'test2']), + 3 => new FileManifest(base_path('tests/fixtures/manifest/3'), ['test', 'test2']), + ]; + + $this->sourceManifest = new SourceManifest($this->manifestPath(), false); + } + + public function tearDown(): void + { + $this->deleteManifest(); + } + + public function testCreateManifest() + { + $this->createManifest(true); + + $this->assertEquals( + '{' . "\n" . + ' "manifest": [' . "\n" . + ' {' . "\n" . + ' "build": 1,' . "\n" . + ' "modules": {' . "\n" . + ' "test": "e1d6c6e4c482688e231ee37d89668268426512013695de47bfcb424f9a645c7b",' . "\n" . + ' "test2": "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"' . "\n" . + ' },' . "\n" . + ' "files": {' . "\n" . + ' "added": {' . "\n" . + ' "\/modules\/test\/file1.php": "6f9b0b94528a85b2a6bb67b5621e074aef1b4c9fc9ee3ea1bd69100ea14cb3db"' . "\n" . + ' }' . "\n" . + ' }' . "\n" . + ' },' . "\n" . + ' {' . "\n" . + ' "build": 2,' . "\n" . + ' "modules": {' . "\n" . + ' "test": "c0b794ff210862a4ce16223802efe6e28969f5a4fb42480ec8c2fef2da23d181",' . "\n" . + ' "test2": "32c9f2fb6e0a22dde288a0fe1e4834798360b25e5a91d2597409d9302221381d"' . "\n" . + ' },' . "\n" . + ' "files": {' . "\n" . + ' "added": {' . "\n" . + ' "\/modules\/test\/file2.php": "96ae9f6b6377ad29226ea169f952de49fc29ae895f18a2caed76aeabdf050f1b",' . "\n" . + ' "\/modules\/test2\/file1.php": "94bd47b1ac7b2837b31883ebcd38c8101687321f497c3c4b9744f68ae846721d"' . "\n" . + ' }' . "\n" . + ' }' . "\n" . + ' },' . "\n" . + ' {' . "\n" . + ' "build": 3,' . "\n" . + ' "modules": {' . "\n" . + ' "test": "419a3c073a4296213cdc9319cfc488383753e2e81cefa1c73db38749b82a3c51",' . "\n" . + ' "test2": "32c9f2fb6e0a22dde288a0fe1e4834798360b25e5a91d2597409d9302221381d"' . "\n" . + ' },' . "\n" . + ' "files": {' . "\n" . + ' "added": {' . "\n" . + ' "\/modules\/test\/file3.php": "7f4132b05911a6b0df4d41bf5dc3d007786b63a5a22daf3060ed222816d57b54"' . "\n" . + ' },' . "\n" . + ' "modified": {' . "\n" . + ' "\/modules\/test\/file2.php": "2c61b2f5688275574251a19a57e06a4eb9e537b3916ebf6f71768e184a4ae538"' . "\n" . + ' },' . "\n" . + ' "removed": [' . "\n" . + ' "\/modules\/test\/file1.php"' . "\n" . + ' ]' . "\n" . + ' }' . "\n" . + ' }' . "\n" . + ' ]' . "\n" . + '}', + file_get_contents($this->manifestPath()) + ); + } + + public function testGetBuilds() + { + $this->createManifest(); + + $buildKeys = array_keys($this->sourceManifest->getBuilds()); + + $this->assertCount(3, $buildKeys); + $this->assertEquals([1, 2, 3], $buildKeys); + } + + public function testGetMaxBuild() + { + $this->createManifest(); + + $this->assertEquals(3, $this->sourceManifest->getMaxBuild()); + } + + public function testGetState() + { + $this->createManifest(); + + $this->assertEquals([ + '/modules/test/file1.php' => '6f9b0b94528a85b2a6bb67b5621e074aef1b4c9fc9ee3ea1bd69100ea14cb3db', + ], $this->sourceManifest->getState(1)); + + $this->assertEquals([ + '/modules/test/file1.php' => '6f9b0b94528a85b2a6bb67b5621e074aef1b4c9fc9ee3ea1bd69100ea14cb3db', + '/modules/test/file2.php' => '96ae9f6b6377ad29226ea169f952de49fc29ae895f18a2caed76aeabdf050f1b', + '/modules/test2/file1.php' => '94bd47b1ac7b2837b31883ebcd38c8101687321f497c3c4b9744f68ae846721d', + ], $this->sourceManifest->getState(2)); + + $this->assertEquals([ + '/modules/test/file2.php' => '2c61b2f5688275574251a19a57e06a4eb9e537b3916ebf6f71768e184a4ae538', + '/modules/test/file3.php' => '7f4132b05911a6b0df4d41bf5dc3d007786b63a5a22daf3060ed222816d57b54', + '/modules/test2/file1.php' => '94bd47b1ac7b2837b31883ebcd38c8101687321f497c3c4b9744f68ae846721d', + ], $this->sourceManifest->getState(3)); + } + + public function testCompare() + { + $this->createManifest(); + + $this->assertEquals([ + 'build' => 1, + 'modified' => false, + 'confident' => true + ], $this->sourceManifest->compare($this->builds[1])); + + $this->assertEquals([ + 'build' => 2, + 'modified' => false, + 'confident' => true + ], $this->sourceManifest->compare($this->builds[2])); + + $this->assertEquals([ + 'build' => 3, + 'modified' => false, + 'confident' => true + ], $this->sourceManifest->compare($this->builds[3])); + } + + public function testCompareModified() + { + $this->createManifest(); + + // Hot-swap "tests/fixtures/manifest/3/modules/test/file3.php" + $old = file_get_contents(base_path('tests/fixtures/manifest/3/modules/test/file3.php')); + file_put_contents(base_path('tests/fixtures/manifest/3/modules/test/file3.php'), 'getFiles(); + + file_put_contents(base_path('tests/fixtures/manifest/3/modules/test/file3.php'), $old); + + $this->assertEquals([ + 'build' => 3, + 'modified' => true, + 'confident' => true, + ], $this->sourceManifest->compare($modifiedManifest)); + } + + protected function createManifest(bool $write = false) + { + $this->deleteManifest(); + + $last = null; + + foreach ($this->builds as $build => $fileManifest) { + $this->sourceManifest->addBuild($build, $fileManifest, $last); + + $last = $build; + } + + if ($write) { + file_put_contents($this->manifestPath(), $this->sourceManifest->generate()); + } + } + + protected function deleteManifest() + { + if (file_exists($this->manifestPath())) { + unlink($this->manifestPath()); + } + } + + protected function manifestPath() + { + return base_path('tests/fixtures/manifest/builds.json'); + } +} diff --git a/tests/unit/system/classes/UpdatesControllerTest.php b/tests/unit/system/classes/UpdatesControllerTest.php new file mode 100644 index 0000000..6342092 --- /dev/null +++ b/tests/unit/system/classes/UpdatesControllerTest.php @@ -0,0 +1,57 @@ +getMockBuilder(Updates::class)->disableOriginalConstructor()->getMock(); + + $expectedVersions = [ + '1.2.0' => [ + '!!! Security update - see: https://octobercms.com', + ], + '1.1.0' => [ + '!!! Drop support for blog settings', + ], + '1.0.5' => [ + 'Create blog settings table', + 'Another update message', + 'Yet one more update message' + ], + '1.0.4' => [ + 'Another fix' + ], + '1.0.3' => [ + 'Bug fix update that uses no scripts' + ], + '1.0.2' => [ + 'Create blog post comments table', + 'Multiple update messages are allowed' + ], + '1.0.1' => [ + 'Added some upgrade file and some seeding', + 'some_upgrade_file.php', //does not exist + 'some_seeding_file.php' //does not exist + ] + ]; + + $versions = self::callProtectedMethod( + $controller, + 'getPluginVersionFile', + [ + base_path().'/tests/fixtures/plugins/october/tester/', + 'updates/version.yaml' + ] + ); + + $this->assertNotNull($versions); + $this->assertEquals($expectedVersions, $versions); + } +} diff --git a/tests/unit/system/classes/VersionManagerTest.php b/tests/unit/system/classes/VersionManagerTest.php new file mode 100644 index 0000000..2a2498f --- /dev/null +++ b/tests/unit/system/classes/VersionManagerTest.php @@ -0,0 +1,220 @@ +assertNotNull($result); + $this->assertEquals('1.2.0', $result); + } + + public function testGetFileVersions() + { + $manager = VersionManager::instance(); + $result = self::callProtectedMethod($manager, 'getFileVersions', ['\October\\Tester']); + + $this->assertCount(7, $result); + $this->assertArrayHasKey('1.0.1', $result); + $this->assertArrayHasKey('1.0.2', $result); + $this->assertArrayHasKey('1.0.3', $result); + $this->assertArrayHasKey('1.0.4', $result); + $this->assertArrayHasKey('1.0.5', $result); + $this->assertArrayHasKey('1.1.0', $result); + $this->assertArrayHasKey('1.2.0', $result); + + $sample = $result['1.0.1']; + $this->assertEquals('Added some upgrade file and some seeding', $sample[0]); + + $sample = $result['1.1.0']; + $this->assertEquals('!!! Drop support for blog settings', $sample[0]); + $this->assertEquals('drop_blog_settings_table.php', $sample[1]); + + $sample = $result['1.2.0']; + $this->assertEquals('!!! Security update - see: https://octobercms.com', $sample[0]); + + /* + * Test junk file + */ + $result = self::callProtectedMethod($manager, 'getFileVersions', ['\October\\Sample']); + $this->assertCount(5, $result); + $this->assertArrayHasKey('junk', $result); + $this->assertArrayHasKey('1', $result); + $this->assertArrayHasKey('1.0.*', $result); + $this->assertArrayHasKey('1.0.x', $result); + $this->assertArrayHasKey('10.3', $result); + + $sample = array_shift($result); + $comment = array_shift($sample); + $this->assertEquals("JUNK JUNK JUNK", $comment); + + /* + * Test empty file + */ + $result = self::callProtectedMethod($manager, 'getFileVersions', ['\October\\NoUpdates']); + $this->assertEmpty($result); + } + + public function testGetNewFileVersions() + { + $manager = VersionManager::instance(); + $result = self::callProtectedMethod($manager, 'getNewFileVersions', ['\October\\Tester', '1.0.3']); + + $this->assertCount(4, $result); + $this->assertArrayHasKey('1.0.4', $result); + $this->assertArrayHasKey('1.0.5', $result); + $this->assertArrayHasKey('1.1.0', $result); + $this->assertArrayHasKey('1.2.0', $result); + + /* + * When at version 0, should return everything + */ + $manager = VersionManager::instance(); + $result = self::callProtectedMethod($manager, 'getNewFileVersions', ['\October\\Tester']); + + $this->assertCount(7, $result); + $this->assertArrayHasKey('1.0.1', $result); + $this->assertArrayHasKey('1.0.2', $result); + $this->assertArrayHasKey('1.0.3', $result); + $this->assertArrayHasKey('1.0.4', $result); + $this->assertArrayHasKey('1.0.5', $result); + $this->assertArrayHasKey('1.1.0', $result); + $this->assertArrayHasKey('1.2.0', $result); + } + + /** + * @dataProvider versionInfoProvider + * + * @param $versionInfo + * @param $expectedComments + * @param $expectedScripts + */ + public function testExtractScriptsAndComments($versionInfo, $expectedComments, $expectedScripts) + { + $manager = VersionManager::instance(); + list($comments, $scripts) = self::callProtectedMethod($manager, 'extractScriptsAndComments', [$versionInfo]); + + $this->assertIsArray($comments); + $this->assertIsArray($scripts); + + $this->assertEquals($expectedComments, $comments); + $this->assertEquals($expectedScripts, $scripts); + } + + public function versionInfoProvider() + { + return [ + [ + 'A single update comment string', + [ + 'A single update comment string' + ], + [] + ], + [ + [ + 'A classic update comment string followed by script', + 'update_script.php' + ], + [ + 'A classic update comment string followed by script' + ], + [ + 'update_script.php' + ] + ], + [ + [ + 'scripts_can_go_first.php', + 'An update comment string after the script', + ], + [ + 'An update comment string after the script' + ], + [ + 'scripts_can_go_first.php' + ] + ], + [ + [ + 'scripts_can_go_first.php', + 'An update comment string after the script', + 'scripts_can_go_anywhere.php', + ], + [ + 'An update comment string after the script' + ], + [ + 'scripts_can_go_first.php', + 'scripts_can_go_anywhere.php' + ] + ], + [ + [ + 'scripts_can_go_first.php', + 'The first update comment', + 'scripts_can_go_anywhere.php', + 'The second update comment', + ], + [ + 'The first update comment', + 'The second update comment' + ], + [ + 'scripts_can_go_first.php', + 'scripts_can_go_anywhere.php' + ] + ], + [ + [ + 'file.name.with.dots.php', + 'The first update comment', + '1.0.2.scripts_can_go_anywhere.php', + 'The second update comment', + ], + [ + 'The first update comment', + 'The second update comment' + ], + [ + 'file.name.with.dots.php', + '1.0.2.scripts_can_go_anywhere.php' + ] + ], + [ + [ + 'subdirectory/file.name.with.dots.php', + 'The first update comment', + 'subdirectory\1.0.2.scripts_can_go_anywhere.php', + 'The second update comment', + ], + [ + 'The first update comment', + 'The second update comment' + ], + [ + 'subdirectory/file.name.with.dots.php', + 'subdirectory\1.0.2.scripts_can_go_anywhere.php' + ] + ] + ]; + } +} diff --git a/tests/unit/system/console/OctoberEnvTest.php b/tests/unit/system/console/OctoberEnvTest.php new file mode 100644 index 0000000..184c3e6 --- /dev/null +++ b/tests/unit/system/console/OctoberEnvTest.php @@ -0,0 +1,133 @@ +setUpConfigFixtures(); + $this->stubOutEnvFile(); + } + + public function testCommand() + { + $command = new OctoberEnv(); + $command->setLaravel($this->app); + $command->run(new ArrayInput([]), new NullOutput); + + // Check environment file + $envFile = file_get_contents(base_path('.env')); + + $this->assertStringContainsString('APP_DEBUG=true', $envFile); + $this->assertStringContainsString('APP_URL=https://localhost', $envFile); + $this->assertStringContainsString('DB_CONNECTION=mysql', $envFile); + $this->assertStringContainsString('DB_DATABASE="data#base"', $envFile); + $this->assertStringContainsString('DB_USERNAME="teal\'c"', $envFile); + $this->assertStringContainsString('DB_PASSWORD="test\\"quotes\'test"', $envFile); + $this->assertStringContainsString('DB_PORT=3306', $envFile); + + // Check app.php config file + $appConfigFile = file_get_contents(storage_path('temp/tests/config/app.php')); + + $this->assertStringContainsString('\'debug\' => env(\'APP_DEBUG\', true),', $appConfigFile); + $this->assertStringContainsString('\'url\' => env(\'APP_URL\', \'https://localhost\'),', $appConfigFile); + + // Check database.php config file + $appConfigFile = file_get_contents(storage_path('temp/tests/config/database.php')); + + $this->assertStringContainsString('\'default\' => env(\'DB_CONNECTION\', \'mysql\')', $appConfigFile); + $this->assertStringContainsString('\'port\' => env(\'DB_PORT\', 3306),', $appConfigFile); + // Both the following configurations had values in the original config, they should be stripped out once + // the .env file is generated. + $this->assertStringContainsString('\'username\' => env(\'DB_USERNAME\', \'\'),', $appConfigFile); + $this->assertStringContainsString('\'password\' => env(\'DB_PASSWORD\', \'\'),', $appConfigFile); + } + + protected function tearDown(): void + { + $this->tearDownConfigFixtures(); + $this->restoreEnvFile(); + + parent::tearDown(); + } + + protected function setUpConfigFixtures() + { + // Mock config path and copy fixtures + if (!is_dir(storage_path('temp/tests/config'))) { + mkdir(storage_path('temp/tests/config'), 0777, true); + } + + foreach (glob(base_path('tests/fixtures/config/*.php')) as $file) { + $path = pathinfo($file); + copy($file, storage_path('temp/tests/config/' . $path['basename'])); + } + + static::$fixturesCopied = true; + + // Store original config path + static::$origConfigPath = $this->app->make('path.config'); + + $this->app->instance('path.config', storage_path('temp/tests/config')); + + // Re-load configuration + $configBootstrap = new LoadConfiguration; + $configBootstrap->bootstrap($this->app); + } + + protected function tearDownConfigFixtures() + { + // Remove copied config fixtures + if (static::$fixturesCopied) { + foreach (glob(storage_path('temp/tests/config/*.php')) as $file) { + unlink($file); + } + rmdir(storage_path('temp/tests/config')); + rmdir(storage_path('temp/tests')); + + static::$fixturesCopied = false; + } + + // Restore config path + if (self::$origConfigPath) { + $this->app->instance('path.config', static::$origConfigPath); + + static::$origConfigPath = null; + } + + // Re-load configuration + $configBootstrap = new LoadConfiguration; + $configBootstrap->bootstrap($this->app); + } + + protected function stubOutEnvFile() + { + if (file_exists(base_path('.env.stub'))) { + unlink(base_path('.env.stub')); + } + if (file_exists(base_path('.env'))) { + rename(base_path('.env'), base_path('.env.stub')); + } + } + + protected function restoreEnvFile() + { + unlink(base_path('.env')); + + if (file_exists(base_path('.env.stub'))) { + rename(base_path('.env.stub'), base_path('.env')); + } + } +} diff --git a/tests/unit/system/traits/AssetMakerTest.php b/tests/unit/system/traits/AssetMakerTest.php new file mode 100644 index 0000000..606df95 --- /dev/null +++ b/tests/unit/system/traits/AssetMakerTest.php @@ -0,0 +1,46 @@ +createApplication(); + $this->stub = new AssetMakerStub(); + } + + // + // Tests + // + + public function testGetLocalPath() + { + $basePath = base_path(); + + // Default assetPath + $assetPath = $this->stub->guessViewPath('/assets', true); + $resolvedPath = $this->callProtectedMethod($this->stub, 'getLocalPath', [$assetPath]); + $this->assertEquals(realpath($basePath.$assetPath), realpath($resolvedPath)); + + // Paths with symbols + $resolvedPath = $this->callProtectedMethod($this->stub, 'getLocalPath', ['~/themes/demo/']); + $this->assertEquals(realpath($basePath.'/themes/demo/'), realpath($resolvedPath)); + + $resolvedPath = $this->callProtectedMethod($this->stub, 'getLocalPath', ['~/plugins/demo/']); + $this->assertEquals(realpath($basePath.'/plugins/demo/'), realpath($resolvedPath)); + + $resolvedPath = $this->callProtectedMethod($this->stub, 'getLocalPath', ['$/demo/']); + $this->assertEquals(realpath($basePath.'/plugins/demo/'), realpath($resolvedPath)); + + // Absolute Path + $resolvedPath = $this->callProtectedMethod($this->stub, 'getLocalPath', [$basePath.'/some/wild/absolute/path/']); + $this->assertEquals(realpath($basePath.'/some/wild/absolute/path/'), realpath($resolvedPath)); + } +} diff --git a/themes/demo/README.md b/themes/demo/README.md new file mode 100644 index 0000000..181268d --- /dev/null +++ b/themes/demo/README.md @@ -0,0 +1,55 @@ +Demo Theme +========== + +OctoberCMS demo theme that demonstrates the basic core functionality and utilizes the accompanying demo plugin. It is a great theme to copy when building a site from scratch. + +The theme acts as a reference implementation for default component markup when distributing plugins. + +Have fun! + +## Clean up instructions + +If you clone this theme to use as a starting point. You may follow these instructions to clean up: + +1. Delete the `pages/ajax.htm` and `pages/plugins.htm` files. +2. Delete the `partials/calcresult.htm` partial file. +3. Delete the `partials/explain/` directory and contents. +4. Delete the `content/placeholder/` directory and contents. + +## Combining CSS and JavaScript + +This theme doesn't combine assets for performance reasons. To combine the stylesheets, replace the following lines in the default layout. When combining with this theme, we recommend enabling the config `enableAssetDeepHashing` in the file **config/cms.php**. + +Uncombined stylesheets: + + + + +Combined stylesheets: + + + +> **Note**: October also includes an SCSS compiler, if you prefer. + +Uncombined JavaScript: + + + + + {% framework extras %} + +Combined JavaScript: + + + +> **Important**: Make sure you keep the `{% styles %}` and `{% scripts %}` placeholder tags as these are used by plugins for injecting assets. diff --git a/themes/demo/assets/css/theme.css b/themes/demo/assets/css/theme.css new file mode 100644 index 0000000..f8de963 --- /dev/null +++ b/themes/demo/assets/css/theme.css @@ -0,0 +1,464 @@ +@font-face { + font-family: 'lato'; + src: url('../fonts/lato-black-webfont.eot'); + src: url('../fonts/lato-black-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/lato-black-webfont.svg#latoblack') format('svg'), url('../fonts/lato-black-webfont.woff') format('woff'), url('../fonts/lato-black-webfont.ttf') format('truetype'); + font-weight: 700; + font-style: normal; +} +@font-face { + font-family: 'lato'; + src: url('../fonts/lato-italic-webfont.eot'); + src: url('../fonts/lato-italic-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/lato-italic-webfont.svg#latoitalic') format('svg'), url('../fonts/lato-italic-webfont.woff') format('woff'), url('../fonts/lato-italic-webfont.ttf') format('truetype'); + font-weight: 400; + font-style: italic; +} +@font-face { + font-family: 'lato'; + src: url('../fonts/lato-regular-webfont.eot'); + src: url('../fonts/lato-regular-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/lato-regular-webfont.svg#latoregular') format('svg'), url('../fonts/lato-regular-webfont.woff') format('woff'), url('../fonts/lato-regular-webfont.ttf') format('truetype'); + font-weight: 400; + font-style: normal; +} +@font-face { + font-family: 'lato'; + src: url('../fonts/lato-light-webfont.eot'); + src: url('../fonts/lato-light-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/lato-light-webfont.svg#latolight') format('svg'), url('../fonts/lato-light-webfont.woff') format('woff'), url('../fonts/lato-light-webfont.ttf') format('truetype'); + font-weight: 300; + font-style: normal; +} +@media screen and (-webkit-min-device-pixel-ratio: 0) { + select { + font-family: sans-serif; + } +} +.callout { + margin-bottom: 25px; + padding: 20px; + border-left: 3px solid #eeeeee; +} +.callout h4 { + margin-top: 0; + margin-bottom: 5px; +} +.callout p:last-child { + margin-bottom: 0; +} +.callout-danger { + background-color: #fdf7f7; + border-color: #ebccd1; +} +.callout-danger h4 { + color: #a94442; +} +.callout-warning { + background-color: #faf8f0; + border-color: #faebcc; +} +.callout-warning h4 { + color: #8a6d3b; +} +.callout-info { + background-color: #f4f8fa; + border-color: #bce8f1; +} +.callout-info h4 { + color: #31708f; +} +.callout-success { + background-color: #f9fdf7; + border-color: #d6e9c6; +} +.callout-success h4 { + color: #3c763d; +} +.t-ww { + word-wrap: break-word; + word-break: break-word; +} +.border-none { + border: 0; +} +.pos-r { + position: relative !important; +} +.pos-a { + position: absolute !important; +} +.pos-f { + position: fixed !important; +} +.w-sm { + width: 25% !important; +} +.w-md { + width: 50% !important; +} +.w-lg { + width: 75% !important; +} +.w-full { + width: 100% !important; +} +.w-50 { + width: 50px !important; +} +.w-100 { + width: 100px !important; +} +.w-120 { + width: 120px !important; +} +.w-130 { + width: 130px !important; +} +.w-140 { + width: 140px !important; +} +.w-150 { + width: 150px !important; +} +.w-200 { + width: 200px !important; +} +.w-300 { + width: 300px !important; +} +.w-350 { + width: 350px !important; +} +.m-a-0 { + margin: 0 !important; +} +.m-t-0 { + margin-top: 0 !important; +} +.m-r-0 { + margin-right: 0 !important; +} +.m-b-0 { + margin-bottom: 0 !important; +} +.m-l-0 { + margin-left: 0 !important; +} +.m-a { + margin: 20px !important; +} +.m-t { + margin-top: 20px !important; +} +.m-r { + margin-right: 20px !important; +} +.m-b { + margin-bottom: 20px !important; +} +.m-l { + margin-left: 20px !important; +} +.m-x { + margin-right: 20px !important; + margin-left: 20px !important; +} +.m-y { + margin-top: 20px !important; + margin-bottom: 20px !important; +} +.m-x-auto { + margin-right: auto !important; + margin-left: auto !important; +} +.m-a-xs { + margin: 5px !important; +} +.m-t-xs { + margin-top: 5px !important; +} +.m-r-xs { + margin-right: 5px !important; +} +.m-b-xs { + margin-bottom: 5px !important; +} +.m-l-xs { + margin-left: 5px !important; +} +.m-x-xs { + margin-right: 5px !important; + margin-left: 5px !important; +} +.m-y-xs { + margin-top: 5px !important; + margin-bottom: 5px !important; +} +.m-a-sm { + margin: 10px !important; +} +.m-t-sm { + margin-top: 10px !important; +} +.m-r-sm { + margin-right: 10px !important; +} +.m-b-sm { + margin-bottom: 10px !important; +} +.m-l-sm { + margin-left: 10px !important; +} +.m-x-sm { + margin-right: 10px !important; + margin-left: 10px !important; +} +.m-y-sm { + margin-top: 10px !important; + margin-bottom: 10px !important; +} +.m-a-md { + margin: 30px !important; +} +.m-t-md { + margin-top: 30px !important; +} +.m-r-md { + margin-right: 30px !important; +} +.m-b-md { + margin-bottom: 30px !important; +} +.m-l-md { + margin-left: 30px !important; +} +.m-x-md { + margin-right: 30px !important; + margin-left: 30px !important; +} +.m-y-md { + margin-top: 30px !important; + margin-bottom: 30px !important; +} +.m-a-lg { + margin: 60px !important; +} +.m-t-lg { + margin-top: 60px !important; +} +.m-r-lg { + margin-right: 60px !important; +} +.m-b-lg { + margin-bottom: 60px !important; +} +.m-l-lg { + margin-left: 60px !important; +} +.m-x-lg { + margin-right: 60px !important; + margin-left: 60px !important; +} +.m-y-lg { + margin-top: 60px !important; + margin-bottom: 60px !important; +} +.p-a-0 { + padding: 0 !important; +} +.p-t-0 { + padding-top: 0 !important; +} +.p-r-0 { + padding-right: 0 !important; +} +.p-b-0 { + padding-bottom: 0 !important; +} +.p-l-0 { + padding-left: 0 !important; +} +.p-a { + padding: 20px !important; +} +.p-t { + padding-top: 20px !important; +} +.p-r { + padding-right: 20px !important; +} +.p-b { + padding-bottom: 20px !important; +} +.p-l { + padding-left: 20px !important; +} +.p-x { + padding-right: 20px !important; + padding-left: 20px !important; +} +.p-y { + padding-top: 20px !important; + padding-bottom: 20px !important; +} +.p-a-xs { + padding: 5px !important; +} +.p-t-xs { + padding-top: 5px !important; +} +.p-r-xs { + padding-right: 5px !important; +} +.p-b-xs { + padding-bottom: 5px !important; +} +.p-l-xs { + padding-left: 5px !important; +} +.p-x-xs { + padding-right: 5px !important; + padding-left: 5px !important; +} +.p-y-xs { + padding-top: 5px !important; + padding-bottom: 5px !important; +} +.p-a-sm { + padding: 10px !important; +} +.p-t-sm { + padding-top: 10px !important; +} +.p-r-sm { + padding-right: 10px !important; +} +.p-b-sm { + padding-bottom: 10px !important; +} +.p-l-sm { + padding-left: 10px !important; +} +.p-x-sm { + padding-right: 10px !important; + padding-left: 10px !important; +} +.p-y-sm { + padding-top: 10px !important; + padding-bottom: 10px !important; +} +.p-a-md { + padding: 30px !important; +} +.p-t-md { + padding-top: 30px !important; +} +.p-r-md { + padding-right: 30px !important; +} +.p-b-md { + padding-bottom: 30px !important; +} +.p-l-md { + padding-left: 30px !important; +} +.p-x-md { + padding-right: 30px !important; + padding-left: 30px !important; +} +.p-y-md { + padding-top: 30px !important; + padding-bottom: 30px !important; +} +.p-a-lg { + padding: 60px !important; +} +.p-t-lg { + padding-top: 60px !important; +} +.p-r-lg { + padding-right: 60px !important; +} +.p-b-lg { + padding-bottom: 60px !important; +} +.p-l-lg { + padding-left: 60px !important; +} +.p-x-lg { + padding-right: 60px !important; + padding-left: 60px !important; +} +.p-y-lg { + padding-top: 60px !important; + padding-bottom: 60px !important; +} +.navbar-header .navbar-brand { + padding-left: 55px; + background-image: url('../images/october.png'); + background-size: auto 60%; + background-repeat: no-repeat; + background-position: 7px 50%; + transition: color 0.2s ease 0.05s; + color: #ccc; +} +.navbar-header .navbar-brand:hover { + color: #fff; +} +.navbar-nav li.separator { + width: 1px; + background: rgba(255, 255, 255, 0.3); + height: 30px; + margin: 20px 10px 0 10px; +} +.navbar-autohide { + transition: transform .5s; +} +.navbar-autohide.is-hidden { + transform: translateY(-72px); +} +.navbar-collapse:not(.in):not(.collapsing) .navbar-nav li > a { + transition: color 0.2s ease 0.05s; +} +.navbar-collapse:not(.in):not(.collapsing) .navbar-nav li > a:after { + position: absolute; + height: 4px; + bottom: -1px; + content: ''; + border-radius: 4px; + z-index: 5; + width: 0; + left: 50%; + transition: all 0.2s ease 0.05s; +} +.navbar-collapse:not(.in):not(.collapsing) .navbar-nav li.active > a:after { + width: 100% !important; + left: 0 !important; +} +.navbar-collapse:not(.in):not(.collapsing) .navbar-nav li:hover > a:after { + width: 100%; + left: 0; +} +.navbar-collapse:not(.in):not(.collapsing) .navbar-nav li.active > a { + background: transparent; +} +.navbar-inverse .navbar-collapse:not(.in):not(.collapsing) .navbar-nav li.active > a:after, +.navbar-inverse .navbar-collapse:not(.in):not(.collapsing) .navbar-nav li > a:hover:after { + background: #000000; +} +.navbar-inverse .navbar-collapse:not(.in):not(.collapsing) .navbar-nav li.active > a:hover:after { + background: #000000; +} +.navbar-inverse .navbar-collapse:not(.in):not(.collapsing) .navbar-nav li > a:hover:after { + background: #e67e22; +} +.navbar-default .navbar-collapse:not(.in):not(.collapsing) .navbar-nav li.active > a:after, +.navbar-default .navbar-collapse:not(.in):not(.collapsing) .navbar-nav li > a:hover:after { + background: #64ae5b; +} +.navbar-default .navbar-collapse:not(.in):not(.collapsing) .navbar-nav li.active > a:hover:after { + background: #64ae5b; +} +.navbar-default .navbar-collapse:not(.in):not(.collapsing) .navbar-nav li > a:hover:after { + background: #93dc8a; +} +body { + padding-top: 70px; +} diff --git a/themes/demo/assets/css/vendor.css b/themes/demo/assets/css/vendor.css new file mode 100644 index 0000000..1f5c1e2 --- /dev/null +++ b/themes/demo/assets/css/vendor.css @@ -0,0 +1,7345 @@ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ +html { + font-family: sans-serif; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; +} +body { + margin: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} +audio, +canvas, +progress, +video { + display: inline-block; + vertical-align: baseline; +} +audio:not([controls]) { + display: none; + height: 0; +} +[hidden], +template { + display: none; +} +a { + background-color: transparent; +} +a:active, +a:hover { + outline: 0; +} +abbr[title] { + border-bottom: 1px dotted; +} +b, +strong { + font-weight: bold; +} +dfn { + font-style: italic; +} +h1 { + font-size: 2em; + margin: 0.67em 0; +} +mark { + background: #ff0; + color: #000; +} +small { + font-size: 80%; +} +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + border: 0; +} +svg:not(:root) { + overflow: hidden; +} +figure { + margin: 1em 40px; +} +hr { + box-sizing: content-box; + height: 0; +} +pre { + overflow: auto; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +button, +input, +optgroup, +select, +textarea { + color: inherit; + font: inherit; + margin: 0; +} +button { + overflow: visible; +} +button, +select { + text-transform: none; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + cursor: pointer; +} +button[disabled], +html input[disabled] { + cursor: default; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} +input { + line-height: normal; +} +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + padding: 0; +} +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} +input[type="search"] { + -webkit-appearance: textfield; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} +legend { + border: 0; + padding: 0; +} +textarea { + overflow: auto; +} +optgroup { + font-weight: bold; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +td, +th { + padding: 0; +} +/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ +@media print { + *, + *:before, + *:after { + background: transparent !important; + color: #000 !important; + box-shadow: none !important; + text-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + a[href^="#"]:after, + a[href^="javascript:"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + .navbar { + display: none; + } + .btn > .caret, + .dropup > .btn > .caret { + border-top-color: #000 !important; + } + .label { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table td, + .table th { + background-color: #fff !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #ddd !important; + } +} +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +html { + font-size: 10px; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +body { + font-family: "lato", sans-serif; + font-size: 16px; + line-height: 1.6; + color: #586667; + background-color: #ffffff; +} +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} +a { + color: #3097d1; + text-decoration: none; +} +a:hover, +a:focus { + color: #216a94; + text-decoration: underline; +} +a:focus { + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +figure { + margin: 0; +} +img { + vertical-align: middle; +} +.img-responsive, +.thumbnail > img, +.thumbnail a > img, +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + max-width: 100%; + height: auto; +} +.img-rounded { + border-radius: 6px; +} +.img-thumbnail { + padding: 4px; + line-height: 1.6; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + display: inline-block; + max-width: 100%; + height: auto; +} +.img-circle { + border-radius: 50%; +} +hr { + margin-top: 25px; + margin-bottom: 25px; + border: 0; + border-top: 1px solid #eeeeee; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; +} +[role="button"] { + cursor: pointer; +} +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: inherit; + font-weight: 500; + line-height: 1.1; + color: #1f3f50; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small, +.h1 small, +.h2 small, +.h3 small, +.h4 small, +.h5 small, +.h6 small, +h1 .small, +h2 .small, +h3 .small, +h4 .small, +h5 .small, +h6 .small, +.h1 .small, +.h2 .small, +.h3 .small, +.h4 .small, +.h5 .small, +.h6 .small { + font-weight: normal; + line-height: 1; + color: #777777; +} +h1, +.h1, +h2, +.h2, +h3, +.h3 { + margin-top: 25px; + margin-bottom: 12.5px; +} +h1 small, +.h1 small, +h2 small, +.h2 small, +h3 small, +.h3 small, +h1 .small, +.h1 .small, +h2 .small, +.h2 .small, +h3 .small, +.h3 .small { + font-size: 65%; +} +h4, +.h4, +h5, +.h5, +h6, +.h6 { + margin-top: 12.5px; + margin-bottom: 12.5px; +} +h4 small, +.h4 small, +h5 small, +.h5 small, +h6 small, +.h6 small, +h4 .small, +.h4 .small, +h5 .small, +.h5 .small, +h6 .small, +.h6 .small { + font-size: 75%; +} +h1, +.h1 { + font-size: 41px; +} +h2, +.h2 { + font-size: 34px; +} +h3, +.h3 { + font-size: 28px; +} +h4, +.h4 { + font-size: 20px; +} +h5, +.h5 { + font-size: 16px; +} +h6, +.h6 { + font-size: 14px; +} +p { + margin: 0 0 12.5px; +} +.lead { + margin-bottom: 25px; + font-size: 18px; + font-weight: 300; + line-height: 1.4; +} +@media (min-width: 768px) { + .lead { + font-size: 24px; + } +} +small, +.small { + font-size: 87%; +} +mark, +.mark { + background-color: #fcf8e3; + padding: .2em; +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +.text-justify { + text-align: justify; +} +.text-nowrap { + white-space: nowrap; +} +.text-lowercase { + text-transform: lowercase; +} +.text-uppercase { + text-transform: uppercase; +} +.text-capitalize { + text-transform: capitalize; +} +.text-muted { + color: #777777; +} +.text-primary { + color: #3097d1; +} +a.text-primary:hover, +a.text-primary:focus { + color: #2579a9; +} +.text-success { + color: #3c763d; +} +a.text-success:hover, +a.text-success:focus { + color: #2b542c; +} +.text-info { + color: #31708f; +} +a.text-info:hover, +a.text-info:focus { + color: #245269; +} +.text-warning { + color: #8a6d3b; +} +a.text-warning:hover, +a.text-warning:focus { + color: #66512c; +} +.text-danger { + color: #a94442; +} +a.text-danger:hover, +a.text-danger:focus { + color: #843534; +} +.bg-primary { + color: #fff; + background-color: #3097d1; +} +a.bg-primary:hover, +a.bg-primary:focus { + background-color: #2579a9; +} +.bg-success { + background-color: #dff0d8; +} +a.bg-success:hover, +a.bg-success:focus { + background-color: #c1e2b3; +} +.bg-info { + background-color: #d9edf7; +} +a.bg-info:hover, +a.bg-info:focus { + background-color: #afd9ee; +} +.bg-warning { + background-color: #fcf8e3; +} +a.bg-warning:hover, +a.bg-warning:focus { + background-color: #f7ecb5; +} +.bg-danger { + background-color: #f2dede; +} +a.bg-danger:hover, +a.bg-danger:focus { + background-color: #e4b9b9; +} +.page-header { + padding-bottom: 11.5px; + margin: 50px 0 25px; + border-bottom: 1px solid #eeeeee; +} +ul, +ol { + margin-top: 0; + margin-bottom: 12.5px; +} +ul ul, +ol ul, +ul ol, +ol ol { + margin-bottom: 0; +} +.list-unstyled { + padding-left: 0; + list-style: none; +} +.list-inline { + padding-left: 0; + list-style: none; + margin-left: -5px; +} +.list-inline > li { + display: inline-block; + padding-left: 5px; + padding-right: 5px; +} +dl { + margin-top: 0; + margin-bottom: 25px; +} +dt, +dd { + line-height: 1.6; +} +dt { + font-weight: bold; +} +dd { + margin-left: 0; +} +@media (min-width: 768px) { + .dl-horizontal dt { + float: left; + width: 160px; + clear: left; + text-align: right; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } +} +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #777777; +} +.initialism { + font-size: 90%; + text-transform: uppercase; +} +blockquote { + padding: 12.5px 25px; + margin: 0 0 25px; + font-size: 20px; + border-left: 5px solid #eeeeee; +} +blockquote p:last-child, +blockquote ul:last-child, +blockquote ol:last-child { + margin-bottom: 0; +} +blockquote footer, +blockquote small, +blockquote .small { + display: block; + font-size: 80%; + line-height: 1.6; + color: #777777; +} +blockquote footer:before, +blockquote small:before, +blockquote .small:before { + content: '\2014 \00A0'; +} +.blockquote-reverse, +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; + text-align: right; +} +.blockquote-reverse footer:before, +blockquote.pull-right footer:before, +.blockquote-reverse small:before, +blockquote.pull-right small:before, +.blockquote-reverse .small:before, +blockquote.pull-right .small:before { + content: ''; +} +.blockquote-reverse footer:after, +blockquote.pull-right footer:after, +.blockquote-reverse small:after, +blockquote.pull-right small:after, +.blockquote-reverse .small:after, +blockquote.pull-right .small:after { + content: '\00A0 \2014'; +} +address { + margin-bottom: 25px; + font-style: normal; + line-height: 1.6; +} +code, +kbd, +pre, +samp { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + background-color: #f9f2f4; + border-radius: 4px; +} +kbd { + padding: 2px 4px; + font-size: 90%; + color: #ffffff; + background-color: #333333; + border-radius: 3px; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); +} +kbd kbd { + padding: 0; + font-size: 100%; + font-weight: bold; + box-shadow: none; +} +pre { + display: block; + padding: 12px; + margin: 0 0 12.5px; + font-size: 15px; + line-height: 1.6; + word-break: break-all; + word-wrap: break-word; + color: #333333; + background-color: #f5f5f5; + border: 1px solid #cccccc; + border-radius: 4px; +} +pre code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +.container { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +@media (min-width: 768px) { + .container { + width: 750px; + } +} +@media (min-width: 992px) { + .container { + width: 970px; + } +} +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} +.container-fluid { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +.row { + margin-left: -15px; + margin-right: -15px; +} +.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + position: relative; + min-height: 1px; + padding-left: 15px; + padding-right: 15px; +} +.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { + float: left; +} +.col-xs-12 { + width: 100%; +} +.col-xs-11 { + width: 91.66666666666666%; +} +.col-xs-10 { + width: 83.33333333333334%; +} +.col-xs-9 { + width: 75%; +} +.col-xs-8 { + width: 66.66666666666666%; +} +.col-xs-7 { + width: 58.333333333333336%; +} +.col-xs-6 { + width: 50%; +} +.col-xs-5 { + width: 41.66666666666667%; +} +.col-xs-4 { + width: 33.33333333333333%; +} +.col-xs-3 { + width: 25%; +} +.col-xs-2 { + width: 16.666666666666664%; +} +.col-xs-1 { + width: 8.333333333333332%; +} +.col-xs-pull-12 { + right: 100%; +} +.col-xs-pull-11 { + right: 91.66666666666666%; +} +.col-xs-pull-10 { + right: 83.33333333333334%; +} +.col-xs-pull-9 { + right: 75%; +} +.col-xs-pull-8 { + right: 66.66666666666666%; +} +.col-xs-pull-7 { + right: 58.333333333333336%; +} +.col-xs-pull-6 { + right: 50%; +} +.col-xs-pull-5 { + right: 41.66666666666667%; +} +.col-xs-pull-4 { + right: 33.33333333333333%; +} +.col-xs-pull-3 { + right: 25%; +} +.col-xs-pull-2 { + right: 16.666666666666664%; +} +.col-xs-pull-1 { + right: 8.333333333333332%; +} +.col-xs-pull-0 { + right: auto; +} +.col-xs-push-12 { + left: 100%; +} +.col-xs-push-11 { + left: 91.66666666666666%; +} +.col-xs-push-10 { + left: 83.33333333333334%; +} +.col-xs-push-9 { + left: 75%; +} +.col-xs-push-8 { + left: 66.66666666666666%; +} +.col-xs-push-7 { + left: 58.333333333333336%; +} +.col-xs-push-6 { + left: 50%; +} +.col-xs-push-5 { + left: 41.66666666666667%; +} +.col-xs-push-4 { + left: 33.33333333333333%; +} +.col-xs-push-3 { + left: 25%; +} +.col-xs-push-2 { + left: 16.666666666666664%; +} +.col-xs-push-1 { + left: 8.333333333333332%; +} +.col-xs-push-0 { + left: auto; +} +.col-xs-offset-12 { + margin-left: 100%; +} +.col-xs-offset-11 { + margin-left: 91.66666666666666%; +} +.col-xs-offset-10 { + margin-left: 83.33333333333334%; +} +.col-xs-offset-9 { + margin-left: 75%; +} +.col-xs-offset-8 { + margin-left: 66.66666666666666%; +} +.col-xs-offset-7 { + margin-left: 58.333333333333336%; +} +.col-xs-offset-6 { + margin-left: 50%; +} +.col-xs-offset-5 { + margin-left: 41.66666666666667%; +} +.col-xs-offset-4 { + margin-left: 33.33333333333333%; +} +.col-xs-offset-3 { + margin-left: 25%; +} +.col-xs-offset-2 { + margin-left: 16.666666666666664%; +} +.col-xs-offset-1 { + margin-left: 8.333333333333332%; +} +.col-xs-offset-0 { + margin-left: 0%; +} +@media (min-width: 768px) { + .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666666666666%; + } + .col-sm-10 { + width: 83.33333333333334%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666666666666%; + } + .col-sm-7 { + width: 58.333333333333336%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666666666667%; + } + .col-sm-4 { + width: 33.33333333333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.666666666666664%; + } + .col-sm-1 { + width: 8.333333333333332%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666666666666%; + } + .col-sm-pull-10 { + right: 83.33333333333334%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666666666666%; + } + .col-sm-pull-7 { + right: 58.333333333333336%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666666666667%; + } + .col-sm-pull-4 { + right: 33.33333333333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.666666666666664%; + } + .col-sm-pull-1 { + right: 8.333333333333332%; + } + .col-sm-pull-0 { + right: auto; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666666666666%; + } + .col-sm-push-10 { + left: 83.33333333333334%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666666666666%; + } + .col-sm-push-7 { + left: 58.333333333333336%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666666666667%; + } + .col-sm-push-4 { + left: 33.33333333333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.666666666666664%; + } + .col-sm-push-1 { + left: 8.333333333333332%; + } + .col-sm-push-0 { + left: auto; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666666666666%; + } + .col-sm-offset-10 { + margin-left: 83.33333333333334%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666666666666%; + } + .col-sm-offset-7 { + margin-left: 58.333333333333336%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666666666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.666666666666664%; + } + .col-sm-offset-1 { + margin-left: 8.333333333333332%; + } + .col-sm-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 992px) { + .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666666666666%; + } + .col-md-10 { + width: 83.33333333333334%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666666666666%; + } + .col-md-7 { + width: 58.333333333333336%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666666666667%; + } + .col-md-4 { + width: 33.33333333333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.666666666666664%; + } + .col-md-1 { + width: 8.333333333333332%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666666666666%; + } + .col-md-pull-10 { + right: 83.33333333333334%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666666666666%; + } + .col-md-pull-7 { + right: 58.333333333333336%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666666666667%; + } + .col-md-pull-4 { + right: 33.33333333333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.666666666666664%; + } + .col-md-pull-1 { + right: 8.333333333333332%; + } + .col-md-pull-0 { + right: auto; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666666666666%; + } + .col-md-push-10 { + left: 83.33333333333334%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666666666666%; + } + .col-md-push-7 { + left: 58.333333333333336%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666666666667%; + } + .col-md-push-4 { + left: 33.33333333333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.666666666666664%; + } + .col-md-push-1 { + left: 8.333333333333332%; + } + .col-md-push-0 { + left: auto; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666666666666%; + } + .col-md-offset-10 { + margin-left: 83.33333333333334%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666666666666%; + } + .col-md-offset-7 { + margin-left: 58.333333333333336%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666666666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.666666666666664%; + } + .col-md-offset-1 { + margin-left: 8.333333333333332%; + } + .col-md-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 1200px) { + .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666666666666%; + } + .col-lg-10 { + width: 83.33333333333334%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666666666666%; + } + .col-lg-7 { + width: 58.333333333333336%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666666666667%; + } + .col-lg-4 { + width: 33.33333333333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.666666666666664%; + } + .col-lg-1 { + width: 8.333333333333332%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666666666666%; + } + .col-lg-pull-10 { + right: 83.33333333333334%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666666666666%; + } + .col-lg-pull-7 { + right: 58.333333333333336%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666666666667%; + } + .col-lg-pull-4 { + right: 33.33333333333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.666666666666664%; + } + .col-lg-pull-1 { + right: 8.333333333333332%; + } + .col-lg-pull-0 { + right: auto; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666666666666%; + } + .col-lg-push-10 { + left: 83.33333333333334%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666666666666%; + } + .col-lg-push-7 { + left: 58.333333333333336%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666666666667%; + } + .col-lg-push-4 { + left: 33.33333333333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.666666666666664%; + } + .col-lg-push-1 { + left: 8.333333333333332%; + } + .col-lg-push-0 { + left: auto; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666666666666%; + } + .col-lg-offset-10 { + margin-left: 83.33333333333334%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666666666666%; + } + .col-lg-offset-7 { + margin-left: 58.333333333333336%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666666666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.666666666666664%; + } + .col-lg-offset-1 { + margin-left: 8.333333333333332%; + } + .col-lg-offset-0 { + margin-left: 0%; + } +} +table { + background-color: transparent; +} +caption { + padding-top: 8px; + padding-bottom: 8px; + color: #777777; + text-align: left; +} +th { + text-align: left; +} +.table { + width: 100%; + max-width: 100%; + margin-bottom: 25px; +} +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + padding: 8px; + line-height: 1.6; + vertical-align: top; + border-top: 1px solid #dddddd; +} +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #dddddd; +} +.table > caption + thead > tr:first-child > th, +.table > colgroup + thead > tr:first-child > th, +.table > thead:first-child > tr:first-child > th, +.table > caption + thead > tr:first-child > td, +.table > colgroup + thead > tr:first-child > td, +.table > thead:first-child > tr:first-child > td { + border-top: 0; +} +.table > tbody + tbody { + border-top: 2px solid #dddddd; +} +.table .table { + background-color: #ffffff; +} +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; +} +.table-bordered { + border: 1px solid #dddddd; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #dddddd; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} +.table-striped > tbody > tr:nth-of-type(odd) { + background-color: #f9f9f9; +} +.table-hover > tbody > tr:hover { + background-color: #f5f5f5; +} +table col[class*="col-"] { + position: static; + float: none; + display: table-column; +} +table td[class*="col-"], +table th[class*="col-"] { + position: static; + float: none; + display: table-cell; +} +.table > thead > tr > td.active, +.table > tbody > tr > td.active, +.table > tfoot > tr > td.active, +.table > thead > tr > th.active, +.table > tbody > tr > th.active, +.table > tfoot > tr > th.active, +.table > thead > tr.active > td, +.table > tbody > tr.active > td, +.table > tfoot > tr.active > td, +.table > thead > tr.active > th, +.table > tbody > tr.active > th, +.table > tfoot > tr.active > th { + background-color: #f5f5f5; +} +.table-hover > tbody > tr > td.active:hover, +.table-hover > tbody > tr > th.active:hover, +.table-hover > tbody > tr.active:hover > td, +.table-hover > tbody > tr:hover > .active, +.table-hover > tbody > tr.active:hover > th { + background-color: #e8e8e8; +} +.table > thead > tr > td.success, +.table > tbody > tr > td.success, +.table > tfoot > tr > td.success, +.table > thead > tr > th.success, +.table > tbody > tr > th.success, +.table > tfoot > tr > th.success, +.table > thead > tr.success > td, +.table > tbody > tr.success > td, +.table > tfoot > tr.success > td, +.table > thead > tr.success > th, +.table > tbody > tr.success > th, +.table > tfoot > tr.success > th { + background-color: #dff0d8; +} +.table-hover > tbody > tr > td.success:hover, +.table-hover > tbody > tr > th.success:hover, +.table-hover > tbody > tr.success:hover > td, +.table-hover > tbody > tr:hover > .success, +.table-hover > tbody > tr.success:hover > th { + background-color: #d0e9c6; +} +.table > thead > tr > td.info, +.table > tbody > tr > td.info, +.table > tfoot > tr > td.info, +.table > thead > tr > th.info, +.table > tbody > tr > th.info, +.table > tfoot > tr > th.info, +.table > thead > tr.info > td, +.table > tbody > tr.info > td, +.table > tfoot > tr.info > td, +.table > thead > tr.info > th, +.table > tbody > tr.info > th, +.table > tfoot > tr.info > th { + background-color: #d9edf7; +} +.table-hover > tbody > tr > td.info:hover, +.table-hover > tbody > tr > th.info:hover, +.table-hover > tbody > tr.info:hover > td, +.table-hover > tbody > tr:hover > .info, +.table-hover > tbody > tr.info:hover > th { + background-color: #c4e3f3; +} +.table > thead > tr > td.warning, +.table > tbody > tr > td.warning, +.table > tfoot > tr > td.warning, +.table > thead > tr > th.warning, +.table > tbody > tr > th.warning, +.table > tfoot > tr > th.warning, +.table > thead > tr.warning > td, +.table > tbody > tr.warning > td, +.table > tfoot > tr.warning > td, +.table > thead > tr.warning > th, +.table > tbody > tr.warning > th, +.table > tfoot > tr.warning > th { + background-color: #fcf8e3; +} +.table-hover > tbody > tr > td.warning:hover, +.table-hover > tbody > tr > th.warning:hover, +.table-hover > tbody > tr.warning:hover > td, +.table-hover > tbody > tr:hover > .warning, +.table-hover > tbody > tr.warning:hover > th { + background-color: #faf2cc; +} +.table > thead > tr > td.danger, +.table > tbody > tr > td.danger, +.table > tfoot > tr > td.danger, +.table > thead > tr > th.danger, +.table > tbody > tr > th.danger, +.table > tfoot > tr > th.danger, +.table > thead > tr.danger > td, +.table > tbody > tr.danger > td, +.table > tfoot > tr.danger > td, +.table > thead > tr.danger > th, +.table > tbody > tr.danger > th, +.table > tfoot > tr.danger > th { + background-color: #f2dede; +} +.table-hover > tbody > tr > td.danger:hover, +.table-hover > tbody > tr > th.danger:hover, +.table-hover > tbody > tr.danger:hover > td, +.table-hover > tbody > tr:hover > .danger, +.table-hover > tbody > tr.danger:hover > th { + background-color: #ebcccc; +} +.table-responsive { + overflow-x: auto; + min-height: 0.01%; +} +@media screen and (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 18.75px; + overflow-y: hidden; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid #dddddd; + } + .table-responsive > .table { + margin-bottom: 0; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} +fieldset { + padding: 0; + margin: 0; + border: 0; + min-width: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 25px; + font-size: 24px; + line-height: inherit; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} +label { + display: inline-block; + max-width: 100%; + margin-bottom: 5px; + font-weight: bold; +} +input[type="search"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + line-height: normal; +} +input[type="file"] { + display: block; +} +input[type="range"] { + display: block; + width: 100%; +} +select[multiple], +select[size] { + height: auto; +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +output { + display: block; + padding-top: 7px; + font-size: 16px; + line-height: 1.6; + color: #555555; +} +.form-control { + display: block; + width: 100%; + height: 39px; + padding: 6px 12px; + font-size: 16px; + line-height: 1.6; + color: #555555; + background-color: #ffffff; + background-image: none; + border: 1px solid #cccccc; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} +.form-control:focus { + border-color: #66afe9; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); +} +.form-control::-moz-placeholder { + color: #999999; + opacity: 1; +} +.form-control:-ms-input-placeholder { + color: #999999; +} +.form-control::-webkit-input-placeholder { + color: #999999; +} +.form-control::-ms-expand { + border: 0; + background-color: transparent; +} +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + background-color: #eeeeee; + opacity: 1; +} +.form-control[disabled], +fieldset[disabled] .form-control { + cursor: not-allowed; +} +textarea.form-control { + height: auto; +} +input[type="search"] { + -webkit-appearance: none; +} +@media screen and (-webkit-min-device-pixel-ratio: 0) { + input[type="date"].form-control, + input[type="time"].form-control, + input[type="datetime-local"].form-control, + input[type="month"].form-control { + line-height: 39px; + } + input[type="date"].input-sm, + input[type="time"].input-sm, + input[type="datetime-local"].input-sm, + input[type="month"].input-sm, + .input-group-sm input[type="date"], + .input-group-sm input[type="time"], + .input-group-sm input[type="datetime-local"], + .input-group-sm input[type="month"] { + line-height: 33px; + } + input[type="date"].input-lg, + input[type="time"].input-lg, + input[type="datetime-local"].input-lg, + input[type="month"].input-lg, + .input-group-lg input[type="date"], + .input-group-lg input[type="time"], + .input-group-lg input[type="datetime-local"], + .input-group-lg input[type="month"] { + line-height: 49px; + } +} +.form-group { + margin-bottom: 15px; +} +.radio, +.checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; +} +.radio label, +.checkbox label { + min-height: 25px; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + position: absolute; + margin-left: -20px; + margin-top: 4px \9; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + vertical-align: middle; + font-weight: normal; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"].disabled, +input[type="checkbox"].disabled, +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"] { + cursor: not-allowed; +} +.radio-inline.disabled, +.checkbox-inline.disabled, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.radio.disabled label, +.checkbox.disabled label, +fieldset[disabled] .radio label, +fieldset[disabled] .checkbox label { + cursor: not-allowed; +} +.form-control-static { + padding-top: 7px; + padding-bottom: 7px; + margin-bottom: 0; + min-height: 41px; +} +.form-control-static.input-lg, +.form-control-static.input-sm { + padding-left: 0; + padding-right: 0; +} +.input-sm { + height: 33px; + padding: 5px 10px; + font-size: 14px; + line-height: 1.5; + border-radius: 3px; +} +select.input-sm { + height: 33px; + line-height: 33px; +} +textarea.input-sm, +select[multiple].input-sm { + height: auto; +} +.form-group-sm .form-control { + height: 33px; + padding: 5px 10px; + font-size: 14px; + line-height: 1.5; + border-radius: 3px; +} +.form-group-sm select.form-control { + height: 33px; + line-height: 33px; +} +.form-group-sm textarea.form-control, +.form-group-sm select[multiple].form-control { + height: auto; +} +.form-group-sm .form-control-static { + height: 33px; + min-height: 39px; + padding: 6px 10px; + font-size: 14px; + line-height: 1.5; +} +.input-lg { + height: 49px; + padding: 10px 16px; + font-size: 20px; + line-height: 1.3333333; + border-radius: 6px; +} +select.input-lg { + height: 49px; + line-height: 49px; +} +textarea.input-lg, +select[multiple].input-lg { + height: auto; +} +.form-group-lg .form-control { + height: 49px; + padding: 10px 16px; + font-size: 20px; + line-height: 1.3333333; + border-radius: 6px; +} +.form-group-lg select.form-control { + height: 49px; + line-height: 49px; +} +.form-group-lg textarea.form-control, +.form-group-lg select[multiple].form-control { + height: auto; +} +.form-group-lg .form-control-static { + height: 49px; + min-height: 45px; + padding: 11px 16px; + font-size: 20px; + line-height: 1.3333333; +} +.has-feedback { + position: relative; +} +.has-feedback .form-control { + padding-right: 48.75px; +} +.form-control-feedback { + position: absolute; + top: 0; + right: 0; + z-index: 2; + display: block; + width: 39px; + height: 39px; + line-height: 39px; + text-align: center; + pointer-events: none; +} +.input-lg + .form-control-feedback, +.input-group-lg + .form-control-feedback, +.form-group-lg .form-control + .form-control-feedback { + width: 49px; + height: 49px; + line-height: 49px; +} +.input-sm + .form-control-feedback, +.input-group-sm + .form-control-feedback, +.form-group-sm .form-control + .form-control-feedback { + width: 33px; + height: 33px; + line-height: 33px; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline, +.has-success.radio label, +.has-success.checkbox label, +.has-success.radio-inline label, +.has-success.checkbox-inline label { + color: #3c763d; +} +.has-success .form-control { + border-color: #3c763d; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-success .form-control:focus { + border-color: #2b542c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; +} +.has-success .input-group-addon { + color: #3c763d; + border-color: #3c763d; + background-color: #dff0d8; +} +.has-success .form-control-feedback { + color: #3c763d; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline, +.has-warning.radio label, +.has-warning.checkbox label, +.has-warning.radio-inline label, +.has-warning.checkbox-inline label { + color: #8a6d3b; +} +.has-warning .form-control { + border-color: #8a6d3b; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-warning .form-control:focus { + border-color: #66512c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; +} +.has-warning .input-group-addon { + color: #8a6d3b; + border-color: #8a6d3b; + background-color: #fcf8e3; +} +.has-warning .form-control-feedback { + color: #8a6d3b; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline, +.has-error.radio label, +.has-error.checkbox label, +.has-error.radio-inline label, +.has-error.checkbox-inline label { + color: #a94442; +} +.has-error .form-control { + border-color: #a94442; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-error .form-control:focus { + border-color: #843534; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; +} +.has-error .input-group-addon { + color: #a94442; + border-color: #a94442; + background-color: #f2dede; +} +.has-error .form-control-feedback { + color: #a94442; +} +.has-feedback label ~ .form-control-feedback { + top: 30px; +} +.has-feedback label.sr-only ~ .form-control-feedback { + top: 0; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #98a6a7; +} +@media (min-width: 768px) { + .form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .form-inline .form-control-static { + display: inline-block; + } + .form-inline .input-group { + display: inline-table; + vertical-align: middle; + } + .form-inline .input-group .input-group-addon, + .form-inline .input-group .input-group-btn, + .form-inline .input-group .form-control { + width: auto; + } + .form-inline .input-group > .form-control { + width: 100%; + } + .form-inline .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio label, + .form-inline .checkbox label { + padding-left: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .form-inline .has-feedback .form-control-feedback { + top: 0; + } +} +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + margin-top: 0; + margin-bottom: 0; + padding-top: 7px; +} +.form-horizontal .radio, +.form-horizontal .checkbox { + min-height: 32px; +} +.form-horizontal .form-group { + margin-left: -15px; + margin-right: -15px; +} +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: right; + margin-bottom: 0; + padding-top: 7px; + } +} +.form-horizontal .has-feedback .form-control-feedback { + right: 15px; +} +@media (min-width: 768px) { + .form-horizontal .form-group-lg .control-label { + padding-top: 11px; + font-size: 20px; + } +} +@media (min-width: 768px) { + .form-horizontal .form-group-sm .control-label { + padding-top: 6px; + font-size: 14px; + } +} +.btn { + display: inline-block; + margin-bottom: 0; + font-weight: normal; + text-align: center; + vertical-align: middle; + touch-action: manipulation; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + white-space: nowrap; + padding: 6px 12px; + font-size: 16px; + line-height: 1.6; + border-radius: 4px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.btn:focus, +.btn:active:focus, +.btn.active:focus, +.btn.focus, +.btn:active.focus, +.btn.active.focus { + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn:hover, +.btn:focus, +.btn.focus { + color: #333333; + text-decoration: none; +} +.btn:active, +.btn.active { + outline: 0; + background-image: none; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + cursor: not-allowed; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} +a.btn.disabled, +fieldset[disabled] a.btn { + pointer-events: none; +} +.btn-default { + color: #333333; + background-color: #ffffff; + border-color: #cccccc; +} +.btn-default:focus, +.btn-default.focus { + color: #333333; + background-color: #e6e6e6; + border-color: #8c8c8c; +} +.btn-default:hover { + color: #333333; + background-color: #e6e6e6; + border-color: #adadad; +} +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + color: #333333; + background-color: #e6e6e6; + border-color: #adadad; +} +.btn-default:active:hover, +.btn-default.active:hover, +.open > .dropdown-toggle.btn-default:hover, +.btn-default:active:focus, +.btn-default.active:focus, +.open > .dropdown-toggle.btn-default:focus, +.btn-default:active.focus, +.btn-default.active.focus, +.open > .dropdown-toggle.btn-default.focus { + color: #333333; + background-color: #d4d4d4; + border-color: #8c8c8c; +} +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + background-image: none; +} +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled.focus, +.btn-default[disabled].focus, +fieldset[disabled] .btn-default.focus { + background-color: #ffffff; + border-color: #cccccc; +} +.btn-default .badge { + color: #ffffff; + background-color: #333333; +} +.btn-primary { + color: #ffffff; + background-color: #3097d1; + border-color: #2a88bd; +} +.btn-primary:focus, +.btn-primary.focus { + color: #ffffff; + background-color: #2579a9; + border-color: #133d55; +} +.btn-primary:hover { + color: #ffffff; + background-color: #2579a9; + border-color: #1f648b; +} +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + color: #ffffff; + background-color: #2579a9; + border-color: #1f648b; +} +.btn-primary:active:hover, +.btn-primary.active:hover, +.open > .dropdown-toggle.btn-primary:hover, +.btn-primary:active:focus, +.btn-primary.active:focus, +.open > .dropdown-toggle.btn-primary:focus, +.btn-primary:active.focus, +.btn-primary.active.focus, +.open > .dropdown-toggle.btn-primary.focus { + color: #ffffff; + background-color: #1f648b; + border-color: #133d55; +} +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + background-image: none; +} +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled.focus, +.btn-primary[disabled].focus, +fieldset[disabled] .btn-primary.focus { + background-color: #3097d1; + border-color: #2a88bd; +} +.btn-primary .badge { + color: #3097d1; + background-color: #ffffff; +} +.btn-success { + color: #ffffff; + background-color: #4eb76e; + border-color: #44a762; +} +.btn-success:focus, +.btn-success.focus { + color: #ffffff; + background-color: #3d9558; + border-color: #1f4d2d; +} +.btn-success:hover { + color: #ffffff; + background-color: #3d9558; + border-color: #327c49; +} +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + color: #ffffff; + background-color: #3d9558; + border-color: #327c49; +} +.btn-success:active:hover, +.btn-success.active:hover, +.open > .dropdown-toggle.btn-success:hover, +.btn-success:active:focus, +.btn-success.active:focus, +.open > .dropdown-toggle.btn-success:focus, +.btn-success:active.focus, +.btn-success.active.focus, +.open > .dropdown-toggle.btn-success.focus { + color: #ffffff; + background-color: #327c49; + border-color: #1f4d2d; +} +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + background-image: none; +} +.btn-success.disabled:hover, +.btn-success[disabled]:hover, +fieldset[disabled] .btn-success:hover, +.btn-success.disabled:focus, +.btn-success[disabled]:focus, +fieldset[disabled] .btn-success:focus, +.btn-success.disabled.focus, +.btn-success[disabled].focus, +fieldset[disabled] .btn-success.focus { + background-color: #4eb76e; + border-color: #44a762; +} +.btn-success .badge { + color: #4eb76e; + background-color: #ffffff; +} +.btn-info { + color: #ffffff; + background-color: #8eb4cb; + border-color: #7da8c3; +} +.btn-info:focus, +.btn-info.focus { + color: #ffffff; + background-color: #6b9dbb; + border-color: #3d6983; +} +.btn-info:hover { + color: #ffffff; + background-color: #6b9dbb; + border-color: #538db0; +} +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + color: #ffffff; + background-color: #6b9dbb; + border-color: #538db0; +} +.btn-info:active:hover, +.btn-info.active:hover, +.open > .dropdown-toggle.btn-info:hover, +.btn-info:active:focus, +.btn-info.active:focus, +.open > .dropdown-toggle.btn-info:focus, +.btn-info:active.focus, +.btn-info.active.focus, +.open > .dropdown-toggle.btn-info.focus { + color: #ffffff; + background-color: #538db0; + border-color: #3d6983; +} +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + background-image: none; +} +.btn-info.disabled:hover, +.btn-info[disabled]:hover, +fieldset[disabled] .btn-info:hover, +.btn-info.disabled:focus, +.btn-info[disabled]:focus, +fieldset[disabled] .btn-info:focus, +.btn-info.disabled.focus, +.btn-info[disabled].focus, +fieldset[disabled] .btn-info.focus { + background-color: #8eb4cb; + border-color: #7da8c3; +} +.btn-info .badge { + color: #8eb4cb; + background-color: #ffffff; +} +.btn-warning { + color: #ffffff; + background-color: #cbb956; + border-color: #c5b142; +} +.btn-warning:focus, +.btn-warning.focus { + color: #ffffff; + background-color: #b6a338; + border-color: #685d20; +} +.btn-warning:hover { + color: #ffffff; + background-color: #b6a338; + border-color: #9b8a30; +} +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + color: #ffffff; + background-color: #b6a338; + border-color: #9b8a30; +} +.btn-warning:active:hover, +.btn-warning.active:hover, +.open > .dropdown-toggle.btn-warning:hover, +.btn-warning:active:focus, +.btn-warning.active:focus, +.open > .dropdown-toggle.btn-warning:focus, +.btn-warning:active.focus, +.btn-warning.active.focus, +.open > .dropdown-toggle.btn-warning.focus { + color: #ffffff; + background-color: #9b8a30; + border-color: #685d20; +} +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + background-image: none; +} +.btn-warning.disabled:hover, +.btn-warning[disabled]:hover, +fieldset[disabled] .btn-warning:hover, +.btn-warning.disabled:focus, +.btn-warning[disabled]:focus, +fieldset[disabled] .btn-warning:focus, +.btn-warning.disabled.focus, +.btn-warning[disabled].focus, +fieldset[disabled] .btn-warning.focus { + background-color: #cbb956; + border-color: #c5b142; +} +.btn-warning .badge { + color: #cbb956; + background-color: #ffffff; +} +.btn-danger { + color: #ffffff; + background-color: #bf5329; + border-color: #aa4a24; +} +.btn-danger:focus, +.btn-danger.focus { + color: #ffffff; + background-color: #954120; + border-color: #411c0e; +} +.btn-danger:hover { + color: #ffffff; + background-color: #954120; + border-color: #78341a; +} +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + color: #ffffff; + background-color: #954120; + border-color: #78341a; +} +.btn-danger:active:hover, +.btn-danger.active:hover, +.open > .dropdown-toggle.btn-danger:hover, +.btn-danger:active:focus, +.btn-danger.active:focus, +.open > .dropdown-toggle.btn-danger:focus, +.btn-danger:active.focus, +.btn-danger.active.focus, +.open > .dropdown-toggle.btn-danger.focus { + color: #ffffff; + background-color: #78341a; + border-color: #411c0e; +} +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + background-image: none; +} +.btn-danger.disabled:hover, +.btn-danger[disabled]:hover, +fieldset[disabled] .btn-danger:hover, +.btn-danger.disabled:focus, +.btn-danger[disabled]:focus, +fieldset[disabled] .btn-danger:focus, +.btn-danger.disabled.focus, +.btn-danger[disabled].focus, +fieldset[disabled] .btn-danger.focus { + background-color: #bf5329; + border-color: #aa4a24; +} +.btn-danger .badge { + color: #bf5329; + background-color: #ffffff; +} +.btn-link { + color: #3097d1; + font-weight: normal; + border-radius: 0; +} +.btn-link, +.btn-link:active, +.btn-link.active, +.btn-link[disabled], +fieldset[disabled] .btn-link { + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-link, +.btn-link:hover, +.btn-link:focus, +.btn-link:active { + border-color: transparent; +} +.btn-link:hover, +.btn-link:focus { + color: #216a94; + text-decoration: underline; + background-color: transparent; +} +.btn-link[disabled]:hover, +fieldset[disabled] .btn-link:hover, +.btn-link[disabled]:focus, +fieldset[disabled] .btn-link:focus { + color: #777777; + text-decoration: none; +} +.btn-lg, +.btn-group-lg > .btn { + padding: 10px 16px; + font-size: 20px; + line-height: 1.3333333; + border-radius: 6px; +} +.btn-sm, +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 14px; + line-height: 1.5; + border-radius: 3px; +} +.btn-xs, +.btn-group-xs > .btn { + padding: 1px 5px; + font-size: 14px; + line-height: 1.5; + border-radius: 3px; +} +.btn-block { + display: block; + width: 100%; +} +.btn-block + .btn-block { + margin-top: 5px; +} +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + display: none; +} +.collapse.in { + display: block; +} +tr.collapse.in { + display: table-row; +} +tbody.collapse.in { + display: table-row-group; +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition-property: height, visibility; + transition-property: height, visibility; + -webkit-transition-duration: 0.35s; + transition-duration: 0.35s; + -webkit-transition-timing-function: ease; + transition-timing-function: ease; +} +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px dashed; + border-top: 4px solid \9; + border-right: 4px solid transparent; + border-left: 4px solid transparent; +} +.dropup, +.dropdown { + position: relative; +} +.dropdown-toggle:focus { + outline: 0; +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + font-size: 16px; + text-align: left; + background-color: #ffffff; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + background-clip: padding-box; +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + height: 1px; + margin: 11.5px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.6; + color: #333333; + white-space: nowrap; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + text-decoration: none; + color: #262626; + background-color: #f5f5f5; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #ffffff; + text-decoration: none; + outline: 0; + background-color: #3097d1; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #777777; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + cursor: not-allowed; +} +.open > .dropdown-menu { + display: block; +} +.open > a { + outline: 0; +} +.dropdown-menu-right { + left: auto; + right: 0; +} +.dropdown-menu-left { + left: 0; + right: auto; +} +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 14px; + line-height: 1.6; + color: #777777; + white-space: nowrap; +} +.dropdown-backdrop { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: 990; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px dashed; + border-bottom: 4px solid \9; + content: ""; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +@media (min-width: 768px) { + .navbar-right .dropdown-menu { + left: auto; + right: 0; + } + .navbar-right .dropdown-menu-left { + left: 0; + right: auto; + } +} +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + float: left; +} +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover, +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus, +.btn-group > .btn:active, +.btn-group-vertical > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn.active { + z-index: 2; +} +.btn-group .btn + .btn, +.btn-group .btn + .btn-group, +.btn-group .btn-group + .btn, +.btn-group .btn-group + .btn-group { + margin-left: -1px; +} +.btn-toolbar { + margin-left: -5px; +} +.btn-toolbar .btn, +.btn-toolbar .btn-group, +.btn-toolbar .input-group { + float: left; +} +.btn-toolbar > .btn, +.btn-toolbar > .btn-group, +.btn-toolbar > .input-group { + margin-left: 5px; +} +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} +.btn-group > .btn:first-child { + margin-left: 0; +} +.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child, +.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-left: 12px; + padding-right: 12px; +} +.btn-group.open .dropdown-toggle { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn-group.open .dropdown-toggle.btn-link { + -webkit-box-shadow: none; + box-shadow: none; +} +.btn .caret { + margin-left: 0; +} +.btn-lg .caret { + border-width: 5px 5px 0; + border-bottom-width: 0; +} +.dropup .btn-lg .caret { + border-width: 0 5px 5px; +} +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group, +.btn-group-vertical > .btn-group > .btn { + display: block; + float: none; + width: 100%; + max-width: 100%; +} +.btn-group-vertical > .btn-group > .btn { + float: none; +} +.btn-group-vertical > .btn + .btn, +.btn-group-vertical > .btn + .btn-group, +.btn-group-vertical > .btn-group + .btn, +.btn-group-vertical > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; +} +.btn-group-vertical > .btn:not(:first-child):not(:last-child) { + border-radius: 0; +} +.btn-group-vertical > .btn:first-child:not(:last-child) { + border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn:last-child:not(:first-child) { + border-top-right-radius: 0; + border-top-left-radius: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; +} +.btn-group-justified > .btn, +.btn-group-justified > .btn-group { + float: none; + display: table-cell; + width: 1%; +} +.btn-group-justified > .btn-group .btn { + width: 100%; +} +.btn-group-justified > .btn-group .dropdown-menu { + left: auto; +} +[data-toggle="buttons"] > .btn input[type="radio"], +[data-toggle="buttons"] > .btn-group > .btn input[type="radio"], +[data-toggle="buttons"] > .btn input[type="checkbox"], +[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} +.input-group { + position: relative; + display: table; + border-collapse: separate; +} +.input-group[class*="col-"] { + float: none; + padding-left: 0; + padding-right: 0; +} +.input-group .form-control { + position: relative; + z-index: 2; + float: left; + width: 100%; + margin-bottom: 0; +} +.input-group .form-control:focus { + z-index: 3; +} +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { + height: 49px; + padding: 10px 16px; + font-size: 20px; + line-height: 1.3333333; + border-radius: 6px; +} +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon, +select.input-group-lg > .input-group-btn > .btn { + height: 49px; + line-height: 49px; +} +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +textarea.input-group-lg > .input-group-btn > .btn, +select[multiple].input-group-lg > .form-control, +select[multiple].input-group-lg > .input-group-addon, +select[multiple].input-group-lg > .input-group-btn > .btn { + height: auto; +} +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon, +.input-group-sm > .input-group-btn > .btn { + height: 33px; + padding: 5px 10px; + font-size: 14px; + line-height: 1.5; + border-radius: 3px; +} +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon, +select.input-group-sm > .input-group-btn > .btn { + height: 33px; + line-height: 33px; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +textarea.input-group-sm > .input-group-btn > .btn, +select[multiple].input-group-sm > .form-control, +select[multiple].input-group-sm > .input-group-addon, +select[multiple].input-group-sm > .input-group-btn > .btn { + height: auto; +} +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; +} +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} +.input-group-addon, +.input-group-btn { + width: 1%; + white-space: nowrap; + vertical-align: middle; +} +.input-group-addon { + padding: 6px 12px; + font-size: 16px; + font-weight: normal; + line-height: 1; + color: #555555; + text-align: center; + background-color: #eeeeee; + border: 1px solid #cccccc; + border-radius: 4px; +} +.input-group-addon.input-sm { + padding: 5px 10px; + font-size: 14px; + border-radius: 3px; +} +.input-group-addon.input-lg { + padding: 10px 16px; + font-size: 20px; + border-radius: 6px; +} +.input-group-addon input[type="radio"], +.input-group-addon input[type="checkbox"] { + margin-top: 0; +} +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child), +.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.input-group-addon:last-child { + border-left: 0; +} +.input-group-btn { + position: relative; + font-size: 0; + white-space: nowrap; +} +.input-group-btn > .btn { + position: relative; +} +.input-group-btn > .btn + .btn { + margin-left: -1px; +} +.input-group-btn > .btn:hover, +.input-group-btn > .btn:focus, +.input-group-btn > .btn:active { + z-index: 2; +} +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group { + margin-right: -1px; +} +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group { + z-index: 2; + margin-left: -1px; +} +.nav { + margin-bottom: 0; + padding-left: 0; + list-style: none; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} +.nav > li.disabled > a { + color: #777777; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #777777; + text-decoration: none; + background-color: transparent; + cursor: not-allowed; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #eeeeee; + border-color: #3097d1; +} +.nav .nav-divider { + height: 1px; + margin: 11.5px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #dddddd; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.6; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555555; + background-color: #ffffff; + border: 1px solid #dddddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 4px; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #ffffff; + background-color: #3097d1; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.navbar { + position: relative; + min-height: 70px; + margin-bottom: 0; + border: 1px solid transparent; +} +@media (min-width: 768px) { + .navbar { + border-radius: 4px; + } +} +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} +.navbar-collapse { + overflow-x: visible; + padding-right: 15px; + padding-left: 15px; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); + -webkit-overflow-scrolling: touch; +} +.navbar-collapse.in { + overflow-y: auto; +} +@media (min-width: 768px) { + .navbar-collapse { + width: auto; + border-top: 0; + box-shadow: none; + } + .navbar-collapse.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; + overflow: visible !important; + } + .navbar-collapse.in { + overflow-y: visible; + } + .navbar-fixed-top .navbar-collapse, + .navbar-static-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-left: 0; + padding-right: 0; + } +} +.navbar-fixed-top .navbar-collapse, +.navbar-fixed-bottom .navbar-collapse { + max-height: 340px; +} +@media (max-device-width: 480px) and (orientation: landscape) { + .navbar-fixed-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + max-height: 200px; + } +} +.container > .navbar-header, +.container-fluid > .navbar-header, +.container > .navbar-collapse, +.container-fluid > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .container > .navbar-header, + .container-fluid > .navbar-header, + .container > .navbar-collapse, + .container-fluid > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} +.navbar-static-top { + z-index: 1000; + border-width: 0 0 1px; +} +@media (min-width: 768px) { + .navbar-static-top { + border-radius: 0; + } +} +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; +} +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; + border-width: 1px 0 0; +} +.navbar-brand { + float: left; + padding: 22.5px 15px; + font-size: 20px; + line-height: 25px; + height: 70px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +.navbar-brand > img { + display: block; +} +@media (min-width: 768px) { + .navbar > .container .navbar-brand, + .navbar > .container-fluid .navbar-brand { + margin-left: -15px; + } +} +.navbar-toggle { + position: relative; + float: right; + margin-right: 15px; + padding: 9px 10px; + margin-top: 18px; + margin-bottom: 18px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.navbar-toggle:focus { + outline: 0; +} +.navbar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; +} +.navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} +@media (min-width: 768px) { + .navbar-toggle { + display: none; + } +} +.navbar-nav { + margin: 11.25px -15px; +} +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 25px; +} +@media (max-width: 767px) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 25px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} +@media (min-width: 768px) { + .navbar-nav { + float: left; + margin: 0; + } + .navbar-nav > li { + float: left; + } + .navbar-nav > li > a { + padding-top: 22.5px; + padding-bottom: 22.5px; + } +} +.navbar-form { + margin-left: -15px; + margin-right: -15px; + padding: 10px 15px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + margin-top: 15.5px; + margin-bottom: 15.5px; +} +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .navbar-form .form-control-static { + display: inline-block; + } + .navbar-form .input-group { + display: inline-table; + vertical-align: middle; + } + .navbar-form .input-group .input-group-addon, + .navbar-form .input-group .input-group-btn, + .navbar-form .input-group .form-control { + width: auto; + } + .navbar-form .input-group > .form-control { + width: 100%; + } + .navbar-form .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio label, + .navbar-form .checkbox label { + padding-left: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .navbar-form .has-feedback .form-control-feedback { + top: 0; + } +} +@media (max-width: 767px) { + .navbar-form .form-group { + margin-bottom: 5px; + } + .navbar-form .form-group:last-child { + margin-bottom: 0; + } +} +@media (min-width: 768px) { + .navbar-form { + width: auto; + border: 0; + margin-left: 0; + margin-right: 0; + padding-top: 0; + padding-bottom: 0; + -webkit-box-shadow: none; + box-shadow: none; + } +} +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + margin-bottom: 0; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.navbar-btn { + margin-top: 15.5px; + margin-bottom: 15.5px; +} +.navbar-btn.btn-sm { + margin-top: 18.5px; + margin-bottom: 18.5px; +} +.navbar-btn.btn-xs { + margin-top: 24px; + margin-bottom: 24px; +} +.navbar-text { + margin-top: 22.5px; + margin-bottom: 22.5px; +} +@media (min-width: 768px) { + .navbar-text { + float: left; + margin-left: 15px; + margin-right: 15px; + } +} +@media (min-width: 768px) { + .navbar-left { + float: left !important; + float: left; + } + .navbar-right { + float: right !important; + float: right; + margin-right: -15px; + } + .navbar-right ~ .navbar-right { + margin-right: 0; + } +} +.navbar-default { + background-color: #f8f8f8; + border-color: #e7e7e7; +} +.navbar-default .navbar-brand { + color: #777777; +} +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #5e5e5e; + background-color: transparent; +} +.navbar-default .navbar-text { + color: #777777; +} +.navbar-default .navbar-nav > li > a { + color: #777777; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #333333; + background-color: transparent; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #555555; + background-color: #e7e7e7; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #cccccc; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: #dddddd; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #dddddd; +} +.navbar-default .navbar-toggle .icon-bar { + background-color: #888888; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #e7e7e7; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + background-color: #e7e7e7; + color: #555555; +} +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #777777; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #333333; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #555555; + background-color: #e7e7e7; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #cccccc; + background-color: transparent; + } +} +.navbar-default .navbar-link { + color: #777777; +} +.navbar-default .navbar-link:hover { + color: #333333; +} +.navbar-default .btn-link { + color: #777777; +} +.navbar-default .btn-link:hover, +.navbar-default .btn-link:focus { + color: #333333; +} +.navbar-default .btn-link[disabled]:hover, +fieldset[disabled] .navbar-default .btn-link:hover, +.navbar-default .btn-link[disabled]:focus, +fieldset[disabled] .navbar-default .btn-link:focus { + color: #cccccc; +} +.navbar-inverse { + background-color: #000000; + border-color: #000000; +} +.navbar-inverse .navbar-brand { + color: rgba(255, 255, 255, 0.6); +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #ffffff; + background-color: transparent; +} +.navbar-inverse .navbar-text { + color: #9d9d9d; +} +.navbar-inverse .navbar-nav > li > a { + color: rgba(255, 255, 255, 0.6); +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #ffffff; + background-color: transparent; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #ffffff; + background-color: #000000; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #444444; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: #333333; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #333333; +} +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #ffffff; +} +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #000000; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + background-color: #000000; + color: #ffffff; +} +@media (max-width: 767px) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #000000; + } + .navbar-inverse .navbar-nav .open .dropdown-menu .divider { + background-color: #000000; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: rgba(255, 255, 255, 0.6); + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #ffffff; + background-color: transparent; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #ffffff; + background-color: #000000; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #444444; + background-color: transparent; + } +} +.navbar-inverse .navbar-link { + color: rgba(255, 255, 255, 0.6); +} +.navbar-inverse .navbar-link:hover { + color: #ffffff; +} +.navbar-inverse .btn-link { + color: rgba(255, 255, 255, 0.6); +} +.navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link:focus { + color: #ffffff; +} +.navbar-inverse .btn-link[disabled]:hover, +fieldset[disabled] .navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link[disabled]:focus, +fieldset[disabled] .navbar-inverse .btn-link:focus { + color: #444444; +} +.breadcrumb { + padding: 8px 15px; + margin-bottom: 25px; + list-style: none; + background-color: #f5f5f5; + border-radius: 4px; +} +.breadcrumb > li { + display: inline-block; +} +.breadcrumb > li + li:before { + content: "/\00a0"; + padding: 0 5px; + color: #cccccc; +} +.breadcrumb > .active { + color: #777777; +} +.pagination { + display: inline-block; + padding-left: 0; + margin: 25px 0; + border-radius: 4px; +} +.pagination > li { + display: inline; +} +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 6px 12px; + line-height: 1.6; + text-decoration: none; + color: #3097d1; + background-color: #ffffff; + border: 1px solid #dddddd; + margin-left: -1px; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-bottom-right-radius: 4px; + border-top-right-radius: 4px; +} +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + z-index: 2; + color: #216a94; + background-color: #eeeeee; + border-color: #dddddd; +} +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 3; + color: #ffffff; + background-color: #3097d1; + border-color: #3097d1; + cursor: default; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #777777; + background-color: #ffffff; + border-color: #dddddd; + cursor: not-allowed; +} +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 10px 16px; + font-size: 20px; + line-height: 1.3333333; +} +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-bottom-left-radius: 6px; + border-top-left-radius: 6px; +} +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-bottom-right-radius: 6px; + border-top-right-radius: 6px; +} +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 14px; + line-height: 1.5; +} +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; +} +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-bottom-right-radius: 3px; + border-top-right-radius: 3px; +} +.pager { + padding-left: 0; + margin: 25px 0; + list-style: none; + text-align: center; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 15px; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #777777; + background-color: #ffffff; + cursor: not-allowed; +} +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} +a.label:hover, +a.label:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} +.label:empty { + display: none; +} +.btn .label { + position: relative; + top: -1px; +} +.label-default { + background-color: #777777; +} +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #5e5e5e; +} +.label-primary { + background-color: #3097d1; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #2579a9; +} +.label-success { + background-color: #4eb76e; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #3d9558; +} +.label-info { + background-color: #8eb4cb; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #6b9dbb; +} +.label-warning { + background-color: #cbb956; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #b6a338; +} +.label-danger { + background-color: #bf5329; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #954120; +} +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 14px; + font-weight: bold; + color: #ffffff; + line-height: 1; + vertical-align: middle; + white-space: nowrap; + text-align: center; + background-color: #777777; + border-radius: 10px; +} +.badge:empty { + display: none; +} +.btn .badge { + position: relative; + top: -1px; +} +.btn-xs .badge, +.btn-group-xs > .btn .badge { + top: 0; + padding: 1px 5px; +} +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} +.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #3097d1; + background-color: #ffffff; +} +.list-group-item > .badge { + float: right; +} +.list-group-item > .badge + .badge { + margin-right: 5px; +} +.nav-pills > li > a > .badge { + margin-left: 3px; +} +.jumbotron { + padding-top: 30px; + padding-bottom: 30px; + margin-bottom: 30px; + color: inherit; + background-color: #eeeeee; +} +.jumbotron h1, +.jumbotron .h1 { + color: #1f3f50; +} +.jumbotron p { + margin-bottom: 15px; + font-size: 24px; + font-weight: 200; +} +.jumbotron > hr { + border-top-color: #d5d5d5; +} +.container .jumbotron, +.container-fluid .jumbotron { + border-radius: 6px; + padding-left: 15px; + padding-right: 15px; +} +.jumbotron .container { + max-width: 100%; +} +@media screen and (min-width: 768px) { + .jumbotron { + padding-top: 48px; + padding-bottom: 48px; + } + .container .jumbotron, + .container-fluid .jumbotron { + padding-left: 60px; + padding-right: 60px; + } + .jumbotron h1, + .jumbotron .h1 { + font-size: 72px; + } +} +.thumbnail { + display: block; + padding: 4px; + margin-bottom: 25px; + line-height: 1.6; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: border 0.2s ease-in-out; + -o-transition: border 0.2s ease-in-out; + transition: border 0.2s ease-in-out; +} +.thumbnail > img, +.thumbnail a > img { + margin-left: auto; + margin-right: auto; +} +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + border-color: #3097d1; +} +.thumbnail .caption { + padding: 9px; + color: #586667; +} +.alert { + padding: 15px; + margin-bottom: 25px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert h4 { + margin-top: 0; + color: inherit; +} +.alert .alert-link { + font-weight: bold; +} +.alert > p, +.alert > ul { + margin-bottom: 0; +} +.alert > p + p { + margin-top: 5px; +} +.alert-dismissable, +.alert-dismissible { + padding-right: 35px; +} +.alert-dismissable .close, +.alert-dismissible .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; + color: #3c763d; +} +.alert-success hr { + border-top-color: #c9e2b3; +} +.alert-success .alert-link { + color: #2b542c; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; + color: #31708f; +} +.alert-info hr { + border-top-color: #a6e1ec; +} +.alert-info .alert-link { + color: #245269; +} +.alert-warning { + background-color: #fcf8e3; + border-color: #faebcc; + color: #8a6d3b; +} +.alert-warning hr { + border-top-color: #f7e1b5; +} +.alert-warning .alert-link { + color: #66512c; +} +.alert-danger { + background-color: #f2dede; + border-color: #ebccd1; + color: #a94442; +} +.alert-danger hr { + border-top-color: #e4b9c0; +} +.alert-danger .alert-link { + color: #843534; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + overflow: hidden; + height: 25px; + margin-bottom: 25px; + background-color: #f5f5f5; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} +.progress-bar { + float: left; + width: 0%; + height: 100%; + font-size: 14px; + line-height: 25px; + color: #ffffff; + text-align: center; + background-color: #3097d1; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .progress-bar, +.progress-bar-striped { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 40px 40px; +} +.progress.active .progress-bar, +.progress-bar.active { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-bar-success { + background-color: #4eb76e; +} +.progress-striped .progress-bar-success { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-info { + background-color: #8eb4cb; +} +.progress-striped .progress-bar-info { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-warning { + background-color: #cbb956; +} +.progress-striped .progress-bar-warning { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-danger { + background-color: #bf5329; +} +.progress-striped .progress-bar-danger { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.media { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} +.media, +.media-body { + zoom: 1; + overflow: hidden; +} +.media-body { + width: 10000px; +} +.media-object { + display: block; +} +.media-object.img-thumbnail { + max-width: none; +} +.media-right, +.media > .pull-right { + padding-left: 10px; +} +.media-left, +.media > .pull-left { + padding-right: 10px; +} +.media-left, +.media-right, +.media-body { + display: table-cell; + vertical-align: top; +} +.media-middle { + vertical-align: middle; +} +.media-bottom { + vertical-align: bottom; +} +.media-heading { + margin-top: 0; + margin-bottom: 5px; +} +.media-list { + padding-left: 0; + list-style: none; +} +.list-group { + margin-bottom: 20px; + padding-left: 0; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #ffffff; + border: 1px solid #dddddd; +} +.list-group-item:first-child { + border-top-right-radius: 4px; + border-top-left-radius: 4px; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +a.list-group-item, +button.list-group-item { + color: #555555; +} +a.list-group-item .list-group-item-heading, +button.list-group-item .list-group-item-heading { + color: #333333; +} +a.list-group-item:hover, +button.list-group-item:hover, +a.list-group-item:focus, +button.list-group-item:focus { + text-decoration: none; + color: #555555; + background-color: #f5f5f5; +} +button.list-group-item { + width: 100%; + text-align: left; +} +.list-group-item.disabled, +.list-group-item.disabled:hover, +.list-group-item.disabled:focus { + background-color: #eeeeee; + color: #777777; + cursor: not-allowed; +} +.list-group-item.disabled .list-group-item-heading, +.list-group-item.disabled:hover .list-group-item-heading, +.list-group-item.disabled:focus .list-group-item-heading { + color: inherit; +} +.list-group-item.disabled .list-group-item-text, +.list-group-item.disabled:hover .list-group-item-text, +.list-group-item.disabled:focus .list-group-item-text { + color: #777777; +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + z-index: 2; + color: #ffffff; + background-color: #3097d1; + border-color: #3097d1; +} +.list-group-item.active .list-group-item-heading, +.list-group-item.active:hover .list-group-item-heading, +.list-group-item.active:focus .list-group-item-heading, +.list-group-item.active .list-group-item-heading > small, +.list-group-item.active:hover .list-group-item-heading > small, +.list-group-item.active:focus .list-group-item-heading > small, +.list-group-item.active .list-group-item-heading > .small, +.list-group-item.active:hover .list-group-item-heading > .small, +.list-group-item.active:focus .list-group-item-heading > .small { + color: inherit; +} +.list-group-item.active .list-group-item-text, +.list-group-item.active:hover .list-group-item-text, +.list-group-item.active:focus .list-group-item-text { + color: #d7ebf6; +} +.list-group-item-success { + color: #3c763d; + background-color: #dff0d8; +} +a.list-group-item-success, +button.list-group-item-success { + color: #3c763d; +} +a.list-group-item-success .list-group-item-heading, +button.list-group-item-success .list-group-item-heading { + color: inherit; +} +a.list-group-item-success:hover, +button.list-group-item-success:hover, +a.list-group-item-success:focus, +button.list-group-item-success:focus { + color: #3c763d; + background-color: #d0e9c6; +} +a.list-group-item-success.active, +button.list-group-item-success.active, +a.list-group-item-success.active:hover, +button.list-group-item-success.active:hover, +a.list-group-item-success.active:focus, +button.list-group-item-success.active:focus { + color: #fff; + background-color: #3c763d; + border-color: #3c763d; +} +.list-group-item-info { + color: #31708f; + background-color: #d9edf7; +} +a.list-group-item-info, +button.list-group-item-info { + color: #31708f; +} +a.list-group-item-info .list-group-item-heading, +button.list-group-item-info .list-group-item-heading { + color: inherit; +} +a.list-group-item-info:hover, +button.list-group-item-info:hover, +a.list-group-item-info:focus, +button.list-group-item-info:focus { + color: #31708f; + background-color: #c4e3f3; +} +a.list-group-item-info.active, +button.list-group-item-info.active, +a.list-group-item-info.active:hover, +button.list-group-item-info.active:hover, +a.list-group-item-info.active:focus, +button.list-group-item-info.active:focus { + color: #fff; + background-color: #31708f; + border-color: #31708f; +} +.list-group-item-warning { + color: #8a6d3b; + background-color: #fcf8e3; +} +a.list-group-item-warning, +button.list-group-item-warning { + color: #8a6d3b; +} +a.list-group-item-warning .list-group-item-heading, +button.list-group-item-warning .list-group-item-heading { + color: inherit; +} +a.list-group-item-warning:hover, +button.list-group-item-warning:hover, +a.list-group-item-warning:focus, +button.list-group-item-warning:focus { + color: #8a6d3b; + background-color: #faf2cc; +} +a.list-group-item-warning.active, +button.list-group-item-warning.active, +a.list-group-item-warning.active:hover, +button.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus, +button.list-group-item-warning.active:focus { + color: #fff; + background-color: #8a6d3b; + border-color: #8a6d3b; +} +.list-group-item-danger { + color: #a94442; + background-color: #f2dede; +} +a.list-group-item-danger, +button.list-group-item-danger { + color: #a94442; +} +a.list-group-item-danger .list-group-item-heading, +button.list-group-item-danger .list-group-item-heading { + color: inherit; +} +a.list-group-item-danger:hover, +button.list-group-item-danger:hover, +a.list-group-item-danger:focus, +button.list-group-item-danger:focus { + color: #a94442; + background-color: #ebcccc; +} +a.list-group-item-danger.active, +button.list-group-item-danger.active, +a.list-group-item-danger.active:hover, +button.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus, +button.list-group-item-danger.active:focus { + color: #fff; + background-color: #a94442; + border-color: #a94442; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} +.panel { + margin-bottom: 25px; + background-color: #ffffff; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); +} +.panel-body { + padding: 15px; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 18px; + color: inherit; +} +.panel-title > a, +.panel-title > small, +.panel-title > .small, +.panel-title > small > a, +.panel-title > .small > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #dddddd; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .list-group, +.panel > .panel-collapse > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item, +.panel > .panel-collapse > .list-group .list-group-item { + border-width: 1px 0; + border-radius: 0; +} +.panel > .list-group:first-child .list-group-item:first-child, +.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { + border-top: 0; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel > .list-group:last-child .list-group-item:last-child, +.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { + border-bottom: 0; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.list-group + .panel-footer { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive > .table, +.panel > .panel-collapse > .table { + margin-bottom: 0; +} +.panel > .table caption, +.panel > .table-responsive > .table caption, +.panel > .panel-collapse > .table caption { + padding-left: 15px; + padding-right: 15px; +} +.panel > .table:first-child, +.panel > .table-responsive:first-child > .table:first-child { + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { + border-top-right-radius: 3px; +} +.panel > .table:last-child, +.panel > .table-responsive:last-child > .table:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { + border-bottom-right-radius: 3px; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive, +.panel > .table + .panel-body, +.panel > .table-responsive + .panel-body { + border-top: 1px solid #dddddd; +} +.panel > .table > tbody:first-child > tr:first-child th, +.panel > .table > tbody:first-child > tr:first-child td { + border-top: 0; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} +.panel > .table-bordered > thead > tr:first-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, +.panel > .table-bordered > tbody > tr:first-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, +.panel > .table-bordered > thead > tr:first-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, +.panel > .table-bordered > tbody > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { + border-bottom: 0; +} +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { + border-bottom: 0; +} +.panel > .table-responsive { + border: 0; + margin-bottom: 0; +} +.panel-group { + margin-bottom: 25px; +} +.panel-group .panel { + margin-bottom: 0; + border-radius: 4px; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse > .panel-body, +.panel-group .panel-heading + .panel-collapse > .list-group { + border-top: 1px solid #dddddd; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #dddddd; +} +.panel-default { + border-color: #dddddd; +} +.panel-default > .panel-heading { + color: #333333; + background-color: #f5f5f5; + border-color: #dddddd; +} +.panel-default > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #dddddd; +} +.panel-default > .panel-heading .badge { + color: #f5f5f5; + background-color: #333333; +} +.panel-default > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #dddddd; +} +.panel-primary { + border-color: #3097d1; +} +.panel-primary > .panel-heading { + color: #ffffff; + background-color: #3097d1; + border-color: #3097d1; +} +.panel-primary > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #3097d1; +} +.panel-primary > .panel-heading .badge { + color: #3097d1; + background-color: #ffffff; +} +.panel-primary > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #3097d1; +} +.panel-success { + border-color: #d6e9c6; +} +.panel-success > .panel-heading { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.panel-success > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #d6e9c6; +} +.panel-success > .panel-heading .badge { + color: #dff0d8; + background-color: #3c763d; +} +.panel-success > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #d6e9c6; +} +.panel-info { + border-color: #bce8f1; +} +.panel-info > .panel-heading { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.panel-info > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #bce8f1; +} +.panel-info > .panel-heading .badge { + color: #d9edf7; + background-color: #31708f; +} +.panel-info > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #bce8f1; +} +.panel-warning { + border-color: #faebcc; +} +.panel-warning > .panel-heading { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.panel-warning > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #faebcc; +} +.panel-warning > .panel-heading .badge { + color: #fcf8e3; + background-color: #8a6d3b; +} +.panel-warning > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #faebcc; +} +.panel-danger { + border-color: #ebccd1; +} +.panel-danger > .panel-heading { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.panel-danger > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #ebccd1; +} +.panel-danger > .panel-heading .badge { + color: #f2dede; + background-color: #a94442; +} +.panel-danger > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #ebccd1; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.well-lg { + padding: 24px; + border-radius: 6px; +} +.well-sm { + padding: 9px; + border-radius: 3px; +} +.close { + float: right; + font-size: 24px; + font-weight: bold; + line-height: 1; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.5; + filter: alpha(opacity=50); +} +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} +.modal-open { + overflow: hidden; +} +.modal { + display: none; + overflow: hidden; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1050; + -webkit-overflow-scrolling: touch; + outline: 0; +} +.modal.fade .modal-dialog { + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + -o-transform: translate(0, -25%); + transform: translate(0, -25%); + -webkit-transition: -webkit-transform 0.3s ease-out; + -moz-transition: -moz-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + transition: transform 0.3s ease-out; +} +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + -o-transform: translate(0, 0); + transform: translate(0, 0); +} +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} +.modal-dialog { + position: relative; + width: auto; + margin: 10px; +} +.modal-content { + position: relative; + background-color: #ffffff; + border: 1px solid #999999; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + background-clip: padding-box; + outline: 0; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; + filter: alpha(opacity=0); +} +.modal-backdrop.in { + opacity: 0.5; + filter: alpha(opacity=50); +} +.modal-header { + padding: 15px; + border-bottom: 1px solid #e5e5e5; +} +.modal-header .close { + margin-top: -2px; +} +.modal-title { + margin: 0; + line-height: 1.6; +} +.modal-body { + position: relative; + padding: 15px; +} +.modal-footer { + padding: 15px; + text-align: right; + border-top: 1px solid #e5e5e5; +} +.modal-footer .btn + .btn { + margin-left: 5px; + margin-bottom: 0; +} +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} +@media (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + } + .modal-sm { + width: 300px; + } +} +@media (min-width: 992px) { + .modal-lg { + width: 900px; + } +} +.tooltip { + position: absolute; + z-index: 1070; + display: block; + font-family: "lato", sans-serif; + font-style: normal; + font-weight: normal; + letter-spacing: normal; + line-break: auto; + line-height: 1.6; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + white-space: normal; + word-break: normal; + word-spacing: normal; + word-wrap: normal; + font-size: 14px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.9; + filter: alpha(opacity=90); +} +.tooltip.top { + margin-top: -3px; + padding: 5px 0; +} +.tooltip.right { + margin-left: 3px; + padding: 0 5px; +} +.tooltip.bottom { + margin-top: 3px; + padding: 5px 0; +} +.tooltip.left { + margin-left: -3px; + padding: 0 5px; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + background-color: #000000; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-width: 5px 5px 0; + border-top-color: #000000; +} +.tooltip.top-left .tooltip-arrow { + bottom: 0; + right: 5px; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #000000; +} +.tooltip.top-right .tooltip-arrow { + bottom: 0; + left: 5px; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000000; +} +.tooltip.bottom-left .tooltip-arrow { + top: 0; + right: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000000; +} +.tooltip.bottom-right .tooltip-arrow { + top: 0; + left: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000000; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1060; + display: none; + max-width: 276px; + padding: 1px; + font-family: "lato", sans-serif; + font-style: normal; + font-weight: normal; + letter-spacing: normal; + line-break: auto; + line-height: 1.6; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + white-space: normal; + word-break: normal; + word-spacing: normal; + word-wrap: normal; + font-size: 16px; + background-color: #ffffff; + background-clip: padding-box; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + margin: 0; + padding: 8px 14px; + font-size: 16px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-radius: 5px 5px 0 0; +} +.popover-content { + padding: 9px 14px; +} +.popover > .arrow, +.popover > .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover > .arrow { + border-width: 11px; +} +.popover > .arrow:after { + border-width: 10px; + content: ""; +} +.popover.top > .arrow { + left: 50%; + margin-left: -11px; + border-bottom-width: 0; + border-top-color: #999999; + border-top-color: rgba(0, 0, 0, 0.25); + bottom: -11px; +} +.popover.top > .arrow:after { + content: " "; + bottom: 1px; + margin-left: -10px; + border-bottom-width: 0; + border-top-color: #ffffff; +} +.popover.right > .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-left-width: 0; + border-right-color: #999999; + border-right-color: rgba(0, 0, 0, 0.25); +} +.popover.right > .arrow:after { + content: " "; + left: 1px; + bottom: -10px; + border-left-width: 0; + border-right-color: #ffffff; +} +.popover.bottom > .arrow { + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #999999; + border-bottom-color: rgba(0, 0, 0, 0.25); + top: -11px; +} +.popover.bottom > .arrow:after { + content: " "; + top: 1px; + margin-left: -10px; + border-top-width: 0; + border-bottom-color: #ffffff; +} +.popover.left > .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #999999; + border-left-color: rgba(0, 0, 0, 0.25); +} +.popover.left > .arrow:after { + content: " "; + right: 1px; + border-right-width: 0; + border-left-color: #ffffff; + bottom: -10px; +} +.carousel { + position: relative; +} +.carousel-inner { + position: relative; + overflow: hidden; + width: 100%; +} +.carousel-inner > .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + line-height: 1; +} +@media all and (transform-3d), (-webkit-transform-3d) { + .carousel-inner > .item { + -webkit-transition: -webkit-transform 0.6s ease-in-out; + -moz-transition: -moz-transform 0.6s ease-in-out; + -o-transition: -o-transform 0.6s ease-in-out; + transition: transform 0.6s ease-in-out; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-perspective: 1000px; + -moz-perspective: 1000px; + perspective: 1000px; + } + .carousel-inner > .item.next, + .carousel-inner > .item.active.right { + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + left: 0; + } + .carousel-inner > .item.prev, + .carousel-inner > .item.active.left { + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + left: 0; + } + .carousel-inner > .item.next.left, + .carousel-inner > .item.prev.right, + .carousel-inner > .item.active { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + left: 0; + } +} +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} +.carousel-inner > .active { + left: 0; +} +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel-inner > .next { + left: 100%; +} +.carousel-inner > .prev { + left: -100%; +} +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} +.carousel-inner > .active.left { + left: -100%; +} +.carousel-inner > .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 15%; + opacity: 0.5; + filter: alpha(opacity=50); + font-size: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); + background-color: rgba(0, 0, 0, 0); +} +.carousel-control.left { + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); +} +.carousel-control.right { + left: auto; + right: 0; + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); +} +.carousel-control:hover, +.carousel-control:focus { + outline: 0; + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-control .icon-prev, +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-left, +.carousel-control .glyphicon-chevron-right { + position: absolute; + top: 50%; + margin-top: -10px; + z-index: 5; + display: inline-block; +} +.carousel-control .icon-prev, +.carousel-control .glyphicon-chevron-left { + left: 50%; + margin-left: -10px; +} +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; + margin-right: -10px; +} +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + line-height: 1; + font-family: serif; +} +.carousel-control .icon-prev:before { + content: '\2039'; +} +.carousel-control .icon-next:before { + content: '\203a'; +} +.carousel-indicators { + position: absolute; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + margin-left: -30%; + padding-left: 0; + list-style: none; + text-align: center; +} +.carousel-indicators li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + border: 1px solid #ffffff; + border-radius: 10px; + cursor: pointer; + background-color: #000 \9; + background-color: rgba(0, 0, 0, 0); +} +.carousel-indicators .active { + margin: 0; + width: 12px; + height: 12px; + background-color: #ffffff; +} +.carousel-caption { + position: absolute; + left: 15%; + right: 15%; + bottom: 20px; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); +} +.carousel-caption .btn { + text-shadow: none; +} +@media screen and (min-width: 768px) { + .carousel-control .glyphicon-chevron-left, + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -10px; + font-size: 30px; + } + .carousel-control .glyphicon-chevron-left, + .carousel-control .icon-prev { + margin-left: -10px; + } + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-next { + margin-right: -10px; + } + .carousel-caption { + left: 20%; + right: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} +.clearfix:before, +.clearfix:after, +.dl-horizontal dd:before, +.dl-horizontal dd:after, +.container:before, +.container:after, +.container-fluid:before, +.container-fluid:after, +.row:before, +.row:after, +.form-horizontal .form-group:before, +.form-horizontal .form-group:after, +.btn-toolbar:before, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after, +.nav:before, +.nav:after, +.navbar:before, +.navbar:after, +.navbar-header:before, +.navbar-header:after, +.navbar-collapse:before, +.navbar-collapse:after, +.pager:before, +.pager:after, +.panel-body:before, +.panel-body:after, +.modal-header:before, +.modal-header:after, +.modal-footer:before, +.modal-footer:after { + content: " "; + display: table; +} +.clearfix:after, +.dl-horizontal dd:after, +.container:after, +.container-fluid:after, +.row:after, +.form-horizontal .form-group:after, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:after, +.nav:after, +.navbar:after, +.navbar-header:after, +.navbar-collapse:after, +.pager:after, +.panel-body:after, +.modal-header:after, +.modal-footer:after { + clear: both; +} +.center-block { + display: block; + margin-left: auto; + margin-right: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; +} +.affix { + position: fixed; +} +@-ms-viewport { + width: device-width; +} +.visible-xs, +.visible-sm, +.visible-md, +.visible-lg { + display: none !important; +} +.visible-xs-block, +.visible-xs-inline, +.visible-xs-inline-block, +.visible-sm-block, +.visible-sm-inline, +.visible-sm-inline-block, +.visible-md-block, +.visible-md-inline, +.visible-md-inline-block, +.visible-lg-block, +.visible-lg-inline, +.visible-lg-inline-block { + display: none !important; +} +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + table.visible-xs { + display: table !important; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.visible-xs { + display: table-cell !important; + } +} +@media (max-width: 767px) { + .visible-xs-block { + display: block !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline { + display: inline !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline-block { + display: inline-block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm { + display: block !important; + } + table.visible-sm { + display: table !important; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-block { + display: block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline { + display: inline !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline-block { + display: inline-block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: block !important; + } + table.visible-md { + display: table !important; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.visible-md { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-block { + display: block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline { + display: inline !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline-block { + display: inline-block !important; + } +} +@media (min-width: 1200px) { + .visible-lg { + display: block !important; + } + table.visible-lg { + display: table !important; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-lg-block { + display: block !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline { + display: inline !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline-block { + display: inline-block !important; + } +} +@media (max-width: 767px) { + .hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-lg { + display: none !important; + } +} +.visible-print { + display: none !important; +} +@media print { + .visible-print { + display: block !important; + } + table.visible-print { + display: table !important; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } +} +.visible-print-block { + display: none !important; +} +@media print { + .visible-print-block { + display: block !important; + } +} +.visible-print-inline { + display: none !important; +} +@media print { + .visible-print-inline { + display: inline !important; + } +} +.visible-print-inline-block { + display: none !important; +} +@media print { + .visible-print-inline-block { + display: inline-block !important; + } +} +@media print { + .hidden-print { + display: none !important; + } +} +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url('../vendor/font-awesome/font/fontawesome-webfont.eot?v=3.2.1'); + src: url('../vendor/font-awesome/font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'), url('../vendor/font-awesome/font/fontawesome-webfont.woff?v=3.2.1') format('woff'), url('../vendor/font-awesome/font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'), url('../vendor/font-awesome/font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg'); + font-weight: normal; + font-style: normal; +} +/* FONT AWESOME CORE + * -------------------------- */ +[class^="icon-"], +[class*=" icon-"] { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; +} +[class^="icon-"]:before, +[class*=" icon-"]:before { + text-decoration: inherit; + display: inline-block; + speak: none; +} +/* makes the font 33% larger relative to the icon container */ +.icon-large:before { + vertical-align: -10%; + font-size: 1.3333333333333333em; +} +/* makes sure icons active on rollover in links */ +a [class^="icon-"], +a [class*=" icon-"] { + display: inline; +} +/* increased font size for icon-large */ +[class^="icon-"].icon-fixed-width, +[class*=" icon-"].icon-fixed-width { + display: inline-block; + width: 1.1428571428571428em; + text-align: right; + padding-right: 0.2857142857142857em; +} +[class^="icon-"].icon-fixed-width.icon-large, +[class*=" icon-"].icon-fixed-width.icon-large { + width: 1.4285714285714286em; +} +.icons-ul { + margin-left: 2.142857142857143em; + list-style-type: none; +} +.icons-ul > li { + position: relative; +} +.icons-ul .icon-li { + position: absolute; + left: -2.142857142857143em; + width: 2.142857142857143em; + text-align: center; + line-height: inherit; +} +[class^="icon-"].hide, +[class*=" icon-"].hide { + display: none; +} +.icon-muted { + color: #eeeeee; +} +.icon-light { + color: #ffffff; +} +.icon-dark { + color: #333333; +} +.icon-border { + border: solid 1px #eeeeee; + padding: .2em .25em .15em; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.icon-2x { + font-size: 2em; +} +.icon-2x.icon-border { + border-width: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.icon-3x { + font-size: 3em; +} +.icon-3x.icon-border { + border-width: 3px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.icon-4x { + font-size: 4em; +} +.icon-4x.icon-border { + border-width: 4px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.icon-5x { + font-size: 5em; +} +.icon-5x.icon-border { + border-width: 5px; + -webkit-border-radius: 7px; + -moz-border-radius: 7px; + border-radius: 7px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +[class^="icon-"].pull-left, +[class*=" icon-"].pull-left { + margin-right: .3em; +} +[class^="icon-"].pull-right, +[class*=" icon-"].pull-right { + margin-left: .3em; +} +/* BOOTSTRAP SPECIFIC CLASSES + * -------------------------- */ +/* Bootstrap 2.0 sprites.less reset */ +[class^="icon-"], +[class*=" icon-"] { + display: inline; + width: auto; + height: auto; + line-height: normal; + vertical-align: baseline; + background-image: none; + background-position: 0% 0%; + background-repeat: repeat; + margin-top: 0; +} +/* more sprites.less reset */ +.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"] { + background-image: none; +} +/* keeps Bootstrap styles with and without icons the same */ +.btn [class^="icon-"].icon-large, +.nav [class^="icon-"].icon-large, +.btn [class*=" icon-"].icon-large, +.nav [class*=" icon-"].icon-large { + line-height: .9em; +} +.btn [class^="icon-"].icon-spin, +.nav [class^="icon-"].icon-spin, +.btn [class*=" icon-"].icon-spin, +.nav [class*=" icon-"].icon-spin { + display: inline-block; +} +.nav-tabs [class^="icon-"], +.nav-pills [class^="icon-"], +.nav-tabs [class*=" icon-"], +.nav-pills [class*=" icon-"], +.nav-tabs [class^="icon-"].icon-large, +.nav-pills [class^="icon-"].icon-large, +.nav-tabs [class*=" icon-"].icon-large, +.nav-pills [class*=" icon-"].icon-large { + line-height: .9em; +} +.btn [class^="icon-"].pull-left.icon-2x, +.btn [class*=" icon-"].pull-left.icon-2x, +.btn [class^="icon-"].pull-right.icon-2x, +.btn [class*=" icon-"].pull-right.icon-2x { + margin-top: .18em; +} +.btn [class^="icon-"].icon-spin.icon-large, +.btn [class*=" icon-"].icon-spin.icon-large { + line-height: .8em; +} +.btn.btn-small [class^="icon-"].pull-left.icon-2x, +.btn.btn-small [class*=" icon-"].pull-left.icon-2x, +.btn.btn-small [class^="icon-"].pull-right.icon-2x, +.btn.btn-small [class*=" icon-"].pull-right.icon-2x { + margin-top: .25em; +} +.btn.btn-large [class^="icon-"], +.btn.btn-large [class*=" icon-"] { + margin-top: 0; +} +.btn.btn-large [class^="icon-"].pull-left.icon-2x, +.btn.btn-large [class*=" icon-"].pull-left.icon-2x, +.btn.btn-large [class^="icon-"].pull-right.icon-2x, +.btn.btn-large [class*=" icon-"].pull-right.icon-2x { + margin-top: .05em; +} +.btn.btn-large [class^="icon-"].pull-left.icon-2x, +.btn.btn-large [class*=" icon-"].pull-left.icon-2x { + margin-right: .2em; +} +.btn.btn-large [class^="icon-"].pull-right.icon-2x, +.btn.btn-large [class*=" icon-"].pull-right.icon-2x { + margin-left: .2em; +} +/* Fixes alignment in nav lists */ +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { + line-height: inherit; +} +/* EXTRAS + * -------------------------- */ +/* Stacked and layered icon */ +.icon-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: -35%; +} +.icon-stack [class^="icon-"], +.icon-stack [class*=" icon-"] { + display: block; + text-align: center; + position: absolute; + width: 100%; + height: 100%; + font-size: 1em; + line-height: inherit; + *line-height: 2em; +} +.icon-stack .icon-stack-base { + font-size: 2em; + *line-height: 1em; +} +/* Animated rotating icon */ +.icon-spin { + display: inline-block; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + -webkit-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} +/* Prevent stack and spinners from being taken inline when inside a link */ +a .icon-stack, +a .icon-spin { + display: inline-block; + text-decoration: none; +} +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + } + 100% { + -moz-transform: rotate(359deg); + } +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + } +} +@-o-keyframes spin { + 0% { + -o-transform: rotate(0deg); + } + 100% { + -o-transform: rotate(359deg); + } +} +@-ms-keyframes spin { + 0% { + -ms-transform: rotate(0deg); + } + 100% { + -ms-transform: rotate(359deg); + } +} +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(359deg); + } +} +/* Icon rotations and mirroring */ +.icon-rotate-90:before { + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -ms-transform: rotate(90deg); + -o-transform: rotate(90deg); + transform: rotate(90deg); + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); +} +.icon-rotate-180:before { + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -ms-transform: rotate(180deg); + -o-transform: rotate(180deg); + transform: rotate(180deg); + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); +} +.icon-rotate-270:before { + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -ms-transform: rotate(270deg); + -o-transform: rotate(270deg); + transform: rotate(270deg); + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); +} +.icon-flip-horizontal:before { + -webkit-transform: scale(-1, 1); + -moz-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + -o-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.icon-flip-vertical:before { + -webkit-transform: scale(1, -1); + -moz-transform: scale(1, -1); + -ms-transform: scale(1, -1); + -o-transform: scale(1, -1); + transform: scale(1, -1); +} +/* ensure rotation occurs inside anchor tags */ +a .icon-rotate-90:before, +a .icon-rotate-180:before, +a .icon-rotate-270:before, +a .icon-flip-horizontal:before, +a .icon-flip-vertical:before { + display: inline-block; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.icon-glass:before { + content: "\f000"; +} +.icon-music:before { + content: "\f001"; +} +.icon-search:before { + content: "\f002"; +} +.icon-envelope-alt:before { + content: "\f003"; +} +.icon-heart:before { + content: "\f004"; +} +.icon-star:before { + content: "\f005"; +} +.icon-star-empty:before { + content: "\f006"; +} +.icon-user:before { + content: "\f007"; +} +.icon-film:before { + content: "\f008"; +} +.icon-th-large:before { + content: "\f009"; +} +.icon-th:before { + content: "\f00a"; +} +.icon-th-list:before { + content: "\f00b"; +} +.icon-ok:before { + content: "\f00c"; +} +.icon-remove:before { + content: "\f00d"; +} +.icon-zoom-in:before { + content: "\f00e"; +} +.icon-zoom-out:before { + content: "\f010"; +} +.icon-power-off:before, +.icon-off:before { + content: "\f011"; +} +.icon-signal:before { + content: "\f012"; +} +.icon-gear:before, +.icon-cog:before { + content: "\f013"; +} +.icon-trash:before { + content: "\f014"; +} +.icon-home:before { + content: "\f015"; +} +.icon-file-alt:before { + content: "\f016"; +} +.icon-time:before { + content: "\f017"; +} +.icon-road:before { + content: "\f018"; +} +.icon-download-alt:before { + content: "\f019"; +} +.icon-download:before { + content: "\f01a"; +} +.icon-upload:before { + content: "\f01b"; +} +.icon-inbox:before { + content: "\f01c"; +} +.icon-play-circle:before { + content: "\f01d"; +} +.icon-rotate-right:before, +.icon-repeat:before { + content: "\f01e"; +} +.icon-refresh:before { + content: "\f021"; +} +.icon-list-alt:before { + content: "\f022"; +} +.icon-lock:before { + content: "\f023"; +} +.icon-flag:before { + content: "\f024"; +} +.icon-headphones:before { + content: "\f025"; +} +.icon-volume-off:before { + content: "\f026"; +} +.icon-volume-down:before { + content: "\f027"; +} +.icon-volume-up:before { + content: "\f028"; +} +.icon-qrcode:before { + content: "\f029"; +} +.icon-barcode:before { + content: "\f02a"; +} +.icon-tag:before { + content: "\f02b"; +} +.icon-tags:before { + content: "\f02c"; +} +.icon-book:before { + content: "\f02d"; +} +.icon-bookmark:before { + content: "\f02e"; +} +.icon-print:before { + content: "\f02f"; +} +.icon-camera:before { + content: "\f030"; +} +.icon-font:before { + content: "\f031"; +} +.icon-bold:before { + content: "\f032"; +} +.icon-italic:before { + content: "\f033"; +} +.icon-text-height:before { + content: "\f034"; +} +.icon-text-width:before { + content: "\f035"; +} +.icon-align-left:before { + content: "\f036"; +} +.icon-align-center:before { + content: "\f037"; +} +.icon-align-right:before { + content: "\f038"; +} +.icon-align-justify:before { + content: "\f039"; +} +.icon-list:before { + content: "\f03a"; +} +.icon-indent-left:before { + content: "\f03b"; +} +.icon-indent-right:before { + content: "\f03c"; +} +.icon-facetime-video:before { + content: "\f03d"; +} +.icon-picture:before { + content: "\f03e"; +} +.icon-pencil:before { + content: "\f040"; +} +.icon-map-marker:before { + content: "\f041"; +} +.icon-adjust:before { + content: "\f042"; +} +.icon-tint:before { + content: "\f043"; +} +.icon-edit:before { + content: "\f044"; +} +.icon-share:before { + content: "\f045"; +} +.icon-check:before { + content: "\f046"; +} +.icon-move:before { + content: "\f047"; +} +.icon-step-backward:before { + content: "\f048"; +} +.icon-fast-backward:before { + content: "\f049"; +} +.icon-backward:before { + content: "\f04a"; +} +.icon-play:before { + content: "\f04b"; +} +.icon-pause:before { + content: "\f04c"; +} +.icon-stop:before { + content: "\f04d"; +} +.icon-forward:before { + content: "\f04e"; +} +.icon-fast-forward:before { + content: "\f050"; +} +.icon-step-forward:before { + content: "\f051"; +} +.icon-eject:before { + content: "\f052"; +} +.icon-chevron-left:before { + content: "\f053"; +} +.icon-chevron-right:before { + content: "\f054"; +} +.icon-plus-sign:before { + content: "\f055"; +} +.icon-minus-sign:before { + content: "\f056"; +} +.icon-remove-sign:before { + content: "\f057"; +} +.icon-ok-sign:before { + content: "\f058"; +} +.icon-question-sign:before { + content: "\f059"; +} +.icon-info-sign:before { + content: "\f05a"; +} +.icon-screenshot:before { + content: "\f05b"; +} +.icon-remove-circle:before { + content: "\f05c"; +} +.icon-ok-circle:before { + content: "\f05d"; +} +.icon-ban-circle:before { + content: "\f05e"; +} +.icon-arrow-left:before { + content: "\f060"; +} +.icon-arrow-right:before { + content: "\f061"; +} +.icon-arrow-up:before { + content: "\f062"; +} +.icon-arrow-down:before { + content: "\f063"; +} +.icon-mail-forward:before, +.icon-share-alt:before { + content: "\f064"; +} +.icon-resize-full:before { + content: "\f065"; +} +.icon-resize-small:before { + content: "\f066"; +} +.icon-plus:before { + content: "\f067"; +} +.icon-minus:before { + content: "\f068"; +} +.icon-asterisk:before { + content: "\f069"; +} +.icon-exclamation-sign:before { + content: "\f06a"; +} +.icon-gift:before { + content: "\f06b"; +} +.icon-leaf:before { + content: "\f06c"; +} +.icon-fire:before { + content: "\f06d"; +} +.icon-eye-open:before { + content: "\f06e"; +} +.icon-eye-close:before { + content: "\f070"; +} +.icon-warning-sign:before { + content: "\f071"; +} +.icon-plane:before { + content: "\f072"; +} +.icon-calendar:before { + content: "\f073"; +} +.icon-random:before { + content: "\f074"; +} +.icon-comment:before { + content: "\f075"; +} +.icon-magnet:before { + content: "\f076"; +} +.icon-chevron-up:before { + content: "\f077"; +} +.icon-chevron-down:before { + content: "\f078"; +} +.icon-retweet:before { + content: "\f079"; +} +.icon-shopping-cart:before { + content: "\f07a"; +} +.icon-folder-close:before { + content: "\f07b"; +} +.icon-folder-open:before { + content: "\f07c"; +} +.icon-resize-vertical:before { + content: "\f07d"; +} +.icon-resize-horizontal:before { + content: "\f07e"; +} +.icon-bar-chart:before { + content: "\f080"; +} +.icon-twitter-sign:before { + content: "\f081"; +} +.icon-facebook-sign:before { + content: "\f082"; +} +.icon-camera-retro:before { + content: "\f083"; +} +.icon-key:before { + content: "\f084"; +} +.icon-gears:before, +.icon-cogs:before { + content: "\f085"; +} +.icon-comments:before { + content: "\f086"; +} +.icon-thumbs-up-alt:before { + content: "\f087"; +} +.icon-thumbs-down-alt:before { + content: "\f088"; +} +.icon-star-half:before { + content: "\f089"; +} +.icon-heart-empty:before { + content: "\f08a"; +} +.icon-signout:before { + content: "\f08b"; +} +.icon-linkedin-sign:before { + content: "\f08c"; +} +.icon-pushpin:before { + content: "\f08d"; +} +.icon-external-link:before { + content: "\f08e"; +} +.icon-signin:before { + content: "\f090"; +} +.icon-trophy:before { + content: "\f091"; +} +.icon-github-sign:before { + content: "\f092"; +} +.icon-upload-alt:before { + content: "\f093"; +} +.icon-lemon:before { + content: "\f094"; +} +.icon-phone:before { + content: "\f095"; +} +.icon-unchecked:before, +.icon-check-empty:before { + content: "\f096"; +} +.icon-bookmark-empty:before { + content: "\f097"; +} +.icon-phone-sign:before { + content: "\f098"; +} +.icon-twitter:before { + content: "\f099"; +} +.icon-facebook:before { + content: "\f09a"; +} +.icon-github:before { + content: "\f09b"; +} +.icon-unlock:before { + content: "\f09c"; +} +.icon-credit-card:before { + content: "\f09d"; +} +.icon-rss:before { + content: "\f09e"; +} +.icon-hdd:before { + content: "\f0a0"; +} +.icon-bullhorn:before { + content: "\f0a1"; +} +.icon-bell:before { + content: "\f0a2"; +} +.icon-certificate:before { + content: "\f0a3"; +} +.icon-hand-right:before { + content: "\f0a4"; +} +.icon-hand-left:before { + content: "\f0a5"; +} +.icon-hand-up:before { + content: "\f0a6"; +} +.icon-hand-down:before { + content: "\f0a7"; +} +.icon-circle-arrow-left:before { + content: "\f0a8"; +} +.icon-circle-arrow-right:before { + content: "\f0a9"; +} +.icon-circle-arrow-up:before { + content: "\f0aa"; +} +.icon-circle-arrow-down:before { + content: "\f0ab"; +} +.icon-globe:before { + content: "\f0ac"; +} +.icon-wrench:before { + content: "\f0ad"; +} +.icon-tasks:before { + content: "\f0ae"; +} +.icon-filter:before { + content: "\f0b0"; +} +.icon-briefcase:before { + content: "\f0b1"; +} +.icon-fullscreen:before { + content: "\f0b2"; +} +.icon-group:before { + content: "\f0c0"; +} +.icon-link:before { + content: "\f0c1"; +} +.icon-cloud:before { + content: "\f0c2"; +} +.icon-beaker:before { + content: "\f0c3"; +} +.icon-cut:before { + content: "\f0c4"; +} +.icon-copy:before { + content: "\f0c5"; +} +.icon-paperclip:before, +.icon-paper-clip:before { + content: "\f0c6"; +} +.icon-save:before { + content: "\f0c7"; +} +.icon-sign-blank:before { + content: "\f0c8"; +} +.icon-reorder:before { + content: "\f0c9"; +} +.icon-list-ul:before { + content: "\f0ca"; +} +.icon-list-ol:before { + content: "\f0cb"; +} +.icon-strikethrough:before { + content: "\f0cc"; +} +.icon-underline:before { + content: "\f0cd"; +} +.icon-table:before { + content: "\f0ce"; +} +.icon-magic:before { + content: "\f0d0"; +} +.icon-truck:before { + content: "\f0d1"; +} +.icon-pinterest:before { + content: "\f0d2"; +} +.icon-pinterest-sign:before { + content: "\f0d3"; +} +.icon-google-plus-sign:before { + content: "\f0d4"; +} +.icon-google-plus:before { + content: "\f0d5"; +} +.icon-money:before { + content: "\f0d6"; +} +.icon-caret-down:before { + content: "\f0d7"; +} +.icon-caret-up:before { + content: "\f0d8"; +} +.icon-caret-left:before { + content: "\f0d9"; +} +.icon-caret-right:before { + content: "\f0da"; +} +.icon-columns:before { + content: "\f0db"; +} +.icon-sort:before { + content: "\f0dc"; +} +.icon-sort-down:before { + content: "\f0dd"; +} +.icon-sort-up:before { + content: "\f0de"; +} +.icon-envelope:before { + content: "\f0e0"; +} +.icon-linkedin:before { + content: "\f0e1"; +} +.icon-rotate-left:before, +.icon-undo:before { + content: "\f0e2"; +} +.icon-legal:before { + content: "\f0e3"; +} +.icon-dashboard:before { + content: "\f0e4"; +} +.icon-comment-alt:before { + content: "\f0e5"; +} +.icon-comments-alt:before { + content: "\f0e6"; +} +.icon-bolt:before { + content: "\f0e7"; +} +.icon-sitemap:before { + content: "\f0e8"; +} +.icon-umbrella:before { + content: "\f0e9"; +} +.icon-paste:before { + content: "\f0ea"; +} +.icon-lightbulb:before { + content: "\f0eb"; +} +.icon-exchange:before { + content: "\f0ec"; +} +.icon-cloud-download:before { + content: "\f0ed"; +} +.icon-cloud-upload:before { + content: "\f0ee"; +} +.icon-user-md:before { + content: "\f0f0"; +} +.icon-stethoscope:before { + content: "\f0f1"; +} +.icon-suitcase:before { + content: "\f0f2"; +} +.icon-bell-alt:before { + content: "\f0f3"; +} +.icon-coffee:before { + content: "\f0f4"; +} +.icon-food:before { + content: "\f0f5"; +} +.icon-file-text-alt:before { + content: "\f0f6"; +} +.icon-building:before { + content: "\f0f7"; +} +.icon-hospital:before { + content: "\f0f8"; +} +.icon-ambulance:before { + content: "\f0f9"; +} +.icon-medkit:before { + content: "\f0fa"; +} +.icon-fighter-jet:before { + content: "\f0fb"; +} +.icon-beer:before { + content: "\f0fc"; +} +.icon-h-sign:before { + content: "\f0fd"; +} +.icon-plus-sign-alt:before { + content: "\f0fe"; +} +.icon-double-angle-left:before { + content: "\f100"; +} +.icon-double-angle-right:before { + content: "\f101"; +} +.icon-double-angle-up:before { + content: "\f102"; +} +.icon-double-angle-down:before { + content: "\f103"; +} +.icon-angle-left:before { + content: "\f104"; +} +.icon-angle-right:before { + content: "\f105"; +} +.icon-angle-up:before { + content: "\f106"; +} +.icon-angle-down:before { + content: "\f107"; +} +.icon-desktop:before { + content: "\f108"; +} +.icon-laptop:before { + content: "\f109"; +} +.icon-tablet:before { + content: "\f10a"; +} +.icon-mobile-phone:before { + content: "\f10b"; +} +.icon-circle-blank:before { + content: "\f10c"; +} +.icon-quote-left:before { + content: "\f10d"; +} +.icon-quote-right:before { + content: "\f10e"; +} +.icon-spinner:before { + content: "\f110"; +} +.icon-circle:before { + content: "\f111"; +} +.icon-mail-reply:before, +.icon-reply:before { + content: "\f112"; +} +.icon-github-alt:before { + content: "\f113"; +} +.icon-folder-close-alt:before { + content: "\f114"; +} +.icon-folder-open-alt:before { + content: "\f115"; +} +.icon-expand-alt:before { + content: "\f116"; +} +.icon-collapse-alt:before { + content: "\f117"; +} +.icon-smile:before { + content: "\f118"; +} +.icon-frown:before { + content: "\f119"; +} +.icon-meh:before { + content: "\f11a"; +} +.icon-gamepad:before { + content: "\f11b"; +} +.icon-keyboard:before { + content: "\f11c"; +} +.icon-flag-alt:before { + content: "\f11d"; +} +.icon-flag-checkered:before { + content: "\f11e"; +} +.icon-terminal:before { + content: "\f120"; +} +.icon-code:before { + content: "\f121"; +} +.icon-reply-all:before { + content: "\f122"; +} +.icon-mail-reply-all:before { + content: "\f122"; +} +.icon-star-half-full:before, +.icon-star-half-empty:before { + content: "\f123"; +} +.icon-location-arrow:before { + content: "\f124"; +} +.icon-crop:before { + content: "\f125"; +} +.icon-code-fork:before { + content: "\f126"; +} +.icon-unlink:before { + content: "\f127"; +} +.icon-question:before { + content: "\f128"; +} +.icon-info:before { + content: "\f129"; +} +.icon-exclamation:before { + content: "\f12a"; +} +.icon-superscript:before { + content: "\f12b"; +} +.icon-subscript:before { + content: "\f12c"; +} +.icon-eraser:before { + content: "\f12d"; +} +.icon-puzzle-piece:before { + content: "\f12e"; +} +.icon-microphone:before { + content: "\f130"; +} +.icon-microphone-off:before { + content: "\f131"; +} +.icon-shield:before { + content: "\f132"; +} +.icon-calendar-empty:before { + content: "\f133"; +} +.icon-fire-extinguisher:before { + content: "\f134"; +} +.icon-rocket:before { + content: "\f135"; +} +.icon-maxcdn:before { + content: "\f136"; +} +.icon-chevron-sign-left:before { + content: "\f137"; +} +.icon-chevron-sign-right:before { + content: "\f138"; +} +.icon-chevron-sign-up:before { + content: "\f139"; +} +.icon-chevron-sign-down:before { + content: "\f13a"; +} +.icon-html5:before { + content: "\f13b"; +} +.icon-css3:before { + content: "\f13c"; +} +.icon-anchor:before { + content: "\f13d"; +} +.icon-unlock-alt:before { + content: "\f13e"; +} +.icon-bullseye:before { + content: "\f140"; +} +.icon-ellipsis-horizontal:before { + content: "\f141"; +} +.icon-ellipsis-vertical:before { + content: "\f142"; +} +.icon-rss-sign:before { + content: "\f143"; +} +.icon-play-sign:before { + content: "\f144"; +} +.icon-ticket:before { + content: "\f145"; +} +.icon-minus-sign-alt:before { + content: "\f146"; +} +.icon-check-minus:before { + content: "\f147"; +} +.icon-level-up:before { + content: "\f148"; +} +.icon-level-down:before { + content: "\f149"; +} +.icon-check-sign:before { + content: "\f14a"; +} +.icon-edit-sign:before { + content: "\f14b"; +} +.icon-external-link-sign:before { + content: "\f14c"; +} +.icon-share-sign:before { + content: "\f14d"; +} +.icon-compass:before { + content: "\f14e"; +} +.icon-collapse:before { + content: "\f150"; +} +.icon-collapse-top:before { + content: "\f151"; +} +.icon-expand:before { + content: "\f152"; +} +.icon-euro:before, +.icon-eur:before { + content: "\f153"; +} +.icon-gbp:before { + content: "\f154"; +} +.icon-dollar:before, +.icon-usd:before { + content: "\f155"; +} +.icon-rupee:before, +.icon-inr:before { + content: "\f156"; +} +.icon-yen:before, +.icon-jpy:before { + content: "\f157"; +} +.icon-renminbi:before, +.icon-cny:before { + content: "\f158"; +} +.icon-won:before, +.icon-krw:before { + content: "\f159"; +} +.icon-bitcoin:before, +.icon-btc:before { + content: "\f15a"; +} +.icon-file:before { + content: "\f15b"; +} +.icon-file-text:before { + content: "\f15c"; +} +.icon-sort-by-alphabet:before { + content: "\f15d"; +} +.icon-sort-by-alphabet-alt:before { + content: "\f15e"; +} +.icon-sort-by-attributes:before { + content: "\f160"; +} +.icon-sort-by-attributes-alt:before { + content: "\f161"; +} +.icon-sort-by-order:before { + content: "\f162"; +} +.icon-sort-by-order-alt:before { + content: "\f163"; +} +.icon-thumbs-up:before { + content: "\f164"; +} +.icon-thumbs-down:before { + content: "\f165"; +} +.icon-youtube-sign:before { + content: "\f166"; +} +.icon-youtube:before { + content: "\f167"; +} +.icon-xing:before { + content: "\f168"; +} +.icon-xing-sign:before { + content: "\f169"; +} +.icon-youtube-play:before { + content: "\f16a"; +} +.icon-dropbox:before { + content: "\f16b"; +} +.icon-stackexchange:before { + content: "\f16c"; +} +.icon-instagram:before { + content: "\f16d"; +} +.icon-flickr:before { + content: "\f16e"; +} +.icon-adn:before { + content: "\f170"; +} +.icon-bitbucket:before { + content: "\f171"; +} +.icon-bitbucket-sign:before { + content: "\f172"; +} +.icon-tumblr:before { + content: "\f173"; +} +.icon-tumblr-sign:before { + content: "\f174"; +} +.icon-long-arrow-down:before { + content: "\f175"; +} +.icon-long-arrow-up:before { + content: "\f176"; +} +.icon-long-arrow-left:before { + content: "\f177"; +} +.icon-long-arrow-right:before { + content: "\f178"; +} +.icon-apple:before { + content: "\f179"; +} +.icon-windows:before { + content: "\f17a"; +} +.icon-android:before { + content: "\f17b"; +} +.icon-linux:before { + content: "\f17c"; +} +.icon-dribbble:before { + content: "\f17d"; +} +.icon-skype:before { + content: "\f17e"; +} +.icon-foursquare:before { + content: "\f180"; +} +.icon-trello:before { + content: "\f181"; +} +.icon-female:before { + content: "\f182"; +} +.icon-male:before { + content: "\f183"; +} +.icon-gittip:before { + content: "\f184"; +} +.icon-sun:before { + content: "\f185"; +} +.icon-moon:before { + content: "\f186"; +} +.icon-archive:before { + content: "\f187"; +} +.icon-bug:before { + content: "\f188"; +} +.icon-vk:before { + content: "\f189"; +} +.icon-weibo:before { + content: "\f18a"; +} +.icon-renren:before { + content: "\f18b"; +} diff --git a/themes/demo/assets/fonts/lato-black-webfont.eot b/themes/demo/assets/fonts/lato-black-webfont.eot new file mode 100644 index 0000000..0571595 Binary files /dev/null and b/themes/demo/assets/fonts/lato-black-webfont.eot differ diff --git a/themes/demo/assets/fonts/lato-black-webfont.svg b/themes/demo/assets/fonts/lato-black-webfont.svg new file mode 100644 index 0000000..1784890 --- /dev/null +++ b/themes/demo/assets/fonts/lato-black-webfont.svg @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/themes/demo/assets/fonts/lato-black-webfont.ttf b/themes/demo/assets/fonts/lato-black-webfont.ttf new file mode 100644 index 0000000..8d1d5e7 Binary files /dev/null and b/themes/demo/assets/fonts/lato-black-webfont.ttf differ diff --git a/themes/demo/assets/fonts/lato-black-webfont.woff b/themes/demo/assets/fonts/lato-black-webfont.woff new file mode 100644 index 0000000..980a9a1 Binary files /dev/null and b/themes/demo/assets/fonts/lato-black-webfont.woff differ diff --git a/themes/demo/assets/fonts/lato-italic-webfont.eot b/themes/demo/assets/fonts/lato-italic-webfont.eot new file mode 100644 index 0000000..d476f10 Binary files /dev/null and b/themes/demo/assets/fonts/lato-italic-webfont.eot differ diff --git a/themes/demo/assets/fonts/lato-italic-webfont.svg b/themes/demo/assets/fonts/lato-italic-webfont.svg new file mode 100644 index 0000000..e077164 --- /dev/null +++ b/themes/demo/assets/fonts/lato-italic-webfont.svg @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/themes/demo/assets/fonts/lato-italic-webfont.ttf b/themes/demo/assets/fonts/lato-italic-webfont.ttf new file mode 100644 index 0000000..9c489f8 Binary files /dev/null and b/themes/demo/assets/fonts/lato-italic-webfont.ttf differ diff --git a/themes/demo/assets/fonts/lato-italic-webfont.woff b/themes/demo/assets/fonts/lato-italic-webfont.woff new file mode 100644 index 0000000..01bf1e0 Binary files /dev/null and b/themes/demo/assets/fonts/lato-italic-webfont.woff differ diff --git a/themes/demo/assets/fonts/lato-light-webfont.eot b/themes/demo/assets/fonts/lato-light-webfont.eot new file mode 100644 index 0000000..ceb7b48 Binary files /dev/null and b/themes/demo/assets/fonts/lato-light-webfont.eot differ diff --git a/themes/demo/assets/fonts/lato-light-webfont.svg b/themes/demo/assets/fonts/lato-light-webfont.svg new file mode 100644 index 0000000..7957db9 --- /dev/null +++ b/themes/demo/assets/fonts/lato-light-webfont.svg @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/themes/demo/assets/fonts/lato-light-webfont.ttf b/themes/demo/assets/fonts/lato-light-webfont.ttf new file mode 100644 index 0000000..714185a Binary files /dev/null and b/themes/demo/assets/fonts/lato-light-webfont.ttf differ diff --git a/themes/demo/assets/fonts/lato-light-webfont.woff b/themes/demo/assets/fonts/lato-light-webfont.woff new file mode 100644 index 0000000..5988c8d Binary files /dev/null and b/themes/demo/assets/fonts/lato-light-webfont.woff differ diff --git a/themes/demo/assets/fonts/lato-regular-webfont.eot b/themes/demo/assets/fonts/lato-regular-webfont.eot new file mode 100644 index 0000000..e6f2d81 Binary files /dev/null and b/themes/demo/assets/fonts/lato-regular-webfont.eot differ diff --git a/themes/demo/assets/fonts/lato-regular-webfont.svg b/themes/demo/assets/fonts/lato-regular-webfont.svg new file mode 100644 index 0000000..2d53540 --- /dev/null +++ b/themes/demo/assets/fonts/lato-regular-webfont.svg @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/themes/demo/assets/fonts/lato-regular-webfont.ttf b/themes/demo/assets/fonts/lato-regular-webfont.ttf new file mode 100644 index 0000000..528f46a Binary files /dev/null and b/themes/demo/assets/fonts/lato-regular-webfont.ttf differ diff --git a/themes/demo/assets/fonts/lato-regular-webfont.woff b/themes/demo/assets/fonts/lato-regular-webfont.woff new file mode 100644 index 0000000..95be324 Binary files /dev/null and b/themes/demo/assets/fonts/lato-regular-webfont.woff differ diff --git a/themes/demo/assets/images/october.png b/themes/demo/assets/images/october.png new file mode 100644 index 0000000..3b5bd99 Binary files /dev/null and b/themes/demo/assets/images/october.png differ diff --git a/themes/demo/assets/images/theme-preview.png b/themes/demo/assets/images/theme-preview.png new file mode 100644 index 0000000..b235f1f Binary files /dev/null and b/themes/demo/assets/images/theme-preview.png differ diff --git a/themes/demo/assets/javascript/app.js b/themes/demo/assets/javascript/app.js new file mode 100644 index 0000000..284f028 --- /dev/null +++ b/themes/demo/assets/javascript/app.js @@ -0,0 +1,48 @@ +/* + * Application + */ + +$(document).tooltip({ + selector: "[data-toggle=tooltip]" +}) + +/* + * Auto hide navbar + */ +jQuery(document).ready(function($){ + var $header = $('.navbar-autohide'), + scrolling = false, + previousTop = 0, + currentTop = 0, + scrollDelta = 10, + scrollOffset = 150 + + $(window).on('scroll', function(){ + if (!scrolling) { + scrolling = true + + if (!window.requestAnimationFrame) { + setTimeout(autoHideHeader, 250) + } + else { + requestAnimationFrame(autoHideHeader) + } + } + }) + + function autoHideHeader() { + var currentTop = $(window).scrollTop() + + // Scrolling up + if (previousTop - currentTop > scrollDelta) { + $header.removeClass('is-hidden') + } + else if (currentTop - previousTop > scrollDelta && currentTop > scrollOffset) { + // Scrolling down + $header.addClass('is-hidden') + } + + previousTop = currentTop + scrolling = false + } +}); \ No newline at end of file diff --git a/themes/demo/assets/less/controls/example.less b/themes/demo/assets/less/controls/example.less new file mode 100644 index 0000000..fb33baf --- /dev/null +++ b/themes/demo/assets/less/controls/example.less @@ -0,0 +1,5 @@ +// +// Example control +// + +.example-control {} diff --git a/themes/demo/assets/less/elements/callouts.less b/themes/demo/assets/less/elements/callouts.less new file mode 100644 index 0000000..b4bec95 --- /dev/null +++ b/themes/demo/assets/less/elements/callouts.less @@ -0,0 +1,50 @@ +// +// Callouts +// -------------------------------------------------- + +.callout { + margin-bottom: @line-height-computed; + padding: @callout-padding; + border-left: 3px solid @callout-border; + code, .highlight { + } + h4 { + margin-top: 0; + margin-bottom: 5px; + } + p:last-child { + margin-bottom: 0; + } +} + +.callout-danger { + background-color: @callout-danger-bg; + border-color: @callout-danger-border; + h4 { + color: @callout-danger-text; + } +} + +.callout-warning { + background-color: @callout-warning-bg; + border-color: @callout-warning-border; + h4 { + color: @callout-warning-text; + } +} + +.callout-info { + background-color: @callout-info-bg; + border-color: @callout-info-border; + h4 { + color: @callout-info-text; + } +} + +.callout-success { + background-color: @callout-success-bg; + border-color: @callout-success-border; + h4 { + color: @callout-success-text; + } +} diff --git a/themes/demo/assets/less/elements/navbar.less b/themes/demo/assets/less/elements/navbar.less new file mode 100644 index 0000000..5364911 --- /dev/null +++ b/themes/demo/assets/less/elements/navbar.less @@ -0,0 +1,89 @@ +.navbar-header .navbar-brand { + padding-left: 55px; + background-image: url('../images/october.png'); + background-size: auto 60%; + background-repeat: no-repeat; + background-position: 7px 50%; + transition: color 0.2s ease 0.05s; + color: #ccc; + &:hover { + color: #fff; + } +} + +.navbar-nav li.separator { + width: 1px; + background: rgba(255, 255, 255, 0.3); + height: 30px; + margin: 20px 10px 0 10px; +} + +.navbar-autohide { + transition: transform .5s; +} + +.navbar-autohide.is-hidden { + transform: translateY(-(@navbar-height + 2px)); +} + +.navbar-collapse:not(.in):not(.collapsing) .navbar-nav li { + > a { + transition: color 0.2s ease 0.05s; + } + + > a:after { + position: absolute; + height: 4px; + bottom: -1px; + content: ''; + border-radius: 4px; + z-index: 5; + width: 0; + left: 50%; + transition: all 0.2s ease 0.05s; + } + + &.active > a:after { + width: 100% !important; + left: 0 !important; + } + + &:hover > a:after { + width: 100%; + left: 0; + } + + &.active > a { + background: transparent; + } +} + +.navbar-inverse .navbar-collapse:not(.in):not(.collapsing) .navbar-nav li { + &.active > a:after, + > a:hover:after { + background: @navbar-inverse-stripe-color-active; + } + + &.active > a:hover:after { + background: @navbar-inverse-stripe-color-active; + } + + > a:hover:after { + background: @navbar-inverse-stripe-color-hover; + } +} + +.navbar-default .navbar-collapse:not(.in):not(.collapsing) .navbar-nav li { + &.active > a:after, + > a:hover:after { + background: @navbar-default-stripe-color-active; + } + + &.active > a:hover:after { + background: @navbar-default-stripe-color-active; + } + + > a:hover:after { + background: @navbar-default-stripe-color-hover; + } +} diff --git a/themes/demo/assets/less/elements/utilities.less b/themes/demo/assets/less/elements/utilities.less new file mode 100644 index 0000000..317910f --- /dev/null +++ b/themes/demo/assets/less/elements/utilities.less @@ -0,0 +1,138 @@ +// +// Typography +// -------------------------------------------------- + +.t-ww { word-wrap: break-word; word-break: break-word; } + +// +// Borders +// -------------------------------------------------- + +.border-none { border: 0; } + +// +// Positioning +// -------------------------------------------------- + +.pos-r { position: relative !important; } +.pos-a { position: absolute !important; } +.pos-f { position: fixed !important; } + +// +// Width +// -------------------------------------------------- + +.w-sm { width: 25% !important; } +.w-md { width: 50% !important; } +.w-lg { width: 75% !important; } +.w-full { width: 100% !important; } +.w-50 { width: 50px !important; } +.w-100 { width: 100px !important; } +.w-120 { width: 120px !important; } +.w-130 { width: 130px !important; } +.w-140 { width: 140px !important; } +.w-150 { width: 150px !important; } +.w-200 { width: 200px !important; } +.w-300 { width: 300px !important; } +.w-350 { width: 350px !important; } + +// +// Margins +// -------------------------------------------------- + +.m-a-0 { margin: 0 !important; } +.m-t-0 { margin-top: 0 !important; } +.m-r-0 { margin-right: 0 !important; } +.m-b-0 { margin-bottom: 0 !important; } +.m-l-0 { margin-left: 0 !important; } + +.m-a { margin: @spacer !important; } +.m-t { margin-top: @spacer-y !important; } +.m-r { margin-right: @spacer-x !important; } +.m-b { margin-bottom: @spacer-y !important; } +.m-l { margin-left: @spacer-x !important; } +.m-x { margin-right: @spacer-x !important; margin-left: @spacer-x !important; } +.m-y { margin-top: @spacer-y !important; margin-bottom: @spacer-y !important; } +.m-x-auto { margin-right: auto !important; margin-left: auto !important; } + +.m-a-xs { margin: (@spacer-y / 4) !important; } +.m-t-xs { margin-top: (@spacer-y / 4) !important; } +.m-r-xs { margin-right: (@spacer-y / 4) !important; } +.m-b-xs { margin-bottom: (@spacer-y / 4) !important; } +.m-l-xs { margin-left: (@spacer-y / 4) !important; } +.m-x-xs { margin-right: (@spacer-x / 4) !important; margin-left: (@spacer-x / 4) !important; } +.m-y-xs { margin-top: (@spacer-y / 4) !important; margin-bottom: (@spacer-y / 4) !important; } + +.m-a-sm { margin: (@spacer-y / 2) !important; } +.m-t-sm { margin-top: (@spacer-y / 2) !important; } +.m-r-sm { margin-right: (@spacer-y / 2) !important; } +.m-b-sm { margin-bottom: (@spacer-y / 2) !important; } +.m-l-sm { margin-left: (@spacer-y / 2) !important; } +.m-x-sm { margin-right: (@spacer-x / 2) !important; margin-left: (@spacer-x / 2) !important; } +.m-y-sm { margin-top: (@spacer-y / 2) !important; margin-bottom: (@spacer-y / 2) !important; } + +.m-a-md { margin: (@spacer-y * 1.5) !important; } +.m-t-md { margin-top: (@spacer-y * 1.5) !important; } +.m-r-md { margin-right: (@spacer-y * 1.5) !important; } +.m-b-md { margin-bottom: (@spacer-y * 1.5) !important; } +.m-l-md { margin-left: (@spacer-y * 1.5) !important; } +.m-x-md { margin-right: (@spacer-x * 1.5) !important; margin-left: (@spacer-x * 1.5) !important; } +.m-y-md { margin-top: (@spacer-y * 1.5) !important; margin-bottom: (@spacer-y * 1.5) !important; } + +.m-a-lg { margin: (@spacer-y * 3) !important; } +.m-t-lg { margin-top: (@spacer-y * 3) !important; } +.m-r-lg { margin-right: (@spacer-y * 3) !important; } +.m-b-lg { margin-bottom: (@spacer-y * 3) !important; } +.m-l-lg { margin-left: (@spacer-y * 3) !important; } +.m-x-lg { margin-right: (@spacer-x * 3) !important; margin-left: (@spacer-x * 3) !important; } +.m-y-lg { margin-top: (@spacer-y * 3) !important; margin-bottom: (@spacer-y * 3) !important; } + +// +// Padding +// -------------------------------------------------- + +.p-a-0 { padding: 0 !important; } +.p-t-0 { padding-top: 0 !important; } +.p-r-0 { padding-right: 0 !important; } +.p-b-0 { padding-bottom: 0 !important; } +.p-l-0 { padding-left: 0 !important; } + +.p-a { padding: @spacer !important; } +.p-t { padding-top: @spacer-y !important; } +.p-r { padding-right: @spacer-x !important; } +.p-b { padding-bottom: @spacer-y !important; } +.p-l { padding-left: @spacer-x !important; } +.p-x { padding-right: @spacer-x !important; padding-left: @spacer-x !important; } +.p-y { padding-top: @spacer-y !important; padding-bottom: @spacer-y !important; } + +.p-a-xs { padding: (@spacer-y / 4) !important; } +.p-t-xs { padding-top: (@spacer-y / 4) !important; } +.p-r-xs { padding-right: (@spacer-y / 4) !important; } +.p-b-xs { padding-bottom: (@spacer-y / 4) !important; } +.p-l-xs { padding-left: (@spacer-y / 4) !important; } +.p-x-xs { padding-right: (@spacer-x / 4) !important; padding-left: (@spacer-x / 4) !important; } +.p-y-xs { padding-top: (@spacer-y / 4) !important; padding-bottom: (@spacer-y / 4) !important; } + +.p-a-sm { padding: (@spacer-y / 2) !important; } +.p-t-sm { padding-top: (@spacer-y / 2) !important; } +.p-r-sm { padding-right: (@spacer-y / 2) !important; } +.p-b-sm { padding-bottom: (@spacer-y / 2) !important; } +.p-l-sm { padding-left: (@spacer-y / 2) !important; } +.p-x-sm { padding-right: (@spacer-x / 2) !important; padding-left: (@spacer-x / 2) !important; } +.p-y-sm { padding-top: (@spacer-y / 2) !important; padding-bottom: (@spacer-y / 2) !important; } + +.p-a-md { padding: (@spacer-y * 1.5) !important; } +.p-t-md { padding-top: (@spacer-y * 1.5) !important; } +.p-r-md { padding-right: (@spacer-y * 1.5) !important; } +.p-b-md { padding-bottom: (@spacer-y * 1.5) !important; } +.p-l-md { padding-left: (@spacer-y * 1.5) !important; } +.p-x-md { padding-right: (@spacer-x * 1.5) !important; padding-left: (@spacer-x * 1.5) !important; } +.p-y-md { padding-top: (@spacer-y * 1.5) !important; padding-bottom: (@spacer-y * 1.5) !important; } + +.p-a-lg { padding: (@spacer-y * 3) !important; } +.p-t-lg { padding-top: (@spacer-y * 3) !important; } +.p-r-lg { padding-right: (@spacer-y * 3) !important; } +.p-b-lg { padding-bottom: (@spacer-y * 3) !important; } +.p-l-lg { padding-left: (@spacer-y * 3) !important; } +.p-x-lg { padding-right: (@spacer-x * 3) !important; padding-left: (@spacer-x * 3) !important; } +.p-y-lg { padding-top: (@spacer-y * 3) !important; padding-bottom: (@spacer-y * 3) !important; } diff --git a/themes/demo/assets/less/layouts/default.less b/themes/demo/assets/less/layouts/default.less new file mode 100644 index 0000000..cd16dd5 --- /dev/null +++ b/themes/demo/assets/less/layouts/default.less @@ -0,0 +1,10 @@ +// +// Layouts +// +// Styles specific to different page layouts. +// + +// Used by the fixed navbar +body { + padding-top: 70px; +} diff --git a/themes/demo/assets/less/pages/ajax.less b/themes/demo/assets/less/pages/ajax.less new file mode 100644 index 0000000..47a1b0a --- /dev/null +++ b/themes/demo/assets/less/pages/ajax.less @@ -0,0 +1,5 @@ +// +// AJAX +// +// Styles specific to the AJAX page +// diff --git a/themes/demo/assets/less/pages/plugins.less b/themes/demo/assets/less/pages/plugins.less new file mode 100644 index 0000000..b4c2cbf --- /dev/null +++ b/themes/demo/assets/less/pages/plugins.less @@ -0,0 +1,5 @@ +// +// Plugins +// +// Styles specific to the plugins page +// diff --git a/themes/demo/assets/less/theme.less b/themes/demo/assets/less/theme.less new file mode 100644 index 0000000..9c90f1d --- /dev/null +++ b/themes/demo/assets/less/theme.less @@ -0,0 +1,46 @@ +// +// Boot theme +// + +@import "theme/boot"; + +// +// Fonts +// + +@import "theme/fonts"; + +// +// Controls +// +// These are interactive controls used in the site. +// + +@import "controls/example"; + +// +// Elements +// +// These are reusable elements used in the site. +// + +@import "elements/callouts"; +@import "elements/utilities"; +@import "elements/navbar"; + +// +// Layouts +// +// Include these here, or directly on the layouts +// + +@import "layouts/default"; + +// +// Pages +// +// Include these here, or directly on the pages +// + +@import "pages/ajax"; +@import "pages/plugins"; diff --git a/themes/demo/assets/less/theme/boot.less b/themes/demo/assets/less/theme/boot.less new file mode 100644 index 0000000..dbc98c9 --- /dev/null +++ b/themes/demo/assets/less/theme/boot.less @@ -0,0 +1,12 @@ +// +// Boot file +// +// Includes non-output LESS files such as mixins and variables +// + +@import "../../vendor/bootstrap/less/variables.less"; +@import "../../vendor/bootstrap/less/mixins.less"; +@import "../../vendor/font-awesome/less/variables.less"; +@import "../../vendor/font-awesome/less/mixins.less"; +@import "mixins.less"; +@import "variables.less"; diff --git a/themes/demo/assets/less/theme/fonts.less b/themes/demo/assets/less/theme/fonts.less new file mode 100644 index 0000000..9e2a2aa --- /dev/null +++ b/themes/demo/assets/less/theme/fonts.less @@ -0,0 +1,59 @@ +// +// Fonts file +// +// Allocated area for font definitions used by this application +// + +@font-face { + font-family: 'lato'; + src: url('../fonts/lato-black-webfont.eot'); + src: url('../fonts/lato-black-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/lato-black-webfont.svg#latoblack') format('svg'), + url('../fonts/lato-black-webfont.woff') format('woff'), + url('../fonts/lato-black-webfont.ttf') format('truetype'); + font-weight: 700; + font-style: normal; +} + +@font-face { + font-family: 'lato'; + src: url('../fonts/lato-italic-webfont.eot'); + src: url('../fonts/lato-italic-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/lato-italic-webfont.svg#latoitalic') format('svg'), + url('../fonts/lato-italic-webfont.woff') format('woff'), + url('../fonts/lato-italic-webfont.ttf') format('truetype'); + font-weight: 400; + font-style: italic; +} + +@font-face { + font-family: 'lato'; + src: url('../fonts/lato-regular-webfont.eot'); + src: url('../fonts/lato-regular-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/lato-regular-webfont.svg#latoregular') format('svg'), + url('../fonts/lato-regular-webfont.woff') format('woff'), + url('../fonts/lato-regular-webfont.ttf') format('truetype'); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family: 'lato'; + src: url('../fonts/lato-light-webfont.eot'); + src: url('../fonts/lato-light-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/lato-light-webfont.svg#latolight') format('svg'), + url('../fonts/lato-light-webfont.woff') format('woff'), + url('../fonts/lato-light-webfont.ttf') format('truetype'); + font-weight: 300; + font-style: normal; +} + +// +// Chrome exhibits strange behavior when custom fonts are used +// on select inputs. This fixes the garbled text. +// +@media screen and (-webkit-min-device-pixel-ratio:0) { + select { + font-family: sans-serif; + } +} \ No newline at end of file diff --git a/themes/demo/assets/less/theme/mixins.less b/themes/demo/assets/less/theme/mixins.less new file mode 100644 index 0000000..65b7771 --- /dev/null +++ b/themes/demo/assets/less/theme/mixins.less @@ -0,0 +1,5 @@ +// +// Mixins file +// +// Space for any custom mixins used by this application +// diff --git a/themes/demo/assets/less/theme/variables.less b/themes/demo/assets/less/theme/variables.less new file mode 100644 index 0000000..6e5ce0a --- /dev/null +++ b/themes/demo/assets/less/theme/variables.less @@ -0,0 +1,67 @@ +// +// Variables file +// +// Space for any custom variables used by this application +// + +// Icons +// -------------------------------------------------- +@FontAwesomePath: "../vendor/font-awesome/font"; + +// Brands +// -------------------------------------------------- +@brand-primary: #3097d1; +@brand-info: #8eb4cb; +@brand-success: #4eb76e; +@brand-warning: #cbb956; +@brand-danger: #bf5329; + +// Typography +// -------------------------------------------------- +@font-family-sans-serif: "lato", sans-serif; +@line-height-base: 1.6; +@font-size-base: 16px; +@text-color: #586667; +@headings-color: #1f3f50; +@jumbotron-heading-color: @headings-color; + +// Spacing +// -------------------------------------------------- +@spacer: 20px; +@spacer-y: @spacer; +@spacer-x: @spacer; + +// Navbar +// -------------------------------------------------- +@navbar-height: 70px; +@navbar-margin-bottom: 0; + +@navbar-inverse-bg: #000; +@navbar-inverse-link-color: rgba(255,255,255,0.6); + +@navbar-inverse-stripe-color-active: #000; +@navbar-inverse-stripe-color-hover: #e67e22; +@navbar-default-stripe-color-active: #64ae5b; +@navbar-default-stripe-color-hover: #93dc8a; + +// Callouts +// -------------------------------------------------- +@callout-padding: 20px; +@callout-border-radius: @border-radius-base; +@callout-border: @gray-lighter; + +@callout-info-bg: #f4f8fa; +@callout-info-text: @state-info-text; +@callout-info-border: @state-info-border; + +@callout-warning-bg: #faf8f0; +@callout-warning-text: @state-warning-text; +@callout-warning-border: @state-warning-border; + +@callout-danger-bg: #fdf7f7; +@callout-danger-text: @state-danger-text; +@callout-danger-border: @state-danger-border; + +@callout-success-bg: #f9fdf7; +@callout-success-text: @state-success-text; +@callout-success-border: @state-success-border; \ No newline at end of file diff --git a/themes/demo/assets/less/vendor.less b/themes/demo/assets/less/vendor.less new file mode 100644 index 0000000..826ce0c --- /dev/null +++ b/themes/demo/assets/less/vendor.less @@ -0,0 +1,66 @@ +// +// Vendor file +// +// Includes all vendor LESS files that contain usable output +// + +@import "theme/boot"; + +// +// Bootstrap +// + +// Reset +@import "../vendor/bootstrap/less/normalize"; +@import "../vendor/bootstrap/less/print"; + +// Core CSS +@import "../vendor/bootstrap/less/scaffolding"; +@import "../vendor/bootstrap/less/type"; +@import "../vendor/bootstrap/less/code"; +@import "../vendor/bootstrap/less/grid"; +@import "../vendor/bootstrap/less/tables"; +@import "../vendor/bootstrap/less/forms"; +@import "../vendor/bootstrap/less/buttons"; + +// Components +@import "../vendor/bootstrap/less/component-animations"; +@import "../vendor/bootstrap/less/dropdowns"; +@import "../vendor/bootstrap/less/button-groups"; +@import "../vendor/bootstrap/less/input-groups"; +@import "../vendor/bootstrap/less/navs"; +@import "../vendor/bootstrap/less/navbar"; +@import "../vendor/bootstrap/less/breadcrumbs"; +@import "../vendor/bootstrap/less/pagination"; +@import "../vendor/bootstrap/less/pager"; +@import "../vendor/bootstrap/less/labels"; +@import "../vendor/bootstrap/less/badges"; +@import "../vendor/bootstrap/less/jumbotron"; +@import "../vendor/bootstrap/less/thumbnails"; +@import "../vendor/bootstrap/less/alerts"; +@import "../vendor/bootstrap/less/progress-bars"; +@import "../vendor/bootstrap/less/media"; +@import "../vendor/bootstrap/less/list-group"; +@import "../vendor/bootstrap/less/panels"; +@import "../vendor/bootstrap/less/wells"; +@import "../vendor/bootstrap/less/close"; + +// Components w/ JavaScript +@import "../vendor/bootstrap/less/modals"; +@import "../vendor/bootstrap/less/tooltip"; +@import "../vendor/bootstrap/less/popovers"; +@import "../vendor/bootstrap/less/carousel"; + +// Utility classes +@import "../vendor/bootstrap/less/utilities"; +@import "../vendor/bootstrap/less/responsive-utilities"; + +// +// Font Awesome +// + +@import "../vendor/font-awesome/less/path"; +@import "../vendor/font-awesome/less/core"; +@import "../vendor/font-awesome/less/bootstrap"; +@import "../vendor/font-awesome/less/extras"; +@import "../vendor/font-awesome/less/icons"; diff --git a/themes/demo/assets/vendor/bootstrap.js b/themes/demo/assets/vendor/bootstrap.js new file mode 100644 index 0000000..9bcd2fc --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap.js @@ -0,0 +1,7 @@ +/*! + * 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&&jdocument.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
        ',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-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.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:''}),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[a]&&(void 0===e[a+1]||b .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=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); \ No newline at end of file diff --git a/themes/demo/assets/vendor/bootstrap/js/affix.js b/themes/demo/assets/vendor/bootstrap/js/affix.js new file mode 100644 index 0000000..7f65168 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/js/affix.js @@ -0,0 +1,162 @@ +/* ======================================================================== + * Bootstrap: affix.js v3.3.7 + * http://getbootstrap.com/javascript/#affix + * ======================================================================== + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // AFFIX CLASS DEFINITION + // ====================== + + var Affix = function (element, options) { + this.options = $.extend({}, Affix.DEFAULTS, options) + + this.$target = $(this.options.target) + .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) + .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) + + this.$element = $(element) + this.affixed = null + this.unpin = null + this.pinnedOffset = null + + this.checkPosition() + } + + Affix.VERSION = '3.3.7' + + Affix.RESET = 'affix affix-top affix-bottom' + + Affix.DEFAULTS = { + offset: 0, + target: window + } + + Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) { + var scrollTop = this.$target.scrollTop() + var position = this.$element.offset() + var targetHeight = this.$target.height() + + if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false + + if (this.affixed == 'bottom') { + if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom' + return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom' + } + + var initializing = this.affixed == null + var colliderTop = initializing ? scrollTop : position.top + var colliderHeight = initializing ? targetHeight : height + + if (offsetTop != null && scrollTop <= offsetTop) return 'top' + if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' + + return false + } + + Affix.prototype.getPinnedOffset = function () { + if (this.pinnedOffset) return this.pinnedOffset + this.$element.removeClass(Affix.RESET).addClass('affix') + var scrollTop = this.$target.scrollTop() + var position = this.$element.offset() + return (this.pinnedOffset = position.top - scrollTop) + } + + Affix.prototype.checkPositionWithEventLoop = function () { + setTimeout($.proxy(this.checkPosition, this), 1) + } + + Affix.prototype.checkPosition = function () { + if (!this.$element.is(':visible')) return + + var height = this.$element.height() + var offset = this.options.offset + var offsetTop = offset.top + var offsetBottom = offset.bottom + var scrollHeight = Math.max($(document).height(), $(document.body).height()) + + if (typeof offset != 'object') offsetBottom = offsetTop = offset + if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) + if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) + + var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom) + + if (this.affixed != affix) { + if (this.unpin != null) this.$element.css('top', '') + + var affixType = 'affix' + (affix ? '-' + affix : '') + var e = $.Event(affixType + '.bs.affix') + + this.$element.trigger(e) + + if (e.isDefaultPrevented()) return + + this.affixed = affix + this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null + + this.$element + .removeClass(Affix.RESET) + .addClass(affixType) + .trigger(affixType.replace('affix', 'affixed') + '.bs.affix') + } + + if (affix == 'bottom') { + this.$element.offset({ + top: scrollHeight - height - offsetBottom + }) + } + } + + + // AFFIX PLUGIN DEFINITION + // ======================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.affix') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.affix', (data = new Affix(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.affix + + $.fn.affix = Plugin + $.fn.affix.Constructor = Affix + + + // AFFIX NO CONFLICT + // ================= + + $.fn.affix.noConflict = function () { + $.fn.affix = old + return this + } + + + // AFFIX DATA-API + // ============== + + $(window).on('load', function () { + $('[data-spy="affix"]').each(function () { + var $spy = $(this) + var data = $spy.data() + + data.offset = data.offset || {} + + if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom + if (data.offsetTop != null) data.offset.top = data.offsetTop + + Plugin.call($spy, data) + }) + }) + +}(jQuery); diff --git a/themes/demo/assets/vendor/bootstrap/js/alert.js b/themes/demo/assets/vendor/bootstrap/js/alert.js new file mode 100644 index 0000000..db97f3b --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/js/alert.js @@ -0,0 +1,94 @@ +/* ======================================================================== + * Bootstrap: alert.js v3.3.7 + * http://getbootstrap.com/javascript/#alerts + * ======================================================================== + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.VERSION = '3.3.7' + + Alert.TRANSITION_DURATION = 150 + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector === '#' ? [] : selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.closest('.alert') + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + // detach from parent, fire event then clean up data + $parent.detach().trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one('bsTransitionEnd', removeElement) + .emulateTransitionEnd(Alert.TRANSITION_DURATION) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + var old = $.fn.alert + + $.fn.alert = Plugin + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(jQuery); diff --git a/themes/demo/assets/vendor/bootstrap/js/button.js b/themes/demo/assets/vendor/bootstrap/js/button.js new file mode 100644 index 0000000..843b39c --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/js/button.js @@ -0,0 +1,125 @@ +/* ======================================================================== + * Bootstrap: button.js v3.3.7 + * http://getbootstrap.com/javascript/#buttons + * ======================================================================== + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + this.isLoading = false + } + + Button.VERSION = '3.3.7' + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state += 'Text' + + if (data.resetText == null) $el.data('resetText', $el[val]()) + + // push to event loop to allow forms to submit + setTimeout($.proxy(function () { + $el[val](data[state] == null ? this.options[state] : data[state]) + + if (state == 'loadingText') { + this.isLoading = true + $el.addClass(d).attr(d, d).prop(d, true) + } else if (this.isLoading) { + this.isLoading = false + $el.removeClass(d).removeAttr(d).prop(d, false) + } + }, this), 0) + } + + Button.prototype.toggle = function () { + var changed = true + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') == 'radio') { + if ($input.prop('checked')) changed = false + $parent.find('.active').removeClass('active') + this.$element.addClass('active') + } else if ($input.prop('type') == 'checkbox') { + if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false + this.$element.toggleClass('active') + } + $input.prop('checked', this.$element.hasClass('active')) + if (changed) $input.trigger('change') + } else { + this.$element.attr('aria-pressed', !this.$element.hasClass('active')) + this.$element.toggleClass('active') + } + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + var old = $.fn.button + + $.fn.button = Plugin + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document) + .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { + var $btn = $(e.target).closest('.btn') + Plugin.call($btn, 'toggle') + if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) { + // Prevent double click on radios, and the double selections (so cancellation) on checkboxes + e.preventDefault() + // The target component still receive the focus + if ($btn.is('input,button')) $btn.trigger('focus') + else $btn.find('input:visible,button:visible').first().trigger('focus') + } + }) + .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { + $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) + }) + +}(jQuery); diff --git a/themes/demo/assets/vendor/bootstrap/js/carousel.js b/themes/demo/assets/vendor/bootstrap/js/carousel.js new file mode 100644 index 0000000..6ff954c --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/js/carousel.js @@ -0,0 +1,237 @@ +/* ======================================================================== + * Bootstrap: carousel.js v3.3.7 + * http://getbootstrap.com/javascript/#carousel + * ======================================================================== + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = null + this.sliding = null + this.interval = null + this.$active = null + this.$items = null + + this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) + + this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element + .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) + .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) + } + + Carousel.VERSION = '3.3.7' + + Carousel.TRANSITION_DURATION = 600 + + Carousel.DEFAULTS = { + interval: 5000, + pause: 'hover', + wrap: true, + keyboard: true + } + + Carousel.prototype.keydown = function (e) { + if (/input|textarea/i.test(e.target.tagName)) return + switch (e.which) { + case 37: this.prev(); break + case 39: this.next(); break + default: return + } + + e.preventDefault() + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getItemIndex = function (item) { + this.$items = item.parent().children('.item') + return this.$items.index(item || this.$active) + } + + Carousel.prototype.getItemForDirection = function (direction, active) { + var activeIndex = this.getItemIndex(active) + var willWrap = (direction == 'prev' && activeIndex === 0) + || (direction == 'next' && activeIndex == (this.$items.length - 1)) + if (willWrap && !this.options.wrap) return active + var delta = direction == 'prev' ? -1 : 1 + var itemIndex = (activeIndex + delta) % this.$items.length + return this.$items.eq(itemIndex) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || this.getItemForDirection(type, $active) + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var that = this + + if ($next.hasClass('active')) return (this.sliding = false) + + var relatedTarget = $next[0] + var slideEvent = $.Event('slide.bs.carousel', { + relatedTarget: relatedTarget, + direction: direction + }) + this.$element.trigger(slideEvent) + if (slideEvent.isDefaultPrevented()) return + + this.sliding = true + + isCycling && this.pause() + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) + $nextIndicator && $nextIndicator.addClass('active') + } + + var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" + if ($.support.transition && this.$element.hasClass('slide')) { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one('bsTransitionEnd', function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { + that.$element.trigger(slidEvent) + }, 0) + }) + .emulateTransitionEnd(Carousel.TRANSITION_DURATION) + } else { + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger(slidEvent) + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + var old = $.fn.carousel + + $.fn.carousel = Plugin + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + var clickHandler = function (e) { + var href + var $this = $(this) + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 + if (!$target.hasClass('carousel')) return + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + Plugin.call($target, options) + + if (slideIndex) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + } + + $(document) + .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) + .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + Plugin.call($carousel, $carousel.data()) + }) + }) + +}(jQuery); diff --git a/themes/demo/assets/vendor/bootstrap/js/collapse.js b/themes/demo/assets/vendor/bootstrap/js/collapse.js new file mode 100644 index 0000000..1203869 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/js/collapse.js @@ -0,0 +1,212 @@ +/* ======================================================================== + * Bootstrap: collapse.js v3.3.7 + * http://getbootstrap.com/javascript/#collapse + * ======================================================================== + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + +/* jshint latedef: false */ + ++function ($) { + 'use strict'; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' + + '[data-toggle="collapse"][data-target="#' + element.id + '"]') + this.transitioning = null + + if (this.options.parent) { + this.$parent = this.getParent() + } else { + this.addAriaAndCollapsedClass(this.$element, this.$trigger) + } + + if (this.options.toggle) this.toggle() + } + + Collapse.VERSION = '3.3.7' + + Collapse.TRANSITION_DURATION = 350 + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var activesData + var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing') + + if (actives && actives.length) { + activesData = actives.data('bs.collapse') + if (activesData && activesData.transitioning) return + } + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + if (actives && actives.length) { + Plugin.call(actives, 'hide') + activesData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing')[dimension](0) + .attr('aria-expanded', true) + + this.$trigger + .removeClass('collapsed') + .attr('aria-expanded', true) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('collapse in')[dimension]('') + this.transitioning = 0 + this.$element + .trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one('bsTransitionEnd', $.proxy(complete, this)) + .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element[dimension](this.$element[dimension]())[0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse in') + .attr('aria-expanded', false) + + this.$trigger + .addClass('collapsed') + .attr('aria-expanded', false) + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .removeClass('collapsing') + .addClass('collapse') + .trigger('hidden.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one('bsTransitionEnd', $.proxy(complete, this)) + .emulateTransitionEnd(Collapse.TRANSITION_DURATION) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + Collapse.prototype.getParent = function () { + return $(this.options.parent) + .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') + .each($.proxy(function (i, element) { + var $element = $(element) + this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) + }, this)) + .end() + } + + Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { + var isOpen = $element.hasClass('in') + + $element.attr('aria-expanded', isOpen) + $trigger + .toggleClass('collapsed', !isOpen) + .attr('aria-expanded', isOpen) + } + + function getTargetFromTrigger($trigger) { + var href + var target = $trigger.attr('data-target') + || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 + + return $(target) + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.collapse + + $.fn.collapse = Plugin + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { + var $this = $(this) + + if (!$this.attr('data-target')) e.preventDefault() + + var $target = getTargetFromTrigger($this) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + + Plugin.call($target, option) + }) + +}(jQuery); diff --git a/themes/demo/assets/vendor/bootstrap/js/dropdown.js b/themes/demo/assets/vendor/bootstrap/js/dropdown.js new file mode 100644 index 0000000..04e9c2d --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/js/dropdown.js @@ -0,0 +1,165 @@ +/* ======================================================================== + * Bootstrap: dropdown.js v3.3.7 + * http://getbootstrap.com/javascript/#dropdowns + * ======================================================================== + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle="dropdown"]' + var Dropdown = function (element) { + $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.VERSION = '3.3.7' + + function getParent($this) { + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = selector && $(selector) + + return $parent && $parent.length ? $parent : $this.parent() + } + + function clearMenus(e) { + if (e && e.which === 3) return + $(backdrop).remove() + $(toggle).each(function () { + var $this = $(this) + var $parent = getParent($this) + var relatedTarget = { relatedTarget: this } + + if (!$parent.hasClass('open')) return + + if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return + + $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget)) + + if (e.isDefaultPrevented()) return + + $this.attr('aria-expanded', 'false') + $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget)) + }) + } + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we use a backdrop because click events don't delegate + $(document.createElement('div')) + .addClass('dropdown-backdrop') + .insertAfter($(this)) + .on('click', clearMenus) + } + + var relatedTarget = { relatedTarget: this } + $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget)) + + if (e.isDefaultPrevented()) return + + $this + .trigger('focus') + .attr('aria-expanded', 'true') + + $parent + .toggleClass('open') + .trigger($.Event('shown.bs.dropdown', relatedTarget)) + } + + return false + } + + Dropdown.prototype.keydown = function (e) { + if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return + + var $this = $(this) + + e.preventDefault() + e.stopPropagation() + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + if (!isActive && e.which != 27 || isActive && e.which == 27) { + if (e.which == 27) $parent.find(toggle).trigger('focus') + return $this.trigger('click') + } + + var desc = ' li:not(.disabled):visible a' + var $items = $parent.find('.dropdown-menu' + desc) + + if (!$items.length) return + + var index = $items.index(e.target) + + if (e.which == 38 && index > 0) index-- // up + if (e.which == 40 && index < $items.length - 1) index++ // down + if (!~index) index = 0 + + $items.eq(index).trigger('focus') + } + + + // DROPDOWN PLUGIN DEFINITION + // ========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.dropdown') + + if (!data) $this.data('bs.dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + var old = $.fn.dropdown + + $.fn.dropdown = Plugin + $.fn.dropdown.Constructor = Dropdown + + + // DROPDOWN NO CONFLICT + // ==================== + + $.fn.dropdown.noConflict = function () { + $.fn.dropdown = old + return this + } + + + // APPLY TO STANDARD DROPDOWN ELEMENTS + // =================================== + + $(document) + .on('click.bs.dropdown.data-api', clearMenus) + .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) + .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle) + .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown) + .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown) + +}(jQuery); diff --git a/themes/demo/assets/vendor/bootstrap/js/modal.js b/themes/demo/assets/vendor/bootstrap/js/modal.js new file mode 100644 index 0000000..f84142d --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/js/modal.js @@ -0,0 +1,339 @@ +/* ======================================================================== + * Bootstrap: modal.js v3.3.7 + * http://getbootstrap.com/javascript/#modals + * ======================================================================== + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // MODAL CLASS DEFINITION + // ====================== + + var Modal = function (element, options) { + this.options = options + this.$body = $(document.body) + this.$element = $(element) + this.$dialog = this.$element.find('.modal-dialog') + this.$backdrop = null + this.isShown = null + this.originalBodyPad = null + this.scrollbarWidth = 0 + this.ignoreBackdropClick = false + + if (this.options.remote) { + this.$element + .find('.modal-content') + .load(this.options.remote, $.proxy(function () { + this.$element.trigger('loaded.bs.modal') + }, this)) + } + } + + Modal.VERSION = '3.3.7' + + Modal.TRANSITION_DURATION = 300 + Modal.BACKDROP_TRANSITION_DURATION = 150 + + Modal.DEFAULTS = { + backdrop: true, + keyboard: true, + show: true + } + + Modal.prototype.toggle = function (_relatedTarget) { + return this.isShown ? this.hide() : this.show(_relatedTarget) + } + + Modal.prototype.show = function (_relatedTarget) { + var that = this + var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) + + this.$element.trigger(e) + + if (this.isShown || e.isDefaultPrevented()) return + + this.isShown = true + + this.checkScrollbar() + this.setScrollbar() + this.$body.addClass('modal-open') + + this.escape() + this.resize() + + this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) + + this.$dialog.on('mousedown.dismiss.bs.modal', function () { + that.$element.one('mouseup.dismiss.bs.modal', function (e) { + if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true + }) + }) + + this.backdrop(function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + if (!that.$element.parent().length) { + that.$element.appendTo(that.$body) // don't move modals dom position + } + + that.$element + .show() + .scrollTop(0) + + that.adjustDialog() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + that.enforceFocus() + + var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) + + transition ? + that.$dialog // wait for modal to slide in + .one('bsTransitionEnd', function () { + that.$element.trigger('focus').trigger(e) + }) + .emulateTransitionEnd(Modal.TRANSITION_DURATION) : + that.$element.trigger('focus').trigger(e) + }) + } + + Modal.prototype.hide = function (e) { + if (e) e.preventDefault() + + e = $.Event('hide.bs.modal') + + this.$element.trigger(e) + + if (!this.isShown || e.isDefaultPrevented()) return + + this.isShown = false + + this.escape() + this.resize() + + $(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') + + $.support.transition && this.$element.hasClass('fade') ? + this.$element + .one('bsTransitionEnd', $.proxy(this.hideModal, this)) + .emulateTransitionEnd(Modal.TRANSITION_DURATION) : + this.hideModal() + } + + Modal.prototype.enforceFocus = function () { + $(document) + .off('focusin.bs.modal') // guard against infinite focus loop + .on('focusin.bs.modal', $.proxy(function (e) { + if (document !== e.target && + this.$element[0] !== e.target && + !this.$element.has(e.target).length) { + this.$element.trigger('focus') + } + }, this)) + } + + Modal.prototype.escape = function () { + if (this.isShown && this.options.keyboard) { + this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) { + e.which == 27 && this.hide() + }, this)) + } else if (!this.isShown) { + this.$element.off('keydown.dismiss.bs.modal') + } + } + + Modal.prototype.resize = function () { + if (this.isShown) { + $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this)) + } else { + $(window).off('resize.bs.modal') + } + } + + Modal.prototype.hideModal = function () { + var that = this + this.$element.hide() + this.backdrop(function () { + that.$body.removeClass('modal-open') + that.resetAdjustments() + that.resetScrollbar() + that.$element.trigger('hidden.bs.modal') + }) + } + + Modal.prototype.removeBackdrop = function () { + this.$backdrop && this.$backdrop.remove() + this.$backdrop = null + } + + Modal.prototype.backdrop = function (callback) { + var that = this + var animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $(document.createElement('div')) + .addClass('modal-backdrop ' + animate) + .appendTo(this.$body) + + this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { + if (this.ignoreBackdropClick) { + this.ignoreBackdropClick = false + return + } + if (e.target !== e.currentTarget) return + this.options.backdrop == 'static' + ? this.$element[0].focus() + : this.hide() + }, this)) + + if (doAnimate) this.$backdrop[0].offsetWidth // force reflow + + this.$backdrop.addClass('in') + + if (!callback) return + + doAnimate ? + this.$backdrop + .one('bsTransitionEnd', callback) + .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : + callback() + + } else if (!this.isShown && this.$backdrop) { + this.$backdrop.removeClass('in') + + var callbackRemove = function () { + that.removeBackdrop() + callback && callback() + } + $.support.transition && this.$element.hasClass('fade') ? + this.$backdrop + .one('bsTransitionEnd', callbackRemove) + .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : + callbackRemove() + + } else if (callback) { + callback() + } + } + + // these following methods are used to handle overflowing modals + + Modal.prototype.handleUpdate = function () { + this.adjustDialog() + } + + Modal.prototype.adjustDialog = function () { + var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight + + this.$element.css({ + paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '', + paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : '' + }) + } + + Modal.prototype.resetAdjustments = function () { + this.$element.css({ + paddingLeft: '', + paddingRight: '' + }) + } + + Modal.prototype.checkScrollbar = function () { + var fullWindowWidth = window.innerWidth + if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8 + var documentElementRect = document.documentElement.getBoundingClientRect() + fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left) + } + this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth + this.scrollbarWidth = this.measureScrollbar() + } + + Modal.prototype.setScrollbar = function () { + var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) + this.originalBodyPad = document.body.style.paddingRight || '' + if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) + } + + Modal.prototype.resetScrollbar = function () { + this.$body.css('padding-right', this.originalBodyPad) + } + + Modal.prototype.measureScrollbar = function () { // thx walsh + var scrollDiv = document.createElement('div') + scrollDiv.className = 'modal-scrollbar-measure' + this.$body.append(scrollDiv) + var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth + this.$body[0].removeChild(scrollDiv) + return scrollbarWidth + } + + + // MODAL PLUGIN DEFINITION + // ======================= + + function Plugin(option, _relatedTarget) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.modal') + var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) $this.data('bs.modal', (data = new Modal(this, options))) + if (typeof option == 'string') data[option](_relatedTarget) + else if (options.show) data.show(_relatedTarget) + }) + } + + var old = $.fn.modal + + $.fn.modal = Plugin + $.fn.modal.Constructor = Modal + + + // MODAL NO CONFLICT + // ================= + + $.fn.modal.noConflict = function () { + $.fn.modal = old + return this + } + + + // MODAL DATA-API + // ============== + + $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { + var $this = $(this) + var href = $this.attr('href') + var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7 + var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) + + if ($this.is('a')) e.preventDefault() + + $target.one('show.bs.modal', function (showEvent) { + if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown + $target.one('hidden.bs.modal', function () { + $this.is(':visible') && $this.trigger('focus') + }) + }) + Plugin.call($target, option, this) + }) + +}(jQuery); diff --git a/themes/demo/assets/vendor/bootstrap/js/popover.js b/themes/demo/assets/vendor/bootstrap/js/popover.js new file mode 100644 index 0000000..efe1956 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/js/popover.js @@ -0,0 +1,108 @@ +/* ======================================================================== + * Bootstrap: popover.js v3.3.7 + * http://getbootstrap.com/javascript/#popovers + * ======================================================================== + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // POPOVER PUBLIC CLASS DEFINITION + // =============================== + + var Popover = function (element, options) { + this.init('popover', element, options) + } + + if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') + + Popover.VERSION = '3.3.7' + + Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { + placement: 'right', + trigger: 'click', + content: '', + template: '' + }) + + + // NOTE: POPOVER EXTENDS tooltip.js + // ================================ + + Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) + + Popover.prototype.constructor = Popover + + Popover.prototype.getDefaults = function () { + return Popover.DEFAULTS + } + + Popover.prototype.setContent = function () { + var $tip = this.tip() + var title = this.getTitle() + var content = this.getContent() + + $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) + $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events + this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' + ](content) + + $tip.removeClass('fade top bottom left right in') + + // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do + // this manually by checking the contents. + if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() + } + + Popover.prototype.hasContent = function () { + return this.getTitle() || this.getContent() + } + + Popover.prototype.getContent = function () { + var $e = this.$element + var o = this.options + + return $e.attr('data-content') + || (typeof o.content == 'function' ? + o.content.call($e[0]) : + o.content) + } + + Popover.prototype.arrow = function () { + return (this.$arrow = this.$arrow || this.tip().find('.arrow')) + } + + + // POPOVER PLUGIN DEFINITION + // ========================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.popover') + var options = typeof option == 'object' && option + + if (!data && /destroy|hide/.test(option)) return + if (!data) $this.data('bs.popover', (data = new Popover(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.popover + + $.fn.popover = Plugin + $.fn.popover.Constructor = Popover + + + // POPOVER NO CONFLICT + // =================== + + $.fn.popover.noConflict = function () { + $.fn.popover = old + return this + } + +}(jQuery); diff --git a/themes/demo/assets/vendor/bootstrap/js/scrollspy.js b/themes/demo/assets/vendor/bootstrap/js/scrollspy.js new file mode 100644 index 0000000..fe19809 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/js/scrollspy.js @@ -0,0 +1,172 @@ +/* ======================================================================== + * Bootstrap: scrollspy.js v3.3.7 + * http://getbootstrap.com/javascript/#scrollspy + * ======================================================================== + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // SCROLLSPY CLASS DEFINITION + // ========================== + + function ScrollSpy(element, options) { + this.$body = $(document.body) + this.$scrollElement = $(element).is(document.body) ? $(window) : $(element) + this.options = $.extend({}, ScrollSpy.DEFAULTS, options) + this.selector = (this.options.target || '') + ' .nav li > a' + this.offsets = [] + this.targets = [] + this.activeTarget = null + this.scrollHeight = 0 + + this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this)) + this.refresh() + this.process() + } + + ScrollSpy.VERSION = '3.3.7' + + ScrollSpy.DEFAULTS = { + offset: 10 + } + + ScrollSpy.prototype.getScrollHeight = function () { + return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight) + } + + ScrollSpy.prototype.refresh = function () { + var that = this + var offsetMethod = 'offset' + var offsetBase = 0 + + this.offsets = [] + this.targets = [] + this.scrollHeight = this.getScrollHeight() + + if (!$.isWindow(this.$scrollElement[0])) { + offsetMethod = 'position' + offsetBase = this.$scrollElement.scrollTop() + } + + this.$body + .find(this.selector) + .map(function () { + var $el = $(this) + var href = $el.data('target') || $el.attr('href') + var $href = /^#./.test(href) && $(href) + + return ($href + && $href.length + && $href.is(':visible') + && [[$href[offsetMethod]().top + offsetBase, href]]) || null + }) + .sort(function (a, b) { return a[0] - b[0] }) + .each(function () { + that.offsets.push(this[0]) + that.targets.push(this[1]) + }) + } + + ScrollSpy.prototype.process = function () { + var scrollTop = this.$scrollElement.scrollTop() + this.options.offset + var scrollHeight = this.getScrollHeight() + var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height() + var offsets = this.offsets + var targets = this.targets + var activeTarget = this.activeTarget + var i + + if (this.scrollHeight != scrollHeight) { + this.refresh() + } + + if (scrollTop >= maxScroll) { + return activeTarget != (i = targets[targets.length - 1]) && this.activate(i) + } + + if (activeTarget && scrollTop < offsets[0]) { + this.activeTarget = null + return this.clear() + } + + for (i = offsets.length; i--;) { + activeTarget != targets[i] + && scrollTop >= offsets[i] + && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1]) + && this.activate(targets[i]) + } + } + + ScrollSpy.prototype.activate = function (target) { + this.activeTarget = target + + this.clear() + + var selector = this.selector + + '[data-target="' + target + '"],' + + this.selector + '[href="' + target + '"]' + + var active = $(selector) + .parents('li') + .addClass('active') + + if (active.parent('.dropdown-menu').length) { + active = active + .closest('li.dropdown') + .addClass('active') + } + + active.trigger('activate.bs.scrollspy') + } + + ScrollSpy.prototype.clear = function () { + $(this.selector) + .parentsUntil(this.options.target, '.active') + .removeClass('active') + } + + + // SCROLLSPY PLUGIN DEFINITION + // =========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.scrollspy') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.scrollspy + + $.fn.scrollspy = Plugin + $.fn.scrollspy.Constructor = ScrollSpy + + + // SCROLLSPY NO CONFLICT + // ===================== + + $.fn.scrollspy.noConflict = function () { + $.fn.scrollspy = old + return this + } + + + // SCROLLSPY DATA-API + // ================== + + $(window).on('load.bs.scrollspy.data-api', function () { + $('[data-spy="scroll"]').each(function () { + var $spy = $(this) + Plugin.call($spy, $spy.data()) + }) + }) + +}(jQuery); diff --git a/themes/demo/assets/vendor/bootstrap/js/tab.js b/themes/demo/assets/vendor/bootstrap/js/tab.js new file mode 100644 index 0000000..c4a8635 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/js/tab.js @@ -0,0 +1,155 @@ +/* ======================================================================== + * Bootstrap: tab.js v3.3.7 + * http://getbootstrap.com/javascript/#tabs + * ======================================================================== + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // TAB CLASS DEFINITION + // ==================== + + var Tab = function (element) { + // jscs:disable requireDollarBeforejQueryAssignment + this.element = $(element) + // jscs:enable requireDollarBeforejQueryAssignment + } + + Tab.VERSION = '3.3.7' + + Tab.TRANSITION_DURATION = 150 + + Tab.prototype.show = function () { + var $this = this.element + var $ul = $this.closest('ul:not(.dropdown-menu)') + var selector = $this.data('target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + if ($this.parent('li').hasClass('active')) return + + var $previous = $ul.find('.active:last a') + var hideEvent = $.Event('hide.bs.tab', { + relatedTarget: $this[0] + }) + var showEvent = $.Event('show.bs.tab', { + relatedTarget: $previous[0] + }) + + $previous.trigger(hideEvent) + $this.trigger(showEvent) + + if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return + + var $target = $(selector) + + this.activate($this.closest('li'), $ul) + this.activate($target, $target.parent(), function () { + $previous.trigger({ + type: 'hidden.bs.tab', + relatedTarget: $this[0] + }) + $this.trigger({ + type: 'shown.bs.tab', + relatedTarget: $previous[0] + }) + }) + } + + Tab.prototype.activate = function (element, container, callback) { + var $active = container.find('> .active') + var transition = callback + && $.support.transition + && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length) + + function next() { + $active + .removeClass('active') + .find('> .dropdown-menu > .active') + .removeClass('active') + .end() + .find('[data-toggle="tab"]') + .attr('aria-expanded', false) + + element + .addClass('active') + .find('[data-toggle="tab"]') + .attr('aria-expanded', true) + + if (transition) { + element[0].offsetWidth // reflow for transition + element.addClass('in') + } else { + element.removeClass('fade') + } + + if (element.parent('.dropdown-menu').length) { + element + .closest('li.dropdown') + .addClass('active') + .end() + .find('[data-toggle="tab"]') + .attr('aria-expanded', true) + } + + callback && callback() + } + + $active.length && transition ? + $active + .one('bsTransitionEnd', next) + .emulateTransitionEnd(Tab.TRANSITION_DURATION) : + next() + + $active.removeClass('in') + } + + + // TAB PLUGIN DEFINITION + // ===================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.tab') + + if (!data) $this.data('bs.tab', (data = new Tab(this))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.tab + + $.fn.tab = Plugin + $.fn.tab.Constructor = Tab + + + // TAB NO CONFLICT + // =============== + + $.fn.tab.noConflict = function () { + $.fn.tab = old + return this + } + + + // TAB DATA-API + // ============ + + var clickHandler = function (e) { + e.preventDefault() + Plugin.call($(this), 'show') + } + + $(document) + .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler) + .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler) + +}(jQuery); diff --git a/themes/demo/assets/vendor/bootstrap/js/tooltip.js b/themes/demo/assets/vendor/bootstrap/js/tooltip.js new file mode 100644 index 0000000..e35d9c7 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/js/tooltip.js @@ -0,0 +1,520 @@ +/* ======================================================================== + * Bootstrap: tooltip.js v3.3.7 + * http://getbootstrap.com/javascript/#tooltip + * Inspired by the original jQuery.tipsy by Jason Frame + * ======================================================================== + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // TOOLTIP PUBLIC CLASS DEFINITION + // =============================== + + var Tooltip = function (element, options) { + this.type = null + this.options = null + this.enabled = null + this.timeout = null + this.hoverState = null + this.$element = null + this.inState = null + + this.init('tooltip', element, options) + } + + Tooltip.VERSION = '3.3.7' + + Tooltip.TRANSITION_DURATION = 150 + + Tooltip.DEFAULTS = { + animation: true, + placement: 'top', + selector: false, + template: '', + trigger: 'hover focus', + title: '', + delay: 0, + html: false, + container: false, + viewport: { + selector: 'body', + padding: 0 + } + } + + Tooltip.prototype.init = function (type, element, options) { + this.enabled = true + this.type = type + this.$element = $(element) + this.options = this.getOptions(options) + this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport)) + this.inState = { click: false, hover: false, focus: false } + + if (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!') + } + + var triggers = this.options.trigger.split(' ') + + for (var i = triggers.length; i--;) { + var trigger = triggers[i] + + if (trigger == 'click') { + this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) + } else if (trigger != 'manual') { + var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' + var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' + + this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) + this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) + } + } + + this.options.selector ? + (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : + this.fixTitle() + } + + Tooltip.prototype.getDefaults = function () { + return Tooltip.DEFAULTS + } + + Tooltip.prototype.getOptions = function (options) { + options = $.extend({}, this.getDefaults(), this.$element.data(), options) + + if (options.delay && typeof options.delay == 'number') { + options.delay = { + show: options.delay, + hide: options.delay + } + } + + return options + } + + Tooltip.prototype.getDelegateOptions = function () { + var options = {} + var defaults = this.getDefaults() + + this._options && $.each(this._options, function (key, value) { + if (defaults[key] != value) options[key] = value + }) + + return options + } + + Tooltip.prototype.enter = function (obj) { + var self = obj instanceof this.constructor ? + obj : $(obj.currentTarget).data('bs.' + this.type) + + if (!self) { + self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) + $(obj.currentTarget).data('bs.' + this.type, self) + } + + if (obj instanceof $.Event) { + self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true + } + + if (self.tip().hasClass('in') || self.hoverState == 'in') { + self.hoverState = 'in' + return + } + + clearTimeout(self.timeout) + + self.hoverState = 'in' + + if (!self.options.delay || !self.options.delay.show) return self.show() + + self.timeout = setTimeout(function () { + if (self.hoverState == 'in') self.show() + }, self.options.delay.show) + } + + Tooltip.prototype.isInStateTrue = function () { + for (var key in this.inState) { + if (this.inState[key]) return true + } + + return false + } + + Tooltip.prototype.leave = function (obj) { + var self = obj instanceof this.constructor ? + obj : $(obj.currentTarget).data('bs.' + this.type) + + if (!self) { + self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) + $(obj.currentTarget).data('bs.' + this.type, self) + } + + if (obj instanceof $.Event) { + self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false + } + + if (self.isInStateTrue()) return + + clearTimeout(self.timeout) + + self.hoverState = 'out' + + if (!self.options.delay || !self.options.delay.hide) return self.hide() + + self.timeout = setTimeout(function () { + if (self.hoverState == 'out') self.hide() + }, self.options.delay.hide) + } + + Tooltip.prototype.show = function () { + var e = $.Event('show.bs.' + this.type) + + if (this.hasContent() && this.enabled) { + this.$element.trigger(e) + + var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]) + if (e.isDefaultPrevented() || !inDom) return + var that = this + + var $tip = this.tip() + + var tipId = this.getUID(this.type) + + this.setContent() + $tip.attr('id', tipId) + this.$element.attr('aria-describedby', tipId) + + if (this.options.animation) $tip.addClass('fade') + + var placement = typeof this.options.placement == 'function' ? + this.options.placement.call(this, $tip[0], this.$element[0]) : + this.options.placement + + var autoToken = /\s?auto?\s?/i + var autoPlace = autoToken.test(placement) + if (autoPlace) placement = placement.replace(autoToken, '') || 'top' + + $tip + .detach() + .css({ top: 0, left: 0, display: 'block' }) + .addClass(placement) + .data('bs.' + this.type, this) + + this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) + this.$element.trigger('inserted.bs.' + this.type) + + var pos = this.getPosition() + var actualWidth = $tip[0].offsetWidth + var actualHeight = $tip[0].offsetHeight + + if (autoPlace) { + var orgPlacement = placement + var viewportDim = this.getPosition(this.$viewport) + + placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' : + placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' : + placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' : + placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' : + placement + + $tip + .removeClass(orgPlacement) + .addClass(placement) + } + + var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) + + this.applyPlacement(calculatedOffset, placement) + + var complete = function () { + var prevHoverState = that.hoverState + that.$element.trigger('shown.bs.' + that.type) + that.hoverState = null + + if (prevHoverState == 'out') that.leave(that) + } + + $.support.transition && this.$tip.hasClass('fade') ? + $tip + .one('bsTransitionEnd', complete) + .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : + complete() + } + } + + Tooltip.prototype.applyPlacement = function (offset, placement) { + var $tip = this.tip() + var width = $tip[0].offsetWidth + var height = $tip[0].offsetHeight + + // manually read margins because getBoundingClientRect includes difference + var marginTop = parseInt($tip.css('margin-top'), 10) + var marginLeft = parseInt($tip.css('margin-left'), 10) + + // we must check for NaN for ie 8/9 + if (isNaN(marginTop)) marginTop = 0 + if (isNaN(marginLeft)) marginLeft = 0 + + offset.top += marginTop + offset.left += marginLeft + + // $.fn.offset doesn't round pixel values + // so we use setOffset directly with our own function B-0 + $.offset.setOffset($tip[0], $.extend({ + using: function (props) { + $tip.css({ + top: Math.round(props.top), + left: Math.round(props.left) + }) + } + }, offset), 0) + + $tip.addClass('in') + + // check to see if placing tip in new offset caused the tip to resize itself + var actualWidth = $tip[0].offsetWidth + var actualHeight = $tip[0].offsetHeight + + if (placement == 'top' && actualHeight != height) { + offset.top = offset.top + height - actualHeight + } + + var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) + + if (delta.left) offset.left += delta.left + else offset.top += delta.top + + var isVertical = /top|bottom/.test(placement) + var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight + var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight' + + $tip.offset(offset) + this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical) + } + + Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) { + this.arrow() + .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%') + .css(isVertical ? 'top' : 'left', '') + } + + Tooltip.prototype.setContent = function () { + var $tip = this.tip() + var title = this.getTitle() + + $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) + $tip.removeClass('fade in top bottom left right') + } + + Tooltip.prototype.hide = function (callback) { + var that = this + var $tip = $(this.$tip) + var e = $.Event('hide.bs.' + this.type) + + function complete() { + if (that.hoverState != 'in') $tip.detach() + if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary. + that.$element + .removeAttr('aria-describedby') + .trigger('hidden.bs.' + that.type) + } + callback && callback() + } + + this.$element.trigger(e) + + if (e.isDefaultPrevented()) return + + $tip.removeClass('in') + + $.support.transition && $tip.hasClass('fade') ? + $tip + .one('bsTransitionEnd', complete) + .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : + complete() + + this.hoverState = null + + return this + } + + Tooltip.prototype.fixTitle = function () { + var $e = this.$element + if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') { + $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') + } + } + + Tooltip.prototype.hasContent = function () { + return this.getTitle() + } + + Tooltip.prototype.getPosition = function ($element) { + $element = $element || this.$element + + var el = $element[0] + var isBody = el.tagName == 'BODY' + + var elRect = el.getBoundingClientRect() + if (elRect.width == null) { + // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 + elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) + } + var isSvg = window.SVGElement && el instanceof window.SVGElement + // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3. + // See https://github.com/twbs/bootstrap/issues/20280 + var elOffset = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset()) + var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } + var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null + + return $.extend({}, elRect, scroll, outerDims, elOffset) + } + + Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { + return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : + placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : + placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : + /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } + + } + + Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { + var delta = { top: 0, left: 0 } + if (!this.$viewport) return delta + + var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 + var viewportDimensions = this.getPosition(this.$viewport) + + if (/right|left/.test(placement)) { + var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll + var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight + if (topEdgeOffset < viewportDimensions.top) { // top overflow + delta.top = viewportDimensions.top - topEdgeOffset + } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow + delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset + } + } else { + var leftEdgeOffset = pos.left - viewportPadding + var rightEdgeOffset = pos.left + viewportPadding + actualWidth + if (leftEdgeOffset < viewportDimensions.left) { // left overflow + delta.left = viewportDimensions.left - leftEdgeOffset + } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow + delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset + } + } + + return delta + } + + Tooltip.prototype.getTitle = function () { + var title + var $e = this.$element + var o = this.options + + title = $e.attr('data-original-title') + || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) + + return title + } + + Tooltip.prototype.getUID = function (prefix) { + do prefix += ~~(Math.random() * 1000000) + while (document.getElementById(prefix)) + return prefix + } + + Tooltip.prototype.tip = function () { + if (!this.$tip) { + this.$tip = $(this.options.template) + if (this.$tip.length != 1) { + throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!') + } + } + return this.$tip + } + + Tooltip.prototype.arrow = function () { + return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')) + } + + Tooltip.prototype.enable = function () { + this.enabled = true + } + + Tooltip.prototype.disable = function () { + this.enabled = false + } + + Tooltip.prototype.toggleEnabled = function () { + this.enabled = !this.enabled + } + + Tooltip.prototype.toggle = function (e) { + var self = this + if (e) { + self = $(e.currentTarget).data('bs.' + this.type) + if (!self) { + self = new this.constructor(e.currentTarget, this.getDelegateOptions()) + $(e.currentTarget).data('bs.' + this.type, self) + } + } + + if (e) { + self.inState.click = !self.inState.click + if (self.isInStateTrue()) self.enter(self) + else self.leave(self) + } else { + self.tip().hasClass('in') ? self.leave(self) : self.enter(self) + } + } + + Tooltip.prototype.destroy = function () { + var that = this + clearTimeout(this.timeout) + this.hide(function () { + that.$element.off('.' + that.type).removeData('bs.' + that.type) + if (that.$tip) { + that.$tip.detach() + } + that.$tip = null + that.$arrow = null + that.$viewport = null + that.$element = null + }) + } + + + // TOOLTIP PLUGIN DEFINITION + // ========================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.tooltip') + var options = typeof option == 'object' && option + + if (!data && /destroy|hide/.test(option)) return + if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.tooltip + + $.fn.tooltip = Plugin + $.fn.tooltip.Constructor = Tooltip + + + // TOOLTIP NO CONFLICT + // =================== + + $.fn.tooltip.noConflict = function () { + $.fn.tooltip = old + return this + } + +}(jQuery); diff --git a/themes/demo/assets/vendor/bootstrap/js/transition.js b/themes/demo/assets/vendor/bootstrap/js/transition.js new file mode 100644 index 0000000..db76596 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/js/transition.js @@ -0,0 +1,59 @@ +/* ======================================================================== + * Bootstrap: transition.js v3.3.7 + * http://getbootstrap.com/javascript/#transitions + * ======================================================================== + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + WebkitTransition : 'webkitTransitionEnd', + MozTransition : 'transitionend', + OTransition : 'oTransitionEnd otransitionend', + transition : 'transitionend' + } + + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + + return false // explicit for ie8 ( ._.) + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false + var $el = this + $(this).one('bsTransitionEnd', function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + + if (!$.support.transition) return + + $.event.special.bsTransitionEnd = { + bindType: $.support.transition.end, + delegateType: $.support.transition.end, + handle: function (e) { + if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) + } + } + }) + +}(jQuery); diff --git a/themes/demo/assets/vendor/bootstrap/less/alerts.less b/themes/demo/assets/vendor/bootstrap/less/alerts.less new file mode 100644 index 0000000..c4199db --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/alerts.less @@ -0,0 +1,73 @@ +// +// Alerts +// -------------------------------------------------- + + +// Base styles +// ------------------------- + +.alert { + padding: @alert-padding; + margin-bottom: @line-height-computed; + border: 1px solid transparent; + border-radius: @alert-border-radius; + + // Headings for larger alerts + h4 { + margin-top: 0; + // Specified for the h4 to prevent conflicts of changing @headings-color + color: inherit; + } + + // Provide class for links that match alerts + .alert-link { + font-weight: @alert-link-font-weight; + } + + // Improve alignment and spacing of inner content + > p, + > ul { + margin-bottom: 0; + } + + > p + p { + margin-top: 5px; + } +} + +// Dismissible alerts +// +// Expand the right padding and account for the close button's positioning. + +.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0. +.alert-dismissible { + padding-right: (@alert-padding + 20); + + // Adjust close link position + .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; + } +} + +// Alternate styles +// +// Generate contextual modifier classes for colorizing the alert. + +.alert-success { + .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text); +} + +.alert-info { + .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text); +} + +.alert-warning { + .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text); +} + +.alert-danger { + .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text); +} diff --git a/themes/demo/assets/vendor/bootstrap/less/badges.less b/themes/demo/assets/vendor/bootstrap/less/badges.less new file mode 100644 index 0000000..6ee16dc --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/badges.less @@ -0,0 +1,66 @@ +// +// Badges +// -------------------------------------------------- + + +// Base class +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: @font-size-small; + font-weight: @badge-font-weight; + color: @badge-color; + line-height: @badge-line-height; + vertical-align: middle; + white-space: nowrap; + text-align: center; + background-color: @badge-bg; + border-radius: @badge-border-radius; + + // Empty badges collapse automatically (not available in IE8) + &:empty { + display: none; + } + + // Quick fix for badges in buttons + .btn & { + position: relative; + top: -1px; + } + + .btn-xs &, + .btn-group-xs > .btn & { + top: 0; + padding: 1px 5px; + } + + // Hover state, but only for links + a& { + &:hover, + &:focus { + color: @badge-link-hover-color; + text-decoration: none; + cursor: pointer; + } + } + + // Account for badges in navs + .list-group-item.active > &, + .nav-pills > .active > a > & { + color: @badge-active-color; + background-color: @badge-active-bg; + } + + .list-group-item > & { + float: right; + } + + .list-group-item > & + & { + margin-right: 5px; + } + + .nav-pills > li > a > & { + margin-left: 3px; + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/bootstrap.less b/themes/demo/assets/vendor/bootstrap/less/bootstrap.less new file mode 100644 index 0000000..f0aa08f --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/bootstrap.less @@ -0,0 +1,56 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +// Core variables and mixins +@import "variables.less"; +@import "mixins.less"; + +// Reset and dependencies +@import "normalize.less"; +@import "print.less"; +@import "glyphicons.less"; + +// Core CSS +@import "scaffolding.less"; +@import "type.less"; +@import "code.less"; +@import "grid.less"; +@import "tables.less"; +@import "forms.less"; +@import "buttons.less"; + +// Components +@import "component-animations.less"; +@import "dropdowns.less"; +@import "button-groups.less"; +@import "input-groups.less"; +@import "navs.less"; +@import "navbar.less"; +@import "breadcrumbs.less"; +@import "pagination.less"; +@import "pager.less"; +@import "labels.less"; +@import "badges.less"; +@import "jumbotron.less"; +@import "thumbnails.less"; +@import "alerts.less"; +@import "progress-bars.less"; +@import "media.less"; +@import "list-group.less"; +@import "panels.less"; +@import "responsive-embed.less"; +@import "wells.less"; +@import "close.less"; + +// Components w/ JavaScript +@import "modals.less"; +@import "tooltip.less"; +@import "popovers.less"; +@import "carousel.less"; + +// Utility classes +@import "utilities.less"; +@import "responsive-utilities.less"; diff --git a/themes/demo/assets/vendor/bootstrap/less/breadcrumbs.less b/themes/demo/assets/vendor/bootstrap/less/breadcrumbs.less new file mode 100644 index 0000000..cb01d50 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/breadcrumbs.less @@ -0,0 +1,26 @@ +// +// Breadcrumbs +// -------------------------------------------------- + + +.breadcrumb { + padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal; + margin-bottom: @line-height-computed; + list-style: none; + background-color: @breadcrumb-bg; + border-radius: @border-radius-base; + + > li { + display: inline-block; + + + li:before { + content: "@{breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space + padding: 0 5px; + color: @breadcrumb-color; + } + } + + > .active { + color: @breadcrumb-active-color; + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/button-groups.less b/themes/demo/assets/vendor/bootstrap/less/button-groups.less new file mode 100644 index 0000000..16db0c6 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/button-groups.less @@ -0,0 +1,244 @@ +// +// Button groups +// -------------------------------------------------- + +// Make the div behave like a button +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; // match .btn alignment given font-size hack above + > .btn { + position: relative; + float: left; + // Bring the "active" button to the front + &:hover, + &:focus, + &:active, + &.active { + z-index: 2; + } + } +} + +// Prevent double borders when buttons are next to each other +.btn-group { + .btn + .btn, + .btn + .btn-group, + .btn-group + .btn, + .btn-group + .btn-group { + margin-left: -1px; + } +} + +// Optional: Group multiple button groups together for a toolbar +.btn-toolbar { + margin-left: -5px; // Offset the first child's margin + &:extend(.clearfix all); + + .btn, + .btn-group, + .input-group { + float: left; + } + > .btn, + > .btn-group, + > .input-group { + margin-left: 5px; + } +} + +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} + +// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match +.btn-group > .btn:first-child { + margin-left: 0; + &:not(:last-child):not(.dropdown-toggle) { + .border-right-radius(0); + } +} +// Need .dropdown-toggle since :last-child doesn't apply, given that a .dropdown-menu is used immediately after it +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + .border-left-radius(0); +} + +// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group) +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child:not(:last-child) { + > .btn:last-child, + > .dropdown-toggle { + .border-right-radius(0); + } +} +.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child { + .border-left-radius(0); +} + +// On active and open, don't show outline +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + + +// Sizing +// +// Remix the default button sizing classes into new ones for easier manipulation. + +.btn-group-xs > .btn { &:extend(.btn-xs); } +.btn-group-sm > .btn { &:extend(.btn-sm); } +.btn-group-lg > .btn { &:extend(.btn-lg); } + + +// Split button dropdowns +// ---------------------- + +// Give the line between buttons some depth +.btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-left: 12px; + padding-right: 12px; +} + +// The clickable button for toggling the menu +// Remove the gradient and set the same inset shadow as the :active state +.btn-group.open .dropdown-toggle { + .box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); + + // Show no shadow for `.btn-link` since it has no other button styles. + &.btn-link { + .box-shadow(none); + } +} + + +// Reposition the caret +.btn .caret { + margin-left: 0; +} +// Carets in other button sizes +.btn-lg .caret { + border-width: @caret-width-large @caret-width-large 0; + border-bottom-width: 0; +} +// Upside down carets for .dropup +.dropup .btn-lg .caret { + border-width: 0 @caret-width-large @caret-width-large; +} + + +// Vertical button groups +// ---------------------- + +.btn-group-vertical { + > .btn, + > .btn-group, + > .btn-group > .btn { + display: block; + float: none; + width: 100%; + max-width: 100%; + } + + // Clear floats so dropdown menus can be properly placed + > .btn-group { + &:extend(.clearfix all); + > .btn { + float: none; + } + } + + > .btn + .btn, + > .btn + .btn-group, + > .btn-group + .btn, + > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; + } +} + +.btn-group-vertical > .btn { + &:not(:first-child):not(:last-child) { + border-radius: 0; + } + &:first-child:not(:last-child) { + .border-top-radius(@btn-border-radius-base); + .border-bottom-radius(0); + } + &:last-child:not(:first-child) { + .border-top-radius(0); + .border-bottom-radius(@btn-border-radius-base); + } +} +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group-vertical > .btn-group:first-child:not(:last-child) { + > .btn:last-child, + > .dropdown-toggle { + .border-bottom-radius(0); + } +} +.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { + .border-top-radius(0); +} + + +// Justified button groups +// ---------------------- + +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; + > .btn, + > .btn-group { + float: none; + display: table-cell; + width: 1%; + } + > .btn-group .btn { + width: 100%; + } + + > .btn-group .dropdown-menu { + left: auto; + } +} + + +// Checkbox and radio options +// +// In order to support the browser's form validation feedback, powered by the +// `required` attribute, we have to "hide" the inputs via `clip`. We cannot use +// `display: none;` or `visibility: hidden;` as that also hides the popover. +// Simply visually hiding the inputs via `opacity` would leave them clickable in +// certain cases which is prevented by using `clip` and `pointer-events`. +// This way, we ensure a DOM element is visible to position the popover from. +// +// See https://github.com/twbs/bootstrap/pull/12794 and +// https://github.com/twbs/bootstrap/pull/14559 for more information. + +[data-toggle="buttons"] { + > .btn, + > .btn-group > .btn { + input[type="radio"], + input[type="checkbox"] { + position: absolute; + clip: rect(0,0,0,0); + pointer-events: none; + } + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/buttons.less b/themes/demo/assets/vendor/bootstrap/less/buttons.less new file mode 100644 index 0000000..9cbb8f4 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/buttons.less @@ -0,0 +1,166 @@ +// +// Buttons +// -------------------------------------------------- + + +// Base styles +// -------------------------------------------------- + +.btn { + display: inline-block; + margin-bottom: 0; // For input.btn + font-weight: @btn-font-weight; + text-align: center; + vertical-align: middle; + touch-action: manipulation; + cursor: pointer; + background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 + border: 1px solid transparent; + white-space: nowrap; + .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @btn-border-radius-base); + .user-select(none); + + &, + &:active, + &.active { + &:focus, + &.focus { + .tab-focus(); + } + } + + &:hover, + &:focus, + &.focus { + color: @btn-default-color; + text-decoration: none; + } + + &:active, + &.active { + outline: 0; + background-image: none; + .box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); + } + + &.disabled, + &[disabled], + fieldset[disabled] & { + cursor: @cursor-disabled; + .opacity(.65); + .box-shadow(none); + } + + a& { + &.disabled, + fieldset[disabled] & { + pointer-events: none; // Future-proof disabling of clicks on `` elements + } + } +} + + +// Alternate buttons +// -------------------------------------------------- + +.btn-default { + .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border); +} +.btn-primary { + .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border); +} +// Success appears as green +.btn-success { + .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border); +} +// Info appears as blue-green +.btn-info { + .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border); +} +// Warning appears as orange +.btn-warning { + .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border); +} +// Danger and error appear as red +.btn-danger { + .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border); +} + + +// Link buttons +// ------------------------- + +// Make a button look and behave like a link +.btn-link { + color: @link-color; + font-weight: normal; + border-radius: 0; + + &, + &:active, + &.active, + &[disabled], + fieldset[disabled] & { + background-color: transparent; + .box-shadow(none); + } + &, + &:hover, + &:focus, + &:active { + border-color: transparent; + } + &:hover, + &:focus { + color: @link-hover-color; + text-decoration: @link-hover-decoration; + background-color: transparent; + } + &[disabled], + fieldset[disabled] & { + &:hover, + &:focus { + color: @btn-link-disabled-color; + text-decoration: none; + } + } +} + + +// Button Sizes +// -------------------------------------------------- + +.btn-lg { + // line-height: ensure even-numbered height of button next to large input + .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @btn-border-radius-large); +} +.btn-sm { + // line-height: ensure proper height of button next to small input + .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small); +} +.btn-xs { + .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small); +} + + +// Block button +// -------------------------------------------------- + +.btn-block { + display: block; + width: 100%; +} + +// Vertically space out multiple block buttons +.btn-block + .btn-block { + margin-top: 5px; +} + +// Specificity overrides +input[type="submit"], +input[type="reset"], +input[type="button"] { + &.btn-block { + width: 100%; + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/carousel.less b/themes/demo/assets/vendor/bootstrap/less/carousel.less new file mode 100644 index 0000000..252011e --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/carousel.less @@ -0,0 +1,270 @@ +// +// Carousel +// -------------------------------------------------- + + +// Wrapper for the slide container and indicators +.carousel { + position: relative; +} + +.carousel-inner { + position: relative; + overflow: hidden; + width: 100%; + + > .item { + display: none; + position: relative; + .transition(.6s ease-in-out left); + + // Account for jankitude on images + > img, + > a > img { + &:extend(.img-responsive); + line-height: 1; + } + + // WebKit CSS3 transforms for supported devices + @media all and (transform-3d), (-webkit-transform-3d) { + .transition-transform(~'0.6s ease-in-out'); + .backface-visibility(~'hidden'); + .perspective(1000px); + + &.next, + &.active.right { + .translate3d(100%, 0, 0); + left: 0; + } + &.prev, + &.active.left { + .translate3d(-100%, 0, 0); + left: 0; + } + &.next.left, + &.prev.right, + &.active { + .translate3d(0, 0, 0); + left: 0; + } + } + } + + > .active, + > .next, + > .prev { + display: block; + } + + > .active { + left: 0; + } + + > .next, + > .prev { + position: absolute; + top: 0; + width: 100%; + } + + > .next { + left: 100%; + } + > .prev { + left: -100%; + } + > .next.left, + > .prev.right { + left: 0; + } + + > .active.left { + left: -100%; + } + > .active.right { + left: 100%; + } + +} + +// Left/right controls for nav +// --------------------------- + +.carousel-control { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: @carousel-control-width; + .opacity(@carousel-control-opacity); + font-size: @carousel-control-font-size; + color: @carousel-control-color; + text-align: center; + text-shadow: @carousel-text-shadow; + background-color: rgba(0, 0, 0, 0); // Fix IE9 click-thru bug + // We can't have this transition here because WebKit cancels the carousel + // animation if you trip this while in the middle of another animation. + + // Set gradients for backgrounds + &.left { + #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001)); + } + &.right { + left: auto; + right: 0; + #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5)); + } + + // Hover/focus state + &:hover, + &:focus { + outline: 0; + color: @carousel-control-color; + text-decoration: none; + .opacity(.9); + } + + // Toggles + .icon-prev, + .icon-next, + .glyphicon-chevron-left, + .glyphicon-chevron-right { + position: absolute; + top: 50%; + margin-top: -10px; + z-index: 5; + display: inline-block; + } + .icon-prev, + .glyphicon-chevron-left { + left: 50%; + margin-left: -10px; + } + .icon-next, + .glyphicon-chevron-right { + right: 50%; + margin-right: -10px; + } + .icon-prev, + .icon-next { + width: 20px; + height: 20px; + line-height: 1; + font-family: serif; + } + + + .icon-prev { + &:before { + content: '\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039) + } + } + .icon-next { + &:before { + content: '\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A) + } + } +} + +// Optional indicator pips +// +// Add an unordered list with the following class and add a list item for each +// slide your carousel holds. + +.carousel-indicators { + position: absolute; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + margin-left: -30%; + padding-left: 0; + list-style: none; + text-align: center; + + li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + border: 1px solid @carousel-indicator-border-color; + border-radius: 10px; + cursor: pointer; + + // IE8-9 hack for event handling + // + // Internet Explorer 8-9 does not support clicks on elements without a set + // `background-color`. We cannot use `filter` since that's not viewed as a + // background color by the browser. Thus, a hack is needed. + // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Internet_Explorer + // + // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we + // set alpha transparency for the best results possible. + background-color: #000 \9; // IE8 + background-color: rgba(0,0,0,0); // IE9 + } + .active { + margin: 0; + width: 12px; + height: 12px; + background-color: @carousel-indicator-active-bg; + } +} + +// Optional captions +// ----------------------------- +// Hidden by default for smaller viewports +.carousel-caption { + position: absolute; + left: 15%; + right: 15%; + bottom: 20px; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: @carousel-caption-color; + text-align: center; + text-shadow: @carousel-text-shadow; + & .btn { + text-shadow: none; // No shadow for button elements in carousel-caption + } +} + + +// Scale up controls for tablets and up +@media screen and (min-width: @screen-sm-min) { + + // Scale up the controls a smidge + .carousel-control { + .glyphicon-chevron-left, + .glyphicon-chevron-right, + .icon-prev, + .icon-next { + width: (@carousel-control-font-size * 1.5); + height: (@carousel-control-font-size * 1.5); + margin-top: (@carousel-control-font-size / -2); + font-size: (@carousel-control-font-size * 1.5); + } + .glyphicon-chevron-left, + .icon-prev { + margin-left: (@carousel-control-font-size / -2); + } + .glyphicon-chevron-right, + .icon-next { + margin-right: (@carousel-control-font-size / -2); + } + } + + // Show and left align the captions + .carousel-caption { + left: 20%; + right: 20%; + padding-bottom: 30px; + } + + // Move up the indicators + .carousel-indicators { + bottom: 20px; + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/close.less b/themes/demo/assets/vendor/bootstrap/less/close.less new file mode 100644 index 0000000..6d5bfe0 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/close.less @@ -0,0 +1,34 @@ +// +// Close icons +// -------------------------------------------------- + + +.close { + float: right; + font-size: (@font-size-base * 1.5); + font-weight: @close-font-weight; + line-height: 1; + color: @close-color; + text-shadow: @close-text-shadow; + .opacity(.2); + + &:hover, + &:focus { + color: @close-color; + text-decoration: none; + cursor: pointer; + .opacity(.5); + } + + // Additional properties for button version + // iOS requires the button element instead of an anchor tag. + // If you want the anchor version, it requires `href="#"`. + // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile + button& { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/code.less b/themes/demo/assets/vendor/bootstrap/less/code.less new file mode 100644 index 0000000..a08b4d4 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/code.less @@ -0,0 +1,69 @@ +// +// Code (inline and block) +// -------------------------------------------------- + + +// Inline and block code styles +code, +kbd, +pre, +samp { + font-family: @font-family-monospace; +} + +// Inline code +code { + padding: 2px 4px; + font-size: 90%; + color: @code-color; + background-color: @code-bg; + border-radius: @border-radius-base; +} + +// User input typically entered via keyboard +kbd { + padding: 2px 4px; + font-size: 90%; + color: @kbd-color; + background-color: @kbd-bg; + border-radius: @border-radius-small; + box-shadow: inset 0 -1px 0 rgba(0,0,0,.25); + + kbd { + padding: 0; + font-size: 100%; + font-weight: bold; + box-shadow: none; + } +} + +// Blocks of code +pre { + display: block; + padding: ((@line-height-computed - 1) / 2); + margin: 0 0 (@line-height-computed / 2); + font-size: (@font-size-base - 1); // 14px to 13px + line-height: @line-height-base; + word-break: break-all; + word-wrap: break-word; + color: @pre-color; + background-color: @pre-bg; + border: 1px solid @pre-border-color; + border-radius: @border-radius-base; + + // Account for some code outputs that place code tags in pre tags + code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; + } +} + +// Enable scrollable blocks of code +.pre-scrollable { + max-height: @pre-scrollable-max-height; + overflow-y: scroll; +} diff --git a/themes/demo/assets/vendor/bootstrap/less/component-animations.less b/themes/demo/assets/vendor/bootstrap/less/component-animations.less new file mode 100644 index 0000000..0bcee91 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/component-animations.less @@ -0,0 +1,33 @@ +// +// Component animations +// -------------------------------------------------- + +// Heads up! +// +// We don't use the `.opacity()` mixin here since it causes a bug with text +// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552. + +.fade { + opacity: 0; + .transition(opacity .15s linear); + &.in { + opacity: 1; + } +} + +.collapse { + display: none; + + &.in { display: block; } + tr&.in { display: table-row; } + tbody&.in { display: table-row-group; } +} + +.collapsing { + position: relative; + height: 0; + overflow: hidden; + .transition-property(~"height, visibility"); + .transition-duration(.35s); + .transition-timing-function(ease); +} diff --git a/themes/demo/assets/vendor/bootstrap/less/dropdowns.less b/themes/demo/assets/vendor/bootstrap/less/dropdowns.less new file mode 100644 index 0000000..f6876c1 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/dropdowns.less @@ -0,0 +1,216 @@ +// +// Dropdown menus +// -------------------------------------------------- + + +// Dropdown arrow/caret +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: @caret-width-base dashed; + border-top: @caret-width-base solid ~"\9"; // IE8 + border-right: @caret-width-base solid transparent; + border-left: @caret-width-base solid transparent; +} + +// The dropdown wrapper (div) +.dropup, +.dropdown { + position: relative; +} + +// Prevent the focus on the dropdown toggle when closing dropdowns +.dropdown-toggle:focus { + outline: 0; +} + +// The dropdown menu (ul) +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: @zindex-dropdown; + display: none; // none by default, but block on "open" of the menu + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; // override default ul + list-style: none; + font-size: @font-size-base; + text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer) + background-color: @dropdown-bg; + border: 1px solid @dropdown-fallback-border; // IE8 fallback + border: 1px solid @dropdown-border; + border-radius: @border-radius-base; + .box-shadow(0 6px 12px rgba(0,0,0,.175)); + background-clip: padding-box; + + // Aligns the dropdown menu to right + // + // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]` + &.pull-right { + right: 0; + left: auto; + } + + // Dividers (basically an hr) within the dropdown + .divider { + .nav-divider(@dropdown-divider-bg); + } + + // Links within the dropdown menu + > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: @line-height-base; + color: @dropdown-link-color; + white-space: nowrap; // prevent links from randomly breaking onto new lines + } +} + +// Hover/Focus state +.dropdown-menu > li > a { + &:hover, + &:focus { + text-decoration: none; + color: @dropdown-link-hover-color; + background-color: @dropdown-link-hover-bg; + } +} + +// Active state +.dropdown-menu > .active > a { + &, + &:hover, + &:focus { + color: @dropdown-link-active-color; + text-decoration: none; + outline: 0; + background-color: @dropdown-link-active-bg; + } +} + +// Disabled state +// +// Gray out text and ensure the hover/focus state remains gray + +.dropdown-menu > .disabled > a { + &, + &:hover, + &:focus { + color: @dropdown-link-disabled-color; + } + + // Nuke hover/focus effects + &:hover, + &:focus { + text-decoration: none; + background-color: transparent; + background-image: none; // Remove CSS gradient + .reset-filter(); + cursor: @cursor-disabled; + } +} + +// Open state for the dropdown +.open { + // Show the menu + > .dropdown-menu { + display: block; + } + + // Remove the outline when :focus is triggered + > a { + outline: 0; + } +} + +// Menu positioning +// +// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown +// menu with the parent. +.dropdown-menu-right { + left: auto; // Reset the default from `.dropdown-menu` + right: 0; +} +// With v3, we enabled auto-flipping if you have a dropdown within a right +// aligned nav component. To enable the undoing of that, we provide an override +// to restore the default dropdown menu alignment. +// +// This is only for left-aligning a dropdown menu within a `.navbar-right` or +// `.pull-right` nav component. +.dropdown-menu-left { + left: 0; + right: auto; +} + +// Dropdown section headers +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: @font-size-small; + line-height: @line-height-base; + color: @dropdown-header-color; + white-space: nowrap; // as with > li > a +} + +// Backdrop to catch body clicks on mobile, etc. +.dropdown-backdrop { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: (@zindex-dropdown - 10); +} + +// Right aligned dropdowns +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +// Allow for dropdowns to go bottom up (aka, dropup-menu) +// +// Just add .dropup after the standard .dropdown class and you're set, bro. +// TODO: abstract this so that the navbar fixed styles are not placed here? + +.dropup, +.navbar-fixed-bottom .dropdown { + // Reverse the caret + .caret { + border-top: 0; + border-bottom: @caret-width-base dashed; + border-bottom: @caret-width-base solid ~"\9"; // IE8 + content: ""; + } + // Different positioning for bottom up menu + .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 2px; + } +} + + +// Component alignment +// +// Reiterate per navbar.less and the modified component alignment there. + +@media (min-width: @grid-float-breakpoint) { + .navbar-right { + .dropdown-menu { + .dropdown-menu-right(); + } + // Necessary for overrides of the default right aligned menu. + // Will remove come v4 in all likelihood. + .dropdown-menu-left { + .dropdown-menu-left(); + } + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/forms.less b/themes/demo/assets/vendor/bootstrap/less/forms.less new file mode 100644 index 0000000..9377d38 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/forms.less @@ -0,0 +1,613 @@ +// +// Forms +// -------------------------------------------------- + + +// Normalize non-controls +// +// Restyle and baseline non-control form elements. + +fieldset { + padding: 0; + margin: 0; + border: 0; + // Chrome and Firefox set a `min-width: min-content;` on fieldsets, + // so we reset that to ensure it behaves more like a standard block element. + // See https://github.com/twbs/bootstrap/issues/12359. + min-width: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: @line-height-computed; + font-size: (@font-size-base * 1.5); + line-height: inherit; + color: @legend-color; + border: 0; + border-bottom: 1px solid @legend-border-color; +} + +label { + display: inline-block; + max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141) + margin-bottom: 5px; + font-weight: bold; +} + + +// Normalize form controls +// +// While most of our form styles require extra classes, some basic normalization +// is required to ensure optimum display with or without those classes to better +// address browser inconsistencies. + +// Override content-box in Normalize (* isn't specific enough) +input[type="search"] { + .box-sizing(border-box); +} + +// Position radios and checkboxes better +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; // IE8-9 + line-height: normal; +} + +input[type="file"] { + display: block; +} + +// Make range inputs behave like textual form controls +input[type="range"] { + display: block; + width: 100%; +} + +// Make multiple select elements height not fixed +select[multiple], +select[size] { + height: auto; +} + +// Focus for file, radio, and checkbox +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + .tab-focus(); +} + +// Adjust output element +output { + display: block; + padding-top: (@padding-base-vertical + 1); + font-size: @font-size-base; + line-height: @line-height-base; + color: @input-color; +} + + +// Common form controls +// +// Shared size and type resets for form controls. Apply `.form-control` to any +// of the following form controls: +// +// select +// textarea +// input[type="text"] +// input[type="password"] +// input[type="datetime"] +// input[type="datetime-local"] +// input[type="date"] +// input[type="month"] +// input[type="time"] +// input[type="week"] +// input[type="number"] +// input[type="email"] +// input[type="url"] +// input[type="search"] +// input[type="tel"] +// input[type="color"] + +.form-control { + display: block; + width: 100%; + height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border) + padding: @padding-base-vertical @padding-base-horizontal; + font-size: @font-size-base; + line-height: @line-height-base; + color: @input-color; + background-color: @input-bg; + background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 + border: 1px solid @input-border; + border-radius: @input-border-radius; // Note: This has no effect on s in CSS. + .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); + .transition(~"border-color ease-in-out .15s, box-shadow ease-in-out .15s"); + + // Customize the `:focus` state to imitate native WebKit styles. + .form-control-focus(); + + // Placeholder + .placeholder(); + + // Unstyle the caret on `` +// element gets special love because it's special, and that's a fact! +.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) { + height: @input-height; + padding: @padding-vertical @padding-horizontal; + font-size: @font-size; + line-height: @line-height; + border-radius: @border-radius; + + select& { + height: @input-height; + line-height: @input-height; + } + + textarea&, + select[multiple]& { + height: auto; + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/gradients.less b/themes/demo/assets/vendor/bootstrap/less/mixins/gradients.less new file mode 100644 index 0000000..0b88a89 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/gradients.less @@ -0,0 +1,59 @@ +// Gradients + +#gradient { + + // Horizontal gradient, from left to right + // + // Creates two color stops, start and end, by specifying a color and position for each color stop. + // Color stops are not available in IE9 and below. + .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) { + background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+ + background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12 + background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+ + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@start-color),argb(@end-color))); // IE9 and down + } + + // Vertical gradient, from top to bottom + // + // Creates two color stops, start and end, by specifying a color and position for each color stop. + // Color stops are not available in IE9 and below. + .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) { + background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+ + background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12 + background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+ + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start-color),argb(@end-color))); // IE9 and down + } + + .directional(@start-color: #555; @end-color: #333; @deg: 45deg) { + background-repeat: repeat-x; + background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+ + background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12 + background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+ + } + .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) { + background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color); + background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color); + background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color); + background-repeat: no-repeat; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback + } + .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) { + background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color); + background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color); + background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color); + background-repeat: no-repeat; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback + } + .radial(@inner-color: #555; @outer-color: #333) { + background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color); + background-image: radial-gradient(circle, @inner-color, @outer-color); + background-repeat: no-repeat; + } + .striped(@color: rgba(255,255,255,.15); @angle: 45deg) { + background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent); + background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent); + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/grid-framework.less b/themes/demo/assets/vendor/bootstrap/less/mixins/grid-framework.less new file mode 100644 index 0000000..8c23eed --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/grid-framework.less @@ -0,0 +1,91 @@ +// Framework grid generation +// +// Used only by Bootstrap to generate the correct number of grid classes given +// any value of `@grid-columns`. + +.make-grid-columns() { + // Common styles for all sizes of grid columns, widths 1-12 + .col(@index) { // initial + @item: ~".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}"; + .col((@index + 1), @item); + } + .col(@index, @list) when (@index =< @grid-columns) { // general; "=<" isn't a typo + @item: ~".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}"; + .col((@index + 1), ~"@{list}, @{item}"); + } + .col(@index, @list) when (@index > @grid-columns) { // terminal + @{list} { + position: relative; + // Prevent columns from collapsing when empty + min-height: 1px; + // Inner gutter via padding + padding-left: ceil((@grid-gutter-width / 2)); + padding-right: floor((@grid-gutter-width / 2)); + } + } + .col(1); // kickstart it +} + +.float-grid-columns(@class) { + .col(@index) { // initial + @item: ~".col-@{class}-@{index}"; + .col((@index + 1), @item); + } + .col(@index, @list) when (@index =< @grid-columns) { // general + @item: ~".col-@{class}-@{index}"; + .col((@index + 1), ~"@{list}, @{item}"); + } + .col(@index, @list) when (@index > @grid-columns) { // terminal + @{list} { + float: left; + } + } + .col(1); // kickstart it +} + +.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) { + .col-@{class}-@{index} { + width: percentage((@index / @grid-columns)); + } +} +.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) { + .col-@{class}-push-@{index} { + left: percentage((@index / @grid-columns)); + } +} +.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) { + .col-@{class}-push-0 { + left: auto; + } +} +.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) { + .col-@{class}-pull-@{index} { + right: percentage((@index / @grid-columns)); + } +} +.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) { + .col-@{class}-pull-0 { + right: auto; + } +} +.calc-grid-column(@index, @class, @type) when (@type = offset) { + .col-@{class}-offset-@{index} { + margin-left: percentage((@index / @grid-columns)); + } +} + +// Basic looping in LESS +.loop-grid-columns(@index, @class, @type) when (@index >= 0) { + .calc-grid-column(@index, @class, @type); + // next iteration + .loop-grid-columns((@index - 1), @class, @type); +} + +// Create grid for specific class +.make-grid(@class) { + .float-grid-columns(@class); + .loop-grid-columns(@grid-columns, @class, width); + .loop-grid-columns(@grid-columns, @class, pull); + .loop-grid-columns(@grid-columns, @class, push); + .loop-grid-columns(@grid-columns, @class, offset); +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/grid.less b/themes/demo/assets/vendor/bootstrap/less/mixins/grid.less new file mode 100644 index 0000000..df496d0 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/grid.less @@ -0,0 +1,122 @@ +// Grid system +// +// Generate semantic grid columns with these mixins. + +// Centered container element +.container-fixed(@gutter: @grid-gutter-width) { + margin-right: auto; + margin-left: auto; + padding-left: floor((@gutter / 2)); + padding-right: ceil((@gutter / 2)); + &:extend(.clearfix all); +} + +// Creates a wrapper for a series of columns +.make-row(@gutter: @grid-gutter-width) { + margin-left: ceil((@gutter / -2)); + margin-right: floor((@gutter / -2)); + &:extend(.clearfix all); +} + +// Generate the extra small columns +.make-xs-column(@columns; @gutter: @grid-gutter-width) { + position: relative; + float: left; + width: percentage((@columns / @grid-columns)); + min-height: 1px; + padding-left: (@gutter / 2); + padding-right: (@gutter / 2); +} +.make-xs-column-offset(@columns) { + margin-left: percentage((@columns / @grid-columns)); +} +.make-xs-column-push(@columns) { + left: percentage((@columns / @grid-columns)); +} +.make-xs-column-pull(@columns) { + right: percentage((@columns / @grid-columns)); +} + +// Generate the small columns +.make-sm-column(@columns; @gutter: @grid-gutter-width) { + position: relative; + min-height: 1px; + padding-left: (@gutter / 2); + padding-right: (@gutter / 2); + + @media (min-width: @screen-sm-min) { + float: left; + width: percentage((@columns / @grid-columns)); + } +} +.make-sm-column-offset(@columns) { + @media (min-width: @screen-sm-min) { + margin-left: percentage((@columns / @grid-columns)); + } +} +.make-sm-column-push(@columns) { + @media (min-width: @screen-sm-min) { + left: percentage((@columns / @grid-columns)); + } +} +.make-sm-column-pull(@columns) { + @media (min-width: @screen-sm-min) { + right: percentage((@columns / @grid-columns)); + } +} + +// Generate the medium columns +.make-md-column(@columns; @gutter: @grid-gutter-width) { + position: relative; + min-height: 1px; + padding-left: (@gutter / 2); + padding-right: (@gutter / 2); + + @media (min-width: @screen-md-min) { + float: left; + width: percentage((@columns / @grid-columns)); + } +} +.make-md-column-offset(@columns) { + @media (min-width: @screen-md-min) { + margin-left: percentage((@columns / @grid-columns)); + } +} +.make-md-column-push(@columns) { + @media (min-width: @screen-md-min) { + left: percentage((@columns / @grid-columns)); + } +} +.make-md-column-pull(@columns) { + @media (min-width: @screen-md-min) { + right: percentage((@columns / @grid-columns)); + } +} + +// Generate the large columns +.make-lg-column(@columns; @gutter: @grid-gutter-width) { + position: relative; + min-height: 1px; + padding-left: (@gutter / 2); + padding-right: (@gutter / 2); + + @media (min-width: @screen-lg-min) { + float: left; + width: percentage((@columns / @grid-columns)); + } +} +.make-lg-column-offset(@columns) { + @media (min-width: @screen-lg-min) { + margin-left: percentage((@columns / @grid-columns)); + } +} +.make-lg-column-push(@columns) { + @media (min-width: @screen-lg-min) { + left: percentage((@columns / @grid-columns)); + } +} +.make-lg-column-pull(@columns) { + @media (min-width: @screen-lg-min) { + right: percentage((@columns / @grid-columns)); + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/hide-text.less b/themes/demo/assets/vendor/bootstrap/less/mixins/hide-text.less new file mode 100644 index 0000000..2bb84a3 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/hide-text.less @@ -0,0 +1,21 @@ +// CSS image replacement +// +// Heads up! v3 launched with only `.hide-text()`, but per our pattern for +// mixins being reused as classes with the same name, this doesn't hold up. As +// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. +// +// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757 + +// Deprecated as of v3.0.1 (has been removed in v4) +.hide-text() { + font: ~"0/0" a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +// New mixin to use as of v3.0.1 +.text-hide() { + .hide-text(); +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/image.less b/themes/demo/assets/vendor/bootstrap/less/mixins/image.less new file mode 100644 index 0000000..f233cb3 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/image.less @@ -0,0 +1,33 @@ +// Image Mixins +// - Responsive image +// - Retina image + + +// Responsive image +// +// Keep images from scaling beyond the width of their parents. +.img-responsive(@display: block) { + display: @display; + max-width: 100%; // Part 1: Set a maximum relative to the parent + height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching +} + + +// Retina image +// +// Short retina mixin for setting background-image and -size. Note that the +// spelling of `min--moz-device-pixel-ratio` is intentional. +.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) { + background-image: url("@{file-1x}"); + + @media + only screen and (-webkit-min-device-pixel-ratio: 2), + only screen and ( min--moz-device-pixel-ratio: 2), + only screen and ( -o-min-device-pixel-ratio: 2/1), + only screen and ( min-device-pixel-ratio: 2), + only screen and ( min-resolution: 192dpi), + only screen and ( min-resolution: 2dppx) { + background-image: url("@{file-2x}"); + background-size: @width-1x @height-1x; + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/labels.less b/themes/demo/assets/vendor/bootstrap/less/mixins/labels.less new file mode 100644 index 0000000..9f7a67e --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/labels.less @@ -0,0 +1,12 @@ +// Labels + +.label-variant(@color) { + background-color: @color; + + &[href] { + &:hover, + &:focus { + background-color: darken(@color, 10%); + } + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/list-group.less b/themes/demo/assets/vendor/bootstrap/less/mixins/list-group.less new file mode 100644 index 0000000..03aa190 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/list-group.less @@ -0,0 +1,30 @@ +// List Groups + +.list-group-item-variant(@state; @background; @color) { + .list-group-item-@{state} { + color: @color; + background-color: @background; + + a&, + button& { + color: @color; + + .list-group-item-heading { + color: inherit; + } + + &:hover, + &:focus { + color: @color; + background-color: darken(@background, 5%); + } + &.active, + &.active:hover, + &.active:focus { + color: #fff; + background-color: @color; + border-color: @color; + } + } + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/nav-divider.less b/themes/demo/assets/vendor/bootstrap/less/mixins/nav-divider.less new file mode 100644 index 0000000..feb1e9e --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/nav-divider.less @@ -0,0 +1,10 @@ +// Horizontal dividers +// +// Dividers (basically an hr) within dropdowns and nav lists + +.nav-divider(@color: #e5e5e5) { + height: 1px; + margin: ((@line-height-computed / 2) - 1) 0; + overflow: hidden; + background-color: @color; +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/nav-vertical-align.less b/themes/demo/assets/vendor/bootstrap/less/mixins/nav-vertical-align.less new file mode 100644 index 0000000..d458c78 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/nav-vertical-align.less @@ -0,0 +1,9 @@ +// Navbar vertical align +// +// Vertically center elements in the navbar. +// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin. + +.navbar-vertical-align(@element-height) { + margin-top: ((@navbar-height - @element-height) / 2); + margin-bottom: ((@navbar-height - @element-height) / 2); +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/opacity.less b/themes/demo/assets/vendor/bootstrap/less/mixins/opacity.less new file mode 100644 index 0000000..33ed25c --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/opacity.less @@ -0,0 +1,8 @@ +// Opacity + +.opacity(@opacity) { + opacity: @opacity; + // IE8 filter + @opacity-ie: (@opacity * 100); + filter: ~"alpha(opacity=@{opacity-ie})"; +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/pagination.less b/themes/demo/assets/vendor/bootstrap/less/mixins/pagination.less new file mode 100644 index 0000000..618804f --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/pagination.less @@ -0,0 +1,24 @@ +// Pagination + +.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) { + > li { + > a, + > span { + padding: @padding-vertical @padding-horizontal; + font-size: @font-size; + line-height: @line-height; + } + &:first-child { + > a, + > span { + .border-left-radius(@border-radius); + } + } + &:last-child { + > a, + > span { + .border-right-radius(@border-radius); + } + } + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/panels.less b/themes/demo/assets/vendor/bootstrap/less/mixins/panels.less new file mode 100644 index 0000000..49ee10d --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/panels.less @@ -0,0 +1,24 @@ +// Panels + +.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) { + border-color: @border; + + & > .panel-heading { + color: @heading-text-color; + background-color: @heading-bg-color; + border-color: @heading-border; + + + .panel-collapse > .panel-body { + border-top-color: @border; + } + .badge { + color: @heading-bg-color; + background-color: @heading-text-color; + } + } + & > .panel-footer { + + .panel-collapse > .panel-body { + border-bottom-color: @border; + } + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/progress-bar.less b/themes/demo/assets/vendor/bootstrap/less/mixins/progress-bar.less new file mode 100644 index 0000000..f07996a --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/progress-bar.less @@ -0,0 +1,10 @@ +// Progress bars + +.progress-bar-variant(@color) { + background-color: @color; + + // Deprecated parent class requirement as of v3.2.0 + .progress-striped & { + #gradient > .striped(); + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/reset-filter.less b/themes/demo/assets/vendor/bootstrap/less/mixins/reset-filter.less new file mode 100644 index 0000000..68cdb5e --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/reset-filter.less @@ -0,0 +1,8 @@ +// Reset filters for IE +// +// When you need to remove a gradient background, do not forget to use this to reset +// the IE filter for IE9 and below. + +.reset-filter() { + filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)")); +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/reset-text.less b/themes/demo/assets/vendor/bootstrap/less/mixins/reset-text.less new file mode 100644 index 0000000..58dd4d1 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/reset-text.less @@ -0,0 +1,18 @@ +.reset-text() { + font-family: @font-family-base; + // We deliberately do NOT reset font-size. + font-style: normal; + font-weight: normal; + letter-spacing: normal; + line-break: auto; + line-height: @line-height-base; + text-align: left; // Fallback for where `start` is not supported + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + white-space: normal; + word-break: normal; + word-spacing: normal; + word-wrap: normal; +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/resize.less b/themes/demo/assets/vendor/bootstrap/less/mixins/resize.less new file mode 100644 index 0000000..3acd3af --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/resize.less @@ -0,0 +1,6 @@ +// Resize anything + +.resizable(@direction) { + resize: @direction; // Options: horizontal, vertical, both + overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible` +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/responsive-visibility.less b/themes/demo/assets/vendor/bootstrap/less/mixins/responsive-visibility.less new file mode 100644 index 0000000..ecf1e97 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/responsive-visibility.less @@ -0,0 +1,15 @@ +// Responsive utilities + +// +// More easily include all the states for responsive-utilities.less. +.responsive-visibility() { + display: block !important; + table& { display: table !important; } + tr& { display: table-row !important; } + th&, + td& { display: table-cell !important; } +} + +.responsive-invisibility() { + display: none !important; +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/size.less b/themes/demo/assets/vendor/bootstrap/less/mixins/size.less new file mode 100644 index 0000000..a8be650 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/size.less @@ -0,0 +1,10 @@ +// Sizing shortcuts + +.size(@width; @height) { + width: @width; + height: @height; +} + +.square(@size) { + .size(@size; @size); +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/tab-focus.less b/themes/demo/assets/vendor/bootstrap/less/mixins/tab-focus.less new file mode 100644 index 0000000..d12d236 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/tab-focus.less @@ -0,0 +1,9 @@ +// WebKit-style focus + +.tab-focus() { + // WebKit-specific. Other browsers will keep their default outline style. + // (Initially tried to also force default via `outline: initial`, + // but that seems to erroneously remove the outline in Firefox altogether.) + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/table-row.less b/themes/demo/assets/vendor/bootstrap/less/mixins/table-row.less new file mode 100644 index 0000000..0f287f1 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/table-row.less @@ -0,0 +1,28 @@ +// Tables + +.table-row-variant(@state; @background) { + // Exact selectors below required to override `.table-striped` and prevent + // inheritance to nested tables. + .table > thead > tr, + .table > tbody > tr, + .table > tfoot > tr { + > td.@{state}, + > th.@{state}, + &.@{state} > td, + &.@{state} > th { + background-color: @background; + } + } + + // Hover states for `.table-hover` + // Note: this is not available for cells or rows within `thead` or `tfoot`. + .table-hover > tbody > tr { + > td.@{state}:hover, + > th.@{state}:hover, + &.@{state}:hover > td, + &:hover > .@{state}, + &.@{state}:hover > th { + background-color: darken(@background, 5%); + } + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/text-emphasis.less b/themes/demo/assets/vendor/bootstrap/less/mixins/text-emphasis.less new file mode 100644 index 0000000..9e8a77a --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/text-emphasis.less @@ -0,0 +1,9 @@ +// Typography + +.text-emphasis-variant(@color) { + color: @color; + a&:hover, + a&:focus { + color: darken(@color, 10%); + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/text-overflow.less b/themes/demo/assets/vendor/bootstrap/less/mixins/text-overflow.less new file mode 100644 index 0000000..c11ad2f --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/text-overflow.less @@ -0,0 +1,8 @@ +// Text overflow +// Requires inline-block or block for proper styling + +.text-overflow() { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/themes/demo/assets/vendor/bootstrap/less/mixins/vendor-prefixes.less b/themes/demo/assets/vendor/bootstrap/less/mixins/vendor-prefixes.less new file mode 100644 index 0000000..2b5e74b --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/mixins/vendor-prefixes.less @@ -0,0 +1,227 @@ +// Vendor Prefixes +// +// All vendor mixins are deprecated as of v3.2.0 due to the introduction of +// Autoprefixer in our Gruntfile. They have been removed in v4. + +// - Animations +// - Backface visibility +// - Box shadow +// - Box sizing +// - Content columns +// - Hyphens +// - Placeholder text +// - Transformations +// - Transitions +// - User Select + + +// Animations +.animation(@animation) { + -webkit-animation: @animation; + -o-animation: @animation; + animation: @animation; +} +.animation-name(@name) { + -webkit-animation-name: @name; + animation-name: @name; +} +.animation-duration(@duration) { + -webkit-animation-duration: @duration; + animation-duration: @duration; +} +.animation-timing-function(@timing-function) { + -webkit-animation-timing-function: @timing-function; + animation-timing-function: @timing-function; +} +.animation-delay(@delay) { + -webkit-animation-delay: @delay; + animation-delay: @delay; +} +.animation-iteration-count(@iteration-count) { + -webkit-animation-iteration-count: @iteration-count; + animation-iteration-count: @iteration-count; +} +.animation-direction(@direction) { + -webkit-animation-direction: @direction; + animation-direction: @direction; +} +.animation-fill-mode(@fill-mode) { + -webkit-animation-fill-mode: @fill-mode; + animation-fill-mode: @fill-mode; +} + +// Backface visibility +// Prevent browsers from flickering when using CSS 3D transforms. +// Default value is `visible`, but can be changed to `hidden` + +.backface-visibility(@visibility) { + -webkit-backface-visibility: @visibility; + -moz-backface-visibility: @visibility; + backface-visibility: @visibility; +} + +// Drop shadows +// +// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's +// supported browsers that have box shadow capabilities now support it. + +.box-shadow(@shadow) { + -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1 + box-shadow: @shadow; +} + +// Box sizing +.box-sizing(@boxmodel) { + -webkit-box-sizing: @boxmodel; + -moz-box-sizing: @boxmodel; + box-sizing: @boxmodel; +} + +// CSS3 Content Columns +.content-columns(@column-count; @column-gap: @grid-gutter-width) { + -webkit-column-count: @column-count; + -moz-column-count: @column-count; + column-count: @column-count; + -webkit-column-gap: @column-gap; + -moz-column-gap: @column-gap; + column-gap: @column-gap; +} + +// Optional hyphenation +.hyphens(@mode: auto) { + word-wrap: break-word; + -webkit-hyphens: @mode; + -moz-hyphens: @mode; + -ms-hyphens: @mode; // IE10+ + -o-hyphens: @mode; + hyphens: @mode; +} + +// Placeholder text +.placeholder(@color: @input-color-placeholder) { + // Firefox + &::-moz-placeholder { + color: @color; + opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526 + } + &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+ + &::-webkit-input-placeholder { color: @color; } // Safari and Chrome +} + +// Transformations +.scale(@ratio) { + -webkit-transform: scale(@ratio); + -ms-transform: scale(@ratio); // IE9 only + -o-transform: scale(@ratio); + transform: scale(@ratio); +} +.scale(@ratioX; @ratioY) { + -webkit-transform: scale(@ratioX, @ratioY); + -ms-transform: scale(@ratioX, @ratioY); // IE9 only + -o-transform: scale(@ratioX, @ratioY); + transform: scale(@ratioX, @ratioY); +} +.scaleX(@ratio) { + -webkit-transform: scaleX(@ratio); + -ms-transform: scaleX(@ratio); // IE9 only + -o-transform: scaleX(@ratio); + transform: scaleX(@ratio); +} +.scaleY(@ratio) { + -webkit-transform: scaleY(@ratio); + -ms-transform: scaleY(@ratio); // IE9 only + -o-transform: scaleY(@ratio); + transform: scaleY(@ratio); +} +.skew(@x; @y) { + -webkit-transform: skewX(@x) skewY(@y); + -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+ + -o-transform: skewX(@x) skewY(@y); + transform: skewX(@x) skewY(@y); +} +.translate(@x; @y) { + -webkit-transform: translate(@x, @y); + -ms-transform: translate(@x, @y); // IE9 only + -o-transform: translate(@x, @y); + transform: translate(@x, @y); +} +.translate3d(@x; @y; @z) { + -webkit-transform: translate3d(@x, @y, @z); + transform: translate3d(@x, @y, @z); +} +.rotate(@degrees) { + -webkit-transform: rotate(@degrees); + -ms-transform: rotate(@degrees); // IE9 only + -o-transform: rotate(@degrees); + transform: rotate(@degrees); +} +.rotateX(@degrees) { + -webkit-transform: rotateX(@degrees); + -ms-transform: rotateX(@degrees); // IE9 only + -o-transform: rotateX(@degrees); + transform: rotateX(@degrees); +} +.rotateY(@degrees) { + -webkit-transform: rotateY(@degrees); + -ms-transform: rotateY(@degrees); // IE9 only + -o-transform: rotateY(@degrees); + transform: rotateY(@degrees); +} +.perspective(@perspective) { + -webkit-perspective: @perspective; + -moz-perspective: @perspective; + perspective: @perspective; +} +.perspective-origin(@perspective) { + -webkit-perspective-origin: @perspective; + -moz-perspective-origin: @perspective; + perspective-origin: @perspective; +} +.transform-origin(@origin) { + -webkit-transform-origin: @origin; + -moz-transform-origin: @origin; + -ms-transform-origin: @origin; // IE9 only + transform-origin: @origin; +} + + +// Transitions + +.transition(@transition) { + -webkit-transition: @transition; + -o-transition: @transition; + transition: @transition; +} +.transition-property(@transition-property) { + -webkit-transition-property: @transition-property; + transition-property: @transition-property; +} +.transition-delay(@transition-delay) { + -webkit-transition-delay: @transition-delay; + transition-delay: @transition-delay; +} +.transition-duration(@transition-duration) { + -webkit-transition-duration: @transition-duration; + transition-duration: @transition-duration; +} +.transition-timing-function(@timing-function) { + -webkit-transition-timing-function: @timing-function; + transition-timing-function: @timing-function; +} +.transition-transform(@transition) { + -webkit-transition: -webkit-transform @transition; + -moz-transition: -moz-transform @transition; + -o-transition: -o-transform @transition; + transition: transform @transition; +} + + +// User select +// For selecting text on the page + +.user-select(@select) { + -webkit-user-select: @select; + -moz-user-select: @select; + -ms-user-select: @select; // IE10+ + user-select: @select; +} diff --git a/themes/demo/assets/vendor/bootstrap/less/modals.less b/themes/demo/assets/vendor/bootstrap/less/modals.less new file mode 100644 index 0000000..767ce36 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/modals.less @@ -0,0 +1,150 @@ +// +// Modals +// -------------------------------------------------- + +// .modal-open - body class for killing the scroll +// .modal - container to scroll within +// .modal-dialog - positioning shell for the actual modal +// .modal-content - actual modal w/ bg and corners and shit + +// Kill the scroll on the body +.modal-open { + overflow: hidden; +} + +// Container that the modal scrolls within +.modal { + display: none; + overflow: hidden; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: @zindex-modal; + -webkit-overflow-scrolling: touch; + + // Prevent Chrome on Windows from adding a focus outline. For details, see + // https://github.com/twbs/bootstrap/pull/10951. + outline: 0; + + // When fading in the modal, animate it to slide down + &.fade .modal-dialog { + .translate(0, -25%); + .transition-transform(~"0.3s ease-out"); + } + &.in .modal-dialog { .translate(0, 0) } +} +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} + +// Shell div to position the modal with bottom padding +.modal-dialog { + position: relative; + width: auto; + margin: 10px; +} + +// Actual modal +.modal-content { + position: relative; + background-color: @modal-content-bg; + border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc) + border: 1px solid @modal-content-border-color; + border-radius: @border-radius-large; + .box-shadow(0 3px 9px rgba(0,0,0,.5)); + background-clip: padding-box; + // Remove focus outline from opened modal + outline: 0; +} + +// Modal background +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: @zindex-modal-background; + background-color: @modal-backdrop-bg; + // Fade for backdrop + &.fade { .opacity(0); } + &.in { .opacity(@modal-backdrop-opacity); } +} + +// Modal header +// Top section of the modal w/ title and dismiss +.modal-header { + padding: @modal-title-padding; + border-bottom: 1px solid @modal-header-border-color; + &:extend(.clearfix all); +} +// Close icon +.modal-header .close { + margin-top: -2px; +} + +// Title text within header +.modal-title { + margin: 0; + line-height: @modal-title-line-height; +} + +// Modal body +// Where all modal content resides (sibling of .modal-header and .modal-footer) +.modal-body { + position: relative; + padding: @modal-inner-padding; +} + +// Footer (for actions) +.modal-footer { + padding: @modal-inner-padding; + text-align: right; // right align buttons + border-top: 1px solid @modal-footer-border-color; + &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons + + // Properly space out buttons + .btn + .btn { + margin-left: 5px; + margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs + } + // but override that for button groups + .btn-group .btn + .btn { + margin-left: -1px; + } + // and override it for block buttons as well + .btn-block + .btn-block { + margin-left: 0; + } +} + +// Measure scrollbar width for padding body during modal show/hide +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} + +// Scale up the modal +@media (min-width: @screen-sm-min) { + // Automatically set modal's width for larger viewports + .modal-dialog { + width: @modal-md; + margin: 30px auto; + } + .modal-content { + .box-shadow(0 5px 15px rgba(0,0,0,.5)); + } + + // Modal sizes + .modal-sm { width: @modal-sm; } +} + +@media (min-width: @screen-md-min) { + .modal-lg { width: @modal-lg; } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/navbar.less b/themes/demo/assets/vendor/bootstrap/less/navbar.less new file mode 100644 index 0000000..6d751bb --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/navbar.less @@ -0,0 +1,660 @@ +// +// Navbars +// -------------------------------------------------- + + +// Wrapper and base class +// +// Provide a static navbar from which we expand to create full-width, fixed, and +// other navbar variations. + +.navbar { + position: relative; + min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode) + margin-bottom: @navbar-margin-bottom; + border: 1px solid transparent; + + // Prevent floats from breaking the navbar + &:extend(.clearfix all); + + @media (min-width: @grid-float-breakpoint) { + border-radius: @navbar-border-radius; + } +} + + +// Navbar heading +// +// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy +// styling of responsive aspects. + +.navbar-header { + &:extend(.clearfix all); + + @media (min-width: @grid-float-breakpoint) { + float: left; + } +} + + +// Navbar collapse (body) +// +// Group your navbar content into this for easy collapsing and expanding across +// various device sizes. By default, this content is collapsed when <768px, but +// will expand past that for a horizontal display. +// +// To start (on mobile devices) the navbar links, forms, and buttons are stacked +// vertically and include a `max-height` to overflow in case you have too much +// content for the user's viewport. + +.navbar-collapse { + overflow-x: visible; + padding-right: @navbar-padding-horizontal; + padding-left: @navbar-padding-horizontal; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255,255,255,.1); + &:extend(.clearfix all); + -webkit-overflow-scrolling: touch; + + &.in { + overflow-y: auto; + } + + @media (min-width: @grid-float-breakpoint) { + width: auto; + border-top: 0; + box-shadow: none; + + &.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; // Override default setting + overflow: visible !important; + } + + &.in { + overflow-y: visible; + } + + // Undo the collapse side padding for navbars with containers to ensure + // alignment of right-aligned contents. + .navbar-fixed-top &, + .navbar-static-top &, + .navbar-fixed-bottom & { + padding-left: 0; + padding-right: 0; + } + } +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + .navbar-collapse { + max-height: @navbar-collapse-max-height; + + @media (max-device-width: @screen-xs-min) and (orientation: landscape) { + max-height: 200px; + } + } +} + + +// Both navbar header and collapse +// +// When a container is present, change the behavior of the header and collapse. + +.container, +.container-fluid { + > .navbar-header, + > .navbar-collapse { + margin-right: -@navbar-padding-horizontal; + margin-left: -@navbar-padding-horizontal; + + @media (min-width: @grid-float-breakpoint) { + margin-right: 0; + margin-left: 0; + } + } +} + + +// +// Navbar alignment options +// +// Display the navbar across the entirety of the page or fixed it to the top or +// bottom of the page. + +// Static top (unfixed, but 100% wide) navbar +.navbar-static-top { + z-index: @zindex-navbar; + border-width: 0 0 1px; + + @media (min-width: @grid-float-breakpoint) { + border-radius: 0; + } +} + +// Fix the top/bottom navbars when screen real estate supports it +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: @zindex-navbar-fixed; + + // Undo the rounded corners + @media (min-width: @grid-float-breakpoint) { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; // override .navbar defaults + border-width: 1px 0 0; +} + + +// Brand/project name + +.navbar-brand { + float: left; + padding: @navbar-padding-vertical @navbar-padding-horizontal; + font-size: @font-size-large; + line-height: @line-height-computed; + height: @navbar-height; + + &:hover, + &:focus { + text-decoration: none; + } + + > img { + display: block; + } + + @media (min-width: @grid-float-breakpoint) { + .navbar > .container &, + .navbar > .container-fluid & { + margin-left: -@navbar-padding-horizontal; + } + } +} + + +// Navbar toggle +// +// Custom button for toggling the `.navbar-collapse`, powered by the collapse +// JavaScript plugin. + +.navbar-toggle { + position: relative; + float: right; + margin-right: @navbar-padding-horizontal; + padding: 9px 10px; + .navbar-vertical-align(34px); + background-color: transparent; + background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 + border: 1px solid transparent; + border-radius: @border-radius-base; + + // We remove the `outline` here, but later compensate by attaching `:hover` + // styles to `:focus`. + &:focus { + outline: 0; + } + + // Bars + .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; + } + .icon-bar + .icon-bar { + margin-top: 4px; + } + + @media (min-width: @grid-float-breakpoint) { + display: none; + } +} + + +// Navbar nav links +// +// Builds on top of the `.nav` components with its own modifier class to make +// the nav the full height of the horizontal nav (above 768px). + +.navbar-nav { + margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal; + + > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: @line-height-computed; + } + + @media (max-width: @grid-float-breakpoint-max) { + // Dropdowns get custom display when collapsed + .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + box-shadow: none; + > li > a, + .dropdown-header { + padding: 5px 15px 5px 25px; + } + > li > a { + line-height: @line-height-computed; + &:hover, + &:focus { + background-image: none; + } + } + } + } + + // Uncollapse the nav + @media (min-width: @grid-float-breakpoint) { + float: left; + margin: 0; + + > li { + float: left; + > a { + padding-top: @navbar-padding-vertical; + padding-bottom: @navbar-padding-vertical; + } + } + } +} + + +// Navbar form +// +// Extension of the `.form-inline` with some extra flavor for optimum display in +// our navbars. + +.navbar-form { + margin-left: -@navbar-padding-horizontal; + margin-right: -@navbar-padding-horizontal; + padding: 10px @navbar-padding-horizontal; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1); + .box-shadow(@shadow); + + // Mixin behavior for optimum display + .form-inline(); + + .form-group { + @media (max-width: @grid-float-breakpoint-max) { + margin-bottom: 5px; + + &:last-child { + margin-bottom: 0; + } + } + } + + // Vertically center in expanded, horizontal navbar + .navbar-vertical-align(@input-height-base); + + // Undo 100% width for pull classes + @media (min-width: @grid-float-breakpoint) { + width: auto; + border: 0; + margin-left: 0; + margin-right: 0; + padding-top: 0; + padding-bottom: 0; + .box-shadow(none); + } +} + + +// Dropdown menus + +// Menu position and menu carets +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + .border-top-radius(0); +} +// Menu position and menu caret support for dropups via extra dropup class +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + margin-bottom: 0; + .border-top-radius(@navbar-border-radius); + .border-bottom-radius(0); +} + + +// Buttons in navbars +// +// Vertically center a button within a navbar (when *not* in a form). + +.navbar-btn { + .navbar-vertical-align(@input-height-base); + + &.btn-sm { + .navbar-vertical-align(@input-height-small); + } + &.btn-xs { + .navbar-vertical-align(22); + } +} + + +// Text in navbars +// +// Add a class to make any element properly align itself vertically within the navbars. + +.navbar-text { + .navbar-vertical-align(@line-height-computed); + + @media (min-width: @grid-float-breakpoint) { + float: left; + margin-left: @navbar-padding-horizontal; + margin-right: @navbar-padding-horizontal; + } +} + + +// Component alignment +// +// Repurpose the pull utilities as their own navbar utilities to avoid specificity +// issues with parents and chaining. Only do this when the navbar is uncollapsed +// though so that navbar contents properly stack and align in mobile. +// +// Declared after the navbar components to ensure more specificity on the margins. + +@media (min-width: @grid-float-breakpoint) { + .navbar-left { .pull-left(); } + .navbar-right { + .pull-right(); + margin-right: -@navbar-padding-horizontal; + + ~ .navbar-right { + margin-right: 0; + } + } +} + + +// Alternate navbars +// -------------------------------------------------- + +// Default navbar +.navbar-default { + background-color: @navbar-default-bg; + border-color: @navbar-default-border; + + .navbar-brand { + color: @navbar-default-brand-color; + &:hover, + &:focus { + color: @navbar-default-brand-hover-color; + background-color: @navbar-default-brand-hover-bg; + } + } + + .navbar-text { + color: @navbar-default-color; + } + + .navbar-nav { + > li > a { + color: @navbar-default-link-color; + + &:hover, + &:focus { + color: @navbar-default-link-hover-color; + background-color: @navbar-default-link-hover-bg; + } + } + > .active > a { + &, + &:hover, + &:focus { + color: @navbar-default-link-active-color; + background-color: @navbar-default-link-active-bg; + } + } + > .disabled > a { + &, + &:hover, + &:focus { + color: @navbar-default-link-disabled-color; + background-color: @navbar-default-link-disabled-bg; + } + } + } + + .navbar-toggle { + border-color: @navbar-default-toggle-border-color; + &:hover, + &:focus { + background-color: @navbar-default-toggle-hover-bg; + } + .icon-bar { + background-color: @navbar-default-toggle-icon-bar-bg; + } + } + + .navbar-collapse, + .navbar-form { + border-color: @navbar-default-border; + } + + // Dropdown menu items + .navbar-nav { + // Remove background color from open dropdown + > .open > a { + &, + &:hover, + &:focus { + background-color: @navbar-default-link-active-bg; + color: @navbar-default-link-active-color; + } + } + + @media (max-width: @grid-float-breakpoint-max) { + // Dropdowns get custom display when collapsed + .open .dropdown-menu { + > li > a { + color: @navbar-default-link-color; + &:hover, + &:focus { + color: @navbar-default-link-hover-color; + background-color: @navbar-default-link-hover-bg; + } + } + > .active > a { + &, + &:hover, + &:focus { + color: @navbar-default-link-active-color; + background-color: @navbar-default-link-active-bg; + } + } + > .disabled > a { + &, + &:hover, + &:focus { + color: @navbar-default-link-disabled-color; + background-color: @navbar-default-link-disabled-bg; + } + } + } + } + } + + + // Links in navbars + // + // Add a class to ensure links outside the navbar nav are colored correctly. + + .navbar-link { + color: @navbar-default-link-color; + &:hover { + color: @navbar-default-link-hover-color; + } + } + + .btn-link { + color: @navbar-default-link-color; + &:hover, + &:focus { + color: @navbar-default-link-hover-color; + } + &[disabled], + fieldset[disabled] & { + &:hover, + &:focus { + color: @navbar-default-link-disabled-color; + } + } + } +} + +// Inverse navbar + +.navbar-inverse { + background-color: @navbar-inverse-bg; + border-color: @navbar-inverse-border; + + .navbar-brand { + color: @navbar-inverse-brand-color; + &:hover, + &:focus { + color: @navbar-inverse-brand-hover-color; + background-color: @navbar-inverse-brand-hover-bg; + } + } + + .navbar-text { + color: @navbar-inverse-color; + } + + .navbar-nav { + > li > a { + color: @navbar-inverse-link-color; + + &:hover, + &:focus { + color: @navbar-inverse-link-hover-color; + background-color: @navbar-inverse-link-hover-bg; + } + } + > .active > a { + &, + &:hover, + &:focus { + color: @navbar-inverse-link-active-color; + background-color: @navbar-inverse-link-active-bg; + } + } + > .disabled > a { + &, + &:hover, + &:focus { + color: @navbar-inverse-link-disabled-color; + background-color: @navbar-inverse-link-disabled-bg; + } + } + } + + // Darken the responsive nav toggle + .navbar-toggle { + border-color: @navbar-inverse-toggle-border-color; + &:hover, + &:focus { + background-color: @navbar-inverse-toggle-hover-bg; + } + .icon-bar { + background-color: @navbar-inverse-toggle-icon-bar-bg; + } + } + + .navbar-collapse, + .navbar-form { + border-color: darken(@navbar-inverse-bg, 7%); + } + + // Dropdowns + .navbar-nav { + > .open > a { + &, + &:hover, + &:focus { + background-color: @navbar-inverse-link-active-bg; + color: @navbar-inverse-link-active-color; + } + } + + @media (max-width: @grid-float-breakpoint-max) { + // Dropdowns get custom display + .open .dropdown-menu { + > .dropdown-header { + border-color: @navbar-inverse-border; + } + .divider { + background-color: @navbar-inverse-border; + } + > li > a { + color: @navbar-inverse-link-color; + &:hover, + &:focus { + color: @navbar-inverse-link-hover-color; + background-color: @navbar-inverse-link-hover-bg; + } + } + > .active > a { + &, + &:hover, + &:focus { + color: @navbar-inverse-link-active-color; + background-color: @navbar-inverse-link-active-bg; + } + } + > .disabled > a { + &, + &:hover, + &:focus { + color: @navbar-inverse-link-disabled-color; + background-color: @navbar-inverse-link-disabled-bg; + } + } + } + } + } + + .navbar-link { + color: @navbar-inverse-link-color; + &:hover { + color: @navbar-inverse-link-hover-color; + } + } + + .btn-link { + color: @navbar-inverse-link-color; + &:hover, + &:focus { + color: @navbar-inverse-link-hover-color; + } + &[disabled], + fieldset[disabled] & { + &:hover, + &:focus { + color: @navbar-inverse-link-disabled-color; + } + } + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/navs.less b/themes/demo/assets/vendor/bootstrap/less/navs.less new file mode 100644 index 0000000..a3d11b1 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/navs.less @@ -0,0 +1,242 @@ +// +// Navs +// -------------------------------------------------- + + +// Base class +// -------------------------------------------------- + +.nav { + margin-bottom: 0; + padding-left: 0; // Override default ul/ol + list-style: none; + &:extend(.clearfix all); + + > li { + position: relative; + display: block; + + > a { + position: relative; + display: block; + padding: @nav-link-padding; + &:hover, + &:focus { + text-decoration: none; + background-color: @nav-link-hover-bg; + } + } + + // Disabled state sets text to gray and nukes hover/tab effects + &.disabled > a { + color: @nav-disabled-link-color; + + &:hover, + &:focus { + color: @nav-disabled-link-hover-color; + text-decoration: none; + background-color: transparent; + cursor: @cursor-disabled; + } + } + } + + // Open dropdowns + .open > a { + &, + &:hover, + &:focus { + background-color: @nav-link-hover-bg; + border-color: @link-color; + } + } + + // Nav dividers (deprecated with v3.0.1) + // + // This should have been removed in v3 with the dropping of `.nav-list`, but + // we missed it. We don't currently support this anywhere, but in the interest + // of maintaining backward compatibility in case you use it, it's deprecated. + .nav-divider { + .nav-divider(); + } + + // Prevent IE8 from misplacing imgs + // + // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989 + > li > a > img { + max-width: none; + } +} + + +// Tabs +// ------------------------- + +// Give the tabs something to sit on +.nav-tabs { + border-bottom: 1px solid @nav-tabs-border-color; + > li { + float: left; + // Make the list-items overlay the bottom border + margin-bottom: -1px; + + // Actual tabs (as links) + > a { + margin-right: 2px; + line-height: @line-height-base; + border: 1px solid transparent; + border-radius: @border-radius-base @border-radius-base 0 0; + &:hover { + border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color; + } + } + + // Active state, and its :hover to override normal :hover + &.active > a { + &, + &:hover, + &:focus { + color: @nav-tabs-active-link-hover-color; + background-color: @nav-tabs-active-link-hover-bg; + border: 1px solid @nav-tabs-active-link-hover-border-color; + border-bottom-color: transparent; + cursor: default; + } + } + } + // pulling this in mainly for less shorthand + &.nav-justified { + .nav-justified(); + .nav-tabs-justified(); + } +} + + +// Pills +// ------------------------- +.nav-pills { + > li { + float: left; + + // Links rendered as pills + > a { + border-radius: @nav-pills-border-radius; + } + + li { + margin-left: 2px; + } + + // Active state + &.active > a { + &, + &:hover, + &:focus { + color: @nav-pills-active-link-hover-color; + background-color: @nav-pills-active-link-hover-bg; + } + } + } +} + + +// Stacked pills +.nav-stacked { + > li { + float: none; + + li { + margin-top: 2px; + margin-left: 0; // no need for this gap between nav items + } + } +} + + +// Nav variations +// -------------------------------------------------- + +// Justified nav links +// ------------------------- + +.nav-justified { + width: 100%; + + > li { + float: none; + > a { + text-align: center; + margin-bottom: 5px; + } + } + + > .dropdown .dropdown-menu { + top: auto; + left: auto; + } + + @media (min-width: @screen-sm-min) { + > li { + display: table-cell; + width: 1%; + > a { + margin-bottom: 0; + } + } + } +} + +// Move borders to anchors instead of bottom of list +// +// Mixin for adding on top the shared `.nav-justified` styles for our tabs +.nav-tabs-justified { + border-bottom: 0; + + > li > a { + // Override margin from .nav-tabs + margin-right: 0; + border-radius: @border-radius-base; + } + + > .active > a, + > .active > a:hover, + > .active > a:focus { + border: 1px solid @nav-tabs-justified-link-border-color; + } + + @media (min-width: @screen-sm-min) { + > li > a { + border-bottom: 1px solid @nav-tabs-justified-link-border-color; + border-radius: @border-radius-base @border-radius-base 0 0; + } + > .active > a, + > .active > a:hover, + > .active > a:focus { + border-bottom-color: @nav-tabs-justified-active-link-border-color; + } + } +} + + +// Tabbable tabs +// ------------------------- + +// Hide tabbable panes to start, show them when `.active` +.tab-content { + > .tab-pane { + display: none; + } + > .active { + display: block; + } +} + + +// Dropdowns +// ------------------------- + +// Specific dropdowns +.nav-tabs .dropdown-menu { + // make dropdown border overlap tab border + margin-top: -1px; + // Remove the top rounded corners here since there is a hard edge above the menu + .border-top-radius(0); +} diff --git a/themes/demo/assets/vendor/bootstrap/less/normalize.less b/themes/demo/assets/vendor/bootstrap/less/normalize.less new file mode 100644 index 0000000..9dddf73 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/normalize.less @@ -0,0 +1,424 @@ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ + +// +// 1. Set default font family to sans-serif. +// 2. Prevent iOS and IE text size adjust after device orientation change, +// without disabling user zoom. +// + +html { + font-family: sans-serif; // 1 + -ms-text-size-adjust: 100%; // 2 + -webkit-text-size-adjust: 100%; // 2 +} + +// +// Remove default margin. +// + +body { + margin: 0; +} + +// HTML5 display definitions +// ========================================================================== + +// +// Correct `block` display not defined for any HTML5 element in IE 8/9. +// Correct `block` display not defined for `details` or `summary` in IE 10/11 +// and Firefox. +// Correct `block` display not defined for `main` in IE 11. +// + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} + +// +// 1. Correct `inline-block` display not defined in IE 8/9. +// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. +// + +audio, +canvas, +progress, +video { + display: inline-block; // 1 + vertical-align: baseline; // 2 +} + +// +// Prevent modern browsers from displaying `audio` without controls. +// Remove excess height in iOS 5 devices. +// + +audio:not([controls]) { + display: none; + height: 0; +} + +// +// Address `[hidden]` styling not present in IE 8/9/10. +// Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. +// + +[hidden], +template { + display: none; +} + +// Links +// ========================================================================== + +// +// Remove the gray background color from active links in IE 10. +// + +a { + background-color: transparent; +} + +// +// Improve readability of focused elements when they are also in an +// active/hover state. +// + +a:active, +a:hover { + outline: 0; +} + +// Text-level semantics +// ========================================================================== + +// +// Address styling not present in IE 8/9/10/11, Safari, and Chrome. +// + +abbr[title] { + border-bottom: 1px dotted; +} + +// +// Address style set to `bolder` in Firefox 4+, Safari, and Chrome. +// + +b, +strong { + font-weight: bold; +} + +// +// Address styling not present in Safari and Chrome. +// + +dfn { + font-style: italic; +} + +// +// Address variable `h1` font-size and margin within `section` and `article` +// contexts in Firefox 4+, Safari, and Chrome. +// + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +// +// Address styling not present in IE 8/9. +// + +mark { + background: #ff0; + color: #000; +} + +// +// Address inconsistent and variable font size in all browsers. +// + +small { + font-size: 80%; +} + +// +// Prevent `sub` and `sup` affecting `line-height` in all browsers. +// + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +// Embedded content +// ========================================================================== + +// +// Remove border when inside `a` element in IE 8/9/10. +// + +img { + border: 0; +} + +// +// Correct overflow not hidden in IE 9/10/11. +// + +svg:not(:root) { + overflow: hidden; +} + +// Grouping content +// ========================================================================== + +// +// Address margin not present in IE 8/9 and Safari. +// + +figure { + margin: 1em 40px; +} + +// +// Address differences between Firefox and other browsers. +// + +hr { + box-sizing: content-box; + height: 0; +} + +// +// Contain overflow in all browsers. +// + +pre { + overflow: auto; +} + +// +// Address odd `em`-unit font size rendering in all browsers. +// + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} + +// Forms +// ========================================================================== + +// +// Known limitation: by default, Chrome and Safari on OS X allow very limited +// styling of `select`, unless a `border` property is set. +// + +// +// 1. Correct color not being inherited. +// Known issue: affects color of disabled elements. +// 2. Correct font properties not being inherited. +// 3. Address margins set differently in Firefox 4+, Safari, and Chrome. +// + +button, +input, +optgroup, +select, +textarea { + color: inherit; // 1 + font: inherit; // 2 + margin: 0; // 3 +} + +// +// Address `overflow` set to `hidden` in IE 8/9/10/11. +// + +button { + overflow: visible; +} + +// +// Address inconsistent `text-transform` inheritance for `button` and `select`. +// All other form control elements do not inherit `text-transform` values. +// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. +// Correct `select` style inheritance in Firefox. +// + +button, +select { + text-transform: none; +} + +// +// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` +// and `video` controls. +// 2. Correct inability to style clickable `input` types in iOS. +// 3. Improve usability and consistency of cursor style between image-type +// `input` and others. +// + +button, +html input[type="button"], // 1 +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; // 2 + cursor: pointer; // 3 +} + +// +// Re-set default cursor for disabled elements. +// + +button[disabled], +html input[disabled] { + cursor: default; +} + +// +// Remove inner padding and border in Firefox 4+. +// + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +// +// Address Firefox 4+ setting `line-height` on `input` using `!important` in +// the UA stylesheet. +// + +input { + line-height: normal; +} + +// +// It's recommended that you don't attempt to style these elements. +// Firefox's implementation doesn't respect box-sizing, padding, or width. +// +// 1. Address box sizing set to `content-box` in IE 8/9/10. +// 2. Remove excess padding in IE 8/9/10. +// + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; // 1 + padding: 0; // 2 +} + +// +// Fix the cursor style for Chrome's increment/decrement buttons. For certain +// `font-size` values of the `input`, it causes the cursor style of the +// decrement button to change from `default` to `text`. +// + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +// +// 1. Address `appearance` set to `searchfield` in Safari and Chrome. +// 2. Address `box-sizing` set to `border-box` in Safari and Chrome. +// + +input[type="search"] { + -webkit-appearance: textfield; // 1 + box-sizing: content-box; //2 +} + +// +// Remove inner padding and search cancel button in Safari and Chrome on OS X. +// Safari (but not Chrome) clips the cancel button when the search input has +// padding (and `textfield` appearance). +// + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +// +// Define consistent border, margin, and padding. +// + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +// +// 1. Correct `color` not being inherited in IE 8/9/10/11. +// 2. Remove padding so people aren't caught out if they zero out fieldsets. +// + +legend { + border: 0; // 1 + padding: 0; // 2 +} + +// +// Remove default vertical scrollbar in IE 8/9/10/11. +// + +textarea { + overflow: auto; +} + +// +// Don't inherit the `font-weight` (applied by a rule above). +// NOTE: the default cannot safely be changed in Chrome and Safari on OS X. +// + +optgroup { + font-weight: bold; +} + +// Tables +// ========================================================================== + +// +// Remove most spacing between table cells. +// + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} diff --git a/themes/demo/assets/vendor/bootstrap/less/pager.less b/themes/demo/assets/vendor/bootstrap/less/pager.less new file mode 100644 index 0000000..41abaaa --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/pager.less @@ -0,0 +1,54 @@ +// +// Pager pagination +// -------------------------------------------------- + + +.pager { + padding-left: 0; + margin: @line-height-computed 0; + list-style: none; + text-align: center; + &:extend(.clearfix all); + li { + display: inline; + > a, + > span { + display: inline-block; + padding: 5px 14px; + background-color: @pager-bg; + border: 1px solid @pager-border; + border-radius: @pager-border-radius; + } + + > a:hover, + > a:focus { + text-decoration: none; + background-color: @pager-hover-bg; + } + } + + .next { + > a, + > span { + float: right; + } + } + + .previous { + > a, + > span { + float: left; + } + } + + .disabled { + > a, + > a:hover, + > a:focus, + > span { + color: @pager-disabled-color; + background-color: @pager-bg; + cursor: @cursor-disabled; + } + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/pagination.less b/themes/demo/assets/vendor/bootstrap/less/pagination.less new file mode 100644 index 0000000..31f77aa --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/pagination.less @@ -0,0 +1,89 @@ +// +// Pagination (multiple pages) +// -------------------------------------------------- +.pagination { + display: inline-block; + padding-left: 0; + margin: @line-height-computed 0; + border-radius: @border-radius-base; + + > li { + display: inline; // Remove list-style and block-level defaults + > a, + > span { + position: relative; + float: left; // Collapse white-space + padding: @padding-base-vertical @padding-base-horizontal; + line-height: @line-height-base; + text-decoration: none; + color: @pagination-color; + background-color: @pagination-bg; + border: 1px solid @pagination-border; + margin-left: -1px; + } + &:first-child { + > a, + > span { + margin-left: 0; + .border-left-radius(@border-radius-base); + } + } + &:last-child { + > a, + > span { + .border-right-radius(@border-radius-base); + } + } + } + + > li > a, + > li > span { + &:hover, + &:focus { + z-index: 2; + color: @pagination-hover-color; + background-color: @pagination-hover-bg; + border-color: @pagination-hover-border; + } + } + + > .active > a, + > .active > span { + &, + &:hover, + &:focus { + z-index: 3; + color: @pagination-active-color; + background-color: @pagination-active-bg; + border-color: @pagination-active-border; + cursor: default; + } + } + + > .disabled { + > span, + > span:hover, + > span:focus, + > a, + > a:hover, + > a:focus { + color: @pagination-disabled-color; + background-color: @pagination-disabled-bg; + border-color: @pagination-disabled-border; + cursor: @cursor-disabled; + } + } +} + +// Sizing +// -------------------------------------------------- + +// Large +.pagination-lg { + .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large); +} + +// Small +.pagination-sm { + .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small); +} diff --git a/themes/demo/assets/vendor/bootstrap/less/panels.less b/themes/demo/assets/vendor/bootstrap/less/panels.less new file mode 100644 index 0000000..65aa3a8 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/panels.less @@ -0,0 +1,271 @@ +// +// Panels +// -------------------------------------------------- + + +// Base class +.panel { + margin-bottom: @line-height-computed; + background-color: @panel-bg; + border: 1px solid transparent; + border-radius: @panel-border-radius; + .box-shadow(0 1px 1px rgba(0,0,0,.05)); +} + +// Panel contents +.panel-body { + padding: @panel-body-padding; + &:extend(.clearfix all); +} + +// Optional heading +.panel-heading { + padding: @panel-heading-padding; + border-bottom: 1px solid transparent; + .border-top-radius((@panel-border-radius - 1)); + + > .dropdown .dropdown-toggle { + color: inherit; + } +} + +// Within heading, strip any `h*` tag of its default margins for spacing. +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: ceil((@font-size-base * 1.125)); + color: inherit; + + > a, + > small, + > .small, + > small > a, + > .small > a { + color: inherit; + } +} + +// Optional footer (stays gray in every modifier class) +.panel-footer { + padding: @panel-footer-padding; + background-color: @panel-footer-bg; + border-top: 1px solid @panel-inner-border; + .border-bottom-radius((@panel-border-radius - 1)); +} + + +// List groups in panels +// +// By default, space out list group content from panel headings to account for +// any kind of custom content between the two. + +.panel { + > .list-group, + > .panel-collapse > .list-group { + margin-bottom: 0; + + .list-group-item { + border-width: 1px 0; + border-radius: 0; + } + + // Add border top radius for first one + &:first-child { + .list-group-item:first-child { + border-top: 0; + .border-top-radius((@panel-border-radius - 1)); + } + } + + // Add border bottom radius for last one + &:last-child { + .list-group-item:last-child { + border-bottom: 0; + .border-bottom-radius((@panel-border-radius - 1)); + } + } + } + > .panel-heading + .panel-collapse > .list-group { + .list-group-item:first-child { + .border-top-radius(0); + } + } +} +// Collapse space between when there's no additional content. +.panel-heading + .list-group { + .list-group-item:first-child { + border-top-width: 0; + } +} +.list-group + .panel-footer { + border-top-width: 0; +} + +// Tables in panels +// +// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and +// watch it go full width. + +.panel { + > .table, + > .table-responsive > .table, + > .panel-collapse > .table { + margin-bottom: 0; + + caption { + padding-left: @panel-body-padding; + padding-right: @panel-body-padding; + } + } + // Add border top radius for first one + > .table:first-child, + > .table-responsive:first-child > .table:first-child { + .border-top-radius((@panel-border-radius - 1)); + + > thead:first-child, + > tbody:first-child { + > tr:first-child { + border-top-left-radius: (@panel-border-radius - 1); + border-top-right-radius: (@panel-border-radius - 1); + + td:first-child, + th:first-child { + border-top-left-radius: (@panel-border-radius - 1); + } + td:last-child, + th:last-child { + border-top-right-radius: (@panel-border-radius - 1); + } + } + } + } + // Add border bottom radius for last one + > .table:last-child, + > .table-responsive:last-child > .table:last-child { + .border-bottom-radius((@panel-border-radius - 1)); + + > tbody:last-child, + > tfoot:last-child { + > tr:last-child { + border-bottom-left-radius: (@panel-border-radius - 1); + border-bottom-right-radius: (@panel-border-radius - 1); + + td:first-child, + th:first-child { + border-bottom-left-radius: (@panel-border-radius - 1); + } + td:last-child, + th:last-child { + border-bottom-right-radius: (@panel-border-radius - 1); + } + } + } + } + > .panel-body + .table, + > .panel-body + .table-responsive, + > .table + .panel-body, + > .table-responsive + .panel-body { + border-top: 1px solid @table-border-color; + } + > .table > tbody:first-child > tr:first-child th, + > .table > tbody:first-child > tr:first-child td { + border-top: 0; + } + > .table-bordered, + > .table-responsive > .table-bordered { + border: 0; + > thead, + > tbody, + > tfoot { + > tr { + > th:first-child, + > td:first-child { + border-left: 0; + } + > th:last-child, + > td:last-child { + border-right: 0; + } + } + } + > thead, + > tbody { + > tr:first-child { + > td, + > th { + border-bottom: 0; + } + } + } + > tbody, + > tfoot { + > tr:last-child { + > td, + > th { + border-bottom: 0; + } + } + } + } + > .table-responsive { + border: 0; + margin-bottom: 0; + } +} + + +// Collapsible panels (aka, accordion) +// +// Wrap a series of panels in `.panel-group` to turn them into an accordion with +// the help of our collapse JavaScript plugin. + +.panel-group { + margin-bottom: @line-height-computed; + + // Tighten up margin so it's only between panels + .panel { + margin-bottom: 0; + border-radius: @panel-border-radius; + + + .panel { + margin-top: 5px; + } + } + + .panel-heading { + border-bottom: 0; + + + .panel-collapse > .panel-body, + + .panel-collapse > .list-group { + border-top: 1px solid @panel-inner-border; + } + } + + .panel-footer { + border-top: 0; + + .panel-collapse .panel-body { + border-bottom: 1px solid @panel-inner-border; + } + } +} + + +// Contextual variations +.panel-default { + .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border); +} +.panel-primary { + .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border); +} +.panel-success { + .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border); +} +.panel-info { + .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border); +} +.panel-warning { + .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border); +} +.panel-danger { + .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border); +} diff --git a/themes/demo/assets/vendor/bootstrap/less/popovers.less b/themes/demo/assets/vendor/bootstrap/less/popovers.less new file mode 100644 index 0000000..3a62a64 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/popovers.less @@ -0,0 +1,131 @@ +// +// Popovers +// -------------------------------------------------- + + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: @zindex-popover; + display: none; + max-width: @popover-max-width; + padding: 1px; + // Our parent element can be arbitrary since popovers are by default inserted as a sibling of their target element. + // So reset our font and text properties to avoid inheriting weird values. + .reset-text(); + font-size: @font-size-base; + + background-color: @popover-bg; + background-clip: padding-box; + border: 1px solid @popover-fallback-border-color; + border: 1px solid @popover-border-color; + border-radius: @border-radius-large; + .box-shadow(0 5px 10px rgba(0,0,0,.2)); + + // Offset the popover to account for the popover arrow + &.top { margin-top: -@popover-arrow-width; } + &.right { margin-left: @popover-arrow-width; } + &.bottom { margin-top: @popover-arrow-width; } + &.left { margin-left: -@popover-arrow-width; } +} + +.popover-title { + margin: 0; // reset heading margin + padding: 8px 14px; + font-size: @font-size-base; + background-color: @popover-title-bg; + border-bottom: 1px solid darken(@popover-title-bg, 5%); + border-radius: (@border-radius-large - 1) (@border-radius-large - 1) 0 0; +} + +.popover-content { + padding: 9px 14px; +} + +// Arrows +// +// .arrow is outer, .arrow:after is inner + +.popover > .arrow { + &, + &:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + } +} +.popover > .arrow { + border-width: @popover-arrow-outer-width; +} +.popover > .arrow:after { + border-width: @popover-arrow-width; + content: ""; +} + +.popover { + &.top > .arrow { + left: 50%; + margin-left: -@popover-arrow-outer-width; + border-bottom-width: 0; + border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback + border-top-color: @popover-arrow-outer-color; + bottom: -@popover-arrow-outer-width; + &:after { + content: " "; + bottom: 1px; + margin-left: -@popover-arrow-width; + border-bottom-width: 0; + border-top-color: @popover-arrow-color; + } + } + &.right > .arrow { + top: 50%; + left: -@popover-arrow-outer-width; + margin-top: -@popover-arrow-outer-width; + border-left-width: 0; + border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback + border-right-color: @popover-arrow-outer-color; + &:after { + content: " "; + left: 1px; + bottom: -@popover-arrow-width; + border-left-width: 0; + border-right-color: @popover-arrow-color; + } + } + &.bottom > .arrow { + left: 50%; + margin-left: -@popover-arrow-outer-width; + border-top-width: 0; + border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback + border-bottom-color: @popover-arrow-outer-color; + top: -@popover-arrow-outer-width; + &:after { + content: " "; + top: 1px; + margin-left: -@popover-arrow-width; + border-top-width: 0; + border-bottom-color: @popover-arrow-color; + } + } + + &.left > .arrow { + top: 50%; + right: -@popover-arrow-outer-width; + margin-top: -@popover-arrow-outer-width; + border-right-width: 0; + border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback + border-left-color: @popover-arrow-outer-color; + &:after { + content: " "; + right: 1px; + border-right-width: 0; + border-left-color: @popover-arrow-color; + bottom: -@popover-arrow-width; + } + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/print.less b/themes/demo/assets/vendor/bootstrap/less/print.less new file mode 100644 index 0000000..66e54ab --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/print.less @@ -0,0 +1,101 @@ +/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ + +// ========================================================================== +// Print styles. +// Inlined to avoid the additional HTTP request: h5bp.com/r +// ========================================================================== + +@media print { + *, + *:before, + *:after { + background: transparent !important; + color: #000 !important; // Black prints faster: h5bp.com/s + box-shadow: none !important; + text-shadow: none !important; + } + + a, + a:visited { + text-decoration: underline; + } + + a[href]:after { + content: " (" attr(href) ")"; + } + + abbr[title]:after { + content: " (" attr(title) ")"; + } + + // Don't show links that are fragment identifiers, + // or use the `javascript:` pseudo protocol + a[href^="#"]:after, + a[href^="javascript:"]:after { + content: ""; + } + + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + + thead { + display: table-header-group; // h5bp.com/t + } + + tr, + img { + page-break-inside: avoid; + } + + img { + max-width: 100% !important; + } + + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + + h2, + h3 { + page-break-after: avoid; + } + + // Bootstrap specific changes start + + // Bootstrap components + .navbar { + display: none; + } + .btn, + .dropup > .btn { + > .caret { + border-top-color: #000 !important; + } + } + .label { + border: 1px solid #000; + } + + .table { + border-collapse: collapse !important; + + td, + th { + background-color: #fff !important; + } + } + .table-bordered { + th, + td { + border: 1px solid #ddd !important; + } + } + + // Bootstrap specific changes end +} diff --git a/themes/demo/assets/vendor/bootstrap/less/progress-bars.less b/themes/demo/assets/vendor/bootstrap/less/progress-bars.less new file mode 100644 index 0000000..8868a1f --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/progress-bars.less @@ -0,0 +1,87 @@ +// +// Progress bars +// -------------------------------------------------- + + +// Bar animations +// ------------------------- + +// WebKit +@-webkit-keyframes progress-bar-stripes { + from { background-position: 40px 0; } + to { background-position: 0 0; } +} + +// Spec and IE10+ +@keyframes progress-bar-stripes { + from { background-position: 40px 0; } + to { background-position: 0 0; } +} + + +// Bar itself +// ------------------------- + +// Outer container +.progress { + overflow: hidden; + height: @line-height-computed; + margin-bottom: @line-height-computed; + background-color: @progress-bg; + border-radius: @progress-border-radius; + .box-shadow(inset 0 1px 2px rgba(0,0,0,.1)); +} + +// Bar of progress +.progress-bar { + float: left; + width: 0%; + height: 100%; + font-size: @font-size-small; + line-height: @line-height-computed; + color: @progress-bar-color; + text-align: center; + background-color: @progress-bar-bg; + .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15)); + .transition(width .6s ease); +} + +// Striped bars +// +// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the +// `.progress-bar-striped` class, which you just add to an existing +// `.progress-bar`. +.progress-striped .progress-bar, +.progress-bar-striped { + #gradient > .striped(); + background-size: 40px 40px; +} + +// Call animation for the active one +// +// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the +// `.progress-bar.active` approach. +.progress.active .progress-bar, +.progress-bar.active { + .animation(progress-bar-stripes 2s linear infinite); +} + + +// Variations +// ------------------------- + +.progress-bar-success { + .progress-bar-variant(@progress-bar-success-bg); +} + +.progress-bar-info { + .progress-bar-variant(@progress-bar-info-bg); +} + +.progress-bar-warning { + .progress-bar-variant(@progress-bar-warning-bg); +} + +.progress-bar-danger { + .progress-bar-variant(@progress-bar-danger-bg); +} diff --git a/themes/demo/assets/vendor/bootstrap/less/responsive-embed.less b/themes/demo/assets/vendor/bootstrap/less/responsive-embed.less new file mode 100644 index 0000000..080a511 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/responsive-embed.less @@ -0,0 +1,35 @@ +// Embeds responsive +// +// Credit: Nicolas Gallagher and SUIT CSS. + +.embed-responsive { + position: relative; + display: block; + height: 0; + padding: 0; + overflow: hidden; + + .embed-responsive-item, + iframe, + embed, + object, + video { + position: absolute; + top: 0; + left: 0; + bottom: 0; + height: 100%; + width: 100%; + border: 0; + } +} + +// Modifier class for 16:9 aspect ratio +.embed-responsive-16by9 { + padding-bottom: 56.25%; +} + +// Modifier class for 4:3 aspect ratio +.embed-responsive-4by3 { + padding-bottom: 75%; +} diff --git a/themes/demo/assets/vendor/bootstrap/less/responsive-utilities.less b/themes/demo/assets/vendor/bootstrap/less/responsive-utilities.less new file mode 100644 index 0000000..b1db31d --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/responsive-utilities.less @@ -0,0 +1,194 @@ +// +// Responsive: Utility classes +// -------------------------------------------------- + + +// IE10 in Windows (Phone) 8 +// +// Support for responsive views via media queries is kind of borked in IE10, for +// Surface/desktop in split view and for Windows Phone 8. This particular fix +// must be accompanied by a snippet of JavaScript to sniff the user agent and +// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at +// our Getting Started page for more information on this bug. +// +// For more information, see the following: +// +// Issue: https://github.com/twbs/bootstrap/issues/10497 +// Docs: http://getbootstrap.com/getting-started/#support-ie10-width +// Source: http://timkadlec.com/2013/01/windows-phone-8-and-device-width/ +// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/ + +@-ms-viewport { + width: device-width; +} + + +// Visibility utilities +// Note: Deprecated .visible-xs, .visible-sm, .visible-md, and .visible-lg as of v3.2.0 +.visible-xs, +.visible-sm, +.visible-md, +.visible-lg { + .responsive-invisibility(); +} + +.visible-xs-block, +.visible-xs-inline, +.visible-xs-inline-block, +.visible-sm-block, +.visible-sm-inline, +.visible-sm-inline-block, +.visible-md-block, +.visible-md-inline, +.visible-md-inline-block, +.visible-lg-block, +.visible-lg-inline, +.visible-lg-inline-block { + display: none !important; +} + +.visible-xs { + @media (max-width: @screen-xs-max) { + .responsive-visibility(); + } +} +.visible-xs-block { + @media (max-width: @screen-xs-max) { + display: block !important; + } +} +.visible-xs-inline { + @media (max-width: @screen-xs-max) { + display: inline !important; + } +} +.visible-xs-inline-block { + @media (max-width: @screen-xs-max) { + display: inline-block !important; + } +} + +.visible-sm { + @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { + .responsive-visibility(); + } +} +.visible-sm-block { + @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { + display: block !important; + } +} +.visible-sm-inline { + @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { + display: inline !important; + } +} +.visible-sm-inline-block { + @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { + display: inline-block !important; + } +} + +.visible-md { + @media (min-width: @screen-md-min) and (max-width: @screen-md-max) { + .responsive-visibility(); + } +} +.visible-md-block { + @media (min-width: @screen-md-min) and (max-width: @screen-md-max) { + display: block !important; + } +} +.visible-md-inline { + @media (min-width: @screen-md-min) and (max-width: @screen-md-max) { + display: inline !important; + } +} +.visible-md-inline-block { + @media (min-width: @screen-md-min) and (max-width: @screen-md-max) { + display: inline-block !important; + } +} + +.visible-lg { + @media (min-width: @screen-lg-min) { + .responsive-visibility(); + } +} +.visible-lg-block { + @media (min-width: @screen-lg-min) { + display: block !important; + } +} +.visible-lg-inline { + @media (min-width: @screen-lg-min) { + display: inline !important; + } +} +.visible-lg-inline-block { + @media (min-width: @screen-lg-min) { + display: inline-block !important; + } +} + +.hidden-xs { + @media (max-width: @screen-xs-max) { + .responsive-invisibility(); + } +} +.hidden-sm { + @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { + .responsive-invisibility(); + } +} +.hidden-md { + @media (min-width: @screen-md-min) and (max-width: @screen-md-max) { + .responsive-invisibility(); + } +} +.hidden-lg { + @media (min-width: @screen-lg-min) { + .responsive-invisibility(); + } +} + + +// Print utilities +// +// Media queries are placed on the inside to be mixin-friendly. + +// Note: Deprecated .visible-print as of v3.2.0 +.visible-print { + .responsive-invisibility(); + + @media print { + .responsive-visibility(); + } +} +.visible-print-block { + display: none !important; + + @media print { + display: block !important; + } +} +.visible-print-inline { + display: none !important; + + @media print { + display: inline !important; + } +} +.visible-print-inline-block { + display: none !important; + + @media print { + display: inline-block !important; + } +} + +.hidden-print { + @media print { + .responsive-invisibility(); + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/scaffolding.less b/themes/demo/assets/vendor/bootstrap/less/scaffolding.less new file mode 100644 index 0000000..64a29c6 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/scaffolding.less @@ -0,0 +1,161 @@ +// +// Scaffolding +// -------------------------------------------------- + + +// Reset the box-sizing +// +// Heads up! This reset may cause conflicts with some third-party widgets. +// For recommendations on resolving such conflicts, see +// http://getbootstrap.com/getting-started/#third-box-sizing +* { + .box-sizing(border-box); +} +*:before, +*:after { + .box-sizing(border-box); +} + + +// Body reset + +html { + font-size: 10px; + -webkit-tap-highlight-color: rgba(0,0,0,0); +} + +body { + font-family: @font-family-base; + font-size: @font-size-base; + line-height: @line-height-base; + color: @text-color; + background-color: @body-bg; +} + +// Reset fonts for relevant elements +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + + +// Links + +a { + color: @link-color; + text-decoration: none; + + &:hover, + &:focus { + color: @link-hover-color; + text-decoration: @link-hover-decoration; + } + + &:focus { + .tab-focus(); + } +} + + +// Figures +// +// We reset this here because previously Normalize had no `figure` margins. This +// ensures we don't break anyone's use of the element. + +figure { + margin: 0; +} + + +// Images + +img { + vertical-align: middle; +} + +// Responsive images (ensure images don't scale beyond their parents) +.img-responsive { + .img-responsive(); +} + +// Rounded corners +.img-rounded { + border-radius: @border-radius-large; +} + +// Image thumbnails +// +// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`. +.img-thumbnail { + padding: @thumbnail-padding; + line-height: @line-height-base; + background-color: @thumbnail-bg; + border: 1px solid @thumbnail-border; + border-radius: @thumbnail-border-radius; + .transition(all .2s ease-in-out); + + // Keep them at most 100% wide + .img-responsive(inline-block); +} + +// Perfect circle +.img-circle { + border-radius: 50%; // set radius in percents +} + + +// Horizontal rules + +hr { + margin-top: @line-height-computed; + margin-bottom: @line-height-computed; + border: 0; + border-top: 1px solid @hr-border; +} + + +// Only display content to screen readers +// +// See: http://a11yproject.com/posts/how-to-hide-content + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0,0,0,0); + border: 0; +} + +// Use in conjunction with .sr-only to only display content when it's focused. +// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 +// Credit: HTML5 Boilerplate + +.sr-only-focusable { + &:active, + &:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; + } +} + + +// iOS "clickable elements" fix for role="button" +// +// Fixes "clickability" issue (and more generally, the firing of events such as focus as well) +// for traditionally non-focusable elements with role="button" +// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile + +[role="button"] { + cursor: pointer; +} diff --git a/themes/demo/assets/vendor/bootstrap/less/tables.less b/themes/demo/assets/vendor/bootstrap/less/tables.less new file mode 100644 index 0000000..2242c03 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/tables.less @@ -0,0 +1,234 @@ +// +// Tables +// -------------------------------------------------- + + +table { + background-color: @table-bg; +} +caption { + padding-top: @table-cell-padding; + padding-bottom: @table-cell-padding; + color: @text-muted; + text-align: left; +} +th { + text-align: left; +} + + +// Baseline styles + +.table { + width: 100%; + max-width: 100%; + margin-bottom: @line-height-computed; + // Cells + > thead, + > tbody, + > tfoot { + > tr { + > th, + > td { + padding: @table-cell-padding; + line-height: @line-height-base; + vertical-align: top; + border-top: 1px solid @table-border-color; + } + } + } + // Bottom align for column headings + > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid @table-border-color; + } + // Remove top border from thead by default + > caption + thead, + > colgroup + thead, + > thead:first-child { + > tr:first-child { + > th, + > td { + border-top: 0; + } + } + } + // Account for multiple tbody instances + > tbody + tbody { + border-top: 2px solid @table-border-color; + } + + // Nesting + .table { + background-color: @body-bg; + } +} + + +// Condensed table w/ half padding + +.table-condensed { + > thead, + > tbody, + > tfoot { + > tr { + > th, + > td { + padding: @table-condensed-cell-padding; + } + } + } +} + + +// Bordered version +// +// Add borders all around the table and between all the columns. + +.table-bordered { + border: 1px solid @table-border-color; + > thead, + > tbody, + > tfoot { + > tr { + > th, + > td { + border: 1px solid @table-border-color; + } + } + } + > thead > tr { + > th, + > td { + border-bottom-width: 2px; + } + } +} + + +// Zebra-striping +// +// Default zebra-stripe styles (alternating gray and transparent backgrounds) + +.table-striped { + > tbody > tr:nth-of-type(odd) { + background-color: @table-bg-accent; + } +} + + +// Hover effect +// +// Placed here since it has to come after the potential zebra striping + +.table-hover { + > tbody > tr:hover { + background-color: @table-bg-hover; + } +} + + +// Table cell sizing +// +// Reset default table behavior + +table col[class*="col-"] { + position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623) + float: none; + display: table-column; +} +table { + td, + th { + &[class*="col-"] { + position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623) + float: none; + display: table-cell; + } + } +} + + +// Table backgrounds +// +// Exact selectors below required to override `.table-striped` and prevent +// inheritance to nested tables. + +// Generate the contextual variants +.table-row-variant(active; @table-bg-active); +.table-row-variant(success; @state-success-bg); +.table-row-variant(info; @state-info-bg); +.table-row-variant(warning; @state-warning-bg); +.table-row-variant(danger; @state-danger-bg); + + +// Responsive tables +// +// Wrap your tables in `.table-responsive` and we'll make them mobile friendly +// by enabling horizontal scrolling. Only applies <768px. Everything above that +// will display normally. + +.table-responsive { + overflow-x: auto; + min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837) + + @media screen and (max-width: @screen-xs-max) { + width: 100%; + margin-bottom: (@line-height-computed * 0.75); + overflow-y: hidden; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid @table-border-color; + + // Tighten up spacing + > .table { + margin-bottom: 0; + + // Ensure the content doesn't wrap + > thead, + > tbody, + > tfoot { + > tr { + > th, + > td { + white-space: nowrap; + } + } + } + } + + // Special overrides for the bordered tables + > .table-bordered { + border: 0; + + // Nuke the appropriate borders so that the parent can handle them + > thead, + > tbody, + > tfoot { + > tr { + > th:first-child, + > td:first-child { + border-left: 0; + } + > th:last-child, + > td:last-child { + border-right: 0; + } + } + } + + // Only nuke the last row's bottom-border in `tbody` and `tfoot` since + // chances are there will be only one `tr` in a `thead` and that would + // remove the border altogether. + > tbody, + > tfoot { + > tr:last-child { + > th, + > td { + border-bottom: 0; + } + } + } + + } + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/theme.less b/themes/demo/assets/vendor/bootstrap/less/theme.less new file mode 100644 index 0000000..fb61744 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/theme.less @@ -0,0 +1,291 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +// +// Load core variables and mixins +// -------------------------------------------------- + +@import "variables.less"; +@import "mixins.less"; + + +// +// Buttons +// -------------------------------------------------- + +// Common styles +.btn-default, +.btn-primary, +.btn-success, +.btn-info, +.btn-warning, +.btn-danger { + text-shadow: 0 -1px 0 rgba(0,0,0,.2); + @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075); + .box-shadow(@shadow); + + // Reset the shadow + &:active, + &.active { + .box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); + } + + &.disabled, + &[disabled], + fieldset[disabled] & { + .box-shadow(none); + } + + .badge { + text-shadow: none; + } +} + +// Mixin for generating new styles +.btn-styles(@btn-color: #555) { + #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%)); + .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620 + background-repeat: repeat-x; + border-color: darken(@btn-color, 14%); + + &:hover, + &:focus { + background-color: darken(@btn-color, 12%); + background-position: 0 -15px; + } + + &:active, + &.active { + background-color: darken(@btn-color, 12%); + border-color: darken(@btn-color, 14%); + } + + &.disabled, + &[disabled], + fieldset[disabled] & { + &, + &:hover, + &:focus, + &.focus, + &:active, + &.active { + background-color: darken(@btn-color, 12%); + background-image: none; + } + } +} + +// Common styles +.btn { + // Remove the gradient for the pressed/active state + &:active, + &.active { + background-image: none; + } +} + +// Apply the mixin to the buttons +.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; } +.btn-primary { .btn-styles(@btn-primary-bg); } +.btn-success { .btn-styles(@btn-success-bg); } +.btn-info { .btn-styles(@btn-info-bg); } +.btn-warning { .btn-styles(@btn-warning-bg); } +.btn-danger { .btn-styles(@btn-danger-bg); } + + +// +// Images +// -------------------------------------------------- + +.thumbnail, +.img-thumbnail { + .box-shadow(0 1px 2px rgba(0,0,0,.075)); +} + + +// +// Dropdowns +// -------------------------------------------------- + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%)); + background-color: darken(@dropdown-link-hover-bg, 5%); +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%)); + background-color: darken(@dropdown-link-active-bg, 5%); +} + + +// +// Navbar +// -------------------------------------------------- + +// Default navbar +.navbar-default { + #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg); + .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered + border-radius: @navbar-border-radius; + @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075); + .box-shadow(@shadow); + + .navbar-nav > .open > a, + .navbar-nav > .active > a { + #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%)); + .box-shadow(inset 0 3px 9px rgba(0,0,0,.075)); + } +} +.navbar-brand, +.navbar-nav > li > a { + text-shadow: 0 1px 0 rgba(255,255,255,.25); +} + +// Inverted navbar +.navbar-inverse { + #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg); + .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257 + border-radius: @navbar-border-radius; + .navbar-nav > .open > a, + .navbar-nav > .active > a { + #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%)); + .box-shadow(inset 0 3px 9px rgba(0,0,0,.25)); + } + + .navbar-brand, + .navbar-nav > li > a { + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + } +} + +// Undo rounded corners in static and fixed navbars +.navbar-static-top, +.navbar-fixed-top, +.navbar-fixed-bottom { + border-radius: 0; +} + +// Fix active state of dropdown items in collapsed mode +@media (max-width: @grid-float-breakpoint-max) { + .navbar .navbar-nav .open .dropdown-menu > .active > a { + &, + &:hover, + &:focus { + color: #fff; + #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%)); + } + } +} + + +// +// Alerts +// -------------------------------------------------- + +// Common styles +.alert { + text-shadow: 0 1px 0 rgba(255,255,255,.2); + @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05); + .box-shadow(@shadow); +} + +// Mixin for generating new styles +.alert-styles(@color) { + #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%)); + border-color: darken(@color, 15%); +} + +// Apply the mixin to the alerts +.alert-success { .alert-styles(@alert-success-bg); } +.alert-info { .alert-styles(@alert-info-bg); } +.alert-warning { .alert-styles(@alert-warning-bg); } +.alert-danger { .alert-styles(@alert-danger-bg); } + + +// +// Progress bars +// -------------------------------------------------- + +// Give the progress background some depth +.progress { + #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg) +} + +// Mixin for generating new styles +.progress-bar-styles(@color) { + #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%)); +} + +// Apply the mixin to the progress bars +.progress-bar { .progress-bar-styles(@progress-bar-bg); } +.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); } +.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); } +.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); } +.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); } + +// Reset the striped class because our mixins don't do multiple gradients and +// the above custom styles override the new `.progress-bar-striped` in v3.2.0. +.progress-bar-striped { + #gradient > .striped(); +} + + +// +// List groups +// -------------------------------------------------- + +.list-group { + border-radius: @border-radius-base; + .box-shadow(0 1px 2px rgba(0,0,0,.075)); +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%); + #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%)); + border-color: darken(@list-group-active-border, 7.5%); + + .badge { + text-shadow: none; + } +} + + +// +// Panels +// -------------------------------------------------- + +// Common styles +.panel { + .box-shadow(0 1px 2px rgba(0,0,0,.05)); +} + +// Mixin for generating new styles +.panel-heading-styles(@color) { + #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%)); +} + +// Apply the mixin to the panel headings only +.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); } +.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); } +.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); } +.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); } +.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); } +.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); } + + +// +// Wells +// -------------------------------------------------- + +.well { + #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg); + border-color: darken(@well-bg, 10%); + @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1); + .box-shadow(@shadow); +} diff --git a/themes/demo/assets/vendor/bootstrap/less/thumbnails.less b/themes/demo/assets/vendor/bootstrap/less/thumbnails.less new file mode 100644 index 0000000..0713e67 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/thumbnails.less @@ -0,0 +1,36 @@ +// +// Thumbnails +// -------------------------------------------------- + + +// Mixin and adjust the regular image class +.thumbnail { + display: block; + padding: @thumbnail-padding; + margin-bottom: @line-height-computed; + line-height: @line-height-base; + background-color: @thumbnail-bg; + border: 1px solid @thumbnail-border; + border-radius: @thumbnail-border-radius; + .transition(border .2s ease-in-out); + + > img, + a > img { + &:extend(.img-responsive); + margin-left: auto; + margin-right: auto; + } + + // Add a hover state for linked versions only + a&:hover, + a&:focus, + a&.active { + border-color: @link-color; + } + + // Image captions + .caption { + padding: @thumbnail-caption-padding; + color: @thumbnail-caption-color; + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/tooltip.less b/themes/demo/assets/vendor/bootstrap/less/tooltip.less new file mode 100644 index 0000000..b48d63e --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/tooltip.less @@ -0,0 +1,101 @@ +// +// Tooltips +// -------------------------------------------------- + + +// Base class +.tooltip { + position: absolute; + z-index: @zindex-tooltip; + display: block; + // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element. + // So reset our font and text properties to avoid inheriting weird values. + .reset-text(); + font-size: @font-size-small; + + .opacity(0); + + &.in { .opacity(@tooltip-opacity); } + &.top { margin-top: -3px; padding: @tooltip-arrow-width 0; } + &.right { margin-left: 3px; padding: 0 @tooltip-arrow-width; } + &.bottom { margin-top: 3px; padding: @tooltip-arrow-width 0; } + &.left { margin-left: -3px; padding: 0 @tooltip-arrow-width; } +} + +// Wrapper for the tooltip content +.tooltip-inner { + max-width: @tooltip-max-width; + padding: 3px 8px; + color: @tooltip-color; + text-align: center; + background-color: @tooltip-bg; + border-radius: @border-radius-base; +} + +// Arrows +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +// Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1 +.tooltip { + &.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -@tooltip-arrow-width; + border-width: @tooltip-arrow-width @tooltip-arrow-width 0; + border-top-color: @tooltip-arrow-color; + } + &.top-left .tooltip-arrow { + bottom: 0; + right: @tooltip-arrow-width; + margin-bottom: -@tooltip-arrow-width; + border-width: @tooltip-arrow-width @tooltip-arrow-width 0; + border-top-color: @tooltip-arrow-color; + } + &.top-right .tooltip-arrow { + bottom: 0; + left: @tooltip-arrow-width; + margin-bottom: -@tooltip-arrow-width; + border-width: @tooltip-arrow-width @tooltip-arrow-width 0; + border-top-color: @tooltip-arrow-color; + } + &.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -@tooltip-arrow-width; + border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0; + border-right-color: @tooltip-arrow-color; + } + &.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -@tooltip-arrow-width; + border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width; + border-left-color: @tooltip-arrow-color; + } + &.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -@tooltip-arrow-width; + border-width: 0 @tooltip-arrow-width @tooltip-arrow-width; + border-bottom-color: @tooltip-arrow-color; + } + &.bottom-left .tooltip-arrow { + top: 0; + right: @tooltip-arrow-width; + margin-top: -@tooltip-arrow-width; + border-width: 0 @tooltip-arrow-width @tooltip-arrow-width; + border-bottom-color: @tooltip-arrow-color; + } + &.bottom-right .tooltip-arrow { + top: 0; + left: @tooltip-arrow-width; + margin-top: -@tooltip-arrow-width; + border-width: 0 @tooltip-arrow-width @tooltip-arrow-width; + border-bottom-color: @tooltip-arrow-color; + } +} diff --git a/themes/demo/assets/vendor/bootstrap/less/type.less b/themes/demo/assets/vendor/bootstrap/less/type.less new file mode 100644 index 0000000..0d4fee4 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/type.less @@ -0,0 +1,302 @@ +// +// Typography +// -------------------------------------------------- + + +// Headings +// ------------------------- + +h1, h2, h3, h4, h5, h6, +.h1, .h2, .h3, .h4, .h5, .h6 { + font-family: @headings-font-family; + font-weight: @headings-font-weight; + line-height: @headings-line-height; + color: @headings-color; + + small, + .small { + font-weight: normal; + line-height: 1; + color: @headings-small-color; + } +} + +h1, .h1, +h2, .h2, +h3, .h3 { + margin-top: @line-height-computed; + margin-bottom: (@line-height-computed / 2); + + small, + .small { + font-size: 65%; + } +} +h4, .h4, +h5, .h5, +h6, .h6 { + margin-top: (@line-height-computed / 2); + margin-bottom: (@line-height-computed / 2); + + small, + .small { + font-size: 75%; + } +} + +h1, .h1 { font-size: @font-size-h1; } +h2, .h2 { font-size: @font-size-h2; } +h3, .h3 { font-size: @font-size-h3; } +h4, .h4 { font-size: @font-size-h4; } +h5, .h5 { font-size: @font-size-h5; } +h6, .h6 { font-size: @font-size-h6; } + + +// Body text +// ------------------------- + +p { + margin: 0 0 (@line-height-computed / 2); +} + +.lead { + margin-bottom: @line-height-computed; + font-size: floor((@font-size-base * 1.15)); + font-weight: 300; + line-height: 1.4; + + @media (min-width: @screen-sm-min) { + font-size: (@font-size-base * 1.5); + } +} + + +// Emphasis & misc +// ------------------------- + +// Ex: (12px small font / 14px base font) * 100% = about 85% +small, +.small { + font-size: floor((100% * @font-size-small / @font-size-base)); +} + +mark, +.mark { + background-color: @state-warning-bg; + padding: .2em; +} + +// Alignment +.text-left { text-align: left; } +.text-right { text-align: right; } +.text-center { text-align: center; } +.text-justify { text-align: justify; } +.text-nowrap { white-space: nowrap; } + +// Transformation +.text-lowercase { text-transform: lowercase; } +.text-uppercase { text-transform: uppercase; } +.text-capitalize { text-transform: capitalize; } + +// Contextual colors +.text-muted { + color: @text-muted; +} +.text-primary { + .text-emphasis-variant(@brand-primary); +} +.text-success { + .text-emphasis-variant(@state-success-text); +} +.text-info { + .text-emphasis-variant(@state-info-text); +} +.text-warning { + .text-emphasis-variant(@state-warning-text); +} +.text-danger { + .text-emphasis-variant(@state-danger-text); +} + +// Contextual backgrounds +// For now we'll leave these alongside the text classes until v4 when we can +// safely shift things around (per SemVer rules). +.bg-primary { + // Given the contrast here, this is the only class to have its color inverted + // automatically. + color: #fff; + .bg-variant(@brand-primary); +} +.bg-success { + .bg-variant(@state-success-bg); +} +.bg-info { + .bg-variant(@state-info-bg); +} +.bg-warning { + .bg-variant(@state-warning-bg); +} +.bg-danger { + .bg-variant(@state-danger-bg); +} + + +// Page header +// ------------------------- + +.page-header { + padding-bottom: ((@line-height-computed / 2) - 1); + margin: (@line-height-computed * 2) 0 @line-height-computed; + border-bottom: 1px solid @page-header-border-color; +} + + +// Lists +// ------------------------- + +// Unordered and Ordered lists +ul, +ol { + margin-top: 0; + margin-bottom: (@line-height-computed / 2); + ul, + ol { + margin-bottom: 0; + } +} + +// List options + +// Unstyled keeps list items block level, just removes default browser padding and list-style +.list-unstyled { + padding-left: 0; + list-style: none; +} + +// Inline turns list items into inline-block +.list-inline { + .list-unstyled(); + margin-left: -5px; + + > li { + display: inline-block; + padding-left: 5px; + padding-right: 5px; + } +} + +// Description Lists +dl { + margin-top: 0; // Remove browser default + margin-bottom: @line-height-computed; +} +dt, +dd { + line-height: @line-height-base; +} +dt { + font-weight: bold; +} +dd { + margin-left: 0; // Undo browser default +} + +// Horizontal description lists +// +// Defaults to being stacked without any of the below styles applied, until the +// grid breakpoint is reached (default of ~768px). + +.dl-horizontal { + dd { + &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present + } + + @media (min-width: @dl-horizontal-breakpoint) { + dt { + float: left; + width: (@dl-horizontal-offset - 20); + clear: left; + text-align: right; + .text-overflow(); + } + dd { + margin-left: @dl-horizontal-offset; + } + } +} + + +// Misc +// ------------------------- + +// Abbreviations and acronyms +abbr[title], +// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257 +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted @abbr-border-color; +} +.initialism { + font-size: 90%; + .text-uppercase(); +} + +// Blockquotes +blockquote { + padding: (@line-height-computed / 2) @line-height-computed; + margin: 0 0 @line-height-computed; + font-size: @blockquote-font-size; + border-left: 5px solid @blockquote-border-color; + + p, + ul, + ol { + &:last-child { + margin-bottom: 0; + } + } + + // Note: Deprecated small and .small as of v3.1.0 + // Context: https://github.com/twbs/bootstrap/issues/11660 + footer, + small, + .small { + display: block; + font-size: 80%; // back to default font-size + line-height: @line-height-base; + color: @blockquote-small-color; + + &:before { + content: '\2014 \00A0'; // em dash, nbsp + } + } +} + +// Opposite alignment of blockquote +// +// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0. +.blockquote-reverse, +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + border-right: 5px solid @blockquote-border-color; + border-left: 0; + text-align: right; + + // Account for citation + footer, + small, + .small { + &:before { content: ''; } + &:after { + content: '\00A0 \2014'; // nbsp, em dash + } + } +} + +// Addresses +address { + margin-bottom: @line-height-computed; + font-style: normal; + line-height: @line-height-base; +} diff --git a/themes/demo/assets/vendor/bootstrap/less/utilities.less b/themes/demo/assets/vendor/bootstrap/less/utilities.less new file mode 100644 index 0000000..7a8ca27 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/utilities.less @@ -0,0 +1,55 @@ +// +// Utility classes +// -------------------------------------------------- + + +// Floats +// ------------------------- + +.clearfix { + .clearfix(); +} +.center-block { + .center-block(); +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} + + +// Toggling content +// ------------------------- + +// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1 +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + .text-hide(); +} + + +// Hide from screenreaders and browsers +// +// Credit: HTML5 Boilerplate + +.hidden { + display: none !important; +} + + +// For Affix plugin +// ------------------------- + +.affix { + position: fixed; +} diff --git a/themes/demo/assets/vendor/bootstrap/less/variables.less b/themes/demo/assets/vendor/bootstrap/less/variables.less new file mode 100644 index 0000000..03b5498 --- /dev/null +++ b/themes/demo/assets/vendor/bootstrap/less/variables.less @@ -0,0 +1,869 @@ +// +// Variables +// -------------------------------------------------- + + +//== Colors +// +//## Gray and brand colors for use across Bootstrap. + +@gray-base: #000; +@gray-darker: lighten(@gray-base, 13.5%); // #222 +@gray-dark: lighten(@gray-base, 20%); // #333 +@gray: lighten(@gray-base, 33.5%); // #555 +@gray-light: lighten(@gray-base, 46.7%); // #777 +@gray-lighter: lighten(@gray-base, 93.5%); // #eee + +@brand-primary: darken(#428bca, 6.5%); // #337ab7 +@brand-success: #5cb85c; +@brand-info: #5bc0de; +@brand-warning: #f0ad4e; +@brand-danger: #d9534f; + + +//== Scaffolding +// +//## Settings for some of the most global styles. + +//** Background color for ``. +@body-bg: #fff; +//** Global text color on ``. +@text-color: @gray-dark; + +//** Global textual link color. +@link-color: @brand-primary; +//** Link hover color set via `darken()` function. +@link-hover-color: darken(@link-color, 15%); +//** Link hover decoration. +@link-hover-decoration: underline; + + +//== Typography +// +//## Font, line-height, and color for body text, headings, and more. + +@font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif; +@font-family-serif: Georgia, "Times New Roman", Times, serif; +//** Default monospace fonts for ``, ``, and `
        `.
        +@font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace;
        +@font-family-base:        @font-family-sans-serif;
        +
        +@font-size-base:          14px;
        +@font-size-large:         ceil((@font-size-base * 1.25)); // ~18px
        +@font-size-small:         ceil((@font-size-base * 0.85)); // ~12px
        +
        +@font-size-h1:            floor((@font-size-base * 2.6)); // ~36px
        +@font-size-h2:            floor((@font-size-base * 2.15)); // ~30px
        +@font-size-h3:            ceil((@font-size-base * 1.7)); // ~24px
        +@font-size-h4:            ceil((@font-size-base * 1.25)); // ~18px
        +@font-size-h5:            @font-size-base;
        +@font-size-h6:            ceil((@font-size-base * 0.85)); // ~12px
        +
        +//** Unit-less `line-height` for use in components like buttons.
        +@line-height-base:        1.428571429; // 20/14
        +//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
        +@line-height-computed:    floor((@font-size-base * @line-height-base)); // ~20px
        +
        +//** By default, this inherits from the ``.
        +@headings-font-family:    inherit;
        +@headings-font-weight:    500;
        +@headings-line-height:    1.1;
        +@headings-color:          inherit;
        +
        +
        +//== Iconography
        +//
        +//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
        +
        +//** Load fonts from this directory.
        +@icon-font-path:          "../fonts/";
        +//** File name for all font files.
        +@icon-font-name:          "glyphicons-halflings-regular";
        +//** Element ID within SVG icon file.
        +@icon-font-svg-id:        "glyphicons_halflingsregular";
        +
        +
        +//== Components
        +//
        +//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
        +
        +@padding-base-vertical:     6px;
        +@padding-base-horizontal:   12px;
        +
        +@padding-large-vertical:    10px;
        +@padding-large-horizontal:  16px;
        +
        +@padding-small-vertical:    5px;
        +@padding-small-horizontal:  10px;
        +
        +@padding-xs-vertical:       1px;
        +@padding-xs-horizontal:     5px;
        +
        +@line-height-large:         1.3333333; // extra decimals for Win 8.1 Chrome
        +@line-height-small:         1.5;
        +
        +@border-radius-base:        4px;
        +@border-radius-large:       6px;
        +@border-radius-small:       3px;
        +
        +//** Global color for active items (e.g., navs or dropdowns).
        +@component-active-color:    #fff;
        +//** Global background color for active items (e.g., navs or dropdowns).
        +@component-active-bg:       @brand-primary;
        +
        +//** Width of the `border` for generating carets that indicate dropdowns.
        +@caret-width-base:          4px;
        +//** Carets increase slightly in size for larger components.
        +@caret-width-large:         5px;
        +
        +
        +//== Tables
        +//
        +//## Customizes the `.table` component with basic values, each used across all table variations.
        +
        +//** Padding for ``s and ``s.
        +@table-cell-padding:            8px;
        +//** Padding for cells in `.table-condensed`.
        +@table-condensed-cell-padding:  5px;
        +
        +//** Default background color used for all tables.
        +@table-bg:                      transparent;
        +//** Background color used for `.table-striped`.
        +@table-bg-accent:               #f9f9f9;
        +//** Background color used for `.table-hover`.
        +@table-bg-hover:                #f5f5f5;
        +@table-bg-active:               @table-bg-hover;
        +
        +//** Border color for table and cell borders.
        +@table-border-color:            #ddd;
        +
        +
        +//== Buttons
        +//
        +//## For each of Bootstrap's buttons, define text, background and border color.
        +
        +@btn-font-weight:                normal;
        +
        +@btn-default-color:              #333;
        +@btn-default-bg:                 #fff;
        +@btn-default-border:             #ccc;
        +
        +@btn-primary-color:              #fff;
        +@btn-primary-bg:                 @brand-primary;
        +@btn-primary-border:             darken(@btn-primary-bg, 5%);
        +
        +@btn-success-color:              #fff;
        +@btn-success-bg:                 @brand-success;
        +@btn-success-border:             darken(@btn-success-bg, 5%);
        +
        +@btn-info-color:                 #fff;
        +@btn-info-bg:                    @brand-info;
        +@btn-info-border:                darken(@btn-info-bg, 5%);
        +
        +@btn-warning-color:              #fff;
        +@btn-warning-bg:                 @brand-warning;
        +@btn-warning-border:             darken(@btn-warning-bg, 5%);
        +
        +@btn-danger-color:               #fff;
        +@btn-danger-bg:                  @brand-danger;
        +@btn-danger-border:              darken(@btn-danger-bg, 5%);
        +
        +@btn-link-disabled-color:        @gray-light;
        +
        +// Allows for customizing button radius independently from global border radius
        +@btn-border-radius-base:         @border-radius-base;
        +@btn-border-radius-large:        @border-radius-large;
        +@btn-border-radius-small:        @border-radius-small;
        +
        +
        +//== Forms
        +//
        +//##
        +
        +//** `` background color
        +@input-bg:                       #fff;
        +//** `` background color
        +@input-bg-disabled:              @gray-lighter;
        +
        +//** Text color for ``s
        +@input-color:                    @gray;
        +//** `` border color
        +@input-border:                   #ccc;
        +
        +// TODO: Rename `@input-border-radius` to `@input-border-radius-base` in v4
        +//** Default `.form-control` border radius
        +// This has no effect on ``s in CSS.
        +@input-border-radius:            @border-radius-base;
        +//** Large `.form-control` border radius
        +@input-border-radius-large:      @border-radius-large;
        +//** Small `.form-control` border radius
        +@input-border-radius-small:      @border-radius-small;
        +
        +//** Border color for inputs on focus
        +@input-border-focus:             #66afe9;
        +
        +//** Placeholder text color
        +@input-color-placeholder:        #999;
        +
        +//** Default `.form-control` height
        +@input-height-base:              (@line-height-computed + (@padding-base-vertical * 2) + 2);
        +//** Large `.form-control` height
        +@input-height-large:             (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
        +//** Small `.form-control` height
        +@input-height-small:             (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
        +
        +//** `.form-group` margin
        +@form-group-margin-bottom:       15px;
        +
        +@legend-color:                   @gray-dark;
        +@legend-border-color:            #e5e5e5;
        +
        +//** Background color for textual input addons
        +@input-group-addon-bg:           @gray-lighter;
        +//** Border color for textual input addons
        +@input-group-addon-border-color: @input-border;
        +
        +//** Disabled cursor for form controls and buttons.
        +@cursor-disabled:                not-allowed;
        +
        +
        +//== Dropdowns
        +//
        +//## Dropdown menu container and contents.
        +
        +//** Background for the dropdown menu.
        +@dropdown-bg:                    #fff;
        +//** Dropdown menu `border-color`.
        +@dropdown-border:                rgba(0,0,0,.15);
        +//** Dropdown menu `border-color` **for IE8**.
        +@dropdown-fallback-border:       #ccc;
        +//** Divider color for between dropdown items.
        +@dropdown-divider-bg:            #e5e5e5;
        +
        +//** Dropdown link text color.
        +@dropdown-link-color:            @gray-dark;
        +//** Hover color for dropdown links.
        +@dropdown-link-hover-color:      darken(@gray-dark, 5%);
        +//** Hover background for dropdown links.
        +@dropdown-link-hover-bg:         #f5f5f5;
        +
        +//** Active dropdown menu item text color.
        +@dropdown-link-active-color:     @component-active-color;
        +//** Active dropdown menu item background color.
        +@dropdown-link-active-bg:        @component-active-bg;
        +
        +//** Disabled dropdown menu item background color.
        +@dropdown-link-disabled-color:   @gray-light;
        +
        +//** Text color for headers within dropdown menus.
        +@dropdown-header-color:          @gray-light;
        +
        +//** Deprecated `@dropdown-caret-color` as of v3.1.0
        +@dropdown-caret-color:           #000;
        +
        +
        +//-- Z-index master list
        +//
        +// Warning: Avoid customizing these values. They're used for a bird's eye view
        +// of components dependent on the z-axis and are designed to all work together.
        +//
        +// Note: These variables are not generated into the Customizer.
        +
        +@zindex-navbar:            1000;
        +@zindex-dropdown:          1000;
        +@zindex-popover:           1060;
        +@zindex-tooltip:           1070;
        +@zindex-navbar-fixed:      1030;
        +@zindex-modal-background:  1040;
        +@zindex-modal:             1050;
        +
        +
        +//== Media queries breakpoints
        +//
        +//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
        +
        +// Extra small screen / phone
        +//** Deprecated `@screen-xs` as of v3.0.1
        +@screen-xs:                  480px;
        +//** Deprecated `@screen-xs-min` as of v3.2.0
        +@screen-xs-min:              @screen-xs;
        +//** Deprecated `@screen-phone` as of v3.0.1
        +@screen-phone:               @screen-xs-min;
        +
        +// Small screen / tablet
        +//** Deprecated `@screen-sm` as of v3.0.1
        +@screen-sm:                  768px;
        +@screen-sm-min:              @screen-sm;
        +//** Deprecated `@screen-tablet` as of v3.0.1
        +@screen-tablet:              @screen-sm-min;
        +
        +// Medium screen / desktop
        +//** Deprecated `@screen-md` as of v3.0.1
        +@screen-md:                  992px;
        +@screen-md-min:              @screen-md;
        +//** Deprecated `@screen-desktop` as of v3.0.1
        +@screen-desktop:             @screen-md-min;
        +
        +// Large screen / wide desktop
        +//** Deprecated `@screen-lg` as of v3.0.1
        +@screen-lg:                  1200px;
        +@screen-lg-min:              @screen-lg;
        +//** Deprecated `@screen-lg-desktop` as of v3.0.1
        +@screen-lg-desktop:          @screen-lg-min;
        +
        +// So media queries don't overlap when required, provide a maximum
        +@screen-xs-max:              (@screen-sm-min - 1);
        +@screen-sm-max:              (@screen-md-min - 1);
        +@screen-md-max:              (@screen-lg-min - 1);
        +
        +
        +//== Grid system
        +//
        +//## Define your custom responsive grid.
        +
        +//** Number of columns in the grid.
        +@grid-columns:              12;
        +//** Padding between columns. Gets divided in half for the left and right.
        +@grid-gutter-width:         30px;
        +// Navbar collapse
        +//** Point at which the navbar becomes uncollapsed.
        +@grid-float-breakpoint:     @screen-sm-min;
        +//** Point at which the navbar begins collapsing.
        +@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
        +
        +
        +//== Container sizes
        +//
        +//## Define the maximum width of `.container` for different screen sizes.
        +
        +// Small screen / tablet
        +@container-tablet:             (720px + @grid-gutter-width);
        +//** For `@screen-sm-min` and up.
        +@container-sm:                 @container-tablet;
        +
        +// Medium screen / desktop
        +@container-desktop:            (940px + @grid-gutter-width);
        +//** For `@screen-md-min` and up.
        +@container-md:                 @container-desktop;
        +
        +// Large screen / wide desktop
        +@container-large-desktop:      (1140px + @grid-gutter-width);
        +//** For `@screen-lg-min` and up.
        +@container-lg:                 @container-large-desktop;
        +
        +
        +//== Navbar
        +//
        +//##
        +
        +// Basics of a navbar
        +@navbar-height:                    50px;
        +@navbar-margin-bottom:             @line-height-computed;
        +@navbar-border-radius:             @border-radius-base;
        +@navbar-padding-horizontal:        floor((@grid-gutter-width / 2));
        +@navbar-padding-vertical:          ((@navbar-height - @line-height-computed) / 2);
        +@navbar-collapse-max-height:       340px;
        +
        +@navbar-default-color:             #777;
        +@navbar-default-bg:                #f8f8f8;
        +@navbar-default-border:            darken(@navbar-default-bg, 6.5%);
        +
        +// Navbar links
        +@navbar-default-link-color:                #777;
        +@navbar-default-link-hover-color:          #333;
        +@navbar-default-link-hover-bg:             transparent;
        +@navbar-default-link-active-color:         #555;
        +@navbar-default-link-active-bg:            darken(@navbar-default-bg, 6.5%);
        +@navbar-default-link-disabled-color:       #ccc;
        +@navbar-default-link-disabled-bg:          transparent;
        +
        +// Navbar brand label
        +@navbar-default-brand-color:               @navbar-default-link-color;
        +@navbar-default-brand-hover-color:         darken(@navbar-default-brand-color, 10%);
        +@navbar-default-brand-hover-bg:            transparent;
        +
        +// Navbar toggle
        +@navbar-default-toggle-hover-bg:           #ddd;
        +@navbar-default-toggle-icon-bar-bg:        #888;
        +@navbar-default-toggle-border-color:       #ddd;
        +
        +
        +//=== Inverted navbar
        +// Reset inverted navbar basics
        +@navbar-inverse-color:                      lighten(@gray-light, 15%);
        +@navbar-inverse-bg:                         #222;
        +@navbar-inverse-border:                     darken(@navbar-inverse-bg, 10%);
        +
        +// Inverted navbar links
        +@navbar-inverse-link-color:                 lighten(@gray-light, 15%);
        +@navbar-inverse-link-hover-color:           #fff;
        +@navbar-inverse-link-hover-bg:              transparent;
        +@navbar-inverse-link-active-color:          @navbar-inverse-link-hover-color;
        +@navbar-inverse-link-active-bg:             darken(@navbar-inverse-bg, 10%);
        +@navbar-inverse-link-disabled-color:        #444;
        +@navbar-inverse-link-disabled-bg:           transparent;
        +
        +// Inverted navbar brand label
        +@navbar-inverse-brand-color:                @navbar-inverse-link-color;
        +@navbar-inverse-brand-hover-color:          #fff;
        +@navbar-inverse-brand-hover-bg:             transparent;
        +
        +// Inverted navbar toggle
        +@navbar-inverse-toggle-hover-bg:            #333;
        +@navbar-inverse-toggle-icon-bar-bg:         #fff;
        +@navbar-inverse-toggle-border-color:        #333;
        +
        +
        +//== Navs
        +//
        +//##
        +
        +//=== Shared nav styles
        +@nav-link-padding:                          10px 15px;
        +@nav-link-hover-bg:                         @gray-lighter;
        +
        +@nav-disabled-link-color:                   @gray-light;
        +@nav-disabled-link-hover-color:             @gray-light;
        +
        +//== Tabs
        +@nav-tabs-border-color:                     #ddd;
        +
        +@nav-tabs-link-hover-border-color:          @gray-lighter;
        +
        +@nav-tabs-active-link-hover-bg:             @body-bg;
        +@nav-tabs-active-link-hover-color:          @gray;
        +@nav-tabs-active-link-hover-border-color:   #ddd;
        +
        +@nav-tabs-justified-link-border-color:            #ddd;
        +@nav-tabs-justified-active-link-border-color:     @body-bg;
        +
        +//== Pills
        +@nav-pills-border-radius:                   @border-radius-base;
        +@nav-pills-active-link-hover-bg:            @component-active-bg;
        +@nav-pills-active-link-hover-color:         @component-active-color;
        +
        +
        +//== Pagination
        +//
        +//##
        +
        +@pagination-color:                     @link-color;
        +@pagination-bg:                        #fff;
        +@pagination-border:                    #ddd;
        +
        +@pagination-hover-color:               @link-hover-color;
        +@pagination-hover-bg:                  @gray-lighter;
        +@pagination-hover-border:              #ddd;
        +
        +@pagination-active-color:              #fff;
        +@pagination-active-bg:                 @brand-primary;
        +@pagination-active-border:             @brand-primary;
        +
        +@pagination-disabled-color:            @gray-light;
        +@pagination-disabled-bg:               #fff;
        +@pagination-disabled-border:           #ddd;
        +
        +
        +//== Pager
        +//
        +//##
        +
        +@pager-bg:                             @pagination-bg;
        +@pager-border:                         @pagination-border;
        +@pager-border-radius:                  15px;
        +
        +@pager-hover-bg:                       @pagination-hover-bg;
        +
        +@pager-active-bg:                      @pagination-active-bg;
        +@pager-active-color:                   @pagination-active-color;
        +
        +@pager-disabled-color:                 @pagination-disabled-color;
        +
        +
        +//== Jumbotron
        +//
        +//##
        +
        +@jumbotron-padding:              30px;
        +@jumbotron-color:                inherit;
        +@jumbotron-bg:                   @gray-lighter;
        +@jumbotron-heading-color:        inherit;
        +@jumbotron-font-size:            ceil((@font-size-base * 1.5));
        +@jumbotron-heading-font-size:    ceil((@font-size-base * 4.5));
        +
        +
        +//== Form states and alerts
        +//
        +//## Define colors for form feedback states and, by default, alerts.
        +
        +@state-success-text:             #3c763d;
        +@state-success-bg:               #dff0d8;
        +@state-success-border:           darken(spin(@state-success-bg, -10), 5%);
        +
        +@state-info-text:                #31708f;
        +@state-info-bg:                  #d9edf7;
        +@state-info-border:              darken(spin(@state-info-bg, -10), 7%);
        +
        +@state-warning-text:             #8a6d3b;
        +@state-warning-bg:               #fcf8e3;
        +@state-warning-border:           darken(spin(@state-warning-bg, -10), 5%);
        +
        +@state-danger-text:              #a94442;
        +@state-danger-bg:                #f2dede;
        +@state-danger-border:            darken(spin(@state-danger-bg, -10), 5%);
        +
        +
        +//== Tooltips
        +//
        +//##
        +
        +//** Tooltip max width
        +@tooltip-max-width:           200px;
        +//** Tooltip text color
        +@tooltip-color:               #fff;
        +//** Tooltip background color
        +@tooltip-bg:                  #000;
        +@tooltip-opacity:             .9;
        +
        +//** Tooltip arrow width
        +@tooltip-arrow-width:         5px;
        +//** Tooltip arrow color
        +@tooltip-arrow-color:         @tooltip-bg;
        +
        +
        +//== Popovers
        +//
        +//##
        +
        +//** Popover body background color
        +@popover-bg:                          #fff;
        +//** Popover maximum width
        +@popover-max-width:                   276px;
        +//** Popover border color
        +@popover-border-color:                rgba(0,0,0,.2);
        +//** Popover fallback border color
        +@popover-fallback-border-color:       #ccc;
        +
        +//** Popover title background color
        +@popover-title-bg:                    darken(@popover-bg, 3%);
        +
        +//** Popover arrow width
        +@popover-arrow-width:                 10px;
        +//** Popover arrow color
        +@popover-arrow-color:                 @popover-bg;
        +
        +//** Popover outer arrow width
        +@popover-arrow-outer-width:           (@popover-arrow-width + 1);
        +//** Popover outer arrow color
        +@popover-arrow-outer-color:           fadein(@popover-border-color, 5%);
        +//** Popover outer arrow fallback color
        +@popover-arrow-outer-fallback-color:  darken(@popover-fallback-border-color, 20%);
        +
        +
        +//== Labels
        +//
        +//##
        +
        +//** Default label background color
        +@label-default-bg:            @gray-light;
        +//** Primary label background color
        +@label-primary-bg:            @brand-primary;
        +//** Success label background color
        +@label-success-bg:            @brand-success;
        +//** Info label background color
        +@label-info-bg:               @brand-info;
        +//** Warning label background color
        +@label-warning-bg:            @brand-warning;
        +//** Danger label background color
        +@label-danger-bg:             @brand-danger;
        +
        +//** Default label text color
        +@label-color:                 #fff;
        +//** Default text color of a linked label
        +@label-link-hover-color:      #fff;
        +
        +
        +//== Modals
        +//
        +//##
        +
        +//** Padding applied to the modal body
        +@modal-inner-padding:         15px;
        +
        +//** Padding applied to the modal title
        +@modal-title-padding:         15px;
        +//** Modal title line-height
        +@modal-title-line-height:     @line-height-base;
        +
        +//** Background color of modal content area
        +@modal-content-bg:                             #fff;
        +//** Modal content border color
        +@modal-content-border-color:                   rgba(0,0,0,.2);
        +//** Modal content border color **for IE8**
        +@modal-content-fallback-border-color:          #999;
        +
        +//** Modal backdrop background color
        +@modal-backdrop-bg:           #000;
        +//** Modal backdrop opacity
        +@modal-backdrop-opacity:      .5;
        +//** Modal header border color
        +@modal-header-border-color:   #e5e5e5;
        +//** Modal footer border color
        +@modal-footer-border-color:   @modal-header-border-color;
        +
        +@modal-lg:                    900px;
        +@modal-md:                    600px;
        +@modal-sm:                    300px;
        +
        +
        +//== Alerts
        +//
        +//## Define alert colors, border radius, and padding.
        +
        +@alert-padding:               15px;
        +@alert-border-radius:         @border-radius-base;
        +@alert-link-font-weight:      bold;
        +
        +@alert-success-bg:            @state-success-bg;
        +@alert-success-text:          @state-success-text;
        +@alert-success-border:        @state-success-border;
        +
        +@alert-info-bg:               @state-info-bg;
        +@alert-info-text:             @state-info-text;
        +@alert-info-border:           @state-info-border;
        +
        +@alert-warning-bg:            @state-warning-bg;
        +@alert-warning-text:          @state-warning-text;
        +@alert-warning-border:        @state-warning-border;
        +
        +@alert-danger-bg:             @state-danger-bg;
        +@alert-danger-text:           @state-danger-text;
        +@alert-danger-border:         @state-danger-border;
        +
        +
        +//== Progress bars
        +//
        +//##
        +
        +//** Background color of the whole progress component
        +@progress-bg:                 #f5f5f5;
        +//** Progress bar text color
        +@progress-bar-color:          #fff;
        +//** Variable for setting rounded corners on progress bar.
        +@progress-border-radius:      @border-radius-base;
        +
        +//** Default progress bar color
        +@progress-bar-bg:             @brand-primary;
        +//** Success progress bar color
        +@progress-bar-success-bg:     @brand-success;
        +//** Warning progress bar color
        +@progress-bar-warning-bg:     @brand-warning;
        +//** Danger progress bar color
        +@progress-bar-danger-bg:      @brand-danger;
        +//** Info progress bar color
        +@progress-bar-info-bg:        @brand-info;
        +
        +
        +//== List group
        +//
        +//##
        +
        +//** Background color on `.list-group-item`
        +@list-group-bg:                 #fff;
        +//** `.list-group-item` border color
        +@list-group-border:             #ddd;
        +//** List group border radius
        +@list-group-border-radius:      @border-radius-base;
        +
        +//** Background color of single list items on hover
        +@list-group-hover-bg:           #f5f5f5;
        +//** Text color of active list items
        +@list-group-active-color:       @component-active-color;
        +//** Background color of active list items
        +@list-group-active-bg:          @component-active-bg;
        +//** Border color of active list elements
        +@list-group-active-border:      @list-group-active-bg;
        +//** Text color for content within active list items
        +@list-group-active-text-color:  lighten(@list-group-active-bg, 40%);
        +
        +//** Text color of disabled list items
        +@list-group-disabled-color:      @gray-light;
        +//** Background color of disabled list items
        +@list-group-disabled-bg:         @gray-lighter;
        +//** Text color for content within disabled list items
        +@list-group-disabled-text-color: @list-group-disabled-color;
        +
        +@list-group-link-color:         #555;
        +@list-group-link-hover-color:   @list-group-link-color;
        +@list-group-link-heading-color: #333;
        +
        +
        +//== Panels
        +//
        +//##
        +
        +@panel-bg:                    #fff;
        +@panel-body-padding:          15px;
        +@panel-heading-padding:       10px 15px;
        +@panel-footer-padding:        @panel-heading-padding;
        +@panel-border-radius:         @border-radius-base;
        +
        +//** Border color for elements within panels
        +@panel-inner-border:          #ddd;
        +@panel-footer-bg:             #f5f5f5;
        +
        +@panel-default-text:          @gray-dark;
        +@panel-default-border:        #ddd;
        +@panel-default-heading-bg:    #f5f5f5;
        +
        +@panel-primary-text:          #fff;
        +@panel-primary-border:        @brand-primary;
        +@panel-primary-heading-bg:    @brand-primary;
        +
        +@panel-success-text:          @state-success-text;
        +@panel-success-border:        @state-success-border;
        +@panel-success-heading-bg:    @state-success-bg;
        +
        +@panel-info-text:             @state-info-text;
        +@panel-info-border:           @state-info-border;
        +@panel-info-heading-bg:       @state-info-bg;
        +
        +@panel-warning-text:          @state-warning-text;
        +@panel-warning-border:        @state-warning-border;
        +@panel-warning-heading-bg:    @state-warning-bg;
        +
        +@panel-danger-text:           @state-danger-text;
        +@panel-danger-border:         @state-danger-border;
        +@panel-danger-heading-bg:     @state-danger-bg;
        +
        +
        +//== Thumbnails
        +//
        +//##
        +
        +//** Padding around the thumbnail image
        +@thumbnail-padding:           4px;
        +//** Thumbnail background color
        +@thumbnail-bg:                @body-bg;
        +//** Thumbnail border color
        +@thumbnail-border:            #ddd;
        +//** Thumbnail border radius
        +@thumbnail-border-radius:     @border-radius-base;
        +
        +//** Custom text color for thumbnail captions
        +@thumbnail-caption-color:     @text-color;
        +//** Padding around the thumbnail caption
        +@thumbnail-caption-padding:   9px;
        +
        +
        +//== Wells
        +//
        +//##
        +
        +@well-bg:                     #f5f5f5;
        +@well-border:                 darken(@well-bg, 7%);
        +
        +
        +//== Badges
        +//
        +//##
        +
        +@badge-color:                 #fff;
        +//** Linked badge text color on hover
        +@badge-link-hover-color:      #fff;
        +@badge-bg:                    @gray-light;
        +
        +//** Badge text color in active nav link
        +@badge-active-color:          @link-color;
        +//** Badge background color in active nav link
        +@badge-active-bg:             #fff;
        +
        +@badge-font-weight:           bold;
        +@badge-line-height:           1;
        +@badge-border-radius:         10px;
        +
        +
        +//== Breadcrumbs
        +//
        +//##
        +
        +@breadcrumb-padding-vertical:   8px;
        +@breadcrumb-padding-horizontal: 15px;
        +//** Breadcrumb background color
        +@breadcrumb-bg:                 #f5f5f5;
        +//** Breadcrumb text color
        +@breadcrumb-color:              #ccc;
        +//** Text color of current page in the breadcrumb
        +@breadcrumb-active-color:       @gray-light;
        +//** Textual separator for between breadcrumb elements
        +@breadcrumb-separator:          "/";
        +
        +
        +//== Carousel
        +//
        +//##
        +
        +@carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6);
        +
        +@carousel-control-color:                      #fff;
        +@carousel-control-width:                      15%;
        +@carousel-control-opacity:                    .5;
        +@carousel-control-font-size:                  20px;
        +
        +@carousel-indicator-active-bg:                #fff;
        +@carousel-indicator-border-color:             #fff;
        +
        +@carousel-caption-color:                      #fff;
        +
        +
        +//== Close
        +//
        +//##
        +
        +@close-font-weight:           bold;
        +@close-color:                 #000;
        +@close-text-shadow:           0 1px 0 #fff;
        +
        +
        +//== Code
        +//
        +//##
        +
        +@code-color:                  #c7254e;
        +@code-bg:                     #f9f2f4;
        +
        +@kbd-color:                   #fff;
        +@kbd-bg:                      #333;
        +
        +@pre-bg:                      #f5f5f5;
        +@pre-color:                   @gray-dark;
        +@pre-border-color:            #ccc;
        +@pre-scrollable-max-height:   340px;
        +
        +
        +//== Type
        +//
        +//##
        +
        +//** Horizontal offset for forms and lists.
        +@component-offset-horizontal: 180px;
        +//** Text muted color
        +@text-muted:                  @gray-light;
        +//** Abbreviations and acronyms border color
        +@abbr-border-color:           @gray-light;
        +//** Headings small color
        +@headings-small-color:        @gray-light;
        +//** Blockquote small color
        +@blockquote-small-color:      @gray-light;
        +//** Blockquote font size
        +@blockquote-font-size:        (@font-size-base * 1.25);
        +//** Blockquote border color
        +@blockquote-border-color:     @gray-lighter;
        +//** Page header border color
        +@page-header-border-color:    @gray-lighter;
        +//** Width of horizontal description list titles
        +@dl-horizontal-offset:        @component-offset-horizontal;
        +//** Point at which .dl-horizontal becomes horizontal
        +@dl-horizontal-breakpoint:    @grid-float-breakpoint;
        +//** Horizontal line color.
        +@hr-border:                   @gray-lighter;
        diff --git a/themes/demo/assets/vendor/bootstrap/less/wells.less b/themes/demo/assets/vendor/bootstrap/less/wells.less
        new file mode 100644
        index 0000000..15d072b
        --- /dev/null
        +++ b/themes/demo/assets/vendor/bootstrap/less/wells.less
        @@ -0,0 +1,29 @@
        +//
        +// Wells
        +// --------------------------------------------------
        +
        +
        +// Base class
        +.well {
        +  min-height: 20px;
        +  padding: 19px;
        +  margin-bottom: 20px;
        +  background-color: @well-bg;
        +  border: 1px solid @well-border;
        +  border-radius: @border-radius-base;
        +  .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
        +  blockquote {
        +    border-color: #ddd;
        +    border-color: rgba(0,0,0,.15);
        +  }
        +}
        +
        +// Sizes
        +.well-lg {
        +  padding: 24px;
        +  border-radius: @border-radius-large;
        +}
        +.well-sm {
        +  padding: 9px;
        +  border-radius: @border-radius-small;
        +}
        diff --git a/themes/demo/assets/vendor/font-awesome/css/font-awesome.css b/themes/demo/assets/vendor/font-awesome/css/font-awesome.css
        new file mode 100644
        index 0000000..7667079
        --- /dev/null
        +++ b/themes/demo/assets/vendor/font-awesome/css/font-awesome.css
        @@ -0,0 +1,1478 @@
        +/*!
        + *  Font Awesome 3.2.1
        + *  the iconic font designed for Bootstrap
        + *  ------------------------------------------------------------------------------
        + *  The full suite of pictographic icons, examples, and documentation can be
        + *  found at http://fontawesome.io.  Stay up to date on Twitter at
        + *  http://twitter.com/fontawesome.
        + *
        + *  License
        + *  ------------------------------------------------------------------------------
        + *  - The Font Awesome font is licensed under SIL OFL 1.1 -
        + *    http://scripts.sil.org/OFL
        + *  - Font Awesome CSS, LESS, and SASS files are licensed under MIT License -
        + *    http://opensource.org/licenses/mit-license.html
        + *  - Font Awesome documentation licensed under CC BY 3.0 -
        + *    http://creativecommons.org/licenses/by/3.0/
        + *  - Attribution is no longer required in Font Awesome 3.0, but much appreciated:
        + *    "Font Awesome by Dave Gandy - http://fontawesome.io"
        + *
        + *  Author - Dave Gandy
        + *  ------------------------------------------------------------------------------
        + *  Email: dave@fontawesome.io
        + *  Twitter: http://twitter.com/davegandy
        + *  Work: Lead Product Designer @ Kyruus - http://kyruus.com
        + */
        +/* FONT PATH
        + * -------------------------- */
        +@font-face {
        +  font-family: 'FontAwesome';
        +  src: url('../font/fontawesome-webfont.eot?v=3.2.1');
        +  src: url('../font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'), url('../font/fontawesome-webfont.woff?v=3.2.1') format('woff'), url('../font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'), url('../font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');
        +  font-weight: normal;
        +  font-style: normal;
        +}
        +/* FONT AWESOME CORE
        + * -------------------------- */
        +[class^="icon-"],
        +[class*=" icon-"] {
        +  font-family: FontAwesome;
        +  font-weight: normal;
        +  font-style: normal;
        +  text-decoration: inherit;
        +  -webkit-font-smoothing: antialiased;
        +}
        +[class^="icon-"]:before,
        +[class*=" icon-"]:before {
        +  text-decoration: inherit;
        +  display: inline-block;
        +  speak: none;
        +}
        +/* makes the font 33% larger relative to the icon container */
        +.icon-large:before {
        +  vertical-align: -10%;
        +  font-size: 1.3333333333333333em;
        +}
        +/* makes sure icons active on rollover in links */
        +a [class^="icon-"],
        +a [class*=" icon-"] {
        +  display: inline;
        +}
        +/* increased font size for icon-large */
        +[class^="icon-"].icon-fixed-width,
        +[class*=" icon-"].icon-fixed-width {
        +  display: inline-block;
        +  width: 1.1428571428571428em;
        +  text-align: right;
        +  padding-right: 0.2857142857142857em;
        +}
        +[class^="icon-"].icon-fixed-width.icon-large,
        +[class*=" icon-"].icon-fixed-width.icon-large {
        +  width: 1.4285714285714286em;
        +}
        +.icons-ul {
        +  margin-left: 2.142857142857143em;
        +  list-style-type: none;
        +}
        +.icons-ul > li {
        +  position: relative;
        +}
        +.icons-ul .icon-li {
        +  position: absolute;
        +  left: -2.142857142857143em;
        +  width: 2.142857142857143em;
        +  text-align: center;
        +  line-height: inherit;
        +}
        +[class^="icon-"].hide,
        +[class*=" icon-"].hide {
        +  display: none;
        +}
        +.icon-muted {
        +  color: #eeeeee;
        +}
        +.icon-light {
        +  color: #ffffff;
        +}
        +.icon-dark {
        +  color: #333333;
        +}
        +.icon-border {
        +  border: solid 1px #eeeeee;
        +  padding: .2em .25em .15em;
        +  -webkit-border-radius: 3px;
        +  -moz-border-radius: 3px;
        +  border-radius: 3px;
        +}
        +.icon-2x {
        +  font-size: 2em;
        +}
        +.icon-2x.icon-border {
        +  border-width: 2px;
        +  -webkit-border-radius: 4px;
        +  -moz-border-radius: 4px;
        +  border-radius: 4px;
        +}
        +.icon-3x {
        +  font-size: 3em;
        +}
        +.icon-3x.icon-border {
        +  border-width: 3px;
        +  -webkit-border-radius: 5px;
        +  -moz-border-radius: 5px;
        +  border-radius: 5px;
        +}
        +.icon-4x {
        +  font-size: 4em;
        +}
        +.icon-4x.icon-border {
        +  border-width: 4px;
        +  -webkit-border-radius: 6px;
        +  -moz-border-radius: 6px;
        +  border-radius: 6px;
        +}
        +.icon-5x {
        +  font-size: 5em;
        +}
        +.icon-5x.icon-border {
        +  border-width: 5px;
        +  -webkit-border-radius: 7px;
        +  -moz-border-radius: 7px;
        +  border-radius: 7px;
        +}
        +.pull-right {
        +  float: right;
        +}
        +.pull-left {
        +  float: left;
        +}
        +[class^="icon-"].pull-left,
        +[class*=" icon-"].pull-left {
        +  margin-right: .3em;
        +}
        +[class^="icon-"].pull-right,
        +[class*=" icon-"].pull-right {
        +  margin-left: .3em;
        +}
        +/* BOOTSTRAP SPECIFIC CLASSES
        + * -------------------------- */
        +/* Bootstrap 2.0 sprites.less reset */
        +[class^="icon-"],
        +[class*=" icon-"] {
        +  display: inline;
        +  width: auto;
        +  height: auto;
        +  line-height: normal;
        +  vertical-align: baseline;
        +  background-image: none;
        +  background-position: 0% 0%;
        +  background-repeat: repeat;
        +  margin-top: 0;
        +}
        +/* more sprites.less reset */
        +.icon-white,
        +.nav-pills > .active > a > [class^="icon-"],
        +.nav-pills > .active > a > [class*=" icon-"],
        +.nav-list > .active > a > [class^="icon-"],
        +.nav-list > .active > a > [class*=" icon-"],
        +.navbar-inverse .nav > .active > a > [class^="icon-"],
        +.navbar-inverse .nav > .active > a > [class*=" icon-"],
        +.dropdown-menu > li > a:hover > [class^="icon-"],
        +.dropdown-menu > li > a:hover > [class*=" icon-"],
        +.dropdown-menu > .active > a > [class^="icon-"],
        +.dropdown-menu > .active > a > [class*=" icon-"],
        +.dropdown-submenu:hover > a > [class^="icon-"],
        +.dropdown-submenu:hover > a > [class*=" icon-"] {
        +  background-image: none;
        +}
        +/* keeps Bootstrap styles with and without icons the same */
        +.btn [class^="icon-"].icon-large,
        +.nav [class^="icon-"].icon-large,
        +.btn [class*=" icon-"].icon-large,
        +.nav [class*=" icon-"].icon-large {
        +  line-height: .9em;
        +}
        +.btn [class^="icon-"].icon-spin,
        +.nav [class^="icon-"].icon-spin,
        +.btn [class*=" icon-"].icon-spin,
        +.nav [class*=" icon-"].icon-spin {
        +  display: inline-block;
        +}
        +.nav-tabs [class^="icon-"],
        +.nav-pills [class^="icon-"],
        +.nav-tabs [class*=" icon-"],
        +.nav-pills [class*=" icon-"],
        +.nav-tabs [class^="icon-"].icon-large,
        +.nav-pills [class^="icon-"].icon-large,
        +.nav-tabs [class*=" icon-"].icon-large,
        +.nav-pills [class*=" icon-"].icon-large {
        +  line-height: .9em;
        +}
        +.btn [class^="icon-"].pull-left.icon-2x,
        +.btn [class*=" icon-"].pull-left.icon-2x,
        +.btn [class^="icon-"].pull-right.icon-2x,
        +.btn [class*=" icon-"].pull-right.icon-2x {
        +  margin-top: .18em;
        +}
        +.btn [class^="icon-"].icon-spin.icon-large,
        +.btn [class*=" icon-"].icon-spin.icon-large {
        +  line-height: .8em;
        +}
        +.btn.btn-small [class^="icon-"].pull-left.icon-2x,
        +.btn.btn-small [class*=" icon-"].pull-left.icon-2x,
        +.btn.btn-small [class^="icon-"].pull-right.icon-2x,
        +.btn.btn-small [class*=" icon-"].pull-right.icon-2x {
        +  margin-top: .25em;
        +}
        +.btn.btn-large [class^="icon-"],
        +.btn.btn-large [class*=" icon-"] {
        +  margin-top: 0;
        +}
        +.btn.btn-large [class^="icon-"].pull-left.icon-2x,
        +.btn.btn-large [class*=" icon-"].pull-left.icon-2x,
        +.btn.btn-large [class^="icon-"].pull-right.icon-2x,
        +.btn.btn-large [class*=" icon-"].pull-right.icon-2x {
        +  margin-top: .05em;
        +}
        +.btn.btn-large [class^="icon-"].pull-left.icon-2x,
        +.btn.btn-large [class*=" icon-"].pull-left.icon-2x {
        +  margin-right: .2em;
        +}
        +.btn.btn-large [class^="icon-"].pull-right.icon-2x,
        +.btn.btn-large [class*=" icon-"].pull-right.icon-2x {
        +  margin-left: .2em;
        +}
        +/* Fixes alignment in nav lists */
        +.nav-list [class^="icon-"],
        +.nav-list [class*=" icon-"] {
        +  line-height: inherit;
        +}
        +/* EXTRAS
        + * -------------------------- */
        +/* Stacked and layered icon */
        +.icon-stack {
        +  position: relative;
        +  display: inline-block;
        +  width: 2em;
        +  height: 2em;
        +  line-height: 2em;
        +  vertical-align: -35%;
        +}
        +.icon-stack [class^="icon-"],
        +.icon-stack [class*=" icon-"] {
        +  display: block;
        +  text-align: center;
        +  position: absolute;
        +  width: 100%;
        +  height: 100%;
        +  font-size: 1em;
        +  line-height: inherit;
        +  *line-height: 2em;
        +}
        +.icon-stack .icon-stack-base {
        +  font-size: 2em;
        +  *line-height: 1em;
        +}
        +/* Animated rotating icon */
        +.icon-spin {
        +  display: inline-block;
        +  -moz-animation: spin 2s infinite linear;
        +  -o-animation: spin 2s infinite linear;
        +  -webkit-animation: spin 2s infinite linear;
        +  animation: spin 2s infinite linear;
        +}
        +/* Prevent stack and spinners from being taken inline when inside a link */
        +a .icon-stack,
        +a .icon-spin {
        +  display: inline-block;
        +  text-decoration: none;
        +}
        +@-moz-keyframes spin {
        +  0% {
        +    -moz-transform: rotate(0deg);
        +  }
        +  100% {
        +    -moz-transform: rotate(359deg);
        +  }
        +}
        +@-webkit-keyframes spin {
        +  0% {
        +    -webkit-transform: rotate(0deg);
        +  }
        +  100% {
        +    -webkit-transform: rotate(359deg);
        +  }
        +}
        +@-o-keyframes spin {
        +  0% {
        +    -o-transform: rotate(0deg);
        +  }
        +  100% {
        +    -o-transform: rotate(359deg);
        +  }
        +}
        +@-ms-keyframes spin {
        +  0% {
        +    -ms-transform: rotate(0deg);
        +  }
        +  100% {
        +    -ms-transform: rotate(359deg);
        +  }
        +}
        +@keyframes spin {
        +  0% {
        +    transform: rotate(0deg);
        +  }
        +  100% {
        +    transform: rotate(359deg);
        +  }
        +}
        +/* Icon rotations and mirroring */
        +.icon-rotate-90:before {
        +  -webkit-transform: rotate(90deg);
        +  -moz-transform: rotate(90deg);
        +  -ms-transform: rotate(90deg);
        +  -o-transform: rotate(90deg);
        +  transform: rotate(90deg);
        +  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
        +}
        +.icon-rotate-180:before {
        +  -webkit-transform: rotate(180deg);
        +  -moz-transform: rotate(180deg);
        +  -ms-transform: rotate(180deg);
        +  -o-transform: rotate(180deg);
        +  transform: rotate(180deg);
        +  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
        +}
        +.icon-rotate-270:before {
        +  -webkit-transform: rotate(270deg);
        +  -moz-transform: rotate(270deg);
        +  -ms-transform: rotate(270deg);
        +  -o-transform: rotate(270deg);
        +  transform: rotate(270deg);
        +  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
        +}
        +.icon-flip-horizontal:before {
        +  -webkit-transform: scale(-1, 1);
        +  -moz-transform: scale(-1, 1);
        +  -ms-transform: scale(-1, 1);
        +  -o-transform: scale(-1, 1);
        +  transform: scale(-1, 1);
        +}
        +.icon-flip-vertical:before {
        +  -webkit-transform: scale(1, -1);
        +  -moz-transform: scale(1, -1);
        +  -ms-transform: scale(1, -1);
        +  -o-transform: scale(1, -1);
        +  transform: scale(1, -1);
        +}
        +/* ensure rotation occurs inside anchor tags */
        +a .icon-rotate-90:before,
        +a .icon-rotate-180:before,
        +a .icon-rotate-270:before,
        +a .icon-flip-horizontal:before,
        +a .icon-flip-vertical:before {
        +  display: inline-block;
        +}
        +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
        +   readers do not read off random characters that represent icons */
        +.icon-glass:before {
        +  content: "\f000";
        +}
        +.icon-music:before {
        +  content: "\f001";
        +}
        +.icon-search:before {
        +  content: "\f002";
        +}
        +.icon-envelope-alt:before {
        +  content: "\f003";
        +}
        +.icon-heart:before {
        +  content: "\f004";
        +}
        +.icon-star:before {
        +  content: "\f005";
        +}
        +.icon-star-empty:before {
        +  content: "\f006";
        +}
        +.icon-user:before {
        +  content: "\f007";
        +}
        +.icon-film:before {
        +  content: "\f008";
        +}
        +.icon-th-large:before {
        +  content: "\f009";
        +}
        +.icon-th:before {
        +  content: "\f00a";
        +}
        +.icon-th-list:before {
        +  content: "\f00b";
        +}
        +.icon-ok:before {
        +  content: "\f00c";
        +}
        +.icon-remove:before {
        +  content: "\f00d";
        +}
        +.icon-zoom-in:before {
        +  content: "\f00e";
        +}
        +.icon-zoom-out:before {
        +  content: "\f010";
        +}
        +.icon-power-off:before,
        +.icon-off:before {
        +  content: "\f011";
        +}
        +.icon-signal:before {
        +  content: "\f012";
        +}
        +.icon-gear:before,
        +.icon-cog:before {
        +  content: "\f013";
        +}
        +.icon-trash:before {
        +  content: "\f014";
        +}
        +.icon-home:before {
        +  content: "\f015";
        +}
        +.icon-file-alt:before {
        +  content: "\f016";
        +}
        +.icon-time:before {
        +  content: "\f017";
        +}
        +.icon-road:before {
        +  content: "\f018";
        +}
        +.icon-download-alt:before {
        +  content: "\f019";
        +}
        +.icon-download:before {
        +  content: "\f01a";
        +}
        +.icon-upload:before {
        +  content: "\f01b";
        +}
        +.icon-inbox:before {
        +  content: "\f01c";
        +}
        +.icon-play-circle:before {
        +  content: "\f01d";
        +}
        +.icon-rotate-right:before,
        +.icon-repeat:before {
        +  content: "\f01e";
        +}
        +.icon-refresh:before {
        +  content: "\f021";
        +}
        +.icon-list-alt:before {
        +  content: "\f022";
        +}
        +.icon-lock:before {
        +  content: "\f023";
        +}
        +.icon-flag:before {
        +  content: "\f024";
        +}
        +.icon-headphones:before {
        +  content: "\f025";
        +}
        +.icon-volume-off:before {
        +  content: "\f026";
        +}
        +.icon-volume-down:before {
        +  content: "\f027";
        +}
        +.icon-volume-up:before {
        +  content: "\f028";
        +}
        +.icon-qrcode:before {
        +  content: "\f029";
        +}
        +.icon-barcode:before {
        +  content: "\f02a";
        +}
        +.icon-tag:before {
        +  content: "\f02b";
        +}
        +.icon-tags:before {
        +  content: "\f02c";
        +}
        +.icon-book:before {
        +  content: "\f02d";
        +}
        +.icon-bookmark:before {
        +  content: "\f02e";
        +}
        +.icon-print:before {
        +  content: "\f02f";
        +}
        +.icon-camera:before {
        +  content: "\f030";
        +}
        +.icon-font:before {
        +  content: "\f031";
        +}
        +.icon-bold:before {
        +  content: "\f032";
        +}
        +.icon-italic:before {
        +  content: "\f033";
        +}
        +.icon-text-height:before {
        +  content: "\f034";
        +}
        +.icon-text-width:before {
        +  content: "\f035";
        +}
        +.icon-align-left:before {
        +  content: "\f036";
        +}
        +.icon-align-center:before {
        +  content: "\f037";
        +}
        +.icon-align-right:before {
        +  content: "\f038";
        +}
        +.icon-align-justify:before {
        +  content: "\f039";
        +}
        +.icon-list:before {
        +  content: "\f03a";
        +}
        +.icon-indent-left:before {
        +  content: "\f03b";
        +}
        +.icon-indent-right:before {
        +  content: "\f03c";
        +}
        +.icon-facetime-video:before {
        +  content: "\f03d";
        +}
        +.icon-picture:before {
        +  content: "\f03e";
        +}
        +.icon-pencil:before {
        +  content: "\f040";
        +}
        +.icon-map-marker:before {
        +  content: "\f041";
        +}
        +.icon-adjust:before {
        +  content: "\f042";
        +}
        +.icon-tint:before {
        +  content: "\f043";
        +}
        +.icon-edit:before {
        +  content: "\f044";
        +}
        +.icon-share:before {
        +  content: "\f045";
        +}
        +.icon-check:before {
        +  content: "\f046";
        +}
        +.icon-move:before {
        +  content: "\f047";
        +}
        +.icon-step-backward:before {
        +  content: "\f048";
        +}
        +.icon-fast-backward:before {
        +  content: "\f049";
        +}
        +.icon-backward:before {
        +  content: "\f04a";
        +}
        +.icon-play:before {
        +  content: "\f04b";
        +}
        +.icon-pause:before {
        +  content: "\f04c";
        +}
        +.icon-stop:before {
        +  content: "\f04d";
        +}
        +.icon-forward:before {
        +  content: "\f04e";
        +}
        +.icon-fast-forward:before {
        +  content: "\f050";
        +}
        +.icon-step-forward:before {
        +  content: "\f051";
        +}
        +.icon-eject:before {
        +  content: "\f052";
        +}
        +.icon-chevron-left:before {
        +  content: "\f053";
        +}
        +.icon-chevron-right:before {
        +  content: "\f054";
        +}
        +.icon-plus-sign:before {
        +  content: "\f055";
        +}
        +.icon-minus-sign:before {
        +  content: "\f056";
        +}
        +.icon-remove-sign:before {
        +  content: "\f057";
        +}
        +.icon-ok-sign:before {
        +  content: "\f058";
        +}
        +.icon-question-sign:before {
        +  content: "\f059";
        +}
        +.icon-info-sign:before {
        +  content: "\f05a";
        +}
        +.icon-screenshot:before {
        +  content: "\f05b";
        +}
        +.icon-remove-circle:before {
        +  content: "\f05c";
        +}
        +.icon-ok-circle:before {
        +  content: "\f05d";
        +}
        +.icon-ban-circle:before {
        +  content: "\f05e";
        +}
        +.icon-arrow-left:before {
        +  content: "\f060";
        +}
        +.icon-arrow-right:before {
        +  content: "\f061";
        +}
        +.icon-arrow-up:before {
        +  content: "\f062";
        +}
        +.icon-arrow-down:before {
        +  content: "\f063";
        +}
        +.icon-mail-forward:before,
        +.icon-share-alt:before {
        +  content: "\f064";
        +}
        +.icon-resize-full:before {
        +  content: "\f065";
        +}
        +.icon-resize-small:before {
        +  content: "\f066";
        +}
        +.icon-plus:before {
        +  content: "\f067";
        +}
        +.icon-minus:before {
        +  content: "\f068";
        +}
        +.icon-asterisk:before {
        +  content: "\f069";
        +}
        +.icon-exclamation-sign:before {
        +  content: "\f06a";
        +}
        +.icon-gift:before {
        +  content: "\f06b";
        +}
        +.icon-leaf:before {
        +  content: "\f06c";
        +}
        +.icon-fire:before {
        +  content: "\f06d";
        +}
        +.icon-eye-open:before {
        +  content: "\f06e";
        +}
        +.icon-eye-close:before {
        +  content: "\f070";
        +}
        +.icon-warning-sign:before {
        +  content: "\f071";
        +}
        +.icon-plane:before {
        +  content: "\f072";
        +}
        +.icon-calendar:before {
        +  content: "\f073";
        +}
        +.icon-random:before {
        +  content: "\f074";
        +}
        +.icon-comment:before {
        +  content: "\f075";
        +}
        +.icon-magnet:before {
        +  content: "\f076";
        +}
        +.icon-chevron-up:before {
        +  content: "\f077";
        +}
        +.icon-chevron-down:before {
        +  content: "\f078";
        +}
        +.icon-retweet:before {
        +  content: "\f079";
        +}
        +.icon-shopping-cart:before {
        +  content: "\f07a";
        +}
        +.icon-folder-close:before {
        +  content: "\f07b";
        +}
        +.icon-folder-open:before {
        +  content: "\f07c";
        +}
        +.icon-resize-vertical:before {
        +  content: "\f07d";
        +}
        +.icon-resize-horizontal:before {
        +  content: "\f07e";
        +}
        +.icon-bar-chart:before {
        +  content: "\f080";
        +}
        +.icon-twitter-sign:before {
        +  content: "\f081";
        +}
        +.icon-facebook-sign:before {
        +  content: "\f082";
        +}
        +.icon-camera-retro:before {
        +  content: "\f083";
        +}
        +.icon-key:before {
        +  content: "\f084";
        +}
        +.icon-gears:before,
        +.icon-cogs:before {
        +  content: "\f085";
        +}
        +.icon-comments:before {
        +  content: "\f086";
        +}
        +.icon-thumbs-up-alt:before {
        +  content: "\f087";
        +}
        +.icon-thumbs-down-alt:before {
        +  content: "\f088";
        +}
        +.icon-star-half:before {
        +  content: "\f089";
        +}
        +.icon-heart-empty:before {
        +  content: "\f08a";
        +}
        +.icon-signout:before {
        +  content: "\f08b";
        +}
        +.icon-linkedin-sign:before {
        +  content: "\f08c";
        +}
        +.icon-pushpin:before {
        +  content: "\f08d";
        +}
        +.icon-external-link:before {
        +  content: "\f08e";
        +}
        +.icon-signin:before {
        +  content: "\f090";
        +}
        +.icon-trophy:before {
        +  content: "\f091";
        +}
        +.icon-github-sign:before {
        +  content: "\f092";
        +}
        +.icon-upload-alt:before {
        +  content: "\f093";
        +}
        +.icon-lemon:before {
        +  content: "\f094";
        +}
        +.icon-phone:before {
        +  content: "\f095";
        +}
        +.icon-unchecked:before,
        +.icon-check-empty:before {
        +  content: "\f096";
        +}
        +.icon-bookmark-empty:before {
        +  content: "\f097";
        +}
        +.icon-phone-sign:before {
        +  content: "\f098";
        +}
        +.icon-twitter:before {
        +  content: "\f099";
        +}
        +.icon-facebook:before {
        +  content: "\f09a";
        +}
        +.icon-github:before {
        +  content: "\f09b";
        +}
        +.icon-unlock:before {
        +  content: "\f09c";
        +}
        +.icon-credit-card:before {
        +  content: "\f09d";
        +}
        +.icon-rss:before {
        +  content: "\f09e";
        +}
        +.icon-hdd:before {
        +  content: "\f0a0";
        +}
        +.icon-bullhorn:before {
        +  content: "\f0a1";
        +}
        +.icon-bell:before {
        +  content: "\f0a2";
        +}
        +.icon-certificate:before {
        +  content: "\f0a3";
        +}
        +.icon-hand-right:before {
        +  content: "\f0a4";
        +}
        +.icon-hand-left:before {
        +  content: "\f0a5";
        +}
        +.icon-hand-up:before {
        +  content: "\f0a6";
        +}
        +.icon-hand-down:before {
        +  content: "\f0a7";
        +}
        +.icon-circle-arrow-left:before {
        +  content: "\f0a8";
        +}
        +.icon-circle-arrow-right:before {
        +  content: "\f0a9";
        +}
        +.icon-circle-arrow-up:before {
        +  content: "\f0aa";
        +}
        +.icon-circle-arrow-down:before {
        +  content: "\f0ab";
        +}
        +.icon-globe:before {
        +  content: "\f0ac";
        +}
        +.icon-wrench:before {
        +  content: "\f0ad";
        +}
        +.icon-tasks:before {
        +  content: "\f0ae";
        +}
        +.icon-filter:before {
        +  content: "\f0b0";
        +}
        +.icon-briefcase:before {
        +  content: "\f0b1";
        +}
        +.icon-fullscreen:before {
        +  content: "\f0b2";
        +}
        +.icon-group:before {
        +  content: "\f0c0";
        +}
        +.icon-link:before {
        +  content: "\f0c1";
        +}
        +.icon-cloud:before {
        +  content: "\f0c2";
        +}
        +.icon-beaker:before {
        +  content: "\f0c3";
        +}
        +.icon-cut:before {
        +  content: "\f0c4";
        +}
        +.icon-copy:before {
        +  content: "\f0c5";
        +}
        +.icon-paperclip:before,
        +.icon-paper-clip:before {
        +  content: "\f0c6";
        +}
        +.icon-save:before {
        +  content: "\f0c7";
        +}
        +.icon-sign-blank:before {
        +  content: "\f0c8";
        +}
        +.icon-reorder:before {
        +  content: "\f0c9";
        +}
        +.icon-list-ul:before {
        +  content: "\f0ca";
        +}
        +.icon-list-ol:before {
        +  content: "\f0cb";
        +}
        +.icon-strikethrough:before {
        +  content: "\f0cc";
        +}
        +.icon-underline:before {
        +  content: "\f0cd";
        +}
        +.icon-table:before {
        +  content: "\f0ce";
        +}
        +.icon-magic:before {
        +  content: "\f0d0";
        +}
        +.icon-truck:before {
        +  content: "\f0d1";
        +}
        +.icon-pinterest:before {
        +  content: "\f0d2";
        +}
        +.icon-pinterest-sign:before {
        +  content: "\f0d3";
        +}
        +.icon-google-plus-sign:before {
        +  content: "\f0d4";
        +}
        +.icon-google-plus:before {
        +  content: "\f0d5";
        +}
        +.icon-money:before {
        +  content: "\f0d6";
        +}
        +.icon-caret-down:before {
        +  content: "\f0d7";
        +}
        +.icon-caret-up:before {
        +  content: "\f0d8";
        +}
        +.icon-caret-left:before {
        +  content: "\f0d9";
        +}
        +.icon-caret-right:before {
        +  content: "\f0da";
        +}
        +.icon-columns:before {
        +  content: "\f0db";
        +}
        +.icon-sort:before {
        +  content: "\f0dc";
        +}
        +.icon-sort-down:before {
        +  content: "\f0dd";
        +}
        +.icon-sort-up:before {
        +  content: "\f0de";
        +}
        +.icon-envelope:before {
        +  content: "\f0e0";
        +}
        +.icon-linkedin:before {
        +  content: "\f0e1";
        +}
        +.icon-rotate-left:before,
        +.icon-undo:before {
        +  content: "\f0e2";
        +}
        +.icon-legal:before {
        +  content: "\f0e3";
        +}
        +.icon-dashboard:before {
        +  content: "\f0e4";
        +}
        +.icon-comment-alt:before {
        +  content: "\f0e5";
        +}
        +.icon-comments-alt:before {
        +  content: "\f0e6";
        +}
        +.icon-bolt:before {
        +  content: "\f0e7";
        +}
        +.icon-sitemap:before {
        +  content: "\f0e8";
        +}
        +.icon-umbrella:before {
        +  content: "\f0e9";
        +}
        +.icon-paste:before {
        +  content: "\f0ea";
        +}
        +.icon-lightbulb:before {
        +  content: "\f0eb";
        +}
        +.icon-exchange:before {
        +  content: "\f0ec";
        +}
        +.icon-cloud-download:before {
        +  content: "\f0ed";
        +}
        +.icon-cloud-upload:before {
        +  content: "\f0ee";
        +}
        +.icon-user-md:before {
        +  content: "\f0f0";
        +}
        +.icon-stethoscope:before {
        +  content: "\f0f1";
        +}
        +.icon-suitcase:before {
        +  content: "\f0f2";
        +}
        +.icon-bell-alt:before {
        +  content: "\f0f3";
        +}
        +.icon-coffee:before {
        +  content: "\f0f4";
        +}
        +.icon-food:before {
        +  content: "\f0f5";
        +}
        +.icon-file-text-alt:before {
        +  content: "\f0f6";
        +}
        +.icon-building:before {
        +  content: "\f0f7";
        +}
        +.icon-hospital:before {
        +  content: "\f0f8";
        +}
        +.icon-ambulance:before {
        +  content: "\f0f9";
        +}
        +.icon-medkit:before {
        +  content: "\f0fa";
        +}
        +.icon-fighter-jet:before {
        +  content: "\f0fb";
        +}
        +.icon-beer:before {
        +  content: "\f0fc";
        +}
        +.icon-h-sign:before {
        +  content: "\f0fd";
        +}
        +.icon-plus-sign-alt:before {
        +  content: "\f0fe";
        +}
        +.icon-double-angle-left:before {
        +  content: "\f100";
        +}
        +.icon-double-angle-right:before {
        +  content: "\f101";
        +}
        +.icon-double-angle-up:before {
        +  content: "\f102";
        +}
        +.icon-double-angle-down:before {
        +  content: "\f103";
        +}
        +.icon-angle-left:before {
        +  content: "\f104";
        +}
        +.icon-angle-right:before {
        +  content: "\f105";
        +}
        +.icon-angle-up:before {
        +  content: "\f106";
        +}
        +.icon-angle-down:before {
        +  content: "\f107";
        +}
        +.icon-desktop:before {
        +  content: "\f108";
        +}
        +.icon-laptop:before {
        +  content: "\f109";
        +}
        +.icon-tablet:before {
        +  content: "\f10a";
        +}
        +.icon-mobile-phone:before {
        +  content: "\f10b";
        +}
        +.icon-circle-blank:before {
        +  content: "\f10c";
        +}
        +.icon-quote-left:before {
        +  content: "\f10d";
        +}
        +.icon-quote-right:before {
        +  content: "\f10e";
        +}
        +.icon-spinner:before {
        +  content: "\f110";
        +}
        +.icon-circle:before {
        +  content: "\f111";
        +}
        +.icon-mail-reply:before,
        +.icon-reply:before {
        +  content: "\f112";
        +}
        +.icon-github-alt:before {
        +  content: "\f113";
        +}
        +.icon-folder-close-alt:before {
        +  content: "\f114";
        +}
        +.icon-folder-open-alt:before {
        +  content: "\f115";
        +}
        +.icon-expand-alt:before {
        +  content: "\f116";
        +}
        +.icon-collapse-alt:before {
        +  content: "\f117";
        +}
        +.icon-smile:before {
        +  content: "\f118";
        +}
        +.icon-frown:before {
        +  content: "\f119";
        +}
        +.icon-meh:before {
        +  content: "\f11a";
        +}
        +.icon-gamepad:before {
        +  content: "\f11b";
        +}
        +.icon-keyboard:before {
        +  content: "\f11c";
        +}
        +.icon-flag-alt:before {
        +  content: "\f11d";
        +}
        +.icon-flag-checkered:before {
        +  content: "\f11e";
        +}
        +.icon-terminal:before {
        +  content: "\f120";
        +}
        +.icon-code:before {
        +  content: "\f121";
        +}
        +.icon-reply-all:before {
        +  content: "\f122";
        +}
        +.icon-mail-reply-all:before {
        +  content: "\f122";
        +}
        +.icon-star-half-full:before,
        +.icon-star-half-empty:before {
        +  content: "\f123";
        +}
        +.icon-location-arrow:before {
        +  content: "\f124";
        +}
        +.icon-crop:before {
        +  content: "\f125";
        +}
        +.icon-code-fork:before {
        +  content: "\f126";
        +}
        +.icon-unlink:before {
        +  content: "\f127";
        +}
        +.icon-question:before {
        +  content: "\f128";
        +}
        +.icon-info:before {
        +  content: "\f129";
        +}
        +.icon-exclamation:before {
        +  content: "\f12a";
        +}
        +.icon-superscript:before {
        +  content: "\f12b";
        +}
        +.icon-subscript:before {
        +  content: "\f12c";
        +}
        +.icon-eraser:before {
        +  content: "\f12d";
        +}
        +.icon-puzzle-piece:before {
        +  content: "\f12e";
        +}
        +.icon-microphone:before {
        +  content: "\f130";
        +}
        +.icon-microphone-off:before {
        +  content: "\f131";
        +}
        +.icon-shield:before {
        +  content: "\f132";
        +}
        +.icon-calendar-empty:before {
        +  content: "\f133";
        +}
        +.icon-fire-extinguisher:before {
        +  content: "\f134";
        +}
        +.icon-rocket:before {
        +  content: "\f135";
        +}
        +.icon-maxcdn:before {
        +  content: "\f136";
        +}
        +.icon-chevron-sign-left:before {
        +  content: "\f137";
        +}
        +.icon-chevron-sign-right:before {
        +  content: "\f138";
        +}
        +.icon-chevron-sign-up:before {
        +  content: "\f139";
        +}
        +.icon-chevron-sign-down:before {
        +  content: "\f13a";
        +}
        +.icon-html5:before {
        +  content: "\f13b";
        +}
        +.icon-css3:before {
        +  content: "\f13c";
        +}
        +.icon-anchor:before {
        +  content: "\f13d";
        +}
        +.icon-unlock-alt:before {
        +  content: "\f13e";
        +}
        +.icon-bullseye:before {
        +  content: "\f140";
        +}
        +.icon-ellipsis-horizontal:before {
        +  content: "\f141";
        +}
        +.icon-ellipsis-vertical:before {
        +  content: "\f142";
        +}
        +.icon-rss-sign:before {
        +  content: "\f143";
        +}
        +.icon-play-sign:before {
        +  content: "\f144";
        +}
        +.icon-ticket:before {
        +  content: "\f145";
        +}
        +.icon-minus-sign-alt:before {
        +  content: "\f146";
        +}
        +.icon-check-minus:before {
        +  content: "\f147";
        +}
        +.icon-level-up:before {
        +  content: "\f148";
        +}
        +.icon-level-down:before {
        +  content: "\f149";
        +}
        +.icon-check-sign:before {
        +  content: "\f14a";
        +}
        +.icon-edit-sign:before {
        +  content: "\f14b";
        +}
        +.icon-external-link-sign:before {
        +  content: "\f14c";
        +}
        +.icon-share-sign:before {
        +  content: "\f14d";
        +}
        +.icon-compass:before {
        +  content: "\f14e";
        +}
        +.icon-collapse:before {
        +  content: "\f150";
        +}
        +.icon-collapse-top:before {
        +  content: "\f151";
        +}
        +.icon-expand:before {
        +  content: "\f152";
        +}
        +.icon-euro:before,
        +.icon-eur:before {
        +  content: "\f153";
        +}
        +.icon-gbp:before {
        +  content: "\f154";
        +}
        +.icon-dollar:before,
        +.icon-usd:before {
        +  content: "\f155";
        +}
        +.icon-rupee:before,
        +.icon-inr:before {
        +  content: "\f156";
        +}
        +.icon-yen:before,
        +.icon-jpy:before {
        +  content: "\f157";
        +}
        +.icon-renminbi:before,
        +.icon-cny:before {
        +  content: "\f158";
        +}
        +.icon-won:before,
        +.icon-krw:before {
        +  content: "\f159";
        +}
        +.icon-bitcoin:before,
        +.icon-btc:before {
        +  content: "\f15a";
        +}
        +.icon-file:before {
        +  content: "\f15b";
        +}
        +.icon-file-text:before {
        +  content: "\f15c";
        +}
        +.icon-sort-by-alphabet:before {
        +  content: "\f15d";
        +}
        +.icon-sort-by-alphabet-alt:before {
        +  content: "\f15e";
        +}
        +.icon-sort-by-attributes:before {
        +  content: "\f160";
        +}
        +.icon-sort-by-attributes-alt:before {
        +  content: "\f161";
        +}
        +.icon-sort-by-order:before {
        +  content: "\f162";
        +}
        +.icon-sort-by-order-alt:before {
        +  content: "\f163";
        +}
        +.icon-thumbs-up:before {
        +  content: "\f164";
        +}
        +.icon-thumbs-down:before {
        +  content: "\f165";
        +}
        +.icon-youtube-sign:before {
        +  content: "\f166";
        +}
        +.icon-youtube:before {
        +  content: "\f167";
        +}
        +.icon-xing:before {
        +  content: "\f168";
        +}
        +.icon-xing-sign:before {
        +  content: "\f169";
        +}
        +.icon-youtube-play:before {
        +  content: "\f16a";
        +}
        +.icon-dropbox:before {
        +  content: "\f16b";
        +}
        +.icon-stackexchange:before {
        +  content: "\f16c";
        +}
        +.icon-instagram:before {
        +  content: "\f16d";
        +}
        +.icon-flickr:before {
        +  content: "\f16e";
        +}
        +.icon-adn:before {
        +  content: "\f170";
        +}
        +.icon-bitbucket:before {
        +  content: "\f171";
        +}
        +.icon-bitbucket-sign:before {
        +  content: "\f172";
        +}
        +.icon-tumblr:before {
        +  content: "\f173";
        +}
        +.icon-tumblr-sign:before {
        +  content: "\f174";
        +}
        +.icon-long-arrow-down:before {
        +  content: "\f175";
        +}
        +.icon-long-arrow-up:before {
        +  content: "\f176";
        +}
        +.icon-long-arrow-left:before {
        +  content: "\f177";
        +}
        +.icon-long-arrow-right:before {
        +  content: "\f178";
        +}
        +.icon-apple:before {
        +  content: "\f179";
        +}
        +.icon-windows:before {
        +  content: "\f17a";
        +}
        +.icon-android:before {
        +  content: "\f17b";
        +}
        +.icon-linux:before {
        +  content: "\f17c";
        +}
        +.icon-dribbble:before {
        +  content: "\f17d";
        +}
        +.icon-skype:before {
        +  content: "\f17e";
        +}
        +.icon-foursquare:before {
        +  content: "\f180";
        +}
        +.icon-trello:before {
        +  content: "\f181";
        +}
        +.icon-female:before {
        +  content: "\f182";
        +}
        +.icon-male:before {
        +  content: "\f183";
        +}
        +.icon-gittip:before {
        +  content: "\f184";
        +}
        +.icon-sun:before {
        +  content: "\f185";
        +}
        +.icon-moon:before {
        +  content: "\f186";
        +}
        +.icon-archive:before {
        +  content: "\f187";
        +}
        +.icon-bug:before {
        +  content: "\f188";
        +}
        +.icon-vk:before {
        +  content: "\f189";
        +}
        +.icon-weibo:before {
        +  content: "\f18a";
        +}
        +.icon-renren:before {
        +  content: "\f18b";
        +}
        diff --git a/themes/demo/assets/vendor/font-awesome/font/FontAwesome.otf b/themes/demo/assets/vendor/font-awesome/font/FontAwesome.otf
        new file mode 100644
        index 0000000..7012545
        Binary files /dev/null and b/themes/demo/assets/vendor/font-awesome/font/FontAwesome.otf differ
        diff --git a/themes/demo/assets/vendor/font-awesome/font/fontawesome-webfont.eot b/themes/demo/assets/vendor/font-awesome/font/fontawesome-webfont.eot
        new file mode 100644
        index 0000000..0662cb9
        Binary files /dev/null and b/themes/demo/assets/vendor/font-awesome/font/fontawesome-webfont.eot differ
        diff --git a/themes/demo/assets/vendor/font-awesome/font/fontawesome-webfont.svg b/themes/demo/assets/vendor/font-awesome/font/fontawesome-webfont.svg
        new file mode 100644
        index 0000000..2edb4ec
        --- /dev/null
        +++ b/themes/demo/assets/vendor/font-awesome/font/fontawesome-webfont.svg
        @@ -0,0 +1,399 @@
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        + 
        \ No newline at end of file
        diff --git a/themes/demo/assets/vendor/font-awesome/font/fontawesome-webfont.ttf b/themes/demo/assets/vendor/font-awesome/font/fontawesome-webfont.ttf
        new file mode 100644
        index 0000000..d365924
        Binary files /dev/null and b/themes/demo/assets/vendor/font-awesome/font/fontawesome-webfont.ttf differ
        diff --git a/themes/demo/assets/vendor/font-awesome/font/fontawesome-webfont.woff b/themes/demo/assets/vendor/font-awesome/font/fontawesome-webfont.woff
        new file mode 100644
        index 0000000..b9bd17e
        Binary files /dev/null and b/themes/demo/assets/vendor/font-awesome/font/fontawesome-webfont.woff differ
        diff --git a/themes/demo/assets/vendor/font-awesome/less/bootstrap.less b/themes/demo/assets/vendor/font-awesome/less/bootstrap.less
        new file mode 100644
        index 0000000..a2c9604
        --- /dev/null
        +++ b/themes/demo/assets/vendor/font-awesome/less/bootstrap.less
        @@ -0,0 +1,84 @@
        +/* BOOTSTRAP SPECIFIC CLASSES
        + * -------------------------- */
        +
        +/* Bootstrap 2.0 sprites.less reset */
        +[class^="icon-"],
        +[class*=" icon-"] {
        +  display: inline;
        +  width: auto;
        +  height: auto;
        +  line-height: normal;
        +  vertical-align: baseline;
        +  background-image: none;
        +  background-position: 0% 0%;
        +  background-repeat: repeat;
        +  margin-top: 0;
        +}
        +
        +/* more sprites.less reset */
        +.icon-white,
        +.nav-pills > .active > a > [class^="icon-"],
        +.nav-pills > .active > a > [class*=" icon-"],
        +.nav-list > .active > a > [class^="icon-"],
        +.nav-list > .active > a > [class*=" icon-"],
        +.navbar-inverse .nav > .active > a > [class^="icon-"],
        +.navbar-inverse .nav > .active > a > [class*=" icon-"],
        +.dropdown-menu > li > a:hover > [class^="icon-"],
        +.dropdown-menu > li > a:hover > [class*=" icon-"],
        +.dropdown-menu > .active > a > [class^="icon-"],
        +.dropdown-menu > .active > a > [class*=" icon-"],
        +.dropdown-submenu:hover > a > [class^="icon-"],
        +.dropdown-submenu:hover > a > [class*=" icon-"] {
        +  background-image: none;
        +}
        +
        +
        +/* keeps Bootstrap styles with and without icons the same */
        +.btn, .nav {
        +  [class^="icon-"],
        +  [class*=" icon-"] {
        +//    display: inline;
        +    &.icon-large { line-height: .9em; }
        +    &.icon-spin { display: inline-block; }
        +  }
        +}
        +.nav-tabs, .nav-pills {
        +  [class^="icon-"],
        +  [class*=" icon-"] {
        +    &, &.icon-large { line-height: .9em; }
        +  }
        +}
        +.btn {
        +  [class^="icon-"],
        +  [class*=" icon-"] {
        +    &.pull-left, &.pull-right {
        +      &.icon-2x { margin-top: .18em; }
        +    }
        +    &.icon-spin.icon-large { line-height: .8em; }
        +  }
        +}
        +.btn.btn-small {
        +  [class^="icon-"],
        +  [class*=" icon-"] {
        +    &.pull-left, &.pull-right {
        +      &.icon-2x { margin-top: .25em; }
        +    }
        +  }
        +}
        +.btn.btn-large {
        +  [class^="icon-"],
        +  [class*=" icon-"] {
        +    margin-top: 0; // overrides bootstrap default
        +    &.pull-left, &.pull-right {
        +      &.icon-2x { margin-top: .05em; }
        +    }
        +    &.pull-left.icon-2x { margin-right: .2em; }
        +    &.pull-right.icon-2x { margin-left: .2em; }
        +  }
        +}
        +
        +/* Fixes alignment in nav lists */
        +.nav-list [class^="icon-"],
        +.nav-list [class*=" icon-"] {
        +  line-height: inherit;
        +}
        diff --git a/themes/demo/assets/vendor/font-awesome/less/core.less b/themes/demo/assets/vendor/font-awesome/less/core.less
        new file mode 100644
        index 0000000..1ef7e22
        --- /dev/null
        +++ b/themes/demo/assets/vendor/font-awesome/less/core.less
        @@ -0,0 +1,129 @@
        +/* FONT AWESOME CORE
        + * -------------------------- */
        +
        +[class^="icon-"],
        +[class*=" icon-"] {
        +  .icon-FontAwesome();
        +}
        +
        +[class^="icon-"]:before,
        +[class*=" icon-"]:before {
        +  text-decoration: inherit;
        +  display: inline-block;
        +  speak: none;
        +}
        +
        +/* makes the font 33% larger relative to the icon container */
        +.icon-large:before {
        +  vertical-align: -10%;
        +  font-size: 4/3em;
        +}
        +
        +/* makes sure icons active on rollover in links */
        +a {
        +  [class^="icon-"],
        +  [class*=" icon-"] {
        +    display: inline;
        +  }
        +}
        +
        +/* increased font size for icon-large */
        +[class^="icon-"],
        +[class*=" icon-"] {
        +  &.icon-fixed-width {
        +    display: inline-block;
        +    width: 16/14em;
        +    text-align: right;
        +    padding-right: 4/14em;
        +    &.icon-large {
        +      width: 20/14em;
        +    }
        +  }
        +}
        +
        +.icons-ul {
        +  margin-left: @icons-li-width;
        +  list-style-type: none;
        +
        +  > li { position: relative; }
        +
        +  .icon-li {
        +    position: absolute;
        +    left: -@icons-li-width;
        +    width: @icons-li-width;
        +    text-align: center;
        +    line-height: inherit;
        +  }
        +}
        +
        +// allows usage of the hide class directly on font awesome icons
        +[class^="icon-"],
        +[class*=" icon-"] {
        +  &.hide {
        +    display: none;
        +  }
        +}
        +
        +.icon-muted { color: @iconMuted; }
        +.icon-light { color: @iconLight; }
        +.icon-dark { color: @iconDark; }
        +
        +// Icon Borders
        +// -------------------------
        +
        +.icon-border {
        +  border: solid 1px @borderColor;
        +  padding: .2em .25em .15em;
        +  .border-radius(3px);
        +}
        +
        +// Icon Sizes
        +// -------------------------
        +
        +.icon-2x {
        +  font-size: 2em;
        +  &.icon-border {
        +    border-width: 2px;
        +    .border-radius(4px);
        +  }
        +}
        +.icon-3x {
        +  font-size: 3em;
        +  &.icon-border {
        +    border-width: 3px;
        +    .border-radius(5px);
        +  }
        +}
        +.icon-4x {
        +  font-size: 4em;
        +  &.icon-border {
        +    border-width: 4px;
        +    .border-radius(6px);
        +  }
        +}
        +
        +.icon-5x {
        +  font-size: 5em;
        +  &.icon-border {
        +    border-width: 5px;
        +    .border-radius(7px);
        +  }
        +}
        +
        +
        +// Floats & Margins
        +// -------------------------
        +
        +// Quick floats
        +.pull-right { float: right; }
        +.pull-left { float: left; }
        +
        +[class^="icon-"],
        +[class*=" icon-"] {
        +  &.pull-left {
        +    margin-right: .3em;
        +  }
        +  &.pull-right {
        +    margin-left: .3em;
        +  }
        +}
        diff --git a/themes/demo/assets/vendor/font-awesome/less/extras.less b/themes/demo/assets/vendor/font-awesome/less/extras.less
        new file mode 100644
        index 0000000..c93c260
        --- /dev/null
        +++ b/themes/demo/assets/vendor/font-awesome/less/extras.less
        @@ -0,0 +1,93 @@
        +/* EXTRAS
        + * -------------------------- */
        +
        +/* Stacked and layered icon */
        +.icon-stack();
        +
        +/* Animated rotating icon */
        +.icon-spin {
        +  display: inline-block;
        +  -moz-animation: spin 2s infinite linear;
        +  -o-animation: spin 2s infinite linear;
        +  -webkit-animation: spin 2s infinite linear;
        +  animation: spin 2s infinite linear;
        +}
        +
        +/* Prevent stack and spinners from being taken inline when inside a link */
        +a .icon-stack,
        +a .icon-spin {
        +  display: inline-block;
        +  text-decoration: none;
        +}
        +
        +@-moz-keyframes spin {
        +  0% { -moz-transform: rotate(0deg); }
        +  100% { -moz-transform: rotate(359deg); }
        +}
        +@-webkit-keyframes spin {
        +  0% { -webkit-transform: rotate(0deg); }
        +  100% { -webkit-transform: rotate(359deg); }
        +}
        +@-o-keyframes spin {
        +  0% { -o-transform: rotate(0deg); }
        +  100% { -o-transform: rotate(359deg); }
        +}
        +@-ms-keyframes spin {
        +  0% { -ms-transform: rotate(0deg); }
        +  100% { -ms-transform: rotate(359deg); }
        +}
        +@keyframes spin {
        +  0% { transform: rotate(0deg); }
        +  100% { transform: rotate(359deg); }
        +}
        +
        +/* Icon rotations and mirroring */
        +.icon-rotate-90:before {
        +  -webkit-transform: rotate(90deg);
        +  -moz-transform: rotate(90deg);
        +  -ms-transform: rotate(90deg);
        +  -o-transform: rotate(90deg);
        +  transform: rotate(90deg);
        +  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
        +}
        +
        +.icon-rotate-180:before {
        +  -webkit-transform: rotate(180deg);
        +  -moz-transform: rotate(180deg);
        +  -ms-transform: rotate(180deg);
        +  -o-transform: rotate(180deg);
        +  transform: rotate(180deg);
        +  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
        +}
        +
        +.icon-rotate-270:before {
        +  -webkit-transform: rotate(270deg);
        +  -moz-transform: rotate(270deg);
        +  -ms-transform: rotate(270deg);
        +  -o-transform: rotate(270deg);
        +  transform: rotate(270deg);
        +  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
        +}
        +
        +.icon-flip-horizontal:before {
        +  -webkit-transform: scale(-1, 1);
        +  -moz-transform: scale(-1, 1);
        +  -ms-transform: scale(-1, 1);
        +  -o-transform: scale(-1, 1);
        +  transform: scale(-1, 1);
        +}
        +
        +.icon-flip-vertical:before {
        +  -webkit-transform: scale(1, -1);
        +  -moz-transform: scale(1, -1);
        +  -ms-transform: scale(1, -1);
        +  -o-transform: scale(1, -1);
        +  transform: scale(1, -1);
        +}
        +
        +/* ensure rotation occurs inside anchor tags */
        +a {
        +  .icon-rotate-90, .icon-rotate-180, .icon-rotate-270, .icon-flip-horizontal, .icon-flip-vertical {
        +    &:before { display: inline-block; }
        +  }
        +}
        diff --git a/themes/demo/assets/vendor/font-awesome/less/font-awesome-ie7.less b/themes/demo/assets/vendor/font-awesome/less/font-awesome-ie7.less
        new file mode 100644
        index 0000000..6675c49
        --- /dev/null
        +++ b/themes/demo/assets/vendor/font-awesome/less/font-awesome-ie7.less
        @@ -0,0 +1,1953 @@
        +/*!
        + *  Font Awesome 3.2.1
        + *  the iconic font designed for Bootstrap
        + *  ------------------------------------------------------------------------------
        + *  The full suite of pictographic icons, examples, and documentation can be
        + *  found at http://fontawesome.io.  Stay up to date on Twitter at
        + *  http://twitter.com/fontawesome.
        + *
        + *  License
        + *  ------------------------------------------------------------------------------
        + *  - The Font Awesome font is licensed under SIL OFL 1.1 -
        + *    http://scripts.sil.org/OFL
        + *  - Font Awesome CSS, LESS, and SASS files are licensed under MIT License -
        + *    http://opensource.org/licenses/mit-license.html
        + *  - Font Awesome documentation licensed under CC BY 3.0 -
        + *    http://creativecommons.org/licenses/by/3.0/
        + *  - Attribution is no longer required in Font Awesome 3.0, but much appreciated:
        + *    "Font Awesome by Dave Gandy - http://fontawesome.io"
        + *
        + *  Author - Dave Gandy
        + *  ------------------------------------------------------------------------------
        + *  Email: dave@fontawesome.io
        + *  Twitter: http://twitter.com/davegandy
        + *  Work: Lead Product Designer @ Kyruus - http://kyruus.com
        + */
        +
        +.icon-large {
        +  font-size: 4/3em;
        +  margin-top: -4px;
        +  padding-top: 3px;
        +  margin-bottom: -4px;
        +  padding-bottom: 3px;
        +  vertical-align: middle;
        +}
        +
        +.nav {
        +  [class^="icon-"],
        +  [class*=" icon-"] {
        +    vertical-align: inherit;
        +    margin-top: -4px;
        +    padding-top: 3px;
        +    margin-bottom: -4px;
        +    padding-bottom: 3px;
        +    &.icon-large {
        +      vertical-align: -25%;
        +    }
        +  }
        +}
        +
        +.nav-pills, .nav-tabs {
        +  [class^="icon-"],
        +  [class*=" icon-"] {
        +    &.icon-large {
        +      line-height: .75em;
        +      margin-top: -7px;
        +      padding-top: 5px;
        +      margin-bottom: -5px;
        +      padding-bottom: 4px;
        +    }
        +  }
        +}
        +
        +.btn {
        +  [class^="icon-"],
        +  [class*=" icon-"] {
        +    &.pull-left, &.pull-right { vertical-align: inherit; }
        +    &.icon-large {
        +      margin-top: -.5em;
        +    }
        +  }
        +}
        +
        +a [class^="icon-"],
        +a [class*=" icon-"] {
        +  cursor: pointer;
        +}
        +
        +.ie7icon(@inner) { *zoom: ~"expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '@{inner}')"; }
        +
        +
        +.icon-glass {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-music {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-search {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-envelope-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-heart {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-star {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-star-empty {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-user {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-film {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-th-large {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-th {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-th-list {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-ok {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-remove {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-zoom-in {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-zoom-out {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-off {
        +  .ie7icon('');
        +}
        +
        +.icon-power-off {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-signal {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-cog {
        +  .ie7icon('');
        +}
        +
        +.icon-gear {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-trash {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-home {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-file-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-time {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-road {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-download-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-download {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-upload {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-inbox {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-play-circle {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-repeat {
        +  .ie7icon('');
        +}
        +
        +.icon-rotate-right {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-refresh {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-list-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-lock {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-flag {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-headphones {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-volume-off {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-volume-down {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-volume-up {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-qrcode {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-barcode {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-tag {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-tags {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-book {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-bookmark {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-print {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-camera {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-font {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-bold {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-italic {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-text-height {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-text-width {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-align-left {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-align-center {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-align-right {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-align-justify {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-list {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-indent-left {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-indent-right {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-facetime-video {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-picture {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-pencil {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-map-marker {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-adjust {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-tint {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-edit {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-share {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-check {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-move {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-step-backward {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-fast-backward {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-backward {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-play {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-pause {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-stop {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-forward {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-fast-forward {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-step-forward {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-eject {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-chevron-left {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-chevron-right {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-plus-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-minus-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-remove-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-ok-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-question-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-info-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-screenshot {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-remove-circle {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-ok-circle {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-ban-circle {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-arrow-left {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-arrow-right {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-arrow-up {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-arrow-down {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-share-alt {
        +  .ie7icon('');
        +}
        +
        +.icon-mail-forward {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-resize-full {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-resize-small {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-plus {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-minus {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-asterisk {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-exclamation-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-gift {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-leaf {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-fire {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-eye-open {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-eye-close {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-warning-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-plane {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-calendar {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-random {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-comment {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-magnet {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-chevron-up {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-chevron-down {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-retweet {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-shopping-cart {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-folder-close {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-folder-open {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-resize-vertical {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-resize-horizontal {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-bar-chart {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-twitter-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-facebook-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-camera-retro {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-key {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-cogs {
        +  .ie7icon('');
        +}
        +
        +.icon-gears {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-comments {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-thumbs-up-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-thumbs-down-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-star-half {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-heart-empty {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-signout {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-linkedin-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-pushpin {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-external-link {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-signin {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-trophy {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-github-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-upload-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-lemon {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-phone {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-check-empty {
        +  .ie7icon('');
        +}
        +
        +.icon-unchecked {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-bookmark-empty {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-phone-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-twitter {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-facebook {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-github {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-unlock {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-credit-card {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-rss {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-hdd {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-bullhorn {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-bell {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-certificate {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-hand-right {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-hand-left {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-hand-up {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-hand-down {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-circle-arrow-left {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-circle-arrow-right {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-circle-arrow-up {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-circle-arrow-down {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-globe {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-wrench {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-tasks {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-filter {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-briefcase {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-fullscreen {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-group {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-link {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-cloud {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-beaker {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-cut {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-copy {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-paper-clip {
        +  .ie7icon('');
        +}
        +
        +.icon-paperclip {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-save {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-sign-blank {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-reorder {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-list-ul {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-list-ol {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-strikethrough {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-underline {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-table {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-magic {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-truck {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-pinterest {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-pinterest-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-google-plus-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-google-plus {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-money {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-caret-down {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-caret-up {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-caret-left {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-caret-right {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-columns {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-sort {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-sort-down {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-sort-up {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-envelope {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-linkedin {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-undo {
        +  .ie7icon('');
        +}
        +
        +.icon-rotate-left {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-legal {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-dashboard {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-comment-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-comments-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-bolt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-sitemap {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-umbrella {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-paste {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-lightbulb {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-exchange {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-cloud-download {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-cloud-upload {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-user-md {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-stethoscope {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-suitcase {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-bell-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-coffee {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-food {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-file-text-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-building {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-hospital {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-ambulance {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-medkit {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-fighter-jet {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-beer {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-h-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-plus-sign-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-double-angle-left {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-double-angle-right {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-double-angle-up {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-double-angle-down {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-angle-left {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-angle-right {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-angle-up {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-angle-down {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-desktop {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-laptop {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-tablet {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-mobile-phone {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-circle-blank {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-quote-left {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-quote-right {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-spinner {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-circle {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-reply {
        +  .ie7icon('');
        +}
        +
        +.icon-mail-reply {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-github-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-folder-close-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-folder-open-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-expand-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-collapse-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-smile {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-frown {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-meh {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-gamepad {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-keyboard {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-flag-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-flag-checkered {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-terminal {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-code {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-reply-all {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-mail-reply-all {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-star-half-empty {
        +  .ie7icon('');
        +}
        +
        +.icon-star-half-full {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-location-arrow {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-crop {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-code-fork {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-unlink {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-question {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-info {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-exclamation {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-superscript {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-subscript {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-eraser {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-puzzle-piece {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-microphone {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-microphone-off {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-shield {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-calendar-empty {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-fire-extinguisher {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-rocket {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-maxcdn {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-chevron-sign-left {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-chevron-sign-right {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-chevron-sign-up {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-chevron-sign-down {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-html5 {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-css3 {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-anchor {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-unlock-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-bullseye {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-ellipsis-horizontal {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-ellipsis-vertical {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-rss-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-play-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-ticket {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-minus-sign-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-check-minus {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-level-up {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-level-down {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-check-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-edit-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-external-link-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-share-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-compass {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-collapse {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-collapse-top {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-expand {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-eur {
        +  .ie7icon('');
        +}
        +
        +.icon-euro {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-gbp {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-usd {
        +  .ie7icon('');
        +}
        +
        +.icon-dollar {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-inr {
        +  .ie7icon('');
        +}
        +
        +.icon-rupee {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-jpy {
        +  .ie7icon('');
        +}
        +
        +.icon-yen {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-cny {
        +  .ie7icon('');
        +}
        +
        +.icon-renminbi {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-krw {
        +  .ie7icon('');
        +}
        +
        +.icon-won {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-btc {
        +  .ie7icon('');
        +}
        +
        +.icon-bitcoin {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-file {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-file-text {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-sort-by-alphabet {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-sort-by-alphabet-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-sort-by-attributes {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-sort-by-attributes-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-sort-by-order {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-sort-by-order-alt {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-thumbs-up {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-thumbs-down {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-youtube-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-youtube {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-xing {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-xing-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-youtube-play {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-dropbox {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-stackexchange {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-instagram {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-flickr {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-adn {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-bitbucket {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-bitbucket-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-tumblr {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-tumblr-sign {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-long-arrow-down {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-long-arrow-up {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-long-arrow-left {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-long-arrow-right {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-apple {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-windows {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-android {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-linux {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-dribbble {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-skype {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-foursquare {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-trello {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-female {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-male {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-gittip {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-sun {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-moon {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-archive {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-bug {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-vk {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-weibo {
        +  .ie7icon('');
        +}
        +
        +
        +.icon-renren {
        +  .ie7icon('');
        +}
        +
        +
        diff --git a/themes/demo/assets/vendor/font-awesome/less/font-awesome.less b/themes/demo/assets/vendor/font-awesome/less/font-awesome.less
        new file mode 100644
        index 0000000..0f45461
        --- /dev/null
        +++ b/themes/demo/assets/vendor/font-awesome/less/font-awesome.less
        @@ -0,0 +1,33 @@
        +/*!
        + *  Font Awesome 3.2.1
        + *  the iconic font designed for Bootstrap
        + *  ------------------------------------------------------------------------------
        + *  The full suite of pictographic icons, examples, and documentation can be
        + *  found at http://fontawesome.io.  Stay up to date on Twitter at
        + *  http://twitter.com/fontawesome.
        + *
        + *  License
        + *  ------------------------------------------------------------------------------
        + *  - The Font Awesome font is licensed under SIL OFL 1.1 -
        + *    http://scripts.sil.org/OFL
        + *  - Font Awesome CSS, LESS, and SASS files are licensed under MIT License -
        + *    http://opensource.org/licenses/mit-license.html
        + *  - Font Awesome documentation licensed under CC BY 3.0 -
        + *    http://creativecommons.org/licenses/by/3.0/
        + *  - Attribution is no longer required in Font Awesome 3.0, but much appreciated:
        + *    "Font Awesome by Dave Gandy - http://fontawesome.io"
        + *
        + *  Author - Dave Gandy
        + *  ------------------------------------------------------------------------------
        + *  Email: dave@fontawesome.io
        + *  Twitter: http://twitter.com/davegandy
        + *  Work: Lead Product Designer @ Kyruus - http://kyruus.com
        + */
        +
        +@import "variables.less";
        +@import "mixins.less";
        +@import "path.less";
        +@import "core.less";
        +@import "bootstrap.less";
        +@import "extras.less";
        +@import "icons.less";
        diff --git a/themes/demo/assets/vendor/font-awesome/less/icons.less b/themes/demo/assets/vendor/font-awesome/less/icons.less
        new file mode 100644
        index 0000000..476d201
        --- /dev/null
        +++ b/themes/demo/assets/vendor/font-awesome/less/icons.less
        @@ -0,0 +1,381 @@
        +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
        +   readers do not read off random characters that represent icons */
        +
        +.icon-glass:before { content: @glass; }
        +.icon-music:before { content: @music; }
        +.icon-search:before { content: @search; }
        +.icon-envelope-alt:before { content: @envelope-alt; }
        +.icon-heart:before { content: @heart; }
        +.icon-star:before { content: @star; }
        +.icon-star-empty:before { content: @star-empty; }
        +.icon-user:before { content: @user; }
        +.icon-film:before { content: @film; }
        +.icon-th-large:before { content: @th-large; }
        +.icon-th:before { content: @th; }
        +.icon-th-list:before { content: @th-list; }
        +.icon-ok:before { content: @ok; }
        +.icon-remove:before { content: @remove; }
        +.icon-zoom-in:before { content: @zoom-in; }
        +.icon-zoom-out:before { content: @zoom-out; }
        +.icon-power-off:before,
        +.icon-off:before { content: @off; }
        +.icon-signal:before { content: @signal; }
        +.icon-gear:before,
        +.icon-cog:before { content: @cog; }
        +.icon-trash:before { content: @trash; }
        +.icon-home:before { content: @home; }
        +.icon-file-alt:before { content: @file-alt; }
        +.icon-time:before { content: @time; }
        +.icon-road:before { content: @road; }
        +.icon-download-alt:before { content: @download-alt; }
        +.icon-download:before { content: @download; }
        +.icon-upload:before { content: @upload; }
        +.icon-inbox:before { content: @inbox; }
        +.icon-play-circle:before { content: @play-circle; }
        +.icon-rotate-right:before,
        +.icon-repeat:before { content: @repeat; }
        +.icon-refresh:before { content: @refresh; }
        +.icon-list-alt:before { content: @list-alt; }
        +.icon-lock:before { content: @lock; }
        +.icon-flag:before { content: @flag; }
        +.icon-headphones:before { content: @headphones; }
        +.icon-volume-off:before { content: @volume-off; }
        +.icon-volume-down:before { content: @volume-down; }
        +.icon-volume-up:before { content: @volume-up; }
        +.icon-qrcode:before { content: @qrcode; }
        +.icon-barcode:before { content: @barcode; }
        +.icon-tag:before { content: @tag; }
        +.icon-tags:before { content: @tags; }
        +.icon-book:before { content: @book; }
        +.icon-bookmark:before { content: @bookmark; }
        +.icon-print:before { content: @print; }
        +.icon-camera:before { content: @camera; }
        +.icon-font:before { content: @font; }
        +.icon-bold:before { content: @bold; }
        +.icon-italic:before { content: @italic; }
        +.icon-text-height:before { content: @text-height; }
        +.icon-text-width:before { content: @text-width; }
        +.icon-align-left:before { content: @align-left; }
        +.icon-align-center:before { content: @align-center; }
        +.icon-align-right:before { content: @align-right; }
        +.icon-align-justify:before { content: @align-justify; }
        +.icon-list:before { content: @list; }
        +.icon-indent-left:before { content: @indent-left; }
        +.icon-indent-right:before { content: @indent-right; }
        +.icon-facetime-video:before { content: @facetime-video; }
        +.icon-picture:before { content: @picture; }
        +.icon-pencil:before { content: @pencil; }
        +.icon-map-marker:before { content: @map-marker; }
        +.icon-adjust:before { content: @adjust; }
        +.icon-tint:before { content: @tint; }
        +.icon-edit:before { content: @edit; }
        +.icon-share:before { content: @share; }
        +.icon-check:before { content: @check; }
        +.icon-move:before { content: @move; }
        +.icon-step-backward:before { content: @step-backward; }
        +.icon-fast-backward:before { content: @fast-backward; }
        +.icon-backward:before { content: @backward; }
        +.icon-play:before { content: @play; }
        +.icon-pause:before { content: @pause; }
        +.icon-stop:before { content: @stop; }
        +.icon-forward:before { content: @forward; }
        +.icon-fast-forward:before { content: @fast-forward; }
        +.icon-step-forward:before { content: @step-forward; }
        +.icon-eject:before { content: @eject; }
        +.icon-chevron-left:before { content: @chevron-left; }
        +.icon-chevron-right:before { content: @chevron-right; }
        +.icon-plus-sign:before { content: @plus-sign; }
        +.icon-minus-sign:before { content: @minus-sign; }
        +.icon-remove-sign:before { content: @remove-sign; }
        +.icon-ok-sign:before { content: @ok-sign; }
        +.icon-question-sign:before { content: @question-sign; }
        +.icon-info-sign:before { content: @info-sign; }
        +.icon-screenshot:before { content: @screenshot; }
        +.icon-remove-circle:before { content: @remove-circle; }
        +.icon-ok-circle:before { content: @ok-circle; }
        +.icon-ban-circle:before { content: @ban-circle; }
        +.icon-arrow-left:before { content: @arrow-left; }
        +.icon-arrow-right:before { content: @arrow-right; }
        +.icon-arrow-up:before { content: @arrow-up; }
        +.icon-arrow-down:before { content: @arrow-down; }
        +.icon-mail-forward:before,
        +.icon-share-alt:before { content: @share-alt; }
        +.icon-resize-full:before { content: @resize-full; }
        +.icon-resize-small:before { content: @resize-small; }
        +.icon-plus:before { content: @plus; }
        +.icon-minus:before { content: @minus; }
        +.icon-asterisk:before { content: @asterisk; }
        +.icon-exclamation-sign:before { content: @exclamation-sign; }
        +.icon-gift:before { content: @gift; }
        +.icon-leaf:before { content: @leaf; }
        +.icon-fire:before { content: @fire; }
        +.icon-eye-open:before { content: @eye-open; }
        +.icon-eye-close:before { content: @eye-close; }
        +.icon-warning-sign:before { content: @warning-sign; }
        +.icon-plane:before { content: @plane; }
        +.icon-calendar:before { content: @calendar; }
        +.icon-random:before { content: @random; }
        +.icon-comment:before { content: @comment; }
        +.icon-magnet:before { content: @magnet; }
        +.icon-chevron-up:before { content: @chevron-up; }
        +.icon-chevron-down:before { content: @chevron-down; }
        +.icon-retweet:before { content: @retweet; }
        +.icon-shopping-cart:before { content: @shopping-cart; }
        +.icon-folder-close:before { content: @folder-close; }
        +.icon-folder-open:before { content: @folder-open; }
        +.icon-resize-vertical:before { content: @resize-vertical; }
        +.icon-resize-horizontal:before { content: @resize-horizontal; }
        +.icon-bar-chart:before { content: @bar-chart; }
        +.icon-twitter-sign:before { content: @twitter-sign; }
        +.icon-facebook-sign:before { content: @facebook-sign; }
        +.icon-camera-retro:before { content: @camera-retro; }
        +.icon-key:before { content: @key; }
        +.icon-gears:before,
        +.icon-cogs:before { content: @cogs; }
        +.icon-comments:before { content: @comments; }
        +.icon-thumbs-up-alt:before { content: @thumbs-up-alt; }
        +.icon-thumbs-down-alt:before { content: @thumbs-down-alt; }
        +.icon-star-half:before { content: @star-half; }
        +.icon-heart-empty:before { content: @heart-empty; }
        +.icon-signout:before { content: @signout; }
        +.icon-linkedin-sign:before { content: @linkedin-sign; }
        +.icon-pushpin:before { content: @pushpin; }
        +.icon-external-link:before { content: @external-link; }
        +.icon-signin:before { content: @signin; }
        +.icon-trophy:before { content: @trophy; }
        +.icon-github-sign:before { content: @github-sign; }
        +.icon-upload-alt:before { content: @upload-alt; }
        +.icon-lemon:before { content: @lemon; }
        +.icon-phone:before { content: @phone; }
        +.icon-unchecked:before,
        +.icon-check-empty:before { content: @check-empty; }
        +.icon-bookmark-empty:before { content: @bookmark-empty; }
        +.icon-phone-sign:before { content: @phone-sign; }
        +.icon-twitter:before { content: @twitter; }
        +.icon-facebook:before { content: @facebook; }
        +.icon-github:before { content: @github; }
        +.icon-unlock:before { content: @unlock; }
        +.icon-credit-card:before { content: @credit-card; }
        +.icon-rss:before { content: @rss; }
        +.icon-hdd:before { content: @hdd; }
        +.icon-bullhorn:before { content: @bullhorn; }
        +.icon-bell:before { content: @bell; }
        +.icon-certificate:before { content: @certificate; }
        +.icon-hand-right:before { content: @hand-right; }
        +.icon-hand-left:before { content: @hand-left; }
        +.icon-hand-up:before { content: @hand-up; }
        +.icon-hand-down:before { content: @hand-down; }
        +.icon-circle-arrow-left:before { content: @circle-arrow-left; }
        +.icon-circle-arrow-right:before { content: @circle-arrow-right; }
        +.icon-circle-arrow-up:before { content: @circle-arrow-up; }
        +.icon-circle-arrow-down:before { content: @circle-arrow-down; }
        +.icon-globe:before { content: @globe; }
        +.icon-wrench:before { content: @wrench; }
        +.icon-tasks:before { content: @tasks; }
        +.icon-filter:before { content: @filter; }
        +.icon-briefcase:before { content: @briefcase; }
        +.icon-fullscreen:before { content: @fullscreen; }
        +.icon-group:before { content: @group; }
        +.icon-link:before { content: @link; }
        +.icon-cloud:before { content: @cloud; }
        +.icon-beaker:before { content: @beaker; }
        +.icon-cut:before { content: @cut; }
        +.icon-copy:before { content: @copy; }
        +.icon-paperclip:before,
        +.icon-paper-clip:before { content: @paper-clip; }
        +.icon-save:before { content: @save; }
        +.icon-sign-blank:before { content: @sign-blank; }
        +.icon-reorder:before { content: @reorder; }
        +.icon-list-ul:before { content: @list-ul; }
        +.icon-list-ol:before { content: @list-ol; }
        +.icon-strikethrough:before { content: @strikethrough; }
        +.icon-underline:before { content: @underline; }
        +.icon-table:before { content: @table; }
        +.icon-magic:before { content: @magic; }
        +.icon-truck:before { content: @truck; }
        +.icon-pinterest:before { content: @pinterest; }
        +.icon-pinterest-sign:before { content: @pinterest-sign; }
        +.icon-google-plus-sign:before { content: @google-plus-sign; }
        +.icon-google-plus:before { content: @google-plus; }
        +.icon-money:before { content: @money; }
        +.icon-caret-down:before { content: @caret-down; }
        +.icon-caret-up:before { content: @caret-up; }
        +.icon-caret-left:before { content: @caret-left; }
        +.icon-caret-right:before { content: @caret-right; }
        +.icon-columns:before { content: @columns; }
        +.icon-sort:before { content: @sort; }
        +.icon-sort-down:before { content: @sort-down; }
        +.icon-sort-up:before { content: @sort-up; }
        +.icon-envelope:before { content: @envelope; }
        +.icon-linkedin:before { content: @linkedin; }
        +.icon-rotate-left:before,
        +.icon-undo:before { content: @undo; }
        +.icon-legal:before { content: @legal; }
        +.icon-dashboard:before { content: @dashboard; }
        +.icon-comment-alt:before { content: @comment-alt; }
        +.icon-comments-alt:before { content: @comments-alt; }
        +.icon-bolt:before { content: @bolt; }
        +.icon-sitemap:before { content: @sitemap; }
        +.icon-umbrella:before { content: @umbrella; }
        +.icon-paste:before { content: @paste; }
        +.icon-lightbulb:before { content: @lightbulb; }
        +.icon-exchange:before { content: @exchange; }
        +.icon-cloud-download:before { content: @cloud-download; }
        +.icon-cloud-upload:before { content: @cloud-upload; }
        +.icon-user-md:before { content: @user-md; }
        +.icon-stethoscope:before { content: @stethoscope; }
        +.icon-suitcase:before { content: @suitcase; }
        +.icon-bell-alt:before { content: @bell-alt; }
        +.icon-coffee:before { content: @coffee; }
        +.icon-food:before { content: @food; }
        +.icon-file-text-alt:before { content: @file-text-alt; }
        +.icon-building:before { content: @building; }
        +.icon-hospital:before { content: @hospital; }
        +.icon-ambulance:before { content: @ambulance; }
        +.icon-medkit:before { content: @medkit; }
        +.icon-fighter-jet:before { content: @fighter-jet; }
        +.icon-beer:before { content: @beer; }
        +.icon-h-sign:before { content: @h-sign; }
        +.icon-plus-sign-alt:before { content: @plus-sign-alt; }
        +.icon-double-angle-left:before { content: @double-angle-left; }
        +.icon-double-angle-right:before { content: @double-angle-right; }
        +.icon-double-angle-up:before { content: @double-angle-up; }
        +.icon-double-angle-down:before { content: @double-angle-down; }
        +.icon-angle-left:before { content: @angle-left; }
        +.icon-angle-right:before { content: @angle-right; }
        +.icon-angle-up:before { content: @angle-up; }
        +.icon-angle-down:before { content: @angle-down; }
        +.icon-desktop:before { content: @desktop; }
        +.icon-laptop:before { content: @laptop; }
        +.icon-tablet:before { content: @tablet; }
        +.icon-mobile-phone:before { content: @mobile-phone; }
        +.icon-circle-blank:before { content: @circle-blank; }
        +.icon-quote-left:before { content: @quote-left; }
        +.icon-quote-right:before { content: @quote-right; }
        +.icon-spinner:before { content: @spinner; }
        +.icon-circle:before { content: @circle; }
        +.icon-mail-reply:before,
        +.icon-reply:before { content: @reply; }
        +.icon-github-alt:before { content: @github-alt; }
        +.icon-folder-close-alt:before { content: @folder-close-alt; }
        +.icon-folder-open-alt:before { content: @folder-open-alt; }
        +.icon-expand-alt:before { content: @expand-alt; }
        +.icon-collapse-alt:before { content: @collapse-alt; }
        +.icon-smile:before { content: @smile; }
        +.icon-frown:before { content: @frown; }
        +.icon-meh:before { content: @meh; }
        +.icon-gamepad:before { content: @gamepad; }
        +.icon-keyboard:before { content: @keyboard; }
        +.icon-flag-alt:before { content: @flag-alt; }
        +.icon-flag-checkered:before { content: @flag-checkered; }
        +.icon-terminal:before { content: @terminal; }
        +.icon-code:before { content: @code; }
        +.icon-reply-all:before { content: @reply-all; }
        +.icon-mail-reply-all:before { content: @mail-reply-all; }
        +.icon-star-half-full:before,
        +.icon-star-half-empty:before { content: @star-half-empty; }
        +.icon-location-arrow:before { content: @location-arrow; }
        +.icon-crop:before { content: @crop; }
        +.icon-code-fork:before { content: @code-fork; }
        +.icon-unlink:before { content: @unlink; }
        +.icon-question:before { content: @question; }
        +.icon-info:before { content: @info; }
        +.icon-exclamation:before { content: @exclamation; }
        +.icon-superscript:before { content: @superscript; }
        +.icon-subscript:before { content: @subscript; }
        +.icon-eraser:before { content: @eraser; }
        +.icon-puzzle-piece:before { content: @puzzle-piece; }
        +.icon-microphone:before { content: @microphone; }
        +.icon-microphone-off:before { content: @microphone-off; }
        +.icon-shield:before { content: @shield; }
        +.icon-calendar-empty:before { content: @calendar-empty; }
        +.icon-fire-extinguisher:before { content: @fire-extinguisher; }
        +.icon-rocket:before { content: @rocket; }
        +.icon-maxcdn:before { content: @maxcdn; }
        +.icon-chevron-sign-left:before { content: @chevron-sign-left; }
        +.icon-chevron-sign-right:before { content: @chevron-sign-right; }
        +.icon-chevron-sign-up:before { content: @chevron-sign-up; }
        +.icon-chevron-sign-down:before { content: @chevron-sign-down; }
        +.icon-html5:before { content: @html5; }
        +.icon-css3:before { content: @css3; }
        +.icon-anchor:before { content: @anchor; }
        +.icon-unlock-alt:before { content: @unlock-alt; }
        +.icon-bullseye:before { content: @bullseye; }
        +.icon-ellipsis-horizontal:before { content: @ellipsis-horizontal; }
        +.icon-ellipsis-vertical:before { content: @ellipsis-vertical; }
        +.icon-rss-sign:before { content: @rss-sign; }
        +.icon-play-sign:before { content: @play-sign; }
        +.icon-ticket:before { content: @ticket; }
        +.icon-minus-sign-alt:before { content: @minus-sign-alt; }
        +.icon-check-minus:before { content: @check-minus; }
        +.icon-level-up:before { content: @level-up; }
        +.icon-level-down:before { content: @level-down; }
        +.icon-check-sign:before { content: @check-sign; }
        +.icon-edit-sign:before { content: @edit-sign; }
        +.icon-external-link-sign:before { content: @external-link-sign; }
        +.icon-share-sign:before { content: @share-sign; }
        +.icon-compass:before { content: @compass; }
        +.icon-collapse:before { content: @collapse; }
        +.icon-collapse-top:before { content: @collapse-top; }
        +.icon-expand:before { content: @expand; }
        +.icon-euro:before,
        +.icon-eur:before { content: @eur; }
        +.icon-gbp:before { content: @gbp; }
        +.icon-dollar:before,
        +.icon-usd:before { content: @usd; }
        +.icon-rupee:before,
        +.icon-inr:before { content: @inr; }
        +.icon-yen:before,
        +.icon-jpy:before { content: @jpy; }
        +.icon-renminbi:before,
        +.icon-cny:before { content: @cny; }
        +.icon-won:before,
        +.icon-krw:before { content: @krw; }
        +.icon-bitcoin:before,
        +.icon-btc:before { content: @btc; }
        +.icon-file:before { content: @file; }
        +.icon-file-text:before { content: @file-text; }
        +.icon-sort-by-alphabet:before { content: @sort-by-alphabet; }
        +.icon-sort-by-alphabet-alt:before { content: @sort-by-alphabet-alt; }
        +.icon-sort-by-attributes:before { content: @sort-by-attributes; }
        +.icon-sort-by-attributes-alt:before { content: @sort-by-attributes-alt; }
        +.icon-sort-by-order:before { content: @sort-by-order; }
        +.icon-sort-by-order-alt:before { content: @sort-by-order-alt; }
        +.icon-thumbs-up:before { content: @thumbs-up; }
        +.icon-thumbs-down:before { content: @thumbs-down; }
        +.icon-youtube-sign:before { content: @youtube-sign; }
        +.icon-youtube:before { content: @youtube; }
        +.icon-xing:before { content: @xing; }
        +.icon-xing-sign:before { content: @xing-sign; }
        +.icon-youtube-play:before { content: @youtube-play; }
        +.icon-dropbox:before { content: @dropbox; }
        +.icon-stackexchange:before { content: @stackexchange; }
        +.icon-instagram:before { content: @instagram; }
        +.icon-flickr:before { content: @flickr; }
        +.icon-adn:before { content: @adn; }
        +.icon-bitbucket:before { content: @bitbucket; }
        +.icon-bitbucket-sign:before { content: @bitbucket-sign; }
        +.icon-tumblr:before { content: @tumblr; }
        +.icon-tumblr-sign:before { content: @tumblr-sign; }
        +.icon-long-arrow-down:before { content: @long-arrow-down; }
        +.icon-long-arrow-up:before { content: @long-arrow-up; }
        +.icon-long-arrow-left:before { content: @long-arrow-left; }
        +.icon-long-arrow-right:before { content: @long-arrow-right; }
        +.icon-apple:before { content: @apple; }
        +.icon-windows:before { content: @windows; }
        +.icon-android:before { content: @android; }
        +.icon-linux:before { content: @linux; }
        +.icon-dribbble:before { content: @dribbble; }
        +.icon-skype:before { content: @skype; }
        +.icon-foursquare:before { content: @foursquare; }
        +.icon-trello:before { content: @trello; }
        +.icon-female:before { content: @female; }
        +.icon-male:before { content: @male; }
        +.icon-gittip:before { content: @gittip; }
        +.icon-sun:before { content: @sun; }
        +.icon-moon:before { content: @moon; }
        +.icon-archive:before { content: @archive; }
        +.icon-bug:before { content: @bug; }
        +.icon-vk:before { content: @vk; }
        +.icon-weibo:before { content: @weibo; }
        +.icon-renren:before { content: @renren; }
        diff --git a/themes/demo/assets/vendor/font-awesome/less/mixins.less b/themes/demo/assets/vendor/font-awesome/less/mixins.less
        new file mode 100644
        index 0000000..9478aae
        --- /dev/null
        +++ b/themes/demo/assets/vendor/font-awesome/less/mixins.less
        @@ -0,0 +1,47 @@
        +// Mixins
        +// --------------------------
        +
        +.icon(@icon) {
        +  .icon-FontAwesome();
        +  content: @icon;
        +}
        +
        +.icon-FontAwesome() {
        +  font-family: FontAwesome;
        +  font-weight: normal;
        +  font-style: normal;
        +  text-decoration: inherit;
        +  -webkit-font-smoothing: antialiased;
        +}
        +
        +.border-radius(@radius) {
        +  -webkit-border-radius: @radius;
        +  -moz-border-radius: @radius;
        +  border-radius: @radius;
        +}
        +
        +.icon-stack(@width: 2em, @height: 2em, @top-font-size: 1em, @base-font-size: 2em) {
        +  .icon-stack {
        +    position: relative;
        +    display: inline-block;
        +    width: @width;
        +    height: @height;
        +    line-height: @width;
        +    vertical-align: -35%;
        +    [class^="icon-"],
        +    [class*=" icon-"] {
        +      display: block;
        +      text-align: center;
        +      position: absolute;
        +      width: 100%;
        +      height: 100%;
        +      font-size: @top-font-size;
        +      line-height: inherit;
        +      *line-height: @height;
        +    }
        +    .icon-stack-base {
        +      font-size: @base-font-size;
        +      *line-height: @height / @base-font-size;
        +    }
        +  }
        +}
        diff --git a/themes/demo/assets/vendor/font-awesome/less/path.less b/themes/demo/assets/vendor/font-awesome/less/path.less
        new file mode 100644
        index 0000000..8ccef8c
        --- /dev/null
        +++ b/themes/demo/assets/vendor/font-awesome/less/path.less
        @@ -0,0 +1,14 @@
        +/* FONT PATH
        + * -------------------------- */
        +
        +@font-face {
        +  font-family: 'FontAwesome';
        +  src: url('@{FontAwesomePath}/fontawesome-webfont.eot?v=@{FontAwesomeVersion}');
        +  src: url('@{FontAwesomePath}/fontawesome-webfont.eot?#iefix&v=@{FontAwesomeVersion}') format('embedded-opentype'),
        +    url('@{FontAwesomePath}/fontawesome-webfont.woff?v=@{FontAwesomeVersion}') format('woff'),
        +    url('@{FontAwesomePath}/fontawesome-webfont.ttf?v=@{FontAwesomeVersion}') format('truetype'),
        +    url('@{FontAwesomePath}/fontawesome-webfont.svg#fontawesomeregular?v=@{FontAwesomeVersion}') format('svg');
        +//  src: url('@{FontAwesomePath}/FontAwesome.otf') format('opentype'); // used when developing fonts
        +  font-weight: normal;
        +  font-style: normal;
        +}
        diff --git a/themes/demo/assets/vendor/font-awesome/less/variables.less b/themes/demo/assets/vendor/font-awesome/less/variables.less
        new file mode 100644
        index 0000000..9d0879b
        --- /dev/null
        +++ b/themes/demo/assets/vendor/font-awesome/less/variables.less
        @@ -0,0 +1,735 @@
        +// Variables
        +// --------------------------
        +
        +@FontAwesomePath:    "../font";
        +//@FontAwesomePath:    "//netdna.bootstrapcdn.com/font-awesome/3.2.1/font"; // for referencing Bootstrap CDN font files directly
        +@FontAwesomeVersion: "3.2.1";
        +@borderColor:        #eee;
        +@iconMuted:          #eee;
        +@iconLight:          #fff;
        +@iconDark:           #333;
        +@icons-li-width:     30/14em;
        +
        +
        +  @glass: "\f000";
        +
        +  @music: "\f001";
        +
        +  @search: "\f002";
        +
        +  @envelope-alt: "\f003";
        +
        +  @heart: "\f004";
        +
        +  @star: "\f005";
        +
        +  @star-empty: "\f006";
        +
        +  @user: "\f007";
        +
        +  @film: "\f008";
        +
        +  @th-large: "\f009";
        +
        +  @th: "\f00a";
        +
        +  @th-list: "\f00b";
        +
        +  @ok: "\f00c";
        +
        +  @remove: "\f00d";
        +
        +  @zoom-in: "\f00e";
        +
        +  @zoom-out: "\f010";
        +
        +  @off: "\f011";
        +
        +  @signal: "\f012";
        +
        +  @cog: "\f013";
        +
        +  @trash: "\f014";
        +
        +  @home: "\f015";
        +
        +  @file-alt: "\f016";
        +
        +  @time: "\f017";
        +
        +  @road: "\f018";
        +
        +  @download-alt: "\f019";
        +
        +  @download: "\f01a";
        +
        +  @upload: "\f01b";
        +
        +  @inbox: "\f01c";
        +
        +  @play-circle: "\f01d";
        +
        +  @repeat: "\f01e";
        +
        +  @refresh: "\f021";
        +
        +  @list-alt: "\f022";
        +
        +  @lock: "\f023";
        +
        +  @flag: "\f024";
        +
        +  @headphones: "\f025";
        +
        +  @volume-off: "\f026";
        +
        +  @volume-down: "\f027";
        +
        +  @volume-up: "\f028";
        +
        +  @qrcode: "\f029";
        +
        +  @barcode: "\f02a";
        +
        +  @tag: "\f02b";
        +
        +  @tags: "\f02c";
        +
        +  @book: "\f02d";
        +
        +  @bookmark: "\f02e";
        +
        +  @print: "\f02f";
        +
        +  @camera: "\f030";
        +
        +  @font: "\f031";
        +
        +  @bold: "\f032";
        +
        +  @italic: "\f033";
        +
        +  @text-height: "\f034";
        +
        +  @text-width: "\f035";
        +
        +  @align-left: "\f036";
        +
        +  @align-center: "\f037";
        +
        +  @align-right: "\f038";
        +
        +  @align-justify: "\f039";
        +
        +  @list: "\f03a";
        +
        +  @indent-left: "\f03b";
        +
        +  @indent-right: "\f03c";
        +
        +  @facetime-video: "\f03d";
        +
        +  @picture: "\f03e";
        +
        +  @pencil: "\f040";
        +
        +  @map-marker: "\f041";
        +
        +  @adjust: "\f042";
        +
        +  @tint: "\f043";
        +
        +  @edit: "\f044";
        +
        +  @share: "\f045";
        +
        +  @check: "\f046";
        +
        +  @move: "\f047";
        +
        +  @step-backward: "\f048";
        +
        +  @fast-backward: "\f049";
        +
        +  @backward: "\f04a";
        +
        +  @play: "\f04b";
        +
        +  @pause: "\f04c";
        +
        +  @stop: "\f04d";
        +
        +  @forward: "\f04e";
        +
        +  @fast-forward: "\f050";
        +
        +  @step-forward: "\f051";
        +
        +  @eject: "\f052";
        +
        +  @chevron-left: "\f053";
        +
        +  @chevron-right: "\f054";
        +
        +  @plus-sign: "\f055";
        +
        +  @minus-sign: "\f056";
        +
        +  @remove-sign: "\f057";
        +
        +  @ok-sign: "\f058";
        +
        +  @question-sign: "\f059";
        +
        +  @info-sign: "\f05a";
        +
        +  @screenshot: "\f05b";
        +
        +  @remove-circle: "\f05c";
        +
        +  @ok-circle: "\f05d";
        +
        +  @ban-circle: "\f05e";
        +
        +  @arrow-left: "\f060";
        +
        +  @arrow-right: "\f061";
        +
        +  @arrow-up: "\f062";
        +
        +  @arrow-down: "\f063";
        +
        +  @share-alt: "\f064";
        +
        +  @resize-full: "\f065";
        +
        +  @resize-small: "\f066";
        +
        +  @plus: "\f067";
        +
        +  @minus: "\f068";
        +
        +  @asterisk: "\f069";
        +
        +  @exclamation-sign: "\f06a";
        +
        +  @gift: "\f06b";
        +
        +  @leaf: "\f06c";
        +
        +  @fire: "\f06d";
        +
        +  @eye-open: "\f06e";
        +
        +  @eye-close: "\f070";
        +
        +  @warning-sign: "\f071";
        +
        +  @plane: "\f072";
        +
        +  @calendar: "\f073";
        +
        +  @random: "\f074";
        +
        +  @comment: "\f075";
        +
        +  @magnet: "\f076";
        +
        +  @chevron-up: "\f077";
        +
        +  @chevron-down: "\f078";
        +
        +  @retweet: "\f079";
        +
        +  @shopping-cart: "\f07a";
        +
        +  @folder-close: "\f07b";
        +
        +  @folder-open: "\f07c";
        +
        +  @resize-vertical: "\f07d";
        +
        +  @resize-horizontal: "\f07e";
        +
        +  @bar-chart: "\f080";
        +
        +  @twitter-sign: "\f081";
        +
        +  @facebook-sign: "\f082";
        +
        +  @camera-retro: "\f083";
        +
        +  @key: "\f084";
        +
        +  @cogs: "\f085";
        +
        +  @comments: "\f086";
        +
        +  @thumbs-up-alt: "\f087";
        +
        +  @thumbs-down-alt: "\f088";
        +
        +  @star-half: "\f089";
        +
        +  @heart-empty: "\f08a";
        +
        +  @signout: "\f08b";
        +
        +  @linkedin-sign: "\f08c";
        +
        +  @pushpin: "\f08d";
        +
        +  @external-link: "\f08e";
        +
        +  @signin: "\f090";
        +
        +  @trophy: "\f091";
        +
        +  @github-sign: "\f092";
        +
        +  @upload-alt: "\f093";
        +
        +  @lemon: "\f094";
        +
        +  @phone: "\f095";
        +
        +  @check-empty: "\f096";
        +
        +  @bookmark-empty: "\f097";
        +
        +  @phone-sign: "\f098";
        +
        +  @twitter: "\f099";
        +
        +  @facebook: "\f09a";
        +
        +  @github: "\f09b";
        +
        +  @unlock: "\f09c";
        +
        +  @credit-card: "\f09d";
        +
        +  @rss: "\f09e";
        +
        +  @hdd: "\f0a0";
        +
        +  @bullhorn: "\f0a1";
        +
        +  @bell: "\f0a2";
        +
        +  @certificate: "\f0a3";
        +
        +  @hand-right: "\f0a4";
        +
        +  @hand-left: "\f0a5";
        +
        +  @hand-up: "\f0a6";
        +
        +  @hand-down: "\f0a7";
        +
        +  @circle-arrow-left: "\f0a8";
        +
        +  @circle-arrow-right: "\f0a9";
        +
        +  @circle-arrow-up: "\f0aa";
        +
        +  @circle-arrow-down: "\f0ab";
        +
        +  @globe: "\f0ac";
        +
        +  @wrench: "\f0ad";
        +
        +  @tasks: "\f0ae";
        +
        +  @filter: "\f0b0";
        +
        +  @briefcase: "\f0b1";
        +
        +  @fullscreen: "\f0b2";
        +
        +  @group: "\f0c0";
        +
        +  @link: "\f0c1";
        +
        +  @cloud: "\f0c2";
        +
        +  @beaker: "\f0c3";
        +
        +  @cut: "\f0c4";
        +
        +  @copy: "\f0c5";
        +
        +  @paper-clip: "\f0c6";
        +
        +  @save: "\f0c7";
        +
        +  @sign-blank: "\f0c8";
        +
        +  @reorder: "\f0c9";
        +
        +  @list-ul: "\f0ca";
        +
        +  @list-ol: "\f0cb";
        +
        +  @strikethrough: "\f0cc";
        +
        +  @underline: "\f0cd";
        +
        +  @table: "\f0ce";
        +
        +  @magic: "\f0d0";
        +
        +  @truck: "\f0d1";
        +
        +  @pinterest: "\f0d2";
        +
        +  @pinterest-sign: "\f0d3";
        +
        +  @google-plus-sign: "\f0d4";
        +
        +  @google-plus: "\f0d5";
        +
        +  @money: "\f0d6";
        +
        +  @caret-down: "\f0d7";
        +
        +  @caret-up: "\f0d8";
        +
        +  @caret-left: "\f0d9";
        +
        +  @caret-right: "\f0da";
        +
        +  @columns: "\f0db";
        +
        +  @sort: "\f0dc";
        +
        +  @sort-down: "\f0dd";
        +
        +  @sort-up: "\f0de";
        +
        +  @envelope: "\f0e0";
        +
        +  @linkedin: "\f0e1";
        +
        +  @undo: "\f0e2";
        +
        +  @legal: "\f0e3";
        +
        +  @dashboard: "\f0e4";
        +
        +  @comment-alt: "\f0e5";
        +
        +  @comments-alt: "\f0e6";
        +
        +  @bolt: "\f0e7";
        +
        +  @sitemap: "\f0e8";
        +
        +  @umbrella: "\f0e9";
        +
        +  @paste: "\f0ea";
        +
        +  @lightbulb: "\f0eb";
        +
        +  @exchange: "\f0ec";
        +
        +  @cloud-download: "\f0ed";
        +
        +  @cloud-upload: "\f0ee";
        +
        +  @user-md: "\f0f0";
        +
        +  @stethoscope: "\f0f1";
        +
        +  @suitcase: "\f0f2";
        +
        +  @bell-alt: "\f0f3";
        +
        +  @coffee: "\f0f4";
        +
        +  @food: "\f0f5";
        +
        +  @file-text-alt: "\f0f6";
        +
        +  @building: "\f0f7";
        +
        +  @hospital: "\f0f8";
        +
        +  @ambulance: "\f0f9";
        +
        +  @medkit: "\f0fa";
        +
        +  @fighter-jet: "\f0fb";
        +
        +  @beer: "\f0fc";
        +
        +  @h-sign: "\f0fd";
        +
        +  @plus-sign-alt: "\f0fe";
        +
        +  @double-angle-left: "\f100";
        +
        +  @double-angle-right: "\f101";
        +
        +  @double-angle-up: "\f102";
        +
        +  @double-angle-down: "\f103";
        +
        +  @angle-left: "\f104";
        +
        +  @angle-right: "\f105";
        +
        +  @angle-up: "\f106";
        +
        +  @angle-down: "\f107";
        +
        +  @desktop: "\f108";
        +
        +  @laptop: "\f109";
        +
        +  @tablet: "\f10a";
        +
        +  @mobile-phone: "\f10b";
        +
        +  @circle-blank: "\f10c";
        +
        +  @quote-left: "\f10d";
        +
        +  @quote-right: "\f10e";
        +
        +  @spinner: "\f110";
        +
        +  @circle: "\f111";
        +
        +  @reply: "\f112";
        +
        +  @github-alt: "\f113";
        +
        +  @folder-close-alt: "\f114";
        +
        +  @folder-open-alt: "\f115";
        +
        +  @expand-alt: "\f116";
        +
        +  @collapse-alt: "\f117";
        +
        +  @smile: "\f118";
        +
        +  @frown: "\f119";
        +
        +  @meh: "\f11a";
        +
        +  @gamepad: "\f11b";
        +
        +  @keyboard: "\f11c";
        +
        +  @flag-alt: "\f11d";
        +
        +  @flag-checkered: "\f11e";
        +
        +  @terminal: "\f120";
        +
        +  @code: "\f121";
        +
        +  @reply-all: "\f122";
        +
        +  @mail-reply-all: "\f122";
        +
        +  @star-half-empty: "\f123";
        +
        +  @location-arrow: "\f124";
        +
        +  @crop: "\f125";
        +
        +  @code-fork: "\f126";
        +
        +  @unlink: "\f127";
        +
        +  @question: "\f128";
        +
        +  @info: "\f129";
        +
        +  @exclamation: "\f12a";
        +
        +  @superscript: "\f12b";
        +
        +  @subscript: "\f12c";
        +
        +  @eraser: "\f12d";
        +
        +  @puzzle-piece: "\f12e";
        +
        +  @microphone: "\f130";
        +
        +  @microphone-off: "\f131";
        +
        +  @shield: "\f132";
        +
        +  @calendar-empty: "\f133";
        +
        +  @fire-extinguisher: "\f134";
        +
        +  @rocket: "\f135";
        +
        +  @maxcdn: "\f136";
        +
        +  @chevron-sign-left: "\f137";
        +
        +  @chevron-sign-right: "\f138";
        +
        +  @chevron-sign-up: "\f139";
        +
        +  @chevron-sign-down: "\f13a";
        +
        +  @html5: "\f13b";
        +
        +  @css3: "\f13c";
        +
        +  @anchor: "\f13d";
        +
        +  @unlock-alt: "\f13e";
        +
        +  @bullseye: "\f140";
        +
        +  @ellipsis-horizontal: "\f141";
        +
        +  @ellipsis-vertical: "\f142";
        +
        +  @rss-sign: "\f143";
        +
        +  @play-sign: "\f144";
        +
        +  @ticket: "\f145";
        +
        +  @minus-sign-alt: "\f146";
        +
        +  @check-minus: "\f147";
        +
        +  @level-up: "\f148";
        +
        +  @level-down: "\f149";
        +
        +  @check-sign: "\f14a";
        +
        +  @edit-sign: "\f14b";
        +
        +  @external-link-sign: "\f14c";
        +
        +  @share-sign: "\f14d";
        +
        +  @compass: "\f14e";
        +
        +  @collapse: "\f150";
        +
        +  @collapse-top: "\f151";
        +
        +  @expand: "\f152";
        +
        +  @eur: "\f153";
        +
        +  @gbp: "\f154";
        +
        +  @usd: "\f155";
        +
        +  @inr: "\f156";
        +
        +  @jpy: "\f157";
        +
        +  @cny: "\f158";
        +
        +  @krw: "\f159";
        +
        +  @btc: "\f15a";
        +
        +  @file: "\f15b";
        +
        +  @file-text: "\f15c";
        +
        +  @sort-by-alphabet: "\f15d";
        +
        +  @sort-by-alphabet-alt: "\f15e";
        +
        +  @sort-by-attributes: "\f160";
        +
        +  @sort-by-attributes-alt: "\f161";
        +
        +  @sort-by-order: "\f162";
        +
        +  @sort-by-order-alt: "\f163";
        +
        +  @thumbs-up: "\f164";
        +
        +  @thumbs-down: "\f165";
        +
        +  @youtube-sign: "\f166";
        +
        +  @youtube: "\f167";
        +
        +  @xing: "\f168";
        +
        +  @xing-sign: "\f169";
        +
        +  @youtube-play: "\f16a";
        +
        +  @dropbox: "\f16b";
        +
        +  @stackexchange: "\f16c";
        +
        +  @instagram: "\f16d";
        +
        +  @flickr: "\f16e";
        +
        +  @adn: "\f170";
        +
        +  @bitbucket: "\f171";
        +
        +  @bitbucket-sign: "\f172";
        +
        +  @tumblr: "\f173";
        +
        +  @tumblr-sign: "\f174";
        +
        +  @long-arrow-down: "\f175";
        +
        +  @long-arrow-up: "\f176";
        +
        +  @long-arrow-left: "\f177";
        +
        +  @long-arrow-right: "\f178";
        +
        +  @apple: "\f179";
        +
        +  @windows: "\f17a";
        +
        +  @android: "\f17b";
        +
        +  @linux: "\f17c";
        +
        +  @dribbble: "\f17d";
        +
        +  @skype: "\f17e";
        +
        +  @foursquare: "\f180";
        +
        +  @trello: "\f181";
        +
        +  @female: "\f182";
        +
        +  @male: "\f183";
        +
        +  @gittip: "\f184";
        +
        +  @sun: "\f185";
        +
        +  @moon: "\f186";
        +
        +  @archive: "\f187";
        +
        +  @bug: "\f188";
        +
        +  @vk: "\f189";
        +
        +  @weibo: "\f18a";
        +
        +  @renren: "\f18b";
        +
        diff --git a/themes/demo/assets/vendor/jquery.js b/themes/demo/assets/vendor/jquery.js
        new file mode 100644
        index 0000000..cea868b
        --- /dev/null
        +++ b/themes/demo/assets/vendor/jquery.js
        @@ -0,0 +1,2 @@
        +/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
        +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
        ",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="
        ","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
        a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,"
        ","
        "],area:[1,"",""],param:[1,"",""],thead:[1,"","
        "],tr:[2,"","
        "],col:[2,"","
        "],td:[3,"","
        "],_default:k.htmlSerialize?[0,"",""]:[1,"X
        ","
        "]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("